IOCTL Linux设备驱动程序

fla*_*isk 122 linux ioctl driver linux-device-driver linux-kernel

任何人都可以解释我,

  1. 什么是IOCTL
  2. 它是干什么用的?
  3. 我怎么用呢?
  4. 为什么我不能定义执行相同工作的新功能IOCTL

anu*_*alp 154

ioctl当实现设备驱动程序以在设备上设置配置时,函数很有用.例如,打印机具有检查和设置字体,字体大小等的配置选项,ioctl可用于获取当前字体以及将字体设置为另一种字体.在用户应用程序中,使用ioctl向打印机发送代码,告诉它返回当前字体或将字体设置为新字体.

int ioctl(int fd, int request, ...)
Run Code Online (Sandbox Code Playgroud)
  1. fd 是文件描述符,由open返回
  2. open是请求代码.例如,GETFONT将从打印机获取当前字体,SETFONT将在打印机上设置字体.
  3. 第三个论点是request.根据第二个参数,第三个参数可能存在也可能不存在.例如,如果第二个参数是SETFONT,则第三个参数可以将字体名称赋予ARIAL.

因此,现在int请求不仅仅是一个宏,需要生成一个请求代码供用户应用程序和设备驱动程序模块使用,以确定必须在设备上使用哪个配置.一个使用GETFONT来自用户应用程序发送请求代码,然后使用设备驱动程序模块中的请求代码来确定要执行的操作.

请求代码有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).  
Run Code Online (Sandbox Code Playgroud)

如果请求代码为SETFONT以在打印机上设置字体,则数据传输的方向将是从用户应用程序到设备驱动程序模块.用户将字体名称Arial发送到打印机.如果请求代码是GETFONT,则方向是从打印机到用户应用程序.

为了生成请求代码,Linux提供了一些预定义的函数,如宏.

1. SETFONT两个都是8位,0到255,例如,让我们说我们要暂停打印机.这不需要adata转移.所以我们将生成如下的请求代码

#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM) 
Run Code Online (Sandbox Code Playgroud)

现在使用void *as

ret_val = ioctl(fd, PAUSE_PRIN);
Run Code Online (Sandbox Code Playgroud)

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

  1. SETFONT "Arial"并且int request与上面相同,但第三部分给出了下一个参数的类型,回想一下ioctlis 的第三个参数SETFONT.W in "Arial"表示数据的方向是从用户应用程序到驱动程序模块.让我们举一个例子,假设一个人告诉打印机将字体设置为Arial.

    #define PRIN_MAGIC 'S'
    #define SEQ_NO 1
    #define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)
    
    Run Code Online (Sandbox Code Playgroud)

进一步,

char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font); 
Run Code Online (Sandbox Code Playgroud)

现在GETFONT是一个指针,这意味着它是一个最佳表示的地址_IO(MAGIC, SEQ_NO),因此第三部分ioctl提到类型.此外,这个字体地址被传递给在设备驱动程序模块中实现的相应系统调用__IOW(MAGIC, SEQ_NO, TYPE) ,我们需要在使用它之前将其转换为正确的类型.内核空间可以访问用户空间,因此这是有效的.另外两个函数像宏是MAGICSEQ_NO其中数据流的方向是从内核空间向用户空间和分别是双向的.

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


Ind*_*oad 93

An ioctl,表示"输入输出控制"是一种特定于设备的系统调用.在Linux(300-400)中只有少数系统调用,这些调用不足以表达设备可能具有的所有独特功能.因此,驱动程序可以定义一个允许用户空间应用程序发送订单的ioctl.然而,ioctls不是很灵活,往往会有点混乱(几十个"魔术数字"只能工作......或者不工作),也可能是不安全的,因为你将缓冲区传递给内核 - 糟糕的处理可能会破坏事情很轻松.

另一种选择是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);
Run Code Online (Sandbox Code Playgroud)

在驱动程序设置期间:

device_create_file(dev, &dev_attr_version);
Run Code Online (Sandbox Code Playgroud)

然后,您将拥有一个适用于您的设备的文件/sys/,例如,/sys/block/myblk/version块驱动程序.

另一种更重要的使用方法是netlink,它是一种IPC(进程间通信)方法,通过BSD套接字接口与驱动程序通信.例如,这由WiFi驱动程序使用.然后使用libnllibnl3库从用户空间与它进行通信.

  • 这个答案部分地"回答"了这个问题. (3认同)