Meilleures pratiques : Utilisation d’URBs
Cette rubrique décrit les meilleures pratiques pour un pilote client pour l’allocation, la création et l’envoi d’un URB à la pile de pilotes USB incluse avec Windows 8.
Windows 8 comprend une nouvelle pile de pilotes USB pour prendre en charge les périphériques USB 3.0. La nouvelle pile de pilotes USB 3.0 implémente plusieurs nouvelles fonctionnalités, conformément à la spécification USB 3.0. En outre, la pile de pilotes inclut d’autres fonctionnalités qui permettent à un pilote client d’effectuer efficacement des tâches courantes. Par instance, la nouvelle pile de pilotes accepte les DLL chaînées qui permettent au pilote client d’envoyer une mémoire tampon de transfert dans des pages discontiguées en mémoire physique.
Avant qu’un pilote client puisse utiliser les nouvelles fonctionnalités de la pile de pilotes USB pour Windows 8, le pilote doit s’inscrire auprès de la pile de pilotes USB sous-jacente chargée par Windows pour le périphérique. Pour inscrire le pilote client, appelez USBD_CreateHandle et spécifiez une version de contrat. Si le pilote client est destiné à générer, exécuter et utiliser les améliorations et les nouvelles fonctionnalités sur Windows 8, la version du contrat client est USBD_CLIENT_CONTRACT_VERSION_602.
Pour un pilote client de version USBD_CLIENT_CONTRACT_VERSION_602, la pile de pilotes USB suppose que le pilote client est conforme à l’ensemble de règles suivant :
- N’envoyez pas de demandes d’E/S à l’aide de handles de canal obsolètes ou non valides
- Allouer des URB en appelant des routines d’allocation dans Windows 8
- Ne pas réutiliser les URB actifs associés aux demandes en attente
- N’utilisez pas la période d’interrogation supérieure à 8 pour les transferts à grande vitesse et SuperSpeed isochronous
- Assurez-vous que le nombre de paquets isochronous qui est un multiple du nombre de paquets par image
- Appeler la routine au niveau IRQL documenté
- Rubriques connexes
La pile de pilotes USB effectue des validations sur les demandes reçues et gère les violations dans la mesure du possible. Si vous ne le faites pas, vous risquez d’avoir un comportement non défini.
N’envoyez pas de demandes d’E/S à l’aide de handles de canal obsolètes ou non valides
Le pilote client ne doit pas utiliser de poignées de canal obsolètes pour envoyer des demandes d’E/S à la pile de pilotes USB. Un handle de canal obsolète fait référence à un handle de canal obtenu dans une demande de sélection d’une configuration, d’une interface ou d’un autre paramètre qui n’est plus sélectionné dans l’appareil. Pour éviter les handles de canal obsolètes, chaque fois que le pilote client sélectionne une configuration ou une interface, le pilote doit actualiser son cache de handles de canal (généralement stocké dans le contexte de l’appareil). Certaines conditions de concurrence peuvent également entraîner des poignées de canal obsolètes. Par instance, le pilote client envoie une demande d’E/S à l’aide d’un handle de canal sur l’interface sélectionnée. Avant la fin de la demande, le pilote client sélectionne un autre paramètre qui n’utilise pas le même point de terminaison associé au handle de canal utilisé. Ces deux demandes en attente peuvent entraîner une condition de concurrence rendant le handle de canal non valide.
Allouer des URB en appelant des routines d’allocation dans Windows 8
Windows 8 fournit de nouvelles routines pour l’allocation, la création et la publication de blocs de requête USB (URB). Pour allouer des URB, un pilote client WDM (Windows Driver Model) doit toujours utiliser les nouvelles routines indiquées dans la liste suivante :
- USBD_UrbAllocate
- USBD_IsochUrbAllocate
- USBD_SelectConfigUrbAllocateAndBuild
- USBD_SelectInterfaceUrbAllocateAndBuild
- USBD_UrbFree
- USBD_AssignUrbToIoStackLocation
Les routines de la liste précédente peuvent attacher un contexte URB opaque à l’URB alloué afin d’améliorer le suivi et le traitement. Le pilote client ne peut pas afficher ou modifier le contenu du contexte URB. Pour plus d’informations sur l’allocation URB dans Windows 8, consultez Allocation et création d’URIB.
Si un pilote client Windows Driver Framework (WDF) qui identifie sa version comme USBD_CLIENT_CONTRACT_VERSION_602 lors de l’inscription (voir WdfUsbTargetDeviceCreateWithParameters), la pile de pilotes USB attend du pilote client qu’il alloue de la mémoire pour l’URB en appelant le nouveau WdfUsbTargetDeviceCreateUrb.
Ne pas réutiliser les URB actifs associés aux demandes en attente
La pile de pilotes USB vérifie délibérément les bogues si elle détecte qu’un URB actif qui a été renvoyé avant la requête associée à l’URB. Un URB est actif tant que la demande est en attente et que la routine d’achèvement IRP du pilote client n’a pas été appelée. N’effectuez pas les tâches suivantes sur un URB actif.
- Ne renvoyez pas un URB actif pour une autre requête (associez l’URB à un autre IRP).
- Ne modifiez pas le contenu d’un URB actif.
- Ne libérez pas un URB actif.
Une fois la routine d’achèvement du pilote client appelée, les pilotes peuvent renvoyer des URB pour certains types de requête au sein de la routine d’achèvement. Les règles suivantes s’appliquent aux réadmissions :
Le pilote client ne doit pas réutiliser un URB alloué par USBD_SelectConfigUrbAllocateAndBuild pour tout type de demande autre qu’une demande de configuration de sélection pour sélectionner la même configuration.
Le pilote client ne doit pas réutiliser un URB alloué par USBD_SelectInterfaceUrbAllocateAndBuild pour tout type de requête autre qu’une demande d’interface de sélection pour sélectionner le même paramètre de remplacement dans une interface. Pour obtenir un exemple, consultez Remarques dans USBD_SelectInterfaceUrbAllocateAndBuild.
Un URB alloué par USBD_IsochUrbAllocate doit être réutilisé uniquement pour les demandes de transfert isochroneuses. À l’inverse, un URB alloué à d’autres types de demandes d’E/S (contrôle, bloc ou interruption) ne doit pas être utilisé pour une requête isochroneuse.
Par instance, un pilote client alloue et génère une structure URB pour une demande de transfert en bloc. Le pilote client souhaite également envoyer des données à des points de terminaison isochroques dans l’appareil. Une fois qu’une demande de transfert en bloc est terminée, le pilote client ne doit pas reformater et envoyer l’URB pour une demande isochroneuse. Cela est dû au fait qu’un URB associé à une requête isochroneuse a une longueur variable en fonction du nombre de paquets. En outre, les paquets sont requis pour démarrer et se terminer sur une limite de frame. L’URB alloué (pour le transfert en bloc) peut ne pas correspondre à la disposition de mémoire tampon requise pour un transfert isochroque et la demande peut échouer.
Un URB alloué par USBD_UrbAllocate ne doit pas être réutilisé pour une requête isochroneuse, select-configuration ou select-interface. L’URB peut être réutilisé pour sélectionner une configuration NULL afin de désactiver la configuration sélectionnée dans l’appareil. L’URB ne doit pas être actif et le pilote client doit reformater l’URB en appelant la macro UsbBuildSelectConfigurationRequest et en transmettant NULL dans le paramètre ConfigurationDescriptor .
Avant de soumettre à nouveau un URB, le pilote client doit reformater l’URB à l’aide de la macro UsbBuildXxx appropriée définie pour le type de requête. Il est important que le pilote formate l’URB, car la pile USB a peut-être modifié une partie de son contenu.
Par instance, supposons qu’un pilote appelle UsbBuildInterruptOrBulkTransferRequest pour initialiser un URB pour une demande de transfert en bloc (voir _URB_BULK_OR_INTERRUPT_TRANSFER). Si le pilote initialise le membre TransferBufferMDL de la structure URB sur NULL, la pile de pilotes USB utilise la mémoire tampon de transfert, spécifiée TransferBuffer, dans pour échanger des données avec le périphérique au lieu d’une MDL. Toutefois, en interne, la pile de pilotes USB peut créer une MDL, stocker un pointeur vers la MDL dans TransferBufferMDL et utiliser la MDL pour transmettre les données dans la pile. Même si la pile de pilotes USB libère la mémoire MDL, TransferBufferMDL peut ne pas avoir la valeur NULL lorsque le pilote client traite l’URB dans la routine d’achèvement. Pour s’assurer que les membres de l’URB sont correctement formatés, le pilote doit appeler à nouveau UsbBuildInterruptOrBulkTransferRequest pour reformater l’URB avant d’envoyer la demande,
N’utilisez pas la période d’interrogation supérieure à 8 pour les transferts à grande vitesse et SuperSpeed isochronous
La pile de pilotes USB prend en charge les canaux isochrones haute vitesse et SuperSpeed avec des numéros de période d’interrogation de 1, 2, 4 ou 8. Un pilote client ne doit pas envoyer d’E/S à un point de terminaison dont la période est supérieure à 8. Cela peut entraîner une vérification d’erreur.
Assurez-vous que le nombre de paquets isochronous qui est un multiple du nombre de paquets par image
Pour les transferts isochronous haute vitesse et SuperSpeed, le nombre de paquets isochrons par image est calculé comme 8 / période d’interrogation. Le pilote client doit s’assurer que la valeur NumberOfPackets spécifiée dans l’URB (voir _URB_ISOCH_TRANSFER) est un multiple du nombre de paquets par image.
La pile de pilotes USB ne prend pas en charge les URB de transfert isochrone dans lesquelles numberOfPackets n’est pas un multiple de paquets par image.
Appeler la routine au niveau IRQL documenté
Si vous inscrivez votre pilote client avec USBD_CLIENT_CONTRACT_VERSION_602 comme version du contrat, la pile de pilotes USB suppose que le pilote client a envoyé la demande au niveau IRQL approprié. Si un pilote client envoie une requête à DISPATCH_LEVEL, qui doit être envoyée à PASSIVE_LEVEL. Lors de la réception de la demande, dans certains cas, la pile de pilotes USB valide la valeur IRQL et échoue à la demande. Toutefois, dans d’autres cas, la pile de pilotes USB peut générer une vérification de bogue.