任何人都可以解释我,
IOCTL
? IOCTL
做同样工作的新function? 一个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,它是一种IPC(进程间通信)方法,通过BSD套接字接口与您的驱动程序通信。 这例如由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提供了一些预定义的函数,如宏。
_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
与上面相同,但是第三部分给出下一个参数的类型,回想一下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
的第三部分提到类型是这样的。 而且,这个字体的地址作为unsigned long
被传递给在设备驱动模块中实现的相应的系统调用,在使用之前我们需要将它转换为适当的类型。 内核空间可以访问用户空间,因此这个工作。 像宏这样的其他两个函数分别是数据流的方向将从内核空间到用户空间以及两个方向的__IORW(MAGIC, SEQ_NO, TYPE)
__IOR(MAGIC, SEQ_NO, TYPE)
和__IORW(MAGIC, SEQ_NO, TYPE)
。
请让我知道这可不可以帮你!