Драйвер устройства ioctl Linux

может кто-нибудь объяснить мне,

  1. что это IOCTL?
  2. для чего он используется?
  3. как я могу его использовать?
  4. почему я не могу определить новую функцию, которая выполняет ту же работу, что и IOCTL?

2 ответов


An ioctl, что означает, что "управление вводом-выводом" является своего рода системным вызовом для конкретного устройства. Есть только несколько системных вызовов в Linux (300-400), которых не хватает, чтобы выразить все уникальные функции устройства могут иметь. Таким образом, драйвер может определить ioctl, который позволяет приложению userspace отправлять ему заказы. Тем не менее, ioctls не очень гибкие и имеют тенденцию немного загромождаться (десятки "магических чисел", которые просто работают... или нет), а также может быть небезопасным, поскольку вы передаете буфер в kernel-плохое обращение может легко сломать вещи.

альтернативой является 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. Затем вы общаетесь с ним из userspace, используя libnl или libnl3 библиотеки.


ioctl функция полезна, когда один реализует драйвер устройства установить конфигурацию на устройство. например, принтер имеет параметры конфигурации для проверки и установки шрифта, размера шрифта и т. д. ioctl может использоваться для получения текущего шрифта, а также установить шрифт на другой. В пользовательском приложении используйте ioctl отправить код на принтер, сообщив ему, чтобы вернуть текущий шрифт или установить шрифт на новый.

int ioctl(int fd, int request, ...)
  1. fd является файловым дескриптором, тот вернулся с открытия
  2. request запрос кода. e.G GETFONT получит текущий шрифт с принтера, SETFONT установит шрифт на принтере.
  3. третий аргумент void *. В зависимости от второго аргумента, третий может присутствовать или не присутствовать. например, если второй аргумент SETFONT, третий аргумент может дать имя шрифта как ARIAL.

таким образом, теперь запрос int-это не просто макрос, он необходим для генерации кода запроса, который будет использоваться пользовательским приложением и драйвером устройства модуль, чтобы определить, какая конфигурация на устройстве должна быть воспроизведена. Один отправляет код запроса, используя 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, например, скажем, мы хотим приостановить принтер. Это не требует передачи adata. Таким образом, мы будем генерировать код запроса, как показано ниже

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

теперь использовать ioctl as

    ret_val = ioctl(fd, PAUSE_PRIN);

соответствующий системный вызов в модуле драйвера получит код и приостановит принтер.

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGIC и SEQ_NO такие же, как и выше, но третья часть дает тип следующего аргумента, напомним третий аргумент 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) где направление потока данных из ядра в пространство пользователя и пространство в обе стороны соответственно.

пожалуйста, дайте мне знать, если это помогает!