IOCTL Linux设备驱动程序

任何人都可以解释我,

  1. 什么是IOCTL
  2. 它是干什么用的?
  3. 我怎样才能使用它?
  4. 为什么我不能定义和IOCTL做同样工作的新function?

一个ioctl意味着“input输出控制”是一种特定于设备的系统调用。 在Linux(300-400)中只有几个系统调用,这不足以表示设备可能具有的所有独特function。 因此,驱动程序可以定义一个允许用户空间应用程序发送订单的ioctl。 然而,ioctl不是很灵活,往往会有点混乱(数十个“魔术数字”只是起作用或者不起作用),并且在将缓冲区传递到内核时也可能不安全 – 错误的处理可能会中断事情很容易。

另一种方法是使用sysfs接口,在/sys/下build立一个文件并读/写,从驱动程序获取信息。 一个如何设置的例子:

 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库从用户空间与它通信。

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

 int ioctl(int fd, int request, ...) 
  1. fd是文件描述符,通过打开返回
  2. request是请求代码。 例如,GETFONT将从打印机获取当前字体,SETFONT将在打印机上设置字体。
  3. 第三个参数是void * 。 根据第二个论点,第三个可能或可能不存在。 例如,如果第二个参数是SETFONT,则第三个参数可能会将字体名称设置为ARIAL。

所以,现在int请求不仅仅是一个macros,还需要生成一个请求代码,供用户应用程序和设备驱动程序模块用来确定设备上的哪个configuration必须被使用。 用户应用程序使用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提供了一些预定义的函数,如macros。

_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与上面相同,但是第三部分给出下一个参数的types,回想一下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的第三部分提到types是这样的。 而且,这个字体的地址作为unsigned long被传递给在设备驱动模块中实现的相应的系统调用,在使用之前我们需要将它转换为适当的types。 内核空间可以访问用户空间,因此这个工作。 像macros这样的其他两个函数分别是数据stream的方向将从内核空间到用户空间以及两个方向的__IORW(MAGIC, SEQ_NO, TYPE) __IOR(MAGIC, SEQ_NO, TYPE)__IORW(MAGIC, SEQ_NO, TYPE)

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