我一直在尝试为 Linux 内核编写一个字符设备模块,但我遇到了一些困惑。
我在网上看到有人谈论使用
ioctl()
将命令/数据从用户程序传输到内核空间,反之亦然。但对于 file_operations struct
已经可以做的事情来说,很多事情似乎有点矫枉过正
// structure containing callbacks
static struct file_operations fops =
{
.read = dev_read, // address of dev_read
.open = dev_open, // address of dev_open
.write = dev_write, // address of dev_write
.release = dev_rls, // address of dev_rls
};
使用
ioctl()
而不是使用 dev_read()
和 dev_write()
定义的函数(仅使用 copy_to_user()
和 copy_from_user()
将数据块复制到/从用户空间)有什么好处?
ioctl
只能用于内核默认未提供的操作。
使用简单的
ioctl
或 read
调用时,必须调用 write
来读取或写入数据,这会大大降低您的易用性。
我所说的非标准操作是指在终端设备驱动程序中设置自动 ASCII/EBCDIC 转换,或者从 DVD 块设备中弹出磁盘,或者修改串行通信的串行通信参数(波特率、停止位等)设备。
无论如何使用
ioctl
将命令传输到设备驱动程序(或从中获取非数据信息,例如当前参数或统计信息)(另一种方法是在数据中使用一些复杂的转义方案,例如 AT
命令集对于调制解调器或(这显示了我的年龄)Apple ][磁盘子系统的CTRL-D,这很少是漂亮的。
将数据传输留给标准调用。
IORW 允许在一次调用中同时进行写入和读取, 如果您需要传递“读”操作的参数,ioctl 允许您通过“写”传递带有两个参数的结构,然后执行“读”将数据从内核传递给用户。
即内核代码将执行“从用户复制”+准备数据+“复制到用户”。
而且读/写是阻塞的,只有一个线程可以调用它,我认为 ioctl 可以被多个用户线程调用,与 poll() 相同