Partager via


Comment récupérer à partir d’erreurs de canal USB

Notes

Cet article s’adresse aux développeurs de pilotes de périphérique. Si vous rencontrez des difficultés avec un périphérique USB, consultez Résoudre les problèmes usb courants

Cet article fournit des informations sur les étapes que vous pouvez essayer en cas d’échec d’un transfert de données vers un canal USB. Les mécanismes décrits dans cet article couvrent l’abandon, la réinitialisation et le cycle des opérations de port sur les canaux en bloc, les interruptions et les canaux isochronieux.

Un pilote client USB communique avec son appareil en envoyant des transferts de contrôle au point de terminaison par défaut ; les transferts de données vers les points de terminaison en bloc, les interruptions et les points de terminaison isochronieux de l’appareil. Parfois, ces transferts peuvent échouer pour diverses raisons, telles qu’une condition de blocage dans le point de terminaison. Si le transfert échoue, le canal associé ne peut pas traiter les demandes tant que la condition d’erreur n’a pas été effacée.

Pour les transferts de contrôle, la pile de pilotes USB efface automatiquement les conditions d’erreur. Pour les transferts de données, le client doit prendre les mesures appropriées pour récupérer à partir de la condition d’erreur. En cas d’échec d’un transfert de données, la pile de pilotes USB signale l’erreur au pilote client par le biais des codes de status USBD ayant échoué. En fonction du code status, le pilote peut ensuite fournir un mécanisme de récupération d’erreurs.

Cet article fournit des instructions sur la récupération d’erreurs par le biais de ces opérations.

  • Réinitialiser le canal USB
  • Réinitialiser le port USB auquel l’appareil est connecté
  • Cycler le port USB pour énumérer à nouveau la pile d’appareils pour le pilote client

Pour effacer une condition d’erreur, commencez par l’opération de canal de réinitialisation et effectuez des opérations plus complexes, telles que reset-port et cycle-port, uniquement si nécessaire.

À propos de la coordination des différents mécanismes de récupération :

Le pilote client doit coordonner les différentes opérations de récupération et s’assurer qu’une seule méthode est utilisée à un moment donné. Par exemple, considérez un appareil avec deux points de terminaison : un en bloc et une interruption. Après avoir envoyé quelques demandes de transfert de données à l’appareil, le pilote remarque que les demandes échouent sur le canal en bloc. Pour récupérer après ces erreurs, le pilote réinitialise le canal en bloc. Toutefois, cette opération ne résout pas les erreurs de transfert et les transferts en bloc continuent d’échouer. Par conséquent, le pilote émet une demande de réinitialisation du port USB. Pendant ce temps, les transferts commencent à échouer sur le canal d’interruption, puis une demande de réinitialisation de l’appareil. Pour récupérer après les échecs de transfert d’interruption, le pilote émet une demande de réinitialisation de canal sur le canal d’interruption. Si ces deux opérations ne sont pas coordonnées, le pilote peut démarrer deux opérations de réinitialisation de périphérique simultanément, en raison de défaillances sur les deux canaux. Ces opérations simultanées peuvent être problématiques.

Le pilote client doit s’assurer qu’à un moment donné, le pilote n’effectue qu’une seule opération de réinitialisation ou de port de cycle. Pendant ces opérations, une opération de réinitialisation de canal ne doit pas être en cours sur un canal et le pilote ne doit pas émettre de nouvelle demande de réinitialisation de canal.

Bon à savoir

Cet article utilise l’infrastructure de pilote en mode noyau (KMDF).

Prérequis

  • Le pilote client doit avoir créé l’objet de périphérique cible USB du framework.

    Si vous utilisez les modèles USB fournis avec Microsoft Visual Studio Professional 2012, le code du modèle effectue ces tâches. Le code de modèle obtient le handle de l’objet d’appareil cible et les stocke dans le contexte de l’appareil.

    Un pilote client KMDF doit obtenir un handle WDFUSBDEVICE en appelant la méthode WdfUsbTargetDeviceCreateWithParameters . Pour plus d’informations, consultez « Code source de l’appareil » dans Présentation de la structure de code du pilote client USB (KMDF).

  • Le pilote client doit avoir un handle pour l’objet de canal cible du framework. Pour plus d’informations, consultez Guide pratique pour énumérer des canaux USB.

Étape 1 : Déterminer la cause de la condition d’erreur

Le pilote client lance un transfert de données à l’aide d’un bloc de requête USB (URB). Une fois la demande terminée, la pile de pilotes USB retourne un code status USBD qui indique si le transfert a réussi ou s’il a échoué. En cas d’échec, le code USBD indique la raison de l’échec.

