Відповіді:
А 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
.
Ця ioctl
функція корисна для реалізації драйвера пристрою для встановлення конфігурації на пристрої. наприклад, принтер, який має параметри конфігурації для перевірки та встановлення сімейства шрифтів, розміру шрифту тощо, ioctl
може бути використаний для отримання поточного шрифту, а також для встановлення шрифту на новий. Користувацька програма використовує ioctl
для надсилання коду на принтер, який повідомляє йому повернути поточний шрифт або встановити шрифт на новий.
int ioctl(int fd, int request, ...)
fd
- дескриптор файлів, той, який повертається open
;request
це код запиту. наприклад GETFONT
, отримає поточний шрифт від принтера, SETFONT
встановить шрифт на принтері;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);
Відповідний системний виклик в модулі драйвера отримає код і призупинить принтер.
__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)
де потік даних буде простір ядра до простору користувача та обидва способи відповідно.
Будь ласка, дайте мені знати, якщо це допомагає!