diff --git a/Linux/KernelDriver/3.2/Char/demo_char.c b/Linux/KernelDriver/3.2/Char/demo_char.c index 8d7e1cc..5890320 100644 --- a/Linux/KernelDriver/3.2/Char/demo_char.c +++ b/Linux/KernelDriver/3.2/Char/demo_char.c @@ -32,15 +32,17 @@ MODULE_LICENSE("GPL"); #define DEMO_CTL_MAX 5 #define DEMO_MODULE_NAME "demo_char" +#define DEMO_DEV_CNT 2 + static int demo_major = 0; struct demo_dev { struct cdev cdev; - struct class *uclass; - struct device *udevice; + struct device *dev; }; +struct class *class; struct demo_dev* demo_devp; static int demo_open(struct inode *inode, struct file* filp) @@ -149,57 +151,88 @@ static struct file_operations demo_fops = { .mmap = demo_mmap }; +static int demo_setup_cdev(struct demo_dev *devp, int index) +{ + char name[16]; + int err, devno = MKDEV(demo_major, index); + + cdev_init(&devp->cdev, &demo_fops); + devp->cdev.owner = THIS_MODULE; + devp->cdev.ops = &demo_fops; + err = cdev_add(&devp->cdev, devno, 1); + if(err) + { + printk(KERN_ERR "Error(%d) %d.\r\n", index, err); + goto out_cdev; + } + + memset(name, 0, 16); + sprintf(name, DEMO_MODULE_NAME"%d", index); + printk(KERN_INFO "New dev name:%s", name); + devp->dev = device_create(class, NULL, devp->cdev.dev, NULL, name); + return 0; +out_cdev: + cdev_del(&devp->cdev); + kfree(devp); + return err; +} + static int __init demo_init(void) { - int result; + int err, i; dev_t devno = MKDEV(demo_major, 0); if(demo_major) - result = register_chrdev_region(devno, 1, DEMO_MODULE_NAME); + err = register_chrdev_region(devno, DEMO_DEV_CNT, DEMO_MODULE_NAME); else { - result = alloc_chrdev_region(&devno, 0, 1, DEMO_MODULE_NAME); + err = alloc_chrdev_region(&devno, 0, DEMO_DEV_CNT, DEMO_MODULE_NAME); demo_major = MAJOR(devno); } - if(result < 0) - return result; + if(err<0) + return err; - demo_devp = kzalloc(sizeof(struct demo_dev), GFP_KERNEL); - if (!demo_devp) + demo_devp = kzalloc(DEMO_DEV_CNT*sizeof(struct demo_dev), GFP_KERNEL); + if(!demo_devp) { - result = - ENOMEM; - goto out_kmalloc; + err = -ENOMEM; + goto out; } - cdev_init(&demo_devp->cdev, &demo_fops); - demo_devp->cdev.owner = THIS_MODULE; - demo_devp->cdev.ops = &demo_fops; - result = cdev_add(&demo_devp->cdev, devno, 1); - if(result) + class = class_create(THIS_MODULE, DEMO_MODULE_NAME); + for(i=0; iuclass = class_create(THIS_MODULE, DEMO_MODULE_NAME); - demo_devp->udevice = device_create(demo_devp->uclass, NULL, demo_devp->cdev.dev, NULL, DEMO_MODULE_NAME"0"); return 0; -out_cdev: - cdev_del(&demo_devp->cdev); - kfree(demo_devp); -out_kmalloc: - unregister_chrdev_region(devno, 1); - return result; + +out_class: + class_destroy(class); +out: + unregister_chrdev_region(devno, DEMO_DEV_CNT); + return err; +} + +static void demo_clean_cdev(struct demo_dev *devp) +{ + device_destroy(class, devp->cdev.dev); + cdev_del(&devp->cdev); } static void __exit demo_exit(void) { - device_destroy(demo_devp->uclass, demo_devp->cdev.dev); - class_destroy(demo_devp->uclass); - cdev_del(&demo_devp->cdev); + int i; + + for(i=0; i #include +#include +#include +#include + MODULE_AUTHOR("Rick Chan"); MODULE_LICENSE("GPL"); @@ -41,9 +30,27 @@ MODULE_LICENSE("GPL"); #define DEMO_CTL_IOW _IOW(DEMO_MAGIC, 3, int32_t) #define DEMO_CTL_IOWR _IOWR(DEMO_MAGIC, 4, uint32_t) #define DEMO_CTL_MAX 5 +#define DEMO_MODULE_NAME "demo_char" + +#define DEMO_DEV_CNT 2 + +static int demo_major = 0; + +struct demo_dev +{ + struct cdev cdev; + struct device *dev; +}; + +struct class *class; +struct demo_dev* demo_devp; static int demo_open(struct inode *inode, struct file* filp) { + struct demo_dev *demo; + demo = container_of(inode->i_cdev, struct demo_dev, cdev); + filp->private_data = demo; + return 0; } @@ -54,41 +61,41 @@ static int demo_release(struct inode *inode, struct file* filp) static loff_t demo_llseek(struct file *filp, loff_t offset, int origin) { + struct demo_dev *devp = filp->private_data; + + (void)devp; return filp->f_pos; } static ssize_t demo_read(struct file *filp, char __user *buffer, size_t count, loff_t *offset) { + struct demo_dev *devp = filp->private_data; const char __user *p = buffer; + + (void)devp; return p-buffer; } static ssize_t demo_write(struct file *filp, const char __user *buffer, size_t count, loff_t *offset) { + struct demo_dev *devp = filp->private_data; const char __user *p = buffer; + + (void)devp; return p-buffer; } static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - static int err = 0; + struct demo_dev *devp = filp->private_data; + (void)devp; - // 检测 cmd 合法性. - if(DEMO_MAGIC!=_IOC_TYPE(cmd)) + // 检测 cmd 合法性 + if (DEMO_MAGIC!=_IOC_TYPE(cmd)) return -EINVAL; - if(DEMO_CTL_MAX<_IOC_NR(cmd)) + if (DEMO_CTL_MAX<_IOC_NR(cmd)) return -EINVAL; - // 根据命令类型, 检测参数空间是否可以访问. - if(_IOC_DIR(cmd)&_IOC_READ) - err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); - else if(_IOC_DIR(cmd)&_IOC_WRITE) - err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); - - if (err) - return -EFAULT; - - // 根据命令, 来选择执行哪个分支. switch(cmd) { case DEMO_CTL_IOC: @@ -127,6 +134,9 @@ static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static int demo_mmap(struct file* filp, struct vm_area_struct* vma) { + struct demo_dev *devp = filp->private_data; + (void)devp; + return 0; } @@ -141,22 +151,91 @@ static struct file_operations demo_fops = { .mmap = demo_mmap }; -static struct miscdevice demo_dev = { - .minor = MISC_DYNAMIC_MINOR, // Dynamically allocate minor. - .name = "demo_misc", - .fops = &demo_fops, -}; +static int demo_setup_cdev(struct demo_dev *devp, int index) +{ + char name[16]; + int err, devno = MKDEV(demo_major, index); + + cdev_init(&devp->cdev, &demo_fops); + devp->cdev.owner = THIS_MODULE; + devp->cdev.ops = &demo_fops; + err = cdev_add(&devp->cdev, devno, 1); + if(err) + { + printk(KERN_ERR "Error(%d) %d.\r\n", index, err); + goto out_cdev; + } + + memset(name, 0, 16); + sprintf(name, DEMO_MODULE_NAME"%d", index); + printk(KERN_INFO "New dev name:%s", name); + devp->dev = device_create(class, NULL, devp->cdev.dev, NULL, name); + return 0; +out_cdev: + cdev_del(&devp->cdev); + kfree(devp); + return err; +} static int __init demo_init(void) { - misc_register(&demo_dev); // 注册混杂设备驱动. + int err, i; + dev_t devno = MKDEV(demo_major, 0); + + if(demo_major) + err = register_chrdev_region(devno, DEMO_DEV_CNT, DEMO_MODULE_NAME); + else + { + err = alloc_chrdev_region(&devno, 0, DEMO_DEV_CNT, DEMO_MODULE_NAME); + demo_major = MAJOR(devno); + } + + if(err<0) + return err; + + demo_devp = kzalloc(DEMO_DEV_CNT*sizeof(struct demo_dev), GFP_KERNEL); + if(!demo_devp) + { + err = -ENOMEM; + goto out; + } + + class = class_create(THIS_MODULE, DEMO_MODULE_NAME); + for(i=0; icdev.dev); + cdev_del(&devp->cdev); } static void __exit demo_exit(void) { - misc_deregister(&demo_dev); // 撤销混杂设备驱动. + int i; + + for(i=0; i