Может ли кто-нибудь объяснить мне,
- Что такое
IOCTL
? - Для чего он используется?
- Как я могу использовать его?
- Почему я не могу определить новую функцию, которая выполняет ту же работу, что и
IOCTL
?
Может ли кто-нибудь объяснить мне,
IOCTL
?IOCTL
?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
.
Функция 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
установлено значение SETFONT
для установки шрифта на принтере, направление передачи данных будет от пользовательского приложения к модулю драйвера устройства (пользовательское приложение отправляет имя шрифта "Arial"
на принтер). Если код запроса GETFONT
, направление от принтера к пользовательскому приложению.
Чтобы сгенерировать код запроса, Linux предоставляет некоторые предопределенные макросы, подобные функциям.
1. _IO(MAGIC, SEQ_NO)
оба 8- _IO(MAGIC, SEQ_NO)
, от 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)
где поток данных будет __IORW(MAGIC, SEQ_NO, TYPE)
из пространства ядра в пространство пользователя и в обе стороны соответственно.
Пожалуйста, дайте мне знать, если это поможет!