Bewährte Methoden: Verwenden von URBs
In diesem Thema werden bewährte Methoden für einen Clienttreiber zum Zuweisen, Erstellen und Senden einer URB an den USB-Treiberstapel beschrieben, der in Windows 8 enthalten ist.
Windows 8 enthält einen neuen USB-Treiberstapel zur Unterstützung von USB 3.0-Geräten (Universal Serial Bus). Der neue USB 3.0-Treiberstapel implementiert mehrere neue Funktionen gemäß der USB 3.0-Spezifikation. Darüber hinaus enthält der Treiberstapel weitere Funktionen, die es einem Clienttreiber ermöglichen, allgemeine Aufgaben effizient auszuführen. Für instance akzeptiert der neue Treiberstapel verkettete MDLs, die es dem Clienttreiber ermöglichen, einen Übertragungspuffer in unauffälligen Seiten im physischen Arbeitsspeicher zu senden.
Bevor ein Clienttreiber die neuen Funktionen des USB-Treiberstapels für Windows 8 nutzen kann, muss sich der Treiber bei dem zugrunde liegenden USB-Treiberstapel registrieren, der von Windows für das Gerät geladen wird. Um den Clienttreiber zu registrieren, rufen Sie USBD_CreateHandle auf, und geben Sie eine Vertragsversion an. Wenn der Clienttreiber zum Erstellen, Ausführen und Verwenden der Verbesserungen und der neuen Funktionen auf Windows 8 vorgesehen ist, wird die Clientvertragsversion USBD_CLIENT_CONTRACT_VERSION_602.
Bei einem Clienttreiber USBD_CLIENT_CONTRACT_VERSION_602 Version geht der USB-Treiberstapel davon aus, dass der Clienttreiber den folgenden Regeln entspricht:
- Senden sie keine E/A-Anforderungen mithilfe veralteter oder ungültiger Pipehandles.
- Zuordnen von URBs durch Aufrufen von Zuordnungsroutinen in Windows 8
- Verwenden Sie aktive URBs, die ausstehenden Anforderungen zugeordnet sind, nicht wieder.
- Verwenden Sie nicht den Abrufzeitraum größer als 8 für hochgeschwindigkeits- und SuperSpeed-isochrone Übertragungen
- Stellen Sie sicher, dass die Anzahl der isochronen Pakete, die ein Vielfaches der Anzahl von Paketen pro Frame ist
- Aufrufen der Routine auf dokumentierter IRQL-Ebene
- Zugehörige Themen
Der USB-Treiberstapel führt Überprüfungen für die empfangenen Anforderungen aus und behandelt die Verstöße nach Möglichkeit. Wenn dies nicht geschieht, kann dies zu einem nicht definierten Verhalten führen.
Senden sie keine E/A-Anforderungen mithilfe veralteter oder ungültiger Pipehandles.
Der Clienttreiber darf keine veralteten Pipehandles verwenden, um E/A-Anforderungen an den USB-Treiberstapel zu senden. Ein veraltetes Pipehandle bezieht sich auf ein Pipehandle, das in einer Anforderung zum Auswählen einer Konfiguration, einer Schnittstelle oder einer alternativen Einstellung abgerufen wurde, die im Gerät nicht mehr ausgewählt ist. Um veraltete Pipehandles zu vermeiden, muss der Treiber jedes Mal, wenn der Clienttreiber eine Konfiguration oder eine Schnittstelle auswählt, seinen Cache mit Pipehandles aktualisieren (normalerweise im Gerätekontext gespeichert). Bestimmte Racebedingungen können auch zu veralteten Pipe handles führen. Für instance sendet der Clienttreiber eine E/A-Anforderung mithilfe eines Pipehandles auf der ausgewählten Schnittstelle. Bevor die Anforderung abgeschlossen ist, wählt der Clienttreiber eine alternative Einstellung aus, die nicht denselben Endpunkt verwendet, der dem verwendeten Pipehandle zugeordnet ist. Beide ausstehenden Anforderungen können zu einer Racebedingung führen, die das Pipehandle ungültig macht.
Zuordnen von URBs durch Aufrufen von Zuordnungsroutinen in Windows 8
Windows 8 bietet neue Routinen zum Zuweisen, Erstellen und Freigeben von USB-Anforderungsblöcken (URBs). Um URBs zuzuordnen, muss ein WDM-Clienttreiber (Windows Driver Model) immer die in der folgenden Liste aufgeführten neuen Routinen verwenden:
- USBD_UrbAllocate
- USBD_IsochUrbAllocate
- USBD_SelectConfigUrbAllocateAndBuild
- USBD_SelectInterfaceUrbAllocateAndBuild
- USBD_UrbFree
- USBD_AssignUrbToIoStackLocation
Die Routinen in der vorherigen Liste können der zugeordneten URB einen undurchsichtigen URB-Kontext anfügen, um die Nachverfolgung und Verarbeitung zu verbessern. Der Clienttreiber kann den Inhalt des URB-Kontexts nicht anzeigen oder ändern. Weitere Informationen zur URB-Zuordnung in Windows 8 finden Sie unter Zuweisen und Erstellen von URBs.
Wenn ein WDF-Clienttreiber (Windows Driver Framework), der seine Version während der Registrierung als USBD_CLIENT_CONTRACT_VERSION_602 identifiziert (siehe WdfUsbTargetDeviceCreateWithParameters), erwartet der USB-Treiberstapel, dass der Clienttreiber Arbeitsspeicher für die URB ordnet, indem er das neue WdfUsbTargetDeviceCreateUrb aufruft.
Verwenden Sie aktive URBs, die ausstehenden Anforderungen zugeordnet sind, nicht wieder.
Der USB-Treiberstapel überprüft absichtlich Fehler, wenn er erkennt, dass eine aktive URB, die vor der Anforderung, die der URB zugeordnet ist, erneut übermittelt wurde. Eine URB ist aktiv, solange die Anforderung aussteht und die IRP-Vervollständigungsroutine des Clienttreibers nicht aufgerufen wurde. Führen Sie die folgenden Aufgaben nicht für eine aktive URB aus.
- Senden Sie keine aktive URB für eine andere Anforderung erneut (ordnen Sie die URB einem anderen IRP zu).
- Ändern Sie nicht den Inhalt einer aktiven URB.
- Geben Sie keine aktive URB frei.
Nachdem die Vervollständigungsroutine des Clienttreibers aufgerufen wurde, können die Treiber URBs für bestimmte Anforderungstypen innerhalb der Vervollständigungsroutine erneut übermitteln. Für erneute Übermittlungen gelten die folgenden Regeln:
Der Clienttreiber darf keine URB wiederverwenden, die von USBD_SelectConfigUrbAllocateAndBuild für einen anderen Anforderungstyp als eine Select-Configuration-Anforderung zugewiesen wird, um dieselbe Konfiguration auszuwählen.
Der Clienttreiber darf keine URB wiederverwenden, die von USBD_SelectInterfaceUrbAllocateAndBuild für einen anderen Anforderungstyp als eine Select-Interface-Anforderung zugewiesen wird, um dieselbe alternative Einstellung in einer Schnittstelle auszuwählen. Ein Beispiel finden Sie unter Hinweise in USBD_SelectInterfaceUrbAllocateAndBuild.
Eine URB, die von USBD_IsochUrbAllocate zugewiesen wird, darf nur für isochrone Übertragungsanforderungen wiederverwendet werden. Umgekehrt darf eine URB, die anderen E/A-Anforderungen zugeordnet ist (Steuerung, Massenanforderung oder Interrupt), nicht für eine isochrone Anforderung verwendet werden.
Für instance weist ein Clienttreiber eine URB-Struktur für eine Massenübertragungsanforderung zu und erstellt diese. Der Clienttreiber möchte auch Daten an isochrone Endpunkte auf dem Gerät senden. Nach Abschluss einer Massenübertragungsanforderung darf der Clienttreiber die URB für eine isochrone Anforderung nicht neu formatieren und übermitteln. Das liegt daran, dass eine URB, die einer isochronen Anforderung zugeordnet ist, abhängig von der Anzahl der Pakete eine variable Länge aufweist. Darüber hinaus sind die Pakete erforderlich, um auf einer Framegrenze zu starten und zu enden. Die zugeordnete URB (für die Massenübertragung) passt möglicherweise nicht zum Pufferlayout, das für eine isochrone Übertragung erforderlich ist, und die Anforderung schlägt möglicherweise fehl.
Eine URB, die von USBD_UrbAllocate zugewiesen wird, darf nicht für eine isochrone, eine Select-Configuration oder eine Select-Interface-Anforderung wiederverwendet werden. Die URB kann wiederverwendet werden, um eine NULL-Konfiguration auszuwählen, um die ausgewählte Konfiguration auf dem Gerät zu deaktivieren. Die URB darf nicht aktiv sein, und der Clienttreiber muss die URB neu formatieren, indem das Makro UsbBuildSelectConfigurationRequest aufgerufen und NULL im Parameter ConfigurationDescriptor übergeben wird.
Vor dem erneuten Übermitteln einer URB muss der Clienttreiber die URB mithilfe des entsprechenden UsbBuildXxx-Makros , das für den Anforderungstyp definiert ist, neu formatieren. Es ist wichtig, dass der Treiber die URB formatiert, da der USB-Stapel möglicherweise einen Teil des Inhalts geändert hat.
Angenommen, ein Treiber ruft für instance UsbBuildInterruptOrBulkTransferRequest auf, um eine URB für eine Massenübertragungsanforderung zu initialisieren (siehe _URB_BULK_OR_INTERRUPT_TRANSFER). Wenn der Treiber das TransferBufferMDL-Element der URB-Struktur auf NULL initialisiert, verwendet der USB-Treiberstapel den übertragungspuffer angegebenen TransferBuffer in, um Daten mit dem Gerät anstelle einer MDL auszutauschen. Intern kann der USB-Treiberstapel jedoch eine MDL erstellen, einen Zeiger auf die MDL in TransferBufferMDL speichern und die MDL verwenden, um Daten im Stapel weiterzureichen. Obwohl der USB-Treiberstapel den MDL-Arbeitsspeicher freigibt, ist TransferBufferMDL möglicherweise nicht NULL, wenn der Clienttreiber die URB in der Vervollständigungsroutine verarbeitet. Um sicherzustellen, dass die Member der URB ordnungsgemäß formatiert sind, muss der Treiber UsbBuildInterruptOrBulkTransferRequest erneut aufrufen, um die URB vor dem Übermitteln der Anforderung neu zu formatieren.
Verwenden Sie nicht den Abrufzeitraum größer als 8 für hochgeschwindigkeits- und SuperSpeed-isochrone Übertragungen
Der USB-Treiberstapel unterstützt isochrone Hochgeschwindigkeits- und SuperSpeed-Rohre mit einer Abrufperiode von 1, 2, 4 oder 8. Ein Clienttreiber darf keine E/A an einen Endpunkt senden, der einen Zeitraum von mehr als 8 aufweist. Dies kann zu einer Fehlerüberprüfung führen.
Stellen Sie sicher, dass die Anzahl der isochronen Pakete, die ein Vielfaches der Anzahl von Paketen pro Frame ist
Bei hochgeschwindigkeits- und SuperSpeed-isochronen Übertragungen wird die Anzahl der isochronen Pakete pro Frame als 8 / Abrufzeitraum berechnet. Der Clienttreiber muss sicherstellen, dass der in der URB angegebene NumberOfPackets-Wert (siehe _URB_ISOCH_TRANSFER) ein Vielfaches der Anzahl von Paketen pro Frame ist.
Der USB-Treiberstapel unterstützt keine isochronen Übertragungs-URBs, bei denen numberOfPackets kein Vielfaches der Anzahl von Paketen pro Frame ist.
Aufrufen der Routine auf dokumentierter IRQL-Ebene
Wenn Sie Ihren Clienttreiber bei USBD_CLIENT_CONTRACT_VERSION_602 als Vertragsversion registrieren, geht der USB-Treiberstapel davon aus, dass der Clienttreiber die Anforderung auf der entsprechenden IRQL-Ebene gesendet hat. Wenn ein Clienttreiber eine Anforderung an DISPATCH_LEVEL sendet, die an PASSIVE_LEVEL gesendet werden sollte. Beim Empfang der Anforderung überprüft der USB-Treiberstapel in einigen Fällen den IRQL-Wert und schlägt die Anforderung fehl. In anderen Fällen generiert der USB-Treiberstapel jedoch möglicherweise eine Fehlerüberprüfung.