基礎 字元裝置驅動框架
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include "hello.h"
MODULE_LICENSE("GPL");
int hello_major = 250;
int hello_minor = 0;
int number_of_devices = 2;
struct hello_device{
char data[128];
struct cdev cdev;
}hello_devices[2];
#define to_hello_t(d) container_of(d, struct hello_device, cdev)
dev_t devno;
static int hello_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO"Hey! device opened\n");
struct hello_device *hello = to_hello_t(inode->i_cdev);
file->private_data = hello;
printk("hello address %p\n", hello);
return 0;
}
static int hello_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO"Hmmm! device closed \n");
return 0;
}
ssize_t hello_read(struct file *file, char *buff, size_t count, loff_t *offp)
{
char str_buf[100] = "";
printk(KERN_INFO"hello read address %p\n", file->private_data);
sprintf(str_buf, "hello read %p", file->private_data);
copy_to_user(buff, str_buf, strlen(str_buf));
return strlen(str_buf); /*return 0 errno*/
}
ssize_t hello_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
ssize_t ret = 0;
char data[100] = "";
#if __dump_stack__
printk("dump_stack start\n");
dump_stack();
printk("dump_stack end \n");
#endif
if(count > 127) return -ENOMEM;
if(copy_from_user(data, buf, count))
{
ret = -EFAULT;
}
else
{
data[count] = '\0';
printk(KERN_INFO"Received: %s\n", data);
ret = count;
}
return ret;
}
long hello_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
switch(cmd)
{
case HELLO_ONE:
printk(KERN_INFO"HELLO_ONE called\n");
break;
case HELLO_TWO:
if(!capable(CAP_SYS_ADMIN))
return -EPERM;
printk(KERN_INFO"HELLO_TWO called\n");
break;
case HELLO_TRE:
{
node_t tmp;
copy_from_user(&tmp, (void*)arg, sizeof(tmp));
printk(KERN_INFO"node_t.a %d node_t.b %d \n", tmp.a, tmp.b);
break;
}
default:
printk(KERN_INFO"CMD is invalude\n");
return -EINVAL;
}
return ret;
}
struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write,
.unlocked_ioctl = hello_ioctl
};
static void char_reg_setup_cdev(dev_t devno)
{
int error;
cdev_init(&hello_devices[0].cdev, &hello_fops);
hello_devices[0].cdev.owner = THIS_MODULE;
cdev_init(&hello_devices[1].cdev, &hello_fops);
hello_devices[1].cdev.owner = THIS_MODULE;
error = cdev_add(&hello_devices[0].cdev, devno, 1);
if(error)
printk(KERN_NOTICE"Error %d adding char_reg_setup_cdev", error);
error = cdev_add(&hello_devices[1].cdev, devno+1, 1);
if(error){
printk(KERN_NOTICE"Error %d adding char_reg_setup_cdev", error);
cdev_del(&hello_devices[0].cdev);
}
}
static int __init hello_2_init(void) /*__init 在模組中失去意義*/
{
int result;
devno = MKDEV(hello_major, hello_minor);
result = register_chrdev_region(devno, number_of_devices, "hello_device");
if(result < 0 )
{
printk(KERN_WARNING"Registered character driver\n");
return result;
}
char_reg_setup_cdev(devno);
printk(KERN_INFO"Registered character driver\n");
printk(KERN_INFO"hello address %p hello address %p \n", &hello_devices[0], &hello_devices[1]);
return 0;
}
static void __exit hello_2_exit(void) /*__exit 在模組中失去意義*/
{
cdev_del(&hello_devices[0].cdev);
cdev_del(&hello_devices[1].cdev);
unregister_chrdev_region(devno, number_of_devices);
printk(KERN_INFO"Char driver cleaned up\n");
}
module_init(hello_2_init);
module_exit(hello_2_exit);