Qualcuno può spiegarmi,
- Che cosa è
IOCTL
? - A cosa serve?
- Come posso usarlo?
- Perché non riesco a definire una nuova funzione che funzioni esattamente come
IOCTL
?
Qualcuno può spiegarmi,
IOCTL
?IOCTL
?Risposte:
Un ioctl
, che significa "controllo input-output" è un tipo di chiamata di sistema specifica del dispositivo. Ci sono solo alcune chiamate di sistema in Linux (300-400), che non sono sufficienti per esprimere tutte le funzioni uniche che i dispositivi potrebbero avere. Quindi un driver può definire un ioctl che consente a un'applicazione di spazio utente di inviargli ordini. Tuttavia, gli ioctl non sono molto flessibili e tendono ad essere un po 'ingombranti (dozzine di "numeri magici" che funzionano solo ... o no) e possono anche essere insicuri, quando si passa un buffer nel kernel - una cattiva gestione può rompersi le cose facilmente.
Un'alternativa è l' sysfs
interfaccia, in cui è possibile impostare un file in /sys/
e leggere / scrivere che per ottenere informazioni da e per il driver. Un esempio di come configurarlo:
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);
E durante l'installazione del driver:
device_create_file(dev, &dev_attr_version);
Avresti quindi un file per il tuo dispositivo /sys/
, ad esempio /sys/block/myblk/version
per un driver di blocco.
Un altro metodo per un uso più pesante è netlink, che è un metodo IPC (comunicazione tra processi) per comunicare con il driver tramite un'interfaccia socket BSD. Questo viene utilizzato, ad esempio, dai driver WiFi. Quindi comunichi con esso dallo spazio utente usando le librerie libnl
o libnl3
.
La ioctl
funzione è utile per implementare un driver di dispositivo per impostare la configurazione sul dispositivo. ad es. una stampante che ha opzioni di configurazione per controllare e impostare la famiglia di caratteri, la dimensione del carattere ecc. ioctl
potrebbe essere utilizzata per ottenere il carattere corrente e impostarne uno nuovo. Un'applicazione utente utilizza ioctl
per inviare un codice a una stampante che gli dice di restituire il carattere corrente o di impostarne uno nuovo.
int ioctl(int fd, int request, ...)
fd
è il descrittore di file, quello restituito da open
;request
è il codice di richiesta. ad es. GETFONT
otterrà il carattere corrente dalla stampante, SETFONT
imposterà il carattere sulla stampante;void *
. A seconda del secondo argomento, il terzo può essere o meno presente, ad esempio se il secondo argomento è SETFONT
, il terzo argomento può essere il nome del carattere come "Arial"
;int request
non è solo una macro. È richiesta un'applicazione utente per generare un codice di richiesta e il modulo del driver del dispositivo per determinare con quale configurazione sul dispositivo deve essere giocato. L'applicazione invia il codice di richiesta utilizzando ioctl
e quindi utilizza il codice di richiesta nel modulo del driver del dispositivo per determinare quale azione eseguire.
Un codice di richiesta ha 4 parti principali
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).
Se il codice di richiesta deve SETFONT
impostare il carattere su una stampante, la direzione per il trasferimento dei dati sarà dall'applicazione utente al modulo del driver del dispositivo (l'applicazione utente invia il nome del carattere "Arial"
alla stampante). Se il codice di richiesta è GETFONT
, la direzione va dalla stampante all'applicazione utente.
Per generare un codice di richiesta, Linux fornisce alcune macro simili a funzioni predefinite.
1. _IO(MAGIC, SEQ_NO)
entrambi sono 8 bit, da 0 a 255, ad esempio diciamo che vogliamo mettere in pausa la stampante. Ciò non richiede un trasferimento di dati. Quindi generiamo il codice di richiesta come di seguito
#define PRIN_MAGIC 'P'
#define NUM 0
#define PAUSE_PRIN __IO(PRIN_MAGIC, NUM)
e ora usa ioctl
come
ret_val = ioctl(fd, PAUSE_PRIN);
La chiamata di sistema corrispondente nel modulo driver riceverà il codice e metterà in pausa la stampante.
__IOW(MAGIC, SEQ_NO, TYPE)
MAGIC
e SEQ_NO
sono gli stessi di cui sopra, e TYPE
fornisce il tipo di argomento successivo, ricordando il terzo argomento di ioctl
is void *
. W in __IOW
indica che il flusso di dati va dall'applicazione utente al modulo driver. Ad esempio, supponiamo di voler impostare il carattere della stampante su "Arial"
.#define PRIN_MAGIC 'S'
#define SEQ_NO 1
#define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)
ulteriore,
char *font = "Arial";
ret_val = ioctl(fd, SETFONT, font);
Ora font
è un puntatore, il che significa che è un indirizzo meglio rappresentato come unsigned long
, quindi la terza parte del _IOW
tipo di menzioni come tale. Inoltre, questo indirizzo di carattere viene passato alla chiamata di sistema corrispondente implementata nel modulo del driver di dispositivo poiché unsigned long
è necessario eseguirne il cast al tipo corretto prima di utilizzarlo. Lo spazio del kernel può accedere allo spazio utente e quindi funziona. altre due macro simili a funzioni sono __IOR(MAGIC, SEQ_NO, TYPE)
e __IORW(MAGIC, SEQ_NO, TYPE)
dove il flusso di dati sarà dallo spazio del kernel allo spazio dell'utente e in entrambi i modi, rispettivamente.
Per favore fatemi sapere se questo aiuta!