Kann mir jemand erklären,
- Was ist
IOCTL
? - Was wird es verwendet?
- Wie kann ich es benutzen?
- Warum kann ich keine neue Funktion definieren, die genauso funktioniert wie
IOCTL
?
Kann mir jemand erklären,
IOCTL
?IOCTL
?Antworten:
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 sysfs
Schnittstelle, ü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/version
fü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 libnl
oder libnl3
Bibliotheken mit dem Benutzerbereich.
Die ioctl
Funktion 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. ioctl
verwendet werden, um die aktuelle Schriftart abzurufen und die Schriftart auf eine neue einzustellen. Eine Benutzeranwendung ioctl
sendet 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, ...)
fd
ist der Dateideskriptor, der von zurückgegeben wird open
;request
ist Anforderungscode. zB GETFONT
wird die aktuelle Schriftart vom Drucker SETFONT
abgerufen, die Schriftart wird auf dem Drucker eingestellt;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 request
ist 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 ioctl
und 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 SETFONT
die 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 ioctl
als
ret_val = ioctl(fd, PAUSE_PRIN);
Der entsprechende Systemaufruf im Treibermodul empfängt den Code und hält den Drucker an.
__IOW(MAGIC, SEQ_NO, TYPE)
MAGIC
und SEQ_NO
sind die gleichen wie oben und TYPE
geben den Typ des nächsten Arguments an, erinnern Sie sich an das dritte Argument von ioctl
is void *
. W in __IOW
zeigt 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 font
ist ein Zeiger, was bedeutet, dass es sich um eine Adresse handelt, die am besten als dargestellt wird unsigned long
, daher der dritte Teil des _IOW
Erwä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!