IOCTL Linux设备驱动程序


Answers:


99

一个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驱动程序使用。然后,您可以使用libnllibnl3库从用户空间与其进行通信。


3
这个答案部分地“回答”了问题。
维沙尔·萨胡

163

ioctl功能对于实现设备驱动程序以在设备上设置配置很有用。例如,具有配置选项以检查和设置字体系列,字体大小等的打印机ioctl可用于获取当前字体以及将字体设置为新字体。用户应用程序用于ioctl将代码发送到打印机,告诉打印机返回当前字体或将字体设置为新字体。

int ioctl(int fd, int request, ...)
  1. fd是文件描述符,由返回open
  2. request是请求代码。例如GETFONT将从打印机获取当前字体,在打印机上SETFONT设置字体;
  3. 第三个论点是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);

驱动程序模块中的相应系统调用将接收代码并暂停打印机。

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGICSEQ_NO相同,并TYPE给出下一个参数的类型,回想ioctlis 的第三个参数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)在那里数据流将是从内核空间向用户空间和分别是双向的。

请让我知道这可不可以帮你!


我想知道上面的__IOW,__ IOR和__IORW函数是否正确(在某些情况下,我是指双下划线,在某些情况下不是。我从未使用过双下划线)...感谢您的明确解释!
jcoppens

很好解释..谢谢!能否请您给使用此ioctl的驱动程序端的一小段代码?
阿迪什里


很好解释。谢谢。我认为不是_IOWR而不是_IORW
穆罕默德·萨米

像博客文章一样回答。
Fredrick Gauss
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.