IOCTL Linux 设备驱动程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15807846/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:39:02  来源:igfitidea点击:

IOCTL Linux device driver

linuxlinux-kerneldriverlinux-device-driverioctl

提问by flashdisk

Can anyone explain me,

谁能给我解释一下

  1. What is IOCTL?
  2. What is it used for?
  3. How can I use it?
  4. Why can't I define new function that does the same work as IOCTL?
  1. 什么是IOCTL
  2. 它是干什么用的?
  3. 我怎样才能使用它?
  4. 为什么我不能定义与 做相同工作的新函数IOCTL

采纳答案by Inductiveload

An ioctl, which means "input-output control" is a kind of device-specific system call. There are only a few system calls in Linux (300-400), which are not enough to express all the unique functions devices may have. So a driver can define an ioctl which allows a userspace application to send it orders. However, ioctls are not very flexible and tend to get a bit cluttered (dozens of "magic numbers" which just work... or not), and can also be insecure, as you pass a buffer into the kernel - bad handling can break things easily.

An ioctl,意思是“输入-输出控制”是一种特定于设备的系统调用。Linux 中只有少数系统调用(300-400),不足以表达设备可能具有的所有独特功能。因此,驱动程序可以定义一个 ioctl,它允许用户空间应用程序向它发送命令。然而,ioctl 不是很灵活,而且往往会变得有点混乱(几十个“神奇数字”不管用……还是不行),而且也可能不安全,因为您将缓冲区传递到内核中 - 处理不当可能会破坏事情容易。

An alternative is the sysfsinterface, where you set up a file under /sys/and read/write that to get information from and to the driver. An example of how to set this up:

另一种选择是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);

And during driver setup:

在驱动程序设置期间:

device_create_file(dev, &dev_attr_version);

You would then have a file for your device in /sys/, for example, /sys/block/myblk/versionfor a block driver.

然后,您将在 中为您的设备创建一个文件/sys/,例如,/sys/block/myblk/version用于块驱动程序。

Another method for heavier use is netlink, which is an IPC (inter-process communication) method to talk to your driver over a BSD socket interface. This is used, for example, by the WiFi drivers. You then communicate with it from userspace using the libnlor libnl3libraries.

另一种更频繁使用的方​​法是 netlink,它是一种 IPC(进程间通信)方法,可通过 BSD 套接字接口与驱动程序通信。例如,这由 WiFi 驱动程序使用。然后,您可以使用libnllibnl3库从用户空间与它通信。

回答by anukalp

The ioctlfunction is useful for implementing a device driver to set the configuration on the device. e.g. a printer that has configuration options to check and set the font family, font size etc. ioctlcould be used to get the current font as well as set the font to a new one. A user application uses ioctlto send a code to a printer telling it to return the current font or to set the font to a new one.

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

int ioctl(int fd, int request, ...)
  1. fdis file descriptor, the one returned by open;
  2. requestis request code. e.g GETFONTwill get the current font from the printer, SETFONTwill set the font on the printer;
  3. the third argument is void *. Depending on the second argument, the third may or may not be present, e.g. if the second argument is SETFONT, the third argument can be the font name such as "Arial";
  1. fd是文件描述符,由open;返回的那个
  2. request是请求代码。例如GETFONT将从打印机获取当前字体,在打印机上SETFONT设置字体;
  3. 第三个参数是void *。根据第二个参数,第三个可能存在也可能不存在,例如,如果第二个参数是SETFONT,则第三个参数可以是字体名称,例如"Arial";

int requestis not just a macro. A user application is required to generate a request code and the device driver module to determine which configuration on device must be played with. The application sends the request code using ioctland then uses the request code in the device driver module to determine which action to perform.

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

A request code has 4 main parts

请求代码有 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).  

If the request code is SETFONTto set font on a printer, the direction for data transfer will be from user application to device driver module (The user application sends the font name "Arial"to the printer). If the request code is GETFONT, direction is from printer to the user application.

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

In order to generate a request code, Linux provides some predefined function-like macros.

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

1._IO(MAGIC, SEQ_NO)both are 8 bits, 0 to 255, e.g. let us say we want to pause printer. This does not require a data transfer. So we would generate the request code as below

1._IO(MAGIC, SEQ_NO)两者都是 8 位,0 到 255,例如让我们说我们要暂停打印机。这不需要数据传输。所以我们将生成如下请求代码

#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM) 

and now use ioctlas

现在ioctl用作

ret_val = ioctl(fd, PAUSE_PRIN);

The corresponding system call in the driver module will receive the code and pause the printer.

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

  1. __IOW(MAGIC, SEQ_NO, TYPE)MAGICand SEQ_NOare the same as above, and TYPEgives the type of the next argument, recall the third argument of ioctlis void *. W in __IOWindicates that the data flow is from user application to driver module. As an example, suppose we want to set the printer font to "Arial".
  1. __IOW(MAGIC, SEQ_NO, TYPE)MAGICand 和SEQ_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)

further,

更远,

char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font); 

Now fontis a pointer, which means it is an address best represented as unsigned long, hence the third part of _IOWmentions type as such. Also, this address of font is passed to corresponding system call implemented in device driver module as unsigned longand we need to cast it to proper type before using it. Kernel space can access user space and hence this works. other two function-like macros are __IOR(MAGIC, SEQ_NO, TYPE)and __IORW(MAGIC, SEQ_NO, TYPE)where the data flow will be from kernel space to user space and both ways respectively.

Nowfont是一个指针,这意味着它是一个地址,最好表示为unsigned long,因此第三部分_IOW提到了类型。此外,这个字体地址被传递给设备驱动模块中实现的相应系统调用unsigned long,我们需要在使用之前将其转换为正确的类型。内核空间可以访问用户空间,因此这是有效的。其他两个类似函数的宏是__IOR(MAGIC, SEQ_NO, TYPE)__IORW(MAGIC, SEQ_NO, TYPE)数据流将分别从内核空间到用户空间以及双向。

Please let me know if this helps!

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