Драйвер пристрою IOCTL Linux [закрито]


126

Хтось може мені пояснити,

  1. Що таке IOCTL?
  2. Для чого він використовується?
  3. Як я можу ним користуватися?
  4. Чому я не можу визначити нову функцію, яка працює так само, як і IOCTL?

Відповіді:


99

А ioctl, що означає "керування входом-виходом", є своєрідним системним викликом. У Linux є лише декілька системних дзвінків (300-400), яких недостатньо, щоб виразити всі унікальні функції пристроїв. Таким чином, драйвер може визначити ioctl, який дозволяє додатку простору користувачів надсилати йому замовлення. Однак йоктли не дуже гнучкі і мають тенденцію дещо захаращуватися (десятки "магічних чисел", які просто працюють ... чи ні), а також можуть бути небезпечними, коли ви переходите буфер в ядро ​​- погана керованість може зламатися речі легко.

Альтернативою є 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.


3
Ця відповідь частково відповідає на питання.
Вішал Саху

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надає тип наступного аргументу, нагадаємо третій аргумент ioctlє 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)де потік даних буде простір ядра до простору користувача та обидва способи відповідно.

Будь ласка, дайте мені знати, якщо це допомагає!


Цікаво, чи правильно вказані функції __IOW, __IOR та __IORW (я маю на увазі подвійне підкреслення в деяких випадках, в деяких випадках ні. Я ніколи не використовував подвійне підкреслення) ... Дякую за чітке пояснення!
jcoppens

Дуже добре пояснено .. Дякую! Чи можете ви надати невеликий фрагмент коду з боку драйвера, який використовує цей ioctl?
Аадішрі


Дуже добре пояснено. Дякую. Я думаю, це _IOWR не _IORW
Мохамед Самі

Відповідь, як повідомлення в блозі.
Фредрік Гаус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.