GNU/Linux >> LINUX-Kenntnisse >  >> Linux

IOCTL-Linux-Gerätetreiber

Der ioctl Die Funktion ist nützlich, um einen Gerätetreiber zu implementieren, um die Konfiguration auf dem Gerät festzulegen. z.B. ein Drucker mit Konfigurationsoptionen zum Überprüfen und Einstellen der Schriftartfamilie, Schriftgröße usw. ioctl könnte verwendet werden, um die aktuelle Schriftart zu erhalten und die Schriftart auf eine neue festzulegen. Eine Benutzeranwendung verwendet ioctl um einen Code an einen Drucker zu senden, der ihm mitteilt, die aktuelle Schriftart zurückzugeben oder die Schriftart auf eine neue einzustellen.

int ioctl(int fd, int request, ...)
  1. fd ist der Dateideskriptor, der von open zurückgegeben wird;
  2. request ist Anfragecode. B. GETFONT erhält die aktuelle Schriftart vom Drucker, SETFONT stellt die Schriftart auf dem Drucker ein;
  3. das dritte Argument ist void * . Abhängig vom zweiten Argument kann das dritte vorhanden sein oder nicht, z. wenn das zweite Argument SETFONT ist , kann das dritte Argument der Schriftartname sein, z. B. "Arial";

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

Ein Anfragecode 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 Anfragecode SETFONT ist Um die Schriftart auf einem Drucker festzulegen, erfolgt die Datenübertragung von der Benutzeranwendung zum Gerätetreibermodul (Die Benutzeranwendung sendet den Schriftartnamen "Arial" an den Drucker). Wenn der Anforderungscode GETFONT ist , Richtung vom Drucker zur Benutzeranwendung.

Um einen Anforderungscode zu generieren, bietet Linux einige vordefinierte funktionsähnliche Makros.

1._IO(MAGIC, SEQ_NO) beide sind 8 Bit, 0 bis 255, z. Angenommen, wir möchten den Drucker anhalten. Dazu ist keine Datenübertragung erforderlich. Wir würden also den Anfragecode wie folgt generieren

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

und verwenden Sie jetzt ioctl als

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) MAGIC und SEQ_NO sind die gleichen wie oben und TYPE gibt den Typ des nächsten Arguments an, erinnern Sie sich an das dritte Argument von ioctl ist void * . W in __IOW gibt an, dass der Datenfluss von der Benutzeranwendung zum Treibermodul erfolgt. Nehmen wir als Beispiel an, wir möchten die Druckerschriftart auf "Arial" setzen .
#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)

weiter,

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

Jetzt font ist ein Zeiger, was bedeutet, dass es sich um eine Adresse handelt, die am besten als unsigned long dargestellt wird , daher der dritte Teil von _IOW erwähnt den Typ als solchen. Außerdem wird diese Schriftartadresse an den entsprechenden Systemaufruf weitergegeben, der im Gerätetreibermodul als unsigned long implementiert ist und wir müssen es vor der Verwendung in den richtigen Typ umwandeln. Der Kernel-Space kann auf den User-Space zugreifen und daher funktioniert dies. zwei weitere funktionsähnliche Makros sind __IOR(MAGIC, SEQ_NO, TYPE) und __IORW(MAGIC, SEQ_NO, TYPE) wobei der Datenfluss vom Kernel-Space zum User-Space bzw. in beide Richtungen erfolgt.

Bitte lassen Sie mich wissen, ob dies hilft!


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

Eine Alternative ist der sysfs Schnittstelle, wo Sie eine Datei unter /sys/ anlegen und lesen/schreiben Sie das, um Informationen vom und zum Treiber zu erhalten. 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 Treiberinstallation:

device_create_file(dev, &dev_attr_version);

Sie hätten dann eine Datei für Ihr Gerät in /sys/ , zum Beispiel /sys/block/myblk/version für einen Blocktreiber.

Eine andere Methode für stärkere Nutzung ist Netlink, eine IPC-Methode (Inter-Process-Communication), um mit Ihrem Treiber über eine BSD-Socket-Schnittstelle zu kommunizieren. Dies wird beispielsweise von den WLAN-Treibern verwendet. Sie kommunizieren dann mit ihm aus dem Userspace mit dem libnl oder libnl3 Bibliotheken.


Linux
  1. Linux – Gemeint mit Mounten eines Geräts in Linux?

  2. Linux:So finden Sie den für ein Gerät verwendeten Gerätetreiber

  3. Linux – Woher kennt der Linux-Kernel Geräte-Major- und Minor-Nummern?

  4. Huawei Linux-Treiber auf Ubuntu 13.04?

  5. So erstellen Sie ein virtuelles Blockgerät (Loop-Gerät/Dateisystem) in Linux

Unter Linux ist alles eine Datei – Teil 1

Linux – Sysfs und Devtmpfs?

Linux – Wie finde ich den Treiber (Modul), der mit einem Gerät unter Linux verbunden ist?

Linux-Kernel-Gerätetreiber zum DMA von einem Gerät in den User-Space-Speicher

Linux-lsblk-Ausgabe

Konsistente Linux-Geräteaufzählung