Les échecs de transfert peuvent résulter d’une erreur d’appareil, telle que USBD_STATUS_STALL_PID ou USBD_STATUS_BABBLE_DETECTED. Elles peuvent également se produire en raison d’une erreur signalée par le contrôleur hôte, telle que USBD_STATUS_XACT_ERROR.

Étape 2 : Déterminer si l’appareil est connecté au port

Avant d’émettre une demande qui réinitialise le canal ou l’appareil, assurez-vous que l’appareil est connecté. Vous pouvez déterminer l’état connecté de l’appareil en appelant la méthode WdfUsbTargetDeviceIsConnectedSynchronous .

Étape 3 : Annuler tous les transferts en attente vers le canal

Avant d’envoyer des requêtes qui réinitialisent le canal ou le port, annulez toutes les demandes de transfert en attente vers le canal, ce que la pile de pilotes USB n’a pas encore terminé. Vous pouvez annuler des demandes de l’une des manières suivantes :

  • Arrêtez la cible d’E/S en appelant la méthode WdfIoTargetStop .

    Pour arrêter la cible d’E/S, commencez par obtenir le handle WDFIOTARGET associé à l’objet de canal d’infrastructure en appelant la méthode WdfUsbTargetPipeGetIoTarget . À l’aide du handle, appelez WdfIoTargetStop. Dans l’appel, définissez l’action sur WdfIoTargetCancelSentIo (voir WDF_IO_TARGET_SENT_IO_ACTION)** pour indiquer à l’infrastructure d’annuler toutes les demandes que la pile de pilotes USB n’a pas terminées. Pour les demandes qui ont été effectuées, le pilote client doit attendre que son rappel d’achèvement soit appelé par l’infrastructure.

  • Envoyez une demande d’abandon du canal. Vous pouvez envoyer la demande en appelant l’une des méthodes suivantes :

    • Appelez la méthode WdfUsbTargetPipeAbortSynchronously .

      L’appel est synchrone et retourne uniquement une fois que toutes les demandes en attente ont été annulées. WdfUsbTargetPipeAbortSynchronously prend un paramètre Request facultatif. Nous vous recommandons de passer un handle WDFREQUEST à un objet de demande d’infrastructure préalloué. Le paramètre permet à l’infrastructure d’utiliser l’objet de requête spécifié au lieu d’un objet de requête interne auquel le pilote ne peut pas accéder. Cette valeur de paramètre garantit que WdfUsbTargetPipeAbortSynchronously n’échoue pas en raison d’une mémoire insuffisante.

    • Appelez la méthode WdfUsbTargetPipeFormatRequestForAbort pour mettre en forme un objet de requête pour une requête de canal d’abandon, puis envoyez la requête en appelant la méthode WdfRequestSend .

      Si le pilote envoie la requête de manière asynchrone, il doit spécifier un pointeur vers le EVT_WDF_REQUEST_COMPLETION_ROUTINE du pilote que le pilote implémente. Pour spécifier le pointeur, appelez la méthode WdfRequestSetCompletionRoutine .

      Le pilote peut envoyer la requête de manière synchrone en spécifiant WDF_REQUEST_SEND_OPTION_SYNCHRONOUS comme l’une des options de requête dans WdfRequestSend. Si vous envoyez la requête de manière synchrone, appelez WdfUsbTargetPipeAbortSynchronously à la place.

Étape 4 : Réinitialiser le canal USB

Démarrez la récupération d’erreur en réinitialisant le canal. Vous pouvez envoyer une demande de réinitialisation de canal en appelant l’une des méthodes suivantes :

  • Appelez le WdfUsbTargetPipeResetSynchronously pour envoyer une requête de canal de réinitialisation de manière synchrone.

  • Appelez la méthode WdfUsbTargetPipeFormatRequestForReset pour mettre en forme un objet de requête pour une requête de canal de réinitialisation, puis envoyez la requête en appelant la méthode WdfRequestSend . Ces appels sont similaires à ceux de la demande d’abandon du canal, comme décrit à l’étape 3.

Notes

N’envoyez pas de nouvelles demandes de transfert tant que l’opération de réinitialisation du canal n’est pas terminée.

La demande de réinitialisation du canal efface la condition d’erreur dans l’appareil et le matériel du contrôleur hôte. Pour effacer l’erreur de périphérique, la pile de pilotes USB envoie une demande de contrôle CLEAR_FEATURE à l’appareil à l’aide du sélecteur de fonctionnalités ENDPOINT_HALT. Le destinataire de la requête est le point de terminaison associé au canal. Si la condition d’erreur s’est produite sur un canal isochrone, la pile des pilotes n’effectue aucune action pour effacer l’appareil, car, en cas d’erreurs, les points de terminaison isochroneux sont automatiquement effacés.

