IOCTL Linux设备驱动程序
任何人都可以解释我,
- 什么是
IOCTL
? - 它是干什么用的?
- 我怎样才能使用它?
- 为什么我不能定义和
IOCTL
做同样工作的新function?
一个ioctl
意味着“input输出控制”是一种特定于设备的系统调用。 在Linux(300-400)中只有几个系统调用,这不足以表示设备可能具有的所有独特function。 因此,驱动程序可以定义一个允许用户空间应用程序发送订单的ioctl。 然而,ioctl不是很灵活,往往会有点混乱(数十个“魔术数字”只是起作用或者不起作用),并且在将缓冲区传递到内核时也可能不安全 – 错误的处理可能会中断事情很容易。
另一种方法是使用sysfs
接口,在/sys/
下build立一个文件并读/写,从驱动程序获取信息。 一个如何设置的例子:
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,它是一种IPC(进程间通信)方法,通过BSD套接字接口与您的驱动程序通信。 这例如由WiFi驱动程序使用。 然后使用libnl
或libnl3
库从用户空间与它通信。
ioctl
函数在实现设备驱动程序以在设备上设置configuration时非常有用。 例如打印机有configuration选项来检查和设置字体,字体大小等ioctl
可以用来获取当前字体以及将字体设置为另一个字体。 在用户应用程序中使用ioctl
将代码发送到打印机,告诉它返回当前字体或将字体设置为新的字体。
int ioctl(int fd, int request, ...)
-
fd
是文件描述符,通过打开返回 -
request
是请求代码。 例如,GETFONT将从打印机获取当前字体,SETFONT将在打印机上设置字体。 - 第三个参数是
void *
。 根据第二个论点,第三个可能或可能不存在。 例如,如果第二个参数是SETFONT,则第三个参数可能会将字体名称设置为ARIAL。
所以,现在int请求不仅仅是一个macros,还需要生成一个请求代码,供用户应用程序和设备驱动程序模块用来确定设备上的哪个configuration必须被使用。 用户应用程序使用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提供了一些预定义的函数,如macros。
_IO(MAGIC, SEQ_NO)
都是8位,0到255,比如说我们要暂停打印机。 这不需要传输数据。 所以我们将生成请求代码如下
#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
与上面相同,但是第三部分给出下一个参数的types,回想一下ioctl
的第三个参数是void *
。__IOW
W表示数据的方向是从用户应用程序到驱动程序模块。 让我们举一个例子,假设你正在告诉打印机将字体设置为Arial。#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
的第三部分提到types是这样的。 而且,这个字体的地址作为unsigned long
被传递给在设备驱动模块中实现的相应的系统调用,在使用之前我们需要将它转换为适当的types。 内核空间可以访问用户空间,因此这个工作。 像macros这样的其他两个函数分别是数据stream的方向将从内核空间到用户空间以及两个方向的__IORW(MAGIC, SEQ_NO, TYPE)
__IOR(MAGIC, SEQ_NO, TYPE)
和__IORW(MAGIC, SEQ_NO, TYPE)
。
请让我知道这可不可以帮你!