Maison  >  Article  >  Tutoriel système  >  Explication détaillée du flux de travail du pilote USB Linux

Explication détaillée du flux de travail du pilote USB Linux

王林
王林avant
2024-02-09 18:40:26637parcourir

Le pilote du noyau Linux est l'un des composants les plus importants du système Linux. Ils sont chargés de communiquer avec les périphériques matériels afin que le système d'exploitation puisse identifier et utiliser correctement le matériel. Cependant, développer des pilotes pour le noyau Linux n’est pas une tâche facile. Dans cet article, nous approfondirons la méthode d'implémentation du pilote du noyau Linux et fournirons aux lecteurs une compréhension et des conseils complets.

详解Linux USB驱动工作流程

1. Hôte USB

Dans les pilotes Linux, la couche inférieure du pilote USB est le matériel du contrôleur hôte USB. Au-dessus se trouve le pilote du contrôleur hôte USB. Au-dessus du contrôleur hôte se trouve la couche principale USB et la couche supérieure est le pilote du périphérique USB. Couche (insérez le disque U, la souris, l'USB vers le port série et d'autres pilotes de périphériques sur l'hôte).

Par conséquent, dans la hiérarchie côté hôte, le pilote USB à implémenter comprend deux catégories : le pilote de contrôleur hôte USB et le pilote de périphérique USB. Le premier contrôle le périphérique USB qui y est inséré, et le second contrôle la manière dont le périphérique USB communique avec le périphérique USB. hôte. Le noyau USB du noyau Linux est responsable du travail principal de gestion des pilotes USB et de traitement des protocoles. Le noyau USB entre le pilote du contrôleur hôte et le pilote de périphérique est très important. Ses fonctions incluent : en définissant certaines structures de données, macros et fonctions, il fournit une interface de programmation pour le pilote de périphérique vers le haut et fournit une interface de programmation pour le contrôleur hôte USB. pilote vers le bas ; les variables globales conservent les informations sur le périphérique USB de l'ensemble du système ; contrôle complet de la connexion à chaud du périphérique, contrôle de la transmission des données du bus, etc.

2. Périphérique USB

Le pilote côté périphérique USB dans le noyau Linux est divisé en trois niveaux : pilote UDC, API Gadget et pilote Gadget. Le pilote UDC accède directement au matériel, contrôle la communication sous-jacente entre le périphérique USB et l'hôte et fournit des fonctions de rappel pour les opérations liées au matériel vers la couche supérieure. L'API Gadget actuelle est un simple wrapper autour des fonctions de rappel du pilote UDC. Le pilote Gadget contrôle spécifiquement l'implémentation des fonctions du périphérique USB, permettant à l'appareil d'afficher des fonctionnalités telles que « connexion réseau », « imprimante » ou « stockage de masse USB ». Il utilise l'API Gadget pour contrôler l'UDC afin d'implémenter les fonctions ci-dessus. L'API Gadget isole le pilote UDC de couche inférieure du pilote Gadget de couche supérieure, permettant ainsi de séparer l'implémentation des fonctions de la communication sous-jacente lors de l'écriture d'un pilote côté périphérique USB dans un système Linux.

3. Dans la structure organisationnelle du périphérique USB, il est divisé en quatre niveaux de haut en bas : périphérique (device), configuration (config), interface (interface) et point final (endpoint). Le programme du périphérique USB est lié à l'interface.

Une brève description de ces quatre niveaux est la suivante :
Les appareils ont généralement une ou plusieurs configurations
Les configurations ont souvent une ou plusieurs interfaces
L'interface n'a pas ou plus d'un point de terminaison

详解Linux USB驱动工作流程

4. La forme de communication USB la plus élémentaire passe par les points de terminaison (les points de terminaison USB sont divisés en quatre types : interruption, masse, ISO et contrôle, chacun avec des utilisations différentes), les points de terminaison USB ne peuvent transmettre des données que dans une seule direction, à partir du de l'hôte vers l'appareil ou de l'appareil vers l'hôte. Le point de terminaison peut être considéré comme un canal unidirectionnel. Le pilote enregistre l'objet pilote auprès du sous-système USB et utilise ensuite l'identification du fabricant et du périphérique pour déterminer si le matériel est installé. Le noyau USB utilise une liste (une structure contenant l'ID du fabricant et l'ID du périphérique) pour déterminer quel pilote utiliser pour un périphérique, et le script de connexion à chaud l'utilise pour déterminer quand un périphérique spécifique est branché sur le système, quelle sonde de pilote doit être. automatiquement exécuté.

5. Structure des données

1) Périphérique USB : structure de données correspondante struct usb_device

