Sterownik urządzenia IOCTL Linux [zamknięty]


126

Czy ktoś może mi wyjaśnić,

  1. Co to jest IOCTL?
  2. Do czego jest to używane?
  3. Jak mogę tego używać?
  4. Dlaczego nie mogę zdefiniować nowej funkcji, która działa tak samo jak IOCTL?

Odpowiedzi:


99

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 sysfsinterfejs, 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/versiondla 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 libnllub libnl3.


3
Ta odpowiedź „odpowiada” na pytanie częściowo.
Vishal Sahu

163

ioctlFunkcja 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. ioctlmoże być użyta do pobrania aktualnej czcionki, jak również ustawienia nowej czcionki. Aplikacja użytkownika używa ioctldo wysyłania kodu do drukarki z poleceniem zwrócenia bieżącej czcionki lub ustawienia nowej czcionki.

int ioctl(int fd, int request, ...)
  1. fdjest deskryptorem pliku, tym zwróconym przez open;
  2. requestto kod żądania. np. GETFONTpobierze aktualną czcionkę z drukarki, SETFONTustawi czcionkę na drukarce;
  3. trzeci argument to 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 requestto 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ą, ioctla 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 SETFONTustawić 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 ioctljako

ret_val = ioctl(fd, PAUSE_PRIN);

Odpowiednie wywołanie systemowe w module sterownika otrzyma kod i wstrzyma drukarkę.

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGICi SEQ_NOsą takie same jak powyżej i TYPEpodaje typ następnego argumentu, przypomnij sobie trzeci argument ioctlis void *. W in __IOWwskazuje, ż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 fontjest wskaźnikiem, co oznacza, że ​​jest to adres najlepiej reprezentowany jako unsigned long, stąd trzecia część _IOWtypu 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!


Zastanawiam się, czy powyższe funkcje __IOW, __IOR i __IORW są poprawne (mam na myśli podwójne podkreślenie w niektórych przypadkach, w niektórych nie. Nigdy nie użyłem podwójnego podkreślenia) ... Dzięki za jasne wyjaśnienie!
jcoppens

Bardzo dobrze wyjaśnione .. Dzięki! Czy możesz podać mały fragment kodu po stronie sterownika, który używa tego ioctl?
Aadishri


Bardzo dobrze wyjaśnione. Dziękuję Ci. Myślę, że to _IOWR, a nie _IORW
Mohamed Samy

Odpowiadaj jak post na blogu.
Fredrick Gauss
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.