Wiederherstellen nach USB-Pipe-Fehlern
Hinweis
Dieser Artikel richtet sich an Entwickler von Gerätetreibern. Wenn Sie Probleme mit einem USB-Gerät haben, lesen Sie bitte USB-C-Probleme in Windows beheben
In diesem Artikel finden Sie Informationen zu Maßnahmen, die Sie ergreifen können, wenn eine Datenübertragung auf eine USB-Pipe fehlschlägt. Die in diesem Artikel beschriebenen Mechanismen umfassen Abbruch-, Reset- und Cycle-Port-Operationen auf Bulk-, Interrupt- und isochronen Pipes.
Ein USB-Client-Treiber kommuniziert mit seinem Gerät, indem er Steuersignale an den Standard-Endpunkt und Datenübertragungen an Bulk-, Interrupt- und isochrone Endpunkte des Geräts sendet. Manchmal können diese Übertragungen aus verschiedenen Gründen fehlschlagen, z. B. wenn der Endpunkt blockiert ist. Wenn die Übertragung fehlschlägt, kann die zugehörige Pipe keine Anforderungen verarbeiten, bis die Fehlerbedingung behoben ist.
Bei Kontrolltransfers löscht der USB-Treiberstapel die Fehlerbedingungen automatisch. Bei Datenübertragungen muss der Client geeignete Maßnahmen ergreifen, um den Fehlerzustand zu beheben. Wenn eine Datenübertragung fehlschlägt, meldet der USB-Treiberstapel den Fehler durch fehlgeschlagene USBD-Statuscodes an den Client-Treiber. Auf der Grundlage des Statuscodes kann der Treiber dann einen Mechanismus zur Fehlerbehebung bereitstellen.
Dieser Artikel enthält Richtlinien zur Fehlerbehebung durch diese Vorgänge.
- Zurücksetzen der USB-Pipe
- Setzen Sie den USB-Anschluss zurück, an den das Gerät angeschlossen ist
- Schalten Sie den USB-Anschluss aus, um den Gerätestapel für den Client-Treiber neu aufzuzählen
Um einen Fehlerzustand zu beheben, beginnen Sie mit der Operation Reset-Pipe und führen komplexere Operationen wie Reset-Port und Cycle-Port nur aus, wenn es notwendig ist.
Koordinierung der verschiedenen Wiederherstellungsmechanismen:
Der Client-Treiber muss die verschiedenen Wiederherstellungsvorgänge koordinieren und sicherstellen, dass jeweils nur eine Methode verwendet wird. Nehmen wir zum Beispiel ein Gerät mit zwei Endpunkten: ein Bulk und ein Interrupt. Nachdem er einige Anforderungen zur Datenübertragung an das Gerät gesendet hat, stellt der Treiber fest, dass Anforderungen auf der Bulk-Pipe fehlschlagen. Um diese Fehler zu beheben, setzt der Treiber die Bulk-Pipe zurück. Dieser Vorgang behebt die Übertragungsfehler jedoch nicht und die Bulk-Transfers schlagen weiterhin fehl. Daher stellt der Treiber eine Anforderung zum Zurücksetzen des USB-Anschlusses. In der Zwischenzeit fangen die Übertragungen auf der Interrupt-Pipe an zu scheitern. Im Anschluss daran wird eine Anforderung zum Zurücksetzen des Geräts gestellt. Um die Fehler bei der Interrupt-Übertragung zu beheben, gibt der Treiber eine Reset-Pipe-Anforderung an die Interrupt-Pipe aus. Wenn diese beiden Vorgänge nicht koordiniert werden, kann der Treiber aufgrund von Fehlern auf beiden Pipes zwei Reset-Vorgänge gleichzeitig starten. Diese gleichzeitigen Vorgänge können problematisch werden.
Der Client-Treiber muss sicherstellen, dass der Treiber zu einem bestimmten Zeitpunkt nur einen Reset-Port- oder Cycle-Port-Vorgang durchführt. Während dieser Vorgänge sollte auf keiner Pipe eine Reset-Pipe-Operation laufen und der Treiber darf keine neue Reset-Pipe-Anforderung stellen.
Was Sie wissen müssen
Dieser Artikel verwendet das Kernel-Mode Driver Framework (KMDF).
Voraussetzungen
Der Client-Treiber muss das Objekt Framework USB-Zielgerät erstellt haben.
Wenn Sie die USB-Vorlagen verwenden, die mit Microsoft Visual Studio Professional 2012 geliefert werden, übernimmt der Vorlagencode diese Aufgaben. Der Vorlagencode erhält das Handle zum Zielgeräteobjekt und speichert es im Gerätekontext.
Ein KMDF-Client-Treiber muss ein WDFUSBDEVICE-Handle erhalten, indem er die Methode WdfUsbTargetDeviceCreateWithParameters anfragt. Weitere Informationen finden Sie unter „Geräte-Quellcode“ in Verstehen der Codestruktur des USB-Client-Treibers (KMDF).
Der Client-Treiber muss ein Handle auf das Framework-Ziel-Pipe-Objekt haben. Für weitere Informationen, siehe Aufzählung der USB-Pipes.
Schritt 1: Ermitteln Sie die Ursache der Fehlerbedingung
Der Client-Treiber leitet eine Datenübertragung ein, indem er einen USB-Anforderungsblock (URB) verwendet. Nach Abschluss der Anforderung gibt der USB-Treiber- Stapel einen USBD-Statuscode 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.
- Wenn Sie URB durch einen Aufruf der Methode WdfUsbTargetDeviceSendUrbSynchronously übermittelt haben, überprüfen Sie das Element Hdr.Status der URB-Struktur, nachdem die Methode zurückgekehrt ist.
- Wenn Sie die URB asynchron durch Aufruf der Methode WdfRequestSend übermittelt haben, überprüfen Sie den URB-Status in der EVT_WDF_REQUEST_COMPLETION_ROUTINE. Der Parameter Params verweist auf eine Struktur WDF_REQUEST_COMPLETION_PARAMS. Um den USBD-Statuscode zu überprüfen, sehen Sie sich das Element Usb->UsbdStatus an. Informationen über den Code finden Sie unter USBD_STATUS.
Übertragungsfehler können auf einen Gerätefehler zurückzuführen sein, wie z. B. USBD_STATUS_STALL_PID oder USBD_STATUS_BABBLE_DETECTED. Sie können auch durch einen vom Host-Controller gemeldeten Fehler entstehen, wie z. B. USBD_STATUS_XACT_ERROR.
Schritt 2: Stellen Sie fest, ob das Gerät mit dem Port verbunden ist
Vergewissern Sie sich, dass das Gerät angeschlossen ist, bevor Sie eine Anforderung stellen, die die Pipe oder das Gerät zurücksetzt. Sie können den Verbindungsstatus des Geräts ermitteln, indem Sie die Methode WdfUsbTargetDeviceIsConnectedSynchronous anfragen.
Schritt 3: Brechen Sie alle ausstehenden Übertragungen an die Pipeline ab.
Bevor Sie Anforderungen senden, die die Pipe oder den Port zurücksetzen, brechen Sie alle ausstehenden Übertragungsanforderungen an die Pipe ab, die der USB-Treiber-Stack noch nicht abgeschlossen hat. Sie können Anforderungen auf eine der folgenden Arten stornieren:
Halten Sie das E/A-Ziel an, indem Sie die Methode WdfIoTargetStop anfragen.
Um das E/A-Ziel anzuhalten, holen Sie sich zunächst das mit dem Framework-Pipe-Objekt verbundene WDFIOTARGET-Handle, indem Sie die Methode WdfUsbTargetPipeGetIoTarget anfragen. Rufen Sie mit dem Handle die Anfrage WdfIoTargetStop auf. Setzen Sie in der Anfrage die Aktion auf WdfIoTargetCancelSentIo (siehe WDF_IO_TARGET_SENT_IO_ACTION)**, um das Framework anzuweisen, alle Anforderungen abzubrechen, die der USB-Treiber-Stack noch nicht abgeschlossen hat. Bei abgeschlossenen Anforderungen muss der Client-Treiber darauf warten, dass sein Abschluss-Callback vom Framework aufgerufen wird.
Senden einer Anforderung zum Abbruch der Pipe. Sie können die Anforderung senden, indem Sie eine der folgenden Methoden aufrufen:
Rufen Sie die Methode WdfUsbTargetPipeAbortSynchronously auf.
Die Anfrage ist synchron und kehrt erst zurück, wenn alle ausstehenden Anforderungen abgebrochen wurden. WdfUsbTargetPipeAbortSynchronously nimmt einen optionalen Parameter Anforderung entgegen. Wir empfehlen Ihnen, ein WDFREQUEST-Handle an ein bereits zugewiesenes Framework-Anforderungsobjekt zu übergeben. Der Parameter ermöglicht dem Framework die Verwendung des angegebenen Anforderungsobjekts anstelle eines internen Anforderungsobjekts, auf das der Treiber nicht zugreifen kann. Dieser Parameterwert stellt sicher, dass WdfUsbTargetPipeAbortSynchronously nicht aufgrund von unzureichendem Speicher fehlschlägt.
Rufen Sie die Methode WdfUsbTargetPipeFormatRequestForAbort auf, um ein Anforderungsobjekt für eine Abort-Pipe-Anforderung zu formatieren, und senden Sie dann die Anforderung mit der Methode WdfRequestSend.
Wenn der Treiber die Anforderung asynchron sendet, muss er einen Verweis auf die EVT_WDF_REQUEST_COMPLETION_ROUTINE des Treibers angeben, die der Treiber implementiert. Um den Verweis anzugeben, fragen Sie die Methode WdfRequestSetCompletionRoutine an.
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, dann rufen Sie stattdessen WdfUsbTargetPipeAbortSynchronously auf.
Schritt 4: Zurücksetzen der USB-Pipe
Starten Sie die Fehlerbehebung, indem Sie die Pipe zurücksetzen. Sie können eine Reset-Pipe-Anforderung senden, indem Sie eine dieser Methoden aufrufen:
Rufen Sie die Funktion WdfUsbTargetPipeResetSynchronously auf, um eine Anforderung zum Zurücksetzen der Pipe synchron zu senden.
Rufen Sie die Methode WdfUsbTargetPipeFormatRequestForReset auf, um ein Anforderungsobjekt für eine Reset-Pipe-Anforderung zu formatieren, und senden Sie dann die Anforderung mit der Methode WdfRequestSend. Diese Anfragen ähneln denen für die Abbruch-Anforderung, wie in Schritt 3 beschrieben.
Hinweis
Senden Sie keine neuen Anforderungen, bis die Reset-Pipe-Operation abgeschlossen ist.
Die Anforderung der Reset-Pipe löscht den Fehlerzustand im Gerät und in der Hardware des Host-Controllers. Um den Gerätefehler zu löschen, sendet der USB-Treiber- Stapel eine CLEAR_FEATURE-Kontrollanforderung an das Gerät, indem er den Funktionsselektor ENDPOINT_HALT verwendet. Der Empfänger der Anforderung ist der Endpunkt, der mit der Pipe verbunden ist. Wenn der Fehler in einer isochronen Pipe aufgetreten ist, unternimmt der Treiberstapel nichts, um das Gerät zu löschen, da isochrone Endpunkte im Falle eines Fehlers automatisch gelöscht werden.
Um den Host-Controller-Fehler zu löschen, löscht der Treiberstapel den HALT-Status der Pipe und setzt den Daten-Toggle der Pipe auf 0 zurück.
Schritt 5: Zurücksetzen des USB-Ports
Wenn eine Reset-Pipe-Operation den Fehlerzustand nicht behebt und die Datenübertragung weiterhin fehlschlägt, senden Sie eine Reset-Port-Anforderung.
Brechen Sie alle Übertragungen an das Gerät ab. Dazu zählen Sie alle Pipes in der aktuellen Konfiguration auf und brechen ausstehende Anforderungen, die für jede Pipe geplant sind, ab.
Halten Sie das E/A-Ziel für das Gerät an.
Rufen Sie die Methode WdfUsbTargetDeviceGetIoTarget auf, um ein WDFIOTARGET-Handle zu erhalten, das mit dem Framework-Zielgeräteobjekt verbunden ist. Rufen Sie dann WdfIoTargetStop auf und geben Sie das WDFIOTARGET-Handle an. Setzen Sie in der Anfrage die Aktion auf WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).
Senden Sie eine Anforderung zum Zurücksetzen des Ports durch die Anfrage der Methode WdfUsbTargetDeviceResetPortSynchronously.
Ein Reset-Port-Vorgang führt dazu, dass das Gerät auf dem USB-Bus neu aufgelistet wird. Der USB-Treiberstapel behält die Gerätekonfiguration nach der Enumeration bei. Der Client-Treiber kann die zuvor erhaltenen Pipe-Handles verwenden, da der Treiberstapel sicherstellt, dass bestehende Pipe-Handles gültig bleiben.
Sie können eine einzelne Funktion eines Verbundgeräts nicht zurücksetzen. Bei einem Verbundgerät wird das gesamte Gerät zurückgesetzt, wenn der Client-Treiber einer bestimmten Funktion eine Anforderung für einen Reset-Port sendet. Wenn das USB-Gerät seinen Zustand beibehält, kann diese Anforderung des Reset-Ports die Client-Treiber anderer Funktionen beeinflussen. Deshalb ist es wichtig, dass der Client-Treiber versucht, die Pipe zurückzusetzen, bevor er den Port zurücksetzt.
Schritt 6: Schalten Sie den USB-Port ab
Eine Cycle-Port-Operation ähnelt dem Gerät, das ausgesteckt und wieder eingesteckt wird, nur dass das Gerät nicht elektrisch getrennt wird. Das Gerät wird in der Software abgetrennt und wieder angeschlossen. Dieser Vorgang führt zu einem Reset und einer Enumeration des Geräts. Infolgedessen baut der PnP Manager den Geräteknoten neu auf.
Wenn eine Reset-Port-Operation den Fehlerzustand nicht beseitigt und die Datenübertragung weiterhin fehlschlägt, senden Sie eine Cycle-Port-Anforderung.
Brechen Sie alle Übertragungen an das Gerät ab. Stellen Sie sicher, dass Sie ausstehende Anforderungen, die für jede Pipe in der aktuellen Konfiguration geplant sind, abbrechen (siehe Schritt 3).
Halten Sie das E/A-Ziel für das Gerät an.
Rufen Sie die Methode WdfUsbTargetDeviceGetIoTarget auf, um ein WDFIOTARGET-Handle zu erhalten, das mit dem Framework-Zielgeräteobjekt verbunden ist. Rufen Sie dann WdfIoTargetStop auf und geben Sie das WDFIOTARGET-Handle an. Setzen Sie in der Anfrage die Aktion auf WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).
Senden Sie eine Cycle-Port-Anforderung, indem Sie eine dieser Methoden anfragen:
- Rufen Sie die Funktion WdfUsbTargetDeviceCyclePortSynchronously auf, um eine Cycle-Port-Anforderung synchron zu senden.
- Rufen Sie die Methode WdfUsbTargetDeviceFormatRequestForCyclePort auf, um ein Anforderungsobjekt für eine Cycle-Port-Anforderung zu formatieren, und senden Sie dann die Anforderung mit der Methode WdfRequestSend. Diese Anfragen ähneln denen für die Abbruch-Anforderung, wie in Schritt 3 beschrieben.
Der Client-Treiber kann erst dann Übertragungsanforderungen an das Gerät senden, wenn die Cycle-Port-Anforderung abgeschlossen ist. Das liegt daran, dass der Geräteknoten entfernt wird, während der USB-Treiberstapel die Anforderung des Cycle-Ports verarbeitet.
Die Anforderung cycle-port führt dazu, dass das Gerät neu aufgezählt wird. Der USB-Treiberstapel informiert den PnP-Manager darüber, dass die Verbindung zum Gerät getrennt wurde. Der PnP Manager baut den mit dem Client-Treiber verbundenen Gerätestapel ab. Der Treiberstapel setzt das Gerät zurück, listet es am USB-Bus neu auf und informiert den PnP-Manager, dass ein Gerät angeschlossen wurde. Der PnP Manager baut dann den Gerätestapel für das USB-Gerät neu auf.
Als Ergebnis der Cycle-Port-Operation erhält jede Anwendung, die ein Handle auf das Gerät geöffnet hat, eine Benachrichtigung über das Entfernen des Geräts (sofern die Anwendung für eine solche Benachrichtigung registriert ist). Als Reaktion darauf meldet die Anwendung dem Benutzer möglicherweise eine Meldung, dass das Gerät nicht mehr verbunden ist. Da sich dies auf die Erfahrung des Benutzers auswirkt, sollte sich der Client-Treiber nur dann für eine Cycle-Port-Anforderung entscheiden, wenn andere Wiederherstellungsmechanismen den Fehlerzustand nicht beheben können.
Ähnlich wie bei der Reset-Port-Operation (beschrieben in Schritt 6) wirkt sich die Cycle-Port-Operation bei einem Verbundgerät auf das gesamte Gerät und nicht auf einzelne Funktionen des Geräts aus.