2) Configuration : struct usb_host_config (Une seule configuration peut prendre effet à tout moment)

3) Interface USB : struct usb_interface (Le noyau USB le transmet au pilote de périphérique USB, et le pilote de périphérique USB est responsable du contrôle ultérieur. Une interface USB représente une fonction de base, et chaque pilote USB contrôle une interface. Donc un physique Les périphériques matériels peuvent nécessiter plusieurs pilotes)

.

4) Endpoint : struct usb_host_endpoint, les véritables informations sur le point final qu'il contient se trouvent dans une autre structure : struct usb_endpoint_descriptor (descripteur de point final, contient toutes les données spécifiques à l'USB).

6. Classification des points de terminaison USB

La forme la plus élémentaire de communication USB passe par ce qu'on appelle un point de terminaison. Un point de terminaison USB ne peut transférer des données que dans une seule direction (de l'hôte vers le périphérique (appelé point de terminaison de sortie) ou du périphérique vers l'hôte (appelé point de terminaison d'entrée)). Un point final peut être considéré comme un canal unidirectionnel.

Il existe 4 types différents de points de terminaison USB, chacun avec des méthodes de transmission de données différentes :

1) CONTRÔLE
Les points de terminaison de contrôle sont utilisés pour contrôler l'accès à différentes parties d'un périphérique USB. Ils sont généralement utilisés pour configurer le périphérique, obtenir des informations sur le périphérique, envoyer des commandes au périphérique ou obtenir des rapports sur l'état du périphérique. Ces points finaux sont généralement plus petits. Chaque périphérique USB possède un point final de contrôle appelé « Endpoint 0 », qui est utilisé par le noyau USB pour configurer le périphérique lorsqu'il est branché. Le protocole USB garantit qu'il reste toujours suffisamment de bande passante pour que le point final de contrôle transmette les données à l'appareil.

2) INTERRUPTION
Chaque fois que l'hôte USB demande des données au périphérique, le point de terminaison d'interruption transmet une petite quantité de données à un débit fixe. Il s’agit de la principale méthode de transfert de données pour les claviers et souris USB. Il est également utilisé pour transférer des données vers des périphériques USB afin de contrôler l'appareil. Généralement non utilisé pour transférer de grandes quantités de données. Le protocole USB garantit qu'il reste toujours suffisamment de bande passante pour que le point final de l'interruption transmette les données à l'appareil.

3) Lot EN VRAC
Les points de terminaison en masse sont utilisés pour transférer de grandes quantités de données. Ces points de terminaison sont généralement beaucoup plus grands que les points de terminaison d’interruption. Ils sont couramment utilisés dans des situations où il ne peut y avoir de perte de données. Le protocole USB ne garantit pas que le transfert sera effectué dans un délai précis. S'il n'y a pas assez d'espace sur le bus pour envoyer l'intégralité du paquet BULK, celui-ci est divisé en plusieurs paquets pour la transmission. Ces points de terminaison sont couramment utilisés sur les imprimantes, le stockage de masse USB et les périphériques réseau USB.

4) ISOCHRONE
Les points de terminaison isochrones transfèrent également de grandes quantités de données par lots, mais leur livraison n'est pas garantie. Ces points de terminaison sont utilisés dans des appareils capables de gérer la perte de données et s'appuient davantage sur le maintien d'un flux continu de données. Tels que les équipements audio et vidéo, etc.

