IOCTL Linux-Gerätetreiber [geschlossen]

126

Kann mir jemand erklären,

  1. Was ist IOCTL?
  2. Was wird es verwendet?
  3. Wie kann ich es benutzen?
  4. Warum kann ich keine neue Funktion definieren, die genauso funktioniert wie IOCTL?
Flash-Disk
quelle

Antworten:

99

Ein ioctl, was "Eingabe-Ausgabe-Steuerung" bedeutet, ist eine Art gerätespezifischer Systemaufruf. Unter Linux (300-400) gibt es nur wenige Systemaufrufe, die nicht ausreichen, um alle einzigartigen Funktionen auszudrücken, die Geräte möglicherweise haben. So kann ein Treiber ein ioctl definieren, mit dem eine Userspace-Anwendung Bestellungen senden kann. Ioctls sind jedoch nicht sehr flexibel und neigen dazu, etwas überladen zu werden (Dutzende von "magischen Zahlen", die einfach funktionieren ... oder nicht) und können auch unsicher sein, wenn Sie einen Puffer in den Kernel übergeben - eine schlechte Handhabung kann brechen Dinge leicht.

Eine Alternative ist die sysfsSchnittstelle, über die Sie eine Datei einrichten /sys/und diese lesen / schreiben, um Informationen vom und zum Treiber abzurufen. Ein Beispiel für die Einrichtung:

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);

Und während der Treibereinrichtung:

device_create_file(dev, &dev_attr_version);

Sie hätten dann eine Datei für Ihr Gerät /sys/, beispielsweise /sys/block/myblk/versionfür einen Blocktreiber.

Eine andere Methode für eine stärkere Nutzung ist Netlink, eine IPC-Methode (Inter-Process Communication), mit der Sie über eine BSD-Socket-Schnittstelle mit Ihrem Treiber kommunizieren können. Dies wird beispielsweise von den WiFi-Treibern verwendet. Anschließend kommunizieren Sie über die libnloder libnl3Bibliotheken mit dem Benutzerbereich.

Induktive Last
quelle
3
Diese Antwort "beantwortet" die Frage teilweise.
Vishal Sahu
161

Die ioctlFunktion ist nützlich, um einen Gerätetreiber zu implementieren, um die Konfiguration auf dem Gerät festzulegen. Beispielsweise kann ein Drucker mit Konfigurationsoptionen zum Überprüfen und Einstellen der Schriftfamilie, Schriftgröße usw. ioctlverwendet werden, um die aktuelle Schriftart abzurufen und die Schriftart auf eine neue einzustellen. Eine Benutzeranwendung ioctlsendet einen Code an einen Drucker, der ihn auffordert, die aktuelle Schriftart zurückzugeben oder die Schriftart auf eine neue festzulegen.

int ioctl(int fd, int request, ...)
  1. fdist der Dateideskriptor, der von zurückgegeben wird open;
  2. requestist Anforderungscode. zB GETFONTwird die aktuelle Schriftart vom Drucker SETFONTabgerufen, die Schriftart wird auf dem Drucker eingestellt;
  3. Das dritte Argument ist void *. Abhängig vom zweiten Argument kann das dritte vorhanden sein oder nicht, z. B. wenn das zweite Argument ist SETFONT, kann das dritte Argument der Schriftname sein, wie z "Arial".

int requestist nicht nur ein Makro. Eine Benutzeranwendung muss einen Anforderungscode generieren und das Gerätetreibermodul bestimmen, mit welcher Konfiguration auf dem Gerät gespielt werden muss. Die Anwendung sendet den Anforderungscode mit ioctlund verwendet dann den Anforderungscode im Gerätetreibermodul, um zu bestimmen, welche Aktion ausgeführt werden soll.

Ein Anforderungscode besteht aus 4 Hauptteilen

    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).  

Wenn der Anforderungscode SETFONTdie Schriftart auf einem Drucker festlegen soll, lautet die Richtung für die Datenübertragung von der Benutzeranwendung zum Gerätetreibermodul (die Benutzeranwendung sendet den Schriftartnamen "Arial"an den Drucker). Wenn der Anforderungscode lautet GETFONT, erfolgt die Richtung vom Drucker zur Benutzeranwendung.

Um einen Anforderungscode zu generieren, stellt Linux einige vordefinierte funktionsähnliche Makros zur Verfügung.

1. _IO(MAGIC, SEQ_NO)Beide sind 8 Bit, 0 bis 255, z. B. sagen wir, wir möchten den Drucker anhalten. Dies erfordert keine Datenübertragung. Wir würden also den Anforderungscode wie folgt generieren

#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM) 

und jetzt verwenden ioctlals

ret_val = ioctl(fd, PAUSE_PRIN);

Der entsprechende Systemaufruf im Treibermodul empfängt den Code und hält den Drucker an.

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGICund SEQ_NOsind die gleichen wie oben und TYPEgeben den Typ des nächsten Arguments an, erinnern Sie sich an das dritte Argument von ioctlis void *. W in __IOWzeigt an, dass der Datenfluss von der Benutzeranwendung zum Treibermodul erfolgt. Angenommen, wir möchten die Schriftart des Druckers auf festlegen "Arial".
#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)

des Weiteren,

char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font); 

Jetzt fontist ein Zeiger, was bedeutet, dass es sich um eine Adresse handelt, die am besten als dargestellt wird unsigned long, daher der dritte Teil des _IOWErwähnungstyps als solcher. Außerdem wird diese Schriftartadresse an den entsprechenden Systemaufruf übergeben, der im Gerätetreibermodul als implementiert ist, unsigned long und wir müssen sie vor der Verwendung in den richtigen Typ umwandeln. Der Kernel-Speicherplatz kann auf den Benutzerbereich zugreifen, und dies funktioniert daher. beiden anderen Funktionsmakros sind __IOR(MAGIC, SEQ_NO, TYPE)und __IORW(MAGIC, SEQ_NO, TYPE)wo der Datenfluss bzw. den User - Space und beide Arten von Kernel - Space sein.

Bitte lassen Sie mich wissen, ob dies hilft!

Anukalp
quelle
Ich frage mich, ob die obigen Funktionen __IOW, __IOR und __IORW korrekt sind (ich meine den doppelten Unterstrich in einigen Fällen, in einigen Fällen nicht. Ich habe den doppelten Unterstrich nie verwendet) ... Vielen Dank für eine klare Erklärung!
Jcoppens
Sehr gut erklärt .. Danke! Können Sie bitte einen kleinen Code-Ausschnitt der Treiberseite geben, der dieses ioctl verwendet?
Aadishri
Sehr gut erklärt. Danke dir. Ich denke, es ist _IOWR nicht _IORW
Mohamed Samy
Antworte wie ein Blogbeitrag.
Fredrick Gauss