ioctl字面意思是输入输出控制lesson12 里面对这个玩意的作用说了个清除超越常规的r/w/open/close 操作之外设备文件有时候需要更多的参数来配置控制。比如典型的触摸屏需要知道触摸屏大小像素等。lesson12/13 讲的就是这ioctl.lesson12 复制的是lesson8/9的代码给了cdev_init(my_cdev,fops) 中fops 添加static struct file_operations fops {.unlocked_ioctl my_ioctl,};查询linux 内核源码file_operation 里面有unlocked_ioctl 和 compate_ioctl 两种。关于这个unlocked_ioctl 以及它和早期的linux 内核中的ioctl() 见其他大佬的说明。按照下文ioctl 已经废弃从古早内核移植的需要改名为unlocked_ioctl 和 compate_ioctl内核新的ioctl方式--unlocked_ioctl和compat_ioctl(解决error:unknown field ioctl specified in initializer)_vgdyvcommonioctl:unknow-CSDN博客然后my_ioctl()添加了打印一句话做提示。lesson12只是给了这个ioctl调用接口实际上没有用它做什么。lesson12的代码忽略看看lesson13代码#include linux/module.h #include linux/init.h #include linux/fs.h #include linux/cdev.h #include my_ioctl.h static dev_t dev_nr; static struct cdev my_cdev; static struct class *my_class; static int answer 42; static long int my_ioctl(struct file *f, unsigned int cmd, unsigned long args) { int status; struct mystruct s; pr_info(hello_cdev - ioctl called with cmd: 0x%x and args: %p\n, cmd, (void *) args); switch (cmd) { case WR_VAL: status copy_from_user(answer, (int *) args, sizeof(int)); if (status) { pr_err(hello_cdev - Error on WR_VAL\n); return status; } break; case RD_VAL: status copy_to_user((int *) args, answer, sizeof(int)); if (status) { pr_err(hello_cdev - Error on RD_VAL\n); return status; } break; case GREET: status copy_from_user(s, (struct mystruct *) args, sizeof(struct mystruct)); if (status) { pr_err(hello_cdev - Error on GREET\n); return status; } for (int i0; is.repeat; i) pr_info(hello_cdev - Hello, %s\n, s.name); break; default: return -EOPNOTSUPP; } return 0; } static struct file_operations fops { .unlocked_ioctl my_ioctl, }; static int __init my_init(void) { int status; #ifdef STATIC_DEVNR dev_nr STATIC_DEVNR; status register_chrdev_region(dev_nr, MINORMASK 1, hello_cdev); #else status alloc_chrdev_region(dev_nr, 0, MINORMASK 1, hello_cdev); #endif if (status) { pr_err(hello_cdev - Error reserving the region of device numbers\n); return status; } cdev_init(my_cdev, fops); my_cdev.owner THIS_MODULE; status cdev_add(my_cdev, dev_nr, MINORMASK 1); if (status) { pr_err(hello_cdev - Error adding cdev\n); goto free_devnr; } pr_info(hello_cdev - Registered a character device for Major %d starting with Minor %d\n, MAJOR(dev_nr), MINOR(dev_nr)); my_class class_create(my_class); if (!my_class) { pr_err(hello_cdev - Could not create class my_class\n); status ENOMEM; goto delete_cdev; } if (!device_create(my_class, NULL, dev_nr, NULL, hello%d, 0)) { pr_err(hello_cdev - Could not create device hello0\n); status ENOMEM; goto delete_class; } pr_info(hello_cdev - Created device under /sys/class/my_class/hello0\n); return 0; delete_class: class_unregister(my_class); class_destroy(my_class); delete_cdev: cdev_del(my_cdev); free_devnr: unregister_chrdev_region(dev_nr, MINORMASK 1); return status; } static void __exit my_exit(void) { device_destroy(my_class, dev_nr); class_unregister(my_class); class_destroy(my_class); cdev_del(my_cdev); unregister_chrdev_region(dev_nr, MINORMASK 1); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(Johannes 4Linux); MODULE_DESCRIPTION(A sample driver for manually registering a character device);应用层代码头文件my_ioctl.h#ifndef MY_IOCTL_H_ #define MY_IOCTL_H_ struct mystruct { int repeat; char name[64]; }; #define WR_VAL _IOW(a, b, int *) #define RD_VAL _IOR(a, c, int *) #define GREET _IOW(a, d, struct mystruct *) #endif应用层测试程序test.c#include stdio.h #include stdlib.h #include string.h #include unistd.h #include fcntl.h #include sys/ioctl.h #include my_ioctl.h int main(int argc, char **argv) { int answer, status; struct mystruct s; int fd open(/dev/hello0, O_RDWR); if (fd 0) { perror(open); return fd; } switch (argc) { case 1: status ioctl(fd, RD_VAL, answer); if (status) perror(ioctl); printf(the answer is %d\n, answer); break; case 2: answer atoi(argv[1]); status ioctl(fd, WR_VAL, answer); if (status) perror(ioctl); break; case 3: s.repeat atoi(argv[1]); strcpy(s.name, argv[2]); status ioctl(fd, GREET, s); if (status) perror(ioctl); break; default: status ioctl(fd, 123, NULL); if (status) perror(ioctl); break; } close(fd); return 0; }看视频lesson13 即可。https://www.bilibili.com/video/BV18SE26cEjn?vd_source92b7efa4daa5bb4fdcdc9f2db97c307bp13总体看都是比较浅显的说明了linux 内核里面字符设备的各种常用概念。。