IOCTL Linux设备驱动程序
ioctl
,这意味着“输入输出控制”是一种设备特定的系统调用。在Linux(300-400)中只有少数系统调用,它们不足以表达设备可能具有的所有独特功能。因此,驱动程序可以定义允许用户空间应用程序发送订单的ioctl。然而,ioctl不是很灵活,并且往往会有点混乱(数十个“魔术数字”只能起作用或者不起作用),并且在将缓冲区传递到内核时也可能不安全 - 错误的处理可能会中断事情很容易。
另一种是sysfs
界面,在这里建立了一个文件/sys/
下,读/写,从和驱动器获取信息。如何设置这个了一个例子:
static ssize_t mydrvr_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", DRIVER_RELEASE);
}
static DEVICE_ATTR(version, S_IRUGO, mydrvr_version_show, NULL);
和驱动程序安装过程中:
device_create_file(dev, &dev_attr_version);
你将不得不为你的设备中的文件/sys/
,例如,/sys/block/myblk/version
块驱动程序。
另一种更重用的方法是netlink,它是一种通过BSD套接字接口与您的驱动程序通信的IPC(进程间通信)方法。例如,这由WiFi驱动程序使用。然后,您使用libnl
或libnl3
库从用户空间与其通信。
ioctl
功能在实现设备驱动程序以在设备上设置配置时非常有用。例如打印机具有配置选项来检查和设置字体,字体大小等。ioctl
可用于获取当前字体以及将字体设置为另一个字体。在用户应用程序中,使用ioctl
向打印机发送代码,告诉其返回当前字体或将字体设置为新字体。
int ioctl(int fd, int request, ...)
-
fd
是文件描述符,由开启 -
request
返回的一个是请求代码。例如GETFONT将从打印机获取当前字体,SETFONT将在打印机上设置字体。 - 第三个参数是
void *
。根据第二个论点,第三个可能会或可能不存在。 例如如果第二个参数是SETFONT,则第三个参数可能会将字体名称设置为ARIAL。
因此,现在int请求不仅仅是一个宏,还需要一个生成请求代码,用于由用户应用程序和设备驱动程序模块使用,以确定设备上的哪个配置必须使用。一个用户应用程序使用ioctl
发送请求代码,然后使用设备驱动程序模块中的请求代码确定要执行的操作。
的请求的代码具有4个主要部分
1. A Magic number - 8 bits
2. A sequence number - 8 bits
3. Argument type (typically 14 bits), if any.
4. Direction of data transfer (2 bits).
如果请求代码是setfont程序设置在打印机上的字体,用于数据传输的方向是从用户的应用程序的设备驱动程序模块。用户将字体名称Arial发送到打印机。如果请求代码是GETFONT,则方向是从打印机到用户应用程序。
要生成请求码的Linux提供一些预定义的函数等的宏。
1. _IO(MAGIC, SEQ_NO)
两者都是8位,0到255,例如让我们说我们想暂停打印机。 这不需要ADATA转移。所以,我们会生成请求代码如下
#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM)
现在使用的驱动模块ioctl
作为
ret_val = ioctl(fd, PAUSE_PRIN);
对应的系统调用将收到的代码,并暂停打印机。
-
__IOW(MAGIC, SEQ_NO, TYPE)
MAGIC
和SEQ_NO
同上,但第三部分对下一个参数的类型,回忆的ioctl
第三个参数是void *
。 W的__IOW
指示数据的方向是从用户应用到驱动模块。让我们举个例子,假设 一个告诉打印机字体设置为宋体。#define PRIN_MAGIC 'S' #define SEQ_NO 1 #define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)
进一步,
char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font);
现在font
是一个指针,这意味着它是最好的表示为unsigned long
的地址,因此的_IOW
第三部分提到类型本身。此外,这个字体地址被传递给设备驱动模块中实现的相应系统调用,如unsigned long
,我们需要在使用它之前将其转换为适当的类型。内核空间可以访问用户空间,因此可以工作。像宏这样的其他两个函数分别是__IOR(MAGIC, SEQ_NO, TYPE)
和__IORW(MAGIC, SEQ_NO, TYPE)
,其中数据流的方向将分别从内核空间到用户空间和两个方向。
请让我知道,如果这有助于!
我不知道上面的__IOW,__IOR和__IORW函数是否正确(在某些情况下,我的意思是双下划线,在某些情况下,我没有使用双下划线)......感谢您的明确解释! – jcoppens 2016-05-09 19:24:27
这个答案部分地回答了这个问题。 – 2016-11-29 03:44:00