Answers:
一个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
是文件描述符,由返回open
;request
是请求代码。例如GETFONT
将从打印机获取当前字体,在打印机上SETFONT
设置字体;void *
。根据第二个参数,第三个参数可能存在也可能不存在,例如,如果第二个参数是SETFONT
,则第三个参数可以是字体名称,例如"Arial"
;int request
不只是一个宏。需要用户应用程序来生成请求代码,并需要设备驱动程序模块来确定必须使用设备上的哪个配置。应用程序使用发送请求代码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,例如,让我们说我们要暂停打印机。这不需要数据传输。所以我们将生成如下的请求代码
#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
相同,并TYPE
给出下一个参数的类型,回想ioctl
is 的第三个参数void *
。W in __IOW
表示数据流是从用户应用程序到驱动程序模块的。作为示例,假设我们要将打印机字体设置为"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
,我们需要在使用它之前将其转换为正确的类型。内核空间可以访问用户空间,因此可以正常工作。其他两个类似于函数的宏是__IOR(MAGIC, SEQ_NO, TYPE)
和__IORW(MAGIC, SEQ_NO, TYPE)
在那里数据流将是从内核空间向用户空间和分别是双向的。
请让我知道这可不可以帮你!