Pour effacer l’erreur du contrôleur hôte, la pile de pilotes efface l’état HALT du canal et réinitialise le bouton bascule de données du canal sur 0.

Étape 5 : Réinitialiser le port USB

Si une opération de réinitialisation de canal n’efface pas la condition d’erreur et que les transferts de données continuent d’échouer, envoyez une demande de réinitialisation de port.

  1. Annulez tous les transferts vers l’appareil. Pour ce faire, énumérez tous les canaux dans la configuration actuelle et annulez les demandes en attente planifiées pour chaque canal.

  2. Arrêtez la cible d’E/S pour l’appareil.

    Appelez la méthode WdfUsbTargetDeviceGetIoTarget pour obtenir un handle WDFIOTARGET associé à l’objet d’appareil cible du framework. Ensuite, appelez WdfIoTargetStop et spécifiez le handle WDFIOTARGET. Dans l’appel, définissez l’action sur WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).

  3. Envoyez une demande de réinitialisation de port en appelant la méthode WdfUsbTargetDeviceResetPortSynchronously .

Une opération de réinitialisation du port entraîne la réinscrire l’appareil sur le bus USB. La pile de pilotes USB conserve la configuration de l’appareil après l’énumération. Le pilote client peut utiliser les poignées de canal obtenues précédemment, car la pile de pilotes garantit que les poignées de canal existantes restent valides.

Vous ne pouvez pas réinitialiser une fonction individuelle d’un appareil composite. Pour un appareil composite, lorsque le pilote client d’une fonction particulière envoie une demande de port de réinitialisation, l’appareil entier est réinitialisé. Si le périphérique USB conserve l’état, cette demande de port de réinitialisation peut affecter les pilotes clients d’autres fonctions. Par conséquent, il est important que le pilote client tente de réinitialiser le canal avant de réinitialiser le port.

Étape 6 : Cycle du port USB

Une opération de port de cycle est similaire à l’appareil qui est débranché et reconnecté au port, sauf que l’appareil n’est pas déconnecté électriquement. L’appareil est déconnecté et reconnecté dans un logiciel. Cette opération conduit à la réinitialisation et à l’énumération de l’appareil. Par conséquent, le Gestionnaire PnP reconstruit le nœud de l’appareil.

Si une opération de réinitialisation du port n’efface pas la condition d’erreur et que les transferts de données continuent d’échouer, envoyez une demande de port de cycle.

  1. Annulez tous les transferts vers l’appareil. Veillez à annuler la demande en attente planifiée pour chaque canal de la configuration actuelle (voir étape 3).

  2. Arrêtez la cible d’E/S pour l’appareil.

    Appelez la méthode WdfUsbTargetDeviceGetIoTarget pour obtenir un handle WDFIOTARGET associé à l’objet d’appareil cible du framework. Ensuite, appelez WdfIoTargetStop et spécifiez le handle WDFIOTARGET. Dans l’appel, définissez l’action sur WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).

  3. Envoyez une demande de port de cycle en appelant l’une des méthodes suivantes :

Le pilote client ne peut envoyer des demandes de transfert à l’appareil qu’une fois la demande de port de cycle terminée. En effet, le nœud d’appareil est supprimé pendant que la pile de pilotes USB traite la demande de port de cycle.

La demande de port de cycle entraîne la réinscrire l’appareil. La pile de pilotes USB informe le Gestionnaire PnP que l’appareil a été déconnecté. Le Gestionnaire PnP détruit la pile d’appareils associée au pilote client. La pile de pilotes réinitialise l’appareil, l’énumère à nouveau sur le bus USB et informe le Gestionnaire PnP qu’un appareil a été connecté. PnP Manager régénère ensuite la pile d’appareils pour le périphérique USB.

À la suite d’une opération de port de cycle, toute application qui a un handle ouvert sur l’appareil reçoit une notification de suppression d’appareil (si l’application inscrite pour une telle notification). En réponse, l’application peut signaler un message déconnecté de l’appareil à l’utilisateur. Étant donné qu’il a un impact sur l’expérience utilisateur, le pilote client ne doit opter pour une demande de port de cycle que si d’autres mécanismes de récupération ne résolvent pas la condition d’erreur.

Comme pour l’opération de réinitialisation du port (décrite à l’étape 6), pour un appareil composite, l’opération de port de cycle affecte l’ensemble de l’appareil et non les fonctions individuelles de l’appareil.