144 votes

IOCTL Pilote de périphérique Linux

Quelqu'un peut-il m'expliquer,

  1. Qu'est-ce que IOCTL ?
  2. A quoi sert-il ?
  3. Comment puis-je l'utiliser ?
  4. Pourquoi je ne peux pas définir une nouvelle fonction qui fait le même travail que IOCTL ?

194voto

anukalp Points 1680

Le site ioctl est utile pour mettre en œuvre un pilote de périphérique afin de définir la configuration du périphérique. Par exemple, une imprimante qui possède des options de configuration pour vérifier et définir la famille de polices, la taille des polices, etc. ioctl peut être utilisé pour obtenir la police actuelle et pour définir une nouvelle police. Une application utilisateur utilise ioctl pour envoyer un code à une imprimante lui demandant de renvoyer la police actuelle ou d'en choisir une nouvelle.

int ioctl(int fd, int request, ...)
  1. fd est un descripteur de fichier, celui retourné par open ;
  2. request est le code de la demande, par exemple GETFONT récupère la police actuelle de l'imprimante, SETFONT définira la police de l'imprimante ;
  3. le troisième argument est void * . Selon le deuxième argument, le troisième peut être présent ou non, par exemple, si le deuxième argument est SETFONT le troisième argument peut être le nom de la police, tel que "Arial" ;

int request n'est pas seulement une macro. Une application utilisateur est nécessaire pour générer un code de demande et le module du pilote de périphérique pour déterminer avec quelle configuration du périphérique il faut jouer. L'application envoie le code de requête en utilisant ioctl et utilise ensuite le code de demande dans le module du pilote de périphérique pour déterminer l'action à effectuer.

Un code de demande comporte 4 parties principales

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

Si le code de la demande est SETFONT pour définir la police de caractères d'une imprimante, le transfert de données s'effectue de l'application utilisateur vers le module du pilote de périphérique (l'application utilisateur envoie le nom de police "Arial" à l'imprimante). Si le code de demande est GETFONT La direction est celle de l'imprimante vers l'application de l'utilisateur.

Afin de générer un code de demande, Linux fournit quelques macros prédéfinies de type fonction.

1. _IO(MAGIC, SEQ_NO) Les deux sont de 8 bits, de 0 à 255, par exemple, disons que nous voulons mettre l'imprimante en pause. Cela ne nécessite pas de transfert de données. Nous générerons donc le code de demande comme suit

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

et utiliser maintenant ioctl comme

ret_val = ioctl(fd, PAUSE_PRIN);

L'appel système correspondant dans le module pilote recevra le code et mettra l'imprimante en pause.

  1. __IOW(MAGIC, SEQ_NO, TYPE) MAGIC y SEQ_NO sont les mêmes que ci-dessus, et TYPE donne le type de l'argument suivant, rappelez-vous le troisième argument de ioctl es void * . W dans __IOW indique que le flux de données va de l'application utilisateur au module pilote. A titre d'exemple, supposons que nous voulions définir la police de l'imprimante sur "Arial" .

    define PRIN_MAGIC 'S'

    define SEQ_NO 1

    define SETFONT __IOW(PRIN_MAGIC, SEQ_NO, unsigned long)

plus loin,

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

Ahora font est un pointeur, ce qui signifie que c'est une adresse représentée au mieux par unsigned long d'où la troisième partie de _IOW mentionne le type en tant que tel. De plus, cette adresse de la police est transmise à l'appel système correspondant mis en œuvre dans le module du pilote de périphérique, comme suit unsigned long et nous devons le convertir en un type approprié avant de l'utiliser. L'espace du noyau peut accéder à l'espace utilisateur et donc cela fonctionne. Les deux autres macros de type fonction sont __IOR(MAGIC, SEQ_NO, TYPE) y __IORW(MAGIC, SEQ_NO, TYPE) où le flux de données sera de l'espace noyau à l'espace utilisateur et dans les deux sens respectivement.

Faites-moi savoir si cela vous aide !

109voto

Inductiveload Points 2975

Un site ioctl La commande d'entrée-sortie est une sorte d'appel système spécifique au périphérique. Il n'y a que quelques appels système dans Linux (300-400), ce qui n'est pas suffisant pour exprimer toutes les fonctions uniques que les périphériques peuvent avoir. Un pilote peut donc définir un ioctl qui permet à une application de l'espace utilisateur de lui envoyer des ordres. Cependant, les ioctl ne sont pas très flexibles et ont tendance à être un peu encombrés (des douzaines de "chiffres magiques" qui fonctionnent... ou pas), et peuvent aussi être peu sûrs, car vous passez un tampon au noyau - une mauvaise manipulation peut facilement casser les choses.

Une alternative est le sysfs où vous configurez un fichier sous /sys/ et le lire/écrire pour obtenir des informations de et vers le pilote. Voici un exemple de configuration :

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

Et pendant la configuration du pilote :

device_create_file(dev, &dev_attr_version);

Vous aurez alors un fichier pour votre appareil dans le dossier /sys/ par exemple, /sys/block/myblk/version pour un conducteur de bloc.

Une autre méthode pour une utilisation plus lourde est netlink, qui est une méthode IPC (communication inter-processus) pour parler à votre pilote via une interface socket BSD. Cette méthode est utilisée, par exemple, par les pilotes WiFi. Vous communiquez ensuite avec lui depuis l'espace utilisateur en utilisant la commande libnl o libnl3 bibliothèques.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X