Les points de terminaison de contrôle et de lot sont utilisés pour le transfert de données asynchrone, tandis que les points de terminaison d'interruption et isochrones sont périodiques. Cela signifie que ces points de terminaison sont configurés pour transmettre des données en continu à une heure fixe et que le cœur USB leur réserve la bande passante correspondante.

7. point final

struct usb_host_endpoint{  struct usb_endpoint_descriptor desc;//端点描述符  struct list_head urb_list;//此端点的URB对列,由USB核心维护  void *hcpriv;  struct ep_device *ep_dev; /* For sysfs info */  unsigned char*extra;/* Extra descriptors */  int extralen;  int enabled;};

Lorsque le pilote de périphérique USB appelle usb_submit_urb pour soumettre une requête urb, int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) sera appelé pour ajouter cette urb à la queue de urb_list. (hcd : pilote de contrôleur hôte, structure de données correspondante struct usb_hcd)

8.urb

Toutes les communications USB sont en mode requête->réponse et les périphériques USB n'enverront pas activement de données à l'hôte. Écrire des données : le pilote de périphérique USB envoie une requête urb au périphérique USB, et le périphérique USB n'a pas besoin de renvoyer de données. Lire les données : le pilote du périphérique USB envoie une requête urb au périphérique USB et le périphérique USB doit renvoyer des données.

Le pilote de périphérique USB communique avec tous les périphériques USB via urb. urb est décrit avec la structure struct urb (include/linux/usb.h).
urb envoie ou reçoit des données de manière asynchrone vers un point de terminaison spécifique d'un périphérique USB spécifique. Un pilote de périphérique USB peut attribuer plusieurs urb à un seul point de terminaison ou réutiliser un seul urb pour plusieurs points de terminaison différents, en fonction des besoins du pilote. Chaque point de terminaison de l'appareil gère une file d'attente Urb, de sorte que plusieurs Urbs peuvent être envoyés au même point de terminaison avant que la file d'attente ne soit vidée.

Le cycle de vie typique d'une urb est le suivant :
(1) Créé ; (2) Un point de terminaison spécifique attribué à un périphérique USB spécifique ; (3) Soumis au noyau USB ; (4) Soumis par le noyau USB à un pilote de contrôleur hôte USB spécifique pour un périphérique spécifique ; (5) Traité par le pilote du contrôleur hôte USB et transmis à l'appareil
 ; (6) Une fois les opérations ci-dessus terminées, le pilote du contrôleur hôte USB informe le pilote du périphérique USB.

urb peut également être annulé à tout moment par le pilote qui l'a soumis ; si le périphérique est supprimé, urb peut être annulé par le noyau USB. Les urbs sont créés dynamiquement et contiennent un décompte de références interne afin qu'ils puissent être automatiquement libérés lorsque le dernier utilisateur les libère.

8.1 Soumettre urb

Une fois l'urb correctement créé et initialisé, il peut être soumis au noyau USB pour être envoyé au périphérique USB. Ceci est réalisé en appelant la fonction sb_submit_urb.

.

int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
Paramètres :
struct urb *urb : pointeur vers l'urb soumis
gfp_t mem_flags : utilise les mêmes paramètres transmis à l'appel kmalloc pour indiquer au cœur USB comment allouer les tampons de mémoire en temps opportun

Comme la fonction usb_submit_urb peut être appelée à tout moment (y compris depuis un contexte d'interruption), la variable mem_flags doit être définie correctement. Selon le moment où usb_submit_urb est appelé, seules 3 valeurs valides sont disponibles :

GFP_ATOMIC
Cette valeur doit être utilisée tant que les conditions suivantes sont remplies :
1) L'appelant se trouve dans un gestionnaire de fin d'urb, un gestionnaire d'interruption, une moitié inférieure, une tasklet ou une fonction de rappel de minuterie.
2) L'appelant détient un verrou tournant ou un verrou en lecture-écriture. Notez que si un sémaphore est détenu, cette valeur n'est pas nécessaire.
. 3) l'état actuel n'est pas TASK_RUNNING. À moins que le pilote n'ait modifié l'état actuel par lui-même, l'état devrait toujours être TASK_RUNNING.

