diff --git a/Linux/KernelDriver/Misc/demo_misc.c b/Linux/KernelDriver/Misc/demo_misc.c index 57be1c6..f59bc11 100644 --- a/Linux/KernelDriver/Misc/demo_misc.c +++ b/Linux/KernelDriver/Misc/demo_misc.c @@ -2,10 +2,25 @@ * @file demo_misc.c * @author Rick Chan (cy187lion@sina.com) * @brief Linux misc driver demo. - * @version 0.1 - * @date 2019-10-15 + 在 Linux 驱动中,会把一些无法归类的设备定义为混杂设备,它们是拥 + 有着共同的特性的简单字符设备。它们的特点是共享统一的主设备号 10, + 但每个设备可以选择一个单独的次设备号。 + + 通常情况下,一个字符设备都不得不在初始化的过程中进行下面的步骤: + + 1.通过alloc_chrdev_region()分配主/次设备号 + 2.使用cdev_init()和cdev_add()来以一个字符设备注册自己 + + 而一个misc驱动,则可以只用一个调用misc_register()来完成这所有 + 的步骤。 + + 所有的 miscdevice 设备形成一个链表,对设备访问时,内核根据次设 + 备号查找对应的 miscdevice 设备,然后调用其 file_operations + 中注册的文件操作方法进行操作。 + * @version 0.1.1 + * @date 2020-04-27 * - * @copyright Copyright (c) 2019 + * @copyright Copyright (c) 2020 * */ #include @@ -17,12 +32,14 @@ MODULE_AUTHOR("Rick Chan"); MODULE_LICENSE("GPL"); -#define IOCTL_IOC_SIZE 8 -#define IOCTL_IOC _IOC(_IOC_READ|_IOC_WRITE, 0, 0, IOCTL_IOC_SIZE) -#define IOCTL_IO _IO(0, 1) -#define IOCTL_IOR _IOR(0, 2, uint16_t) -#define IOCTL_IOW _IOW(0, 3, int32_t) -#define IOCTL_IOWR _IOWR(0, 4, uint32_t) +#define DEMO_MAGIC 'R' +#define DEMO_IOC_SIZE 8 +#define DEMO_CTL_IOC _IOC(_IOC_READ|_IOC_WRITE, DEMO_MAGIC, 0, DEMO_IOC_SIZE) +#define DEMO_CTL_IO _IO(DEMO_MAGIC, 1) +#define DEMO_CTL_IOR _IOR(DEMO_MAGIC, 2, uint16_t) +#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 static int demo_open(struct inode *inode, struct file* filp) { @@ -53,30 +70,48 @@ static ssize_t demo_write(struct file *filp, const char __user *buffer, size_t c static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + static int err = 0; + + // 检测 cmd 合法性. + if(DEMO_MAGIC!=_IOC_TYPE(cmd)) + return -EINVAL; + 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 IOCTL_IOC: - { - uint8_t tmp[IOCTL_IOC_SIZE]; + case DEMO_CTL_IOC: + { + uint8_t tmp[DEMO_IOC_SIZE]; copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd)); copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd)); } break; - case IOCTL_IO: + case DEMO_CTL_IO: break; - case IOCTL_IOR: + case DEMO_CTL_IOR: { uint16_t tmp = 0x55AA; copy_to_user((void*)arg, &tmp, _IOC_SIZE(cmd)); } break; - case IOCTL_IOW: + case DEMO_CTL_IOW: { int32_t tmp = 0; copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd)); } break; - case IOCTL_IOWR: + case DEMO_CTL_IOWR: { uint32_t tmp = 0; copy_from_user(&tmp, (void*)arg, _IOC_SIZE(cmd)); @@ -113,14 +148,14 @@ static struct miscdevice demo_dev = { static int __init demo_init(void) { - misc_register(&demo_dev); + misc_register(&demo_dev); // 注册混杂设备驱动. return 0; } static void __exit demo_exit(void) { - misc_deregister(&demo_dev); + misc_deregister(&demo_dev); // 撤销混杂设备驱动. } module_init(demo_init); -module_exit(demo_exit); \ No newline at end of file +module_exit(demo_exit);