Драйвер устройства IOCTL Linux [закрыто]

126

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

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

Ответы:

99

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);

И во время установки драйвера:

device_create_file(dev, &dev_attr_version);

Тогда у вас будет файл для вашего устройства /sys/, например, /sys/block/myblk/versionдля блочного драйвера.

Другой способ более интенсивного использования - это netlink, который представляет собой метод IPC (межпроцессного взаимодействия) для связи с вашим драйвером через интерфейс сокета BSD. Это используется, например, драйверами WiFi. Затем вы общаетесь с ним из пользовательского пространства, используя библиотеки libnlили libnl3.

Inductiveload
источник
3
Этот ответ частично отвечает на вопрос.
Vishal Sahu
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) MAGICи SEQ_NOтакие же, как указано выше, и TYPEзадает тип следующего аргумента, вспомните третий аргумент ioctlis void *. W __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)где поток данных будет из пространства ядра в пространство пользователя и в обоих направлениях соответственно.

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

anukalp
источник
Интересно, верны ли приведенные выше функции __IOW, __IOR и __IORW (в некоторых случаях я имею в виду двойное подчеркивание, в некоторых случаях нет. Я никогда не использовал двойное подчеркивание) ... Спасибо за четкое объяснение!
jcoppens
Очень хорошо объяснил .. Спасибо! Не могли бы вы дать небольшой фрагмент кода со стороны драйвера, который использует этот ioctl?
Aadishri
обратитесь к opensourceforu.com/2011/08/io-control-in-linux, например
chandola
Очень хорошо объяснено. Спасибо. Я думаю, что это _IOWR, а не _IORW
Мохамед Сами
Ответьте как сообщение в блоге.
Фредрик Гаусс