.

GFP_NOIO
Le pilote est utilisé lors du traitement des E/S des blocs. Il doit également être utilisé lors de la gestion des erreurs pour tous les types de stockage.

GFP_KERNEL
Toutes autres situations qui n'entrent pas dans les situations mentionnées précédemment

Une fois l'urb soumis avec succès au noyau USB, aucun membre de la structure urb n'est accessible jusqu'à ce que la fonction de routine de traitement final soit appelée

8.2 Routine de traitement de fin d'urb

Si usb_submit_urb est appelé avec succès et transfère le contrôle de l'urb au noyau USB, la fonction renvoie 0 ; sinon, un code d'erreur négatif est renvoyé. Si la fonction est appelée avec succès, la routine du gestionnaire de fin sera appelée une fois à la fin de l'urb. .Lorsque cette fonction est appelée, le noyau USB complète l'urb et rend son contrôle au pilote de périphérique.

Il n'y a que 3 situations pour terminer urb et appeler la routine de traitement de fin :
(1) urb est envoyé avec succès à l'appareil et l'appareil renvoie la confirmation correcte. Si tel est le cas, la variable d'état dans urb est définie sur 0.
. (2) Une erreur se produit et la valeur de l'erreur est enregistrée dans la variable d'état de la structure urbaine.
(3) Dissociation de l'URB du noyau USB. Cela se produit soit lorsque le pilote demande au noyau USB d'annuler un urb soumis en appelant usb_unlink_urb ou usb_kill_urb, soit lorsqu'un urb lui a été soumis et que le périphérique est supprimé du système.

9. Détection et déconnexion

Dans la structure struct usb_driver, il y a 2 fonctions que le noyau USB appelle au moment opportun :
(1) Lorsque le périphérique est branché, si le cœur USB pense que le pilote peut le gérer (le cœur USB utilise une liste (une structure contenant l'ID du fabricant et l'ID du numéro de périphérique) pour déterminer quel pilote utiliser pour un périphérique) , la fonction de sonde est appelée. La fonction de sonde vérifie les informations sur l'appareil qui lui sont transmises et détermine si le pilote est réellement adapté à cet appareil.
(2) Pour certaines raisons, lorsque l'appareil est retiré ou que le pilote ne contrôle plus l'appareil, appelez la fonction de déconnexion et effectuez le nettoyage approprié.

Les fonctions de rappel de détection et de déconnexion sont appelées dans le contexte du thread du noyau du hub USB, il est donc légal de les mettre en veille. Afin de réduire le temps de détection USB, la plupart du travail est effectué lorsque l'appareil est allumé. L'ajout et la suppression de périphériques USB sont gérés dans le thread, de sorte que tout pilote de périphérique lent peut allonger le temps de détection du périphérique USB.

9.1 Analyse de la fonction de détection
Dans la fonction de rappel de sonde, le pilote de périphérique USB doit initialiser toutes les structures locales qu'il peut utiliser pour gérer le périphérique USB et enregistrer toutes les informations requises sur le périphérique dans les structures locales, car il est généralement plus facile de le faire à ce moment-là pour communiquer. avec l'appareil, le pilote USB sonde généralement l'adresse du point de terminaison et la taille du tampon de l'appareil.

Dans cet article, nous présentons en détail la méthode d'implémentation du pilote du noyau Linux, y compris le cadre du pilote du noyau, l'écriture du module du noyau, l'enregistrement et la désinscription du pilote de périphérique, etc. Nous pensons qu'en étudiant cet article, les lecteurs pourront mieux comprendre les principes d'implémentation du pilote du noyau Linux et fournir davantage de références et d'aide pour leur propre travail de développement.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer