Wiederherstellen nach USB-Pipefehlern

Hinweis

Dieser Artikel richtet sich an Gerätetreiberentwickler. Wenn Probleme mit einem USB-Gerät auftreten, finden Sie weitere Informationen unter Behandeln häufiger USB-Probleme.

Dieser Artikel enthält Informationen zu Schritten, die Sie ausprobieren können, wenn bei der Datenübertragung an eine USB-Pipe ein Fehler auftritt. Die in diesem Artikel beschriebenen Mechanismen umfassen Abbruch-, Zurücksetzungs- und Zyklusportvorgänge für Massen-, Unterbrechungs- und isochrone Rohre.

Ein USB-Clienttreiber kommuniziert mit seinem Gerät, indem er Steuerungsübertragungen an den Standardendpunkt sendet. Datenübertragungen an Massen-, Unterbrechungs- und isochrone Endpunkte des Geräts. Manchmal können diese Übertragungen aus verschiedenen Gründen fehlschlagen, z. B. aufgrund einer Stockbedingung im Endpunkt. Wenn die Übertragung fehlschlägt, kann die zugeordnete Pipe Anforderungen erst verarbeiten, wenn die Fehlerbedingung gelöscht wird.

Bei Steuerungsübertragungen löscht der USB-Treiberstapel die Fehlerbedingungen automatisch. Bei Datenübertragungen muss der Client geeignete Schritte unternehmen, um die Fehlerbedingung wiederherzustellen. Wenn eine Datenübertragung fehlschlägt, meldet der USB-Treiberstapel den Fehler über fehlerhafte USBD-status-Codes an den Clienttreiber. Basierend auf dem status Code kann der Treiber dann einen Fehlerwiederherstellungsmechanismus bereitstellen.

Dieser Artikel enthält Richtlinien zur Fehlerwiederherstellung durch diese Vorgänge.

  • Zurücksetzen der USB-Pipe
  • Zurücksetzen des USB-Anschlusses, an den das Gerät angeschlossen ist
  • Führen Sie den USB-Port aus, um den Gerätestapel für den Clienttreiber neu aufzulisten.

Um eine Fehlerbedingung zu löschen, beginnen Sie mit dem Reset-Pipe-Vorgang, und führen Sie komplexere Vorgänge wie reset-port und cycle-port nur dann aus, wenn dies erforderlich ist.

Informationen zur Koordinierung verschiedener Wiederherstellungsmechanismen:

Der Clienttreiber muss die verschiedenen Vorgänge für die Wiederherstellung koordinieren und sicherstellen, dass zu einem bestimmten Zeitpunkt nur eine Methode verwendet wird. Betrachten Sie beispielsweise ein Gerät mit zwei Endpunkten: einem Massenvorgang und einem Interrupt. Nach dem Senden einiger Datenübertragungsanforderungen an das Gerät erkennt der Treiber, dass Anforderungen auf der Massenpipe fehlschlagen. Um diese Fehler wiederherzustellen, setzt der Treiber die Massenpipe zurück. Mit diesem Vorgang werden die Übertragungsfehler jedoch nicht behoben, und bei Massenübertragungen tritt weiterhin ein Fehler auf. Daher gibt der Treiber eine Anforderung zum Zurücksetzen des USB-Ports aus. In der Zwischenzeit beginnen die Übertragungen, auf der Interruptpipe fehlzuschlagen, und dann eine Zurücksetzungsanforderung für das Gerät. Um die Fehler der Interruptübertragung wiederherzustellen, gibt der Treiber eine Reset-Pipe-Anforderung für die Interruptpipe aus. Wenn diese beiden Vorgänge nicht koordiniert sind, kann der Treiber zwei Gerätezurücksetzungsvorgänge gleichzeitig starten, aufgrund von Fehlern an beiden Pipes. Diese gleichzeitigen Vorgänge können problematisch sein.

Der Clienttreiber muss sicherstellen, dass der Treiber zu einem bestimmten Zeitpunkt nur einen Rücksetzport- oder Zyklusportvorgang ausführt. Während dieser Vorgänge sollte für keine Pipe ein Reset-Pipe-Vorgang ausgeführt werden, und der Treiber darf keine neue Reset-Pipe-Anforderung ausgeben.

Wichtige Informationen

In diesem Artikel wird das Kernelmodus-Treiberframework (KMDF) verwendet.

Voraussetzungen

  • Der Clienttreiber muss das Framework-USB-Zielgerätobjekt erstellt haben.

    Wenn Sie die USB-Vorlagen verwenden, die mit Microsoft Visual Studio Professional 2012 bereitgestellt werden, führt der Vorlagencode diese Aufgaben aus. Der Vorlagencode ruft das Handle für das Zielgerätobjekt ab und speichert im Gerätekontext.

    Ein KMDF-Clienttreiber muss ein WDFUSBDEVICE-Handle abrufen, indem er die WdfUsbTargetDeviceCreateWithParameters-Methode aufruft . Weitere Informationen finden Sie unter "Gerätequellcode" unter Grundlegendes zur USB-Clienttreibercodestruktur (KMDF).

  • Der Clienttreiber muss über ein Handle für das Zielpipeobjekt des Frameworks verfügen. Weitere Informationen finden Sie unter Auflisten von USB-Rohren.

Schritt 1: Ermitteln der Ursache der Fehlerbedingung

Der Clienttreiber initiiert eine Datenübertragung mithilfe eines USB-Anforderungsblocks (URB). Nach Abschluss der Anforderung gibt der USB-Treiberstapel einen USBD-status Code zurück, der angibt, ob die Übertragung erfolgreich war oder fehlgeschlagen ist. Bei einem Fehler gibt der USBD-Code den Grund für den Fehler an.

Übertragungsfehler können aus einem Gerätefehler resultieren, z. B. USBD_STATUS_STALL_PID oder USBD_STATUS_BABBLE_DETECTED. Sie können auch aufgrund eines vom Hostcontroller gemeldeten Fehlers auftreten, z. B. USBD_STATUS_XACT_ERROR.

Schritt 2: Bestimmen, ob das Gerät mit dem Port verbunden ist

Bevor Sie eine Anforderung ausgeben, die die Pipe oder das Gerät zurücksetzt, stellen Sie sicher, dass das Gerät verbunden ist. Sie können den Verbindungsstatus des Geräts ermitteln, indem Sie die WdfUsbTargetDeviceIsConnectedSynchronous-Methode aufrufen.

Schritt 3: Abbrechen aller ausstehenden Übertragungen an die Pipe

Vor dem Senden von Anforderungen, die die Pipe oder den Port zurücksetzen, brechen Sie alle ausstehenden Übertragungsanforderungen an die Pipe ab, die der USB-Treiberstapel noch nicht abgeschlossen hat. Sie können Anforderungen auf eine der folgenden Arten abbrechen:

  • Beenden Sie das E/A-Ziel, indem Sie die WdfIoTargetStop-Methode aufrufen.

    Um das E/A-Ziel zu beenden, rufen Sie zuerst das WDFIOTARGET-Handle ab, das dem Framework-Pipeobjekt zugeordnet ist, indem Sie die WdfUsbTargetPipeGetIoTarget-Methode aufrufen. Rufen Sie mithilfe des Handles WdfIoTargetStop auf. Legen Sie im Aufruf die Aktion auf WdfIoTargetCancelSentIo fest (siehe WDF_IO_TARGET_SENT_IO_ACTION)**, um das Framework anzuweisen, alle Anforderungen abzubrechen, die der USB-Treiberstapel nicht abgeschlossen hat. Bei anforderungen, die abgeschlossen wurden, muss der Clienttreiber warten, bis sein Abschlussrückruf vom Framework aufgerufen wird.

  • Senden Sie eine Abbruchpipeanforderung. Sie können die Anforderung senden, indem Sie eine der folgenden Methoden aufrufen:

    • Rufen Sie die WdfUsbTargetPipeAbortSynchronously-Methode auf .

      Der Aufruf ist synchron und wird erst zurückgegeben, nachdem alle ausstehenden Anforderungen abgebrochen wurden. WdfUsbTargetPipeAbortSynchronously verwendet einen optionalen Request-Parameter . Es wird empfohlen, ein WDFREQUEST-Handle an ein vorab zugewiesenes Frameworkanforderungsobjekt zu übergeben. Der Parameter ermöglicht es dem Framework, das angegebene Anforderungsobjekt anstelle eines internen Anforderungsobjekts zu verwenden, auf das der Treiber nicht zugreifen kann. Dieser Parameterwert stellt sicher, dass WdfUsbTargetPipeAbortSynchronously nicht aufgrund von unzureichendem Arbeitsspeicher fehlschlägt.

    • Rufen Sie die WdfUsbTargetPipeFormatRequestForAbort-Methode auf, um ein Anforderungsobjekt für eine abort-pipe-Anforderung zu formatieren, und senden Sie die Anforderung dann durch Aufrufen der WdfRequestSend-Methode .

      Wenn der Treiber die Anforderung asynchron sendet, muss er einen Zeiger auf die EVT_WDF_REQUEST_COMPLETION_ROUTINE des Treibers angeben, die der Treiber implementiert. Um den Zeiger anzugeben, rufen Sie die WdfRequestSetCompletionRoutine-Methode auf .

      Der Treiber kann die Anforderung synchron senden, indem er WDF_REQUEST_SEND_OPTION_SYNCHRONOUS als eine der Anforderungsoptionen in WdfRequestSend angibt. Wenn Sie die Anforderung synchron senden, rufen Sie stattdessen WdfUsbTargetPipeAbortSynchronously auf.

Schritt 4: Zurücksetzen der USB-Pipe

Starten Sie die Fehlerwiederherstellung, indem Sie die Pipe zurücksetzen. Sie können eine Reset-Pipe-Anforderung senden, indem Sie eine der folgenden Methoden aufrufen:

Hinweis

Senden Sie keine neuen Übertragungsanforderungen, bis der Vorgang zum Zurücksetzen der Pipe abgeschlossen ist.

Die Anforderung zum Zurücksetzen der Pipe löscht die Fehlerbedingung auf dem Gerät und der Hostcontrollerhardware. Um den Gerätefehler zu beheben, sendet der USB-Treiberstapel mithilfe der ENDPOINT_HALT Featureauswahl eine CLEAR_FEATURE-Steuerungsanforderung an das Gerät. Der Empfänger für die Anforderung ist der Endpunkt, der der Pipe zugeordnet ist. Wenn die Fehlerbedingung für eine isochrone Pipe aufgetreten ist, führt der Treiberstapel keine Aktion aus, um das Gerät zu löschen, da bei Fehlern isochrone Endpunkte automatisch gelöscht werden.

Um den Hostcontrollerfehler zu löschen, löscht der Treiberstapel den HALT-Zustand der Pipe und setzt den Datenschalter der Pipe auf 0 zurück.

Schritt 5: Zurücksetzen des USB-Anschlusses

Wenn bei einem Reset-Pipe-Vorgang die Fehlerbedingung nicht gelöscht wird und die Datenübertragung weiterhin fehlschlägt, senden Sie eine Anforderung zum Zurücksetzen des Ports.

  1. Abbrechen aller Übertragungen an das Gerät. Um dies zu tun, auflisten Sie alle Pipes in der aktuellen Konfiguration, und brechen Sie ausstehende Anforderungen ab, die für jede Pipe geplant sind.

  2. Beenden Sie das E/A-Ziel für das Gerät.

    Rufen Sie die WdfUsbTargetDeviceGetIoTarget-Methode auf, um ein WDFIOTARGET-Handle abzurufen, das dem Framework-Zielgerätobjekt zugeordnet ist. Rufen Sie dann WdfIoTargetStop auf, und geben Sie das WDFIOTARGET-Handle an. Legen Sie im Aufruf die Aktion auf WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION) fest.

  3. Senden Sie eine Anforderung zum Zurücksetzen des Ports, indem Sie die WdfUsbTargetDeviceResetPortSynchronously-Methode aufrufen.

Ein Reset-Port-Vorgang bewirkt, dass das Gerät auf dem USB-Bus erneut aufgelistet wird. Der USB-Treiberstapel behält die Gerätekonfiguration nach der Enumeration bei. Der Clienttreiber kann die zuvor abgerufenen Pipehandles verwenden, da der Treiberstapel sicherstellt, dass vorhandene Pipehandles gültig bleiben.

Sie können eine einzelne Funktion eines zusammengesetzten Geräts nicht zurücksetzen. Wenn bei einem zusammengesetzten Gerät der Clienttreiber einer bestimmten Funktion eine Anforderung zum Zurücksetzen des Ports sendet, wird das gesamte Gerät zurückgesetzt. Wenn das USB-Gerät den Zustand beibehält, kann sich diese Anforderung zum Zurücksetzen des Ports auf die Clienttreiber anderer Funktionen auswirken. Daher ist es wichtig, dass der Clienttreiber versucht, die Pipe zurückzusetzen, bevor der Port zurückgesetzt wird.

Schritt 6: Usb-Anschluss

Ein Zyklusportvorgang ähnelt dem Gerät, das ent- und wieder an den Port angeschlossen wird, mit der Ausnahme, dass das Gerät nicht elektrisch getrennt ist. Das Gerät wird getrennt und in softwareintern wieder verbunden. Dieser Vorgang führt zur Zurücksetzung und Enumeration des Geräts. Daher erstellt der PnP-Manager den Geräteknoten neu.

Wenn bei einem Vorgang zum Zurücksetzen des Ports die Fehlerbedingung nicht gelöscht wird und die Datenübertragung weiterhin fehlschlägt, senden Sie eine Zyklusportanforderung.

  1. Brechen Sie alle Übertragungen auf das Gerät ab. Stellen Sie sicher, dass Sie die für jede Pipe in der aktuellen Konfiguration geplante ausstehende Anforderung abbrechen (siehe Schritt 3).

  2. Beenden Sie das E/A-Ziel für das Gerät.

    Rufen Sie die WdfUsbTargetDeviceGetIoTarget-Methode auf, um ein WDFIOTARGET-Handle abzurufen, das dem Zielgerätobjekt des Frameworks zugeordnet ist. Rufen Sie dann WdfIoTargetStop auf, und geben Sie das WDFIOTARGET-Handle an. Legen Sie beim Aufruf die Aktion auf WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION) fest.

  3. Senden Sie eine Zyklusportanforderung, indem Sie eine der folgenden Methoden aufrufen:

Der Clienttreiber kann Erst nach Abschluss der Zyklusportanforderung Übertragungsanforderungen an das Gerät senden. Dies liegt daran, dass der Geräteknoten entfernt wird, während der USB-Treiberstapel die Zyklusportanforderung verarbeitet.

Die Cycle-Port-Anforderung bewirkt, dass das Gerät erneut aufgelistet wird. Der USB-Treiberstapel informiert den PnP-Manager darüber, dass das Gerät getrennt wurde. Der PnP-Manager reißt den Gerätestapel ab, der dem Clienttreiber zugeordnet ist. Der Treiberstapel setzt das Gerät zurück, zählt es auf dem USB-Bus neu auf und informiert den PnP-Manager darüber, dass ein Gerät verbunden wurde. Der PnP-Manager erstellt dann den Gerätestapel für das USB-Gerät neu.

Als Ergebnis des Zyklusportvorgangs erhält jede Anwendung, für die ein Handle für das Gerät geöffnet ist, eine Benachrichtigung zum Entfernen des Geräts (wenn die Anwendung für eine solche Benachrichtigung registriert ist). Als Reaktion meldet die Anwendung dem Benutzer möglicherweise eine Nachricht, die vom Gerät getrennt wurde. Da sich dies auf die Benutzerfreundlichkeit auswirkt, sollte sich der Clienttreiber nur für eine Zyklusportanforderung entscheiden, wenn andere Wiederherstellungsmechanismen die Fehlerbedingung nicht beheben.

Ähnlich wie beim Vorgang zum Zurücksetzen des Ports (beschrieben in Schritt 6) wirkt sich der Zyklusportbetrieb bei einem zusammengesetzten Gerät auf das gesamte Gerät und nicht auf einzelne Funktionen des Geräts aus.