Odpowiedzi:
An ioctl
, co oznacza „sterowanie wejściem / wyjściem”, jest rodzajem wywołania systemowego specyficznego dla urządzenia. W Linuksie (300-400) jest tylko kilka wywołań systemowych, które nie wystarczają do wyrażenia wszystkich unikalnych funkcji, jakie mogą mieć urządzenia. Tak więc kierowca może zdefiniować ioctl, który pozwala aplikacji w przestrzeni użytkownika na wysyłanie zamówień. Jednak ioctl nie są zbyt elastyczne i mają tendencję do trochę zaśmiecania (dziesiątki "magicznych liczb", które po prostu działają ... lub nie), a także mogą być niepewne, gdy przekazujesz bufor do jądra - zła obsługa może się zepsuć rzeczy łatwo.
Alternatywą jest sysfs
interfejs, w którym ustawiasz plik pod /sys/
i odczytujesz / zapisujesz, aby uzyskać informacje od i do sterownika. Przykład, jak to ustawić:
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);
A podczas konfiguracji sterownika:
device_create_file(dev, &dev_attr_version);
Miałbyś wtedy plik dla swojego urządzenia /sys/
, na przykład /sys/block/myblk/version
dla sterownika blokowego.
Inną metodą do intensywniejszego wykorzystania jest netlink, czyli metoda IPC (komunikacja między procesami) służąca do komunikacji ze sterownikiem przez interfejs gniazda BSD. Jest to używane na przykład przez sterowniki WiFi. Następnie komunikujesz się z nim z przestrzeni użytkownika za pomocą bibliotek libnl
lub libnl3
.
ioctl
Funkcja ta jest przydatna do realizacji sterownika ustawić konfigurację urządzenia. np. drukarka posiadająca opcje konfiguracyjne do sprawdzania i ustawiania rodziny czcionek, rozmiaru czcionki itp. ioctl
może być użyta do pobrania aktualnej czcionki, jak również ustawienia nowej czcionki. Aplikacja użytkownika używa ioctl
do wysyłania kodu do drukarki z poleceniem zwrócenia bieżącej czcionki lub ustawienia nowej czcionki.
int ioctl(int fd, int request, ...)
fd
jest deskryptorem pliku, tym zwróconym przez open
;request
to kod żądania. np. GETFONT
pobierze aktualną czcionkę z drukarki, SETFONT
ustawi czcionkę na drukarce;void *
. W zależności od drugiego argumentu, trzeci może być obecny lub nie, np. Jeśli drugi argument jest SETFONT
, trzecim argumentem może być nazwa czcionki, taka jak "Arial"
;int request
to nie tylko makro. Aplikacja użytkownika jest wymagana do wygenerowania kodu żądania i modułu sterownika urządzenia, aby określić, z jaką konfiguracją urządzenia należy odtwarzać. Aplikacja wysyła kod żądania za pomocą, ioctl
a następnie używa kodu żądania w module sterownika urządzenia, aby określić, jakie działanie ma wykonać.
Kod żądania składa się z 4 głównych części
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).
Jeśli kod żądania ma SETFONT
ustawić czcionkę na drukarce, dane będą przesyłane z aplikacji użytkownika do modułu sterownika urządzenia (aplikacja użytkownika wysyła nazwę czcionki "Arial"
do drukarki). Jeśli kod żądania to GETFONT
, kierunek prowadzi z drukarki do aplikacji użytkownika.
Aby wygenerować kod żądania, Linux udostępnia pewne predefiniowane makra podobne do funkcji.
1. _IO(MAGIC, SEQ_NO)
oba mają 8 bitów, od 0 do 255, np. Powiedzmy, że chcemy wstrzymać drukarkę. Nie wymaga to przesyłania danych. Więc wygenerujemy kod żądania, jak poniżej
#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM)
a teraz użyj ioctl
jako
ret_val = ioctl(fd, PAUSE_PRIN);
Odpowiednie wywołanie systemowe w module sterownika otrzyma kod i wstrzyma drukarkę.
__IOW(MAGIC, SEQ_NO, TYPE)
MAGIC
i SEQ_NO
są takie same jak powyżej i TYPE
podaje typ następnego argumentu, przypomnij sobie trzeci argument ioctl
is void *
. W in __IOW
wskazuje, że przepływ danych odbywa się z aplikacji użytkownika do modułu sterownika. Na przykład załóżmy, że chcemy ustawić czcionkę drukarki na "Arial"
.#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)
dalej,
char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font);
Teraz font
jest wskaźnikiem, co oznacza, że jest to adres najlepiej reprezentowany jako unsigned long
, stąd trzecia część _IOW
typu jako takiego. Ponadto ten adres czcionki jest przekazywany do odpowiedniego wywołania systemowego zaimplementowanego w module sterownika urządzenia jako unsigned long
i przed użyciem musimy go rzutować na odpowiedni typ. Przestrzeń jądra może uzyskać dostęp do przestrzeni użytkownika i dlatego to działa. pozostałe dwa makra podobne do funkcji to __IOR(MAGIC, SEQ_NO, TYPE)
i __IORW(MAGIC, SEQ_NO, TYPE)
gdzie przepływ danych będzie odbywał się odpowiednio z przestrzeni jądra do przestrzeni użytkownika iw obie strony.
Proszę daj mi znać, czy to pomogło!