Senden einer USB-Steuerungsübertragung
In diesem Artikel wird die Struktur einer Steuerungsübertragung erläutert und erläutert, wie ein Clienttreiber eine Steuerelementanforderung an das Gerät senden soll.
Informationen zum Standardendpunkt
Alle USB-Geräte müssen mindestens einen Endpunkt unterstützen, der als Standardendpunkt bezeichnet wird. Jede Übertragung, die auf den Standardendpunkt abzielt, wird als Steuerelementübertragung bezeichnet. Der Zweck einer Steuerungsübertragung besteht darin, dem Host das Abrufen von Geräteinformationen, das Konfigurieren des Geräts oder das Ausführen von Steuerungsvorgängen zu ermöglichen, die für das Gerät eindeutig sind.
Beginnen wir damit, diese Merkmale des Standardendpunkts zu untersuchen.
- Die Adresse des Standardendpunkts ist 0.
- Der Standardendpunkt ist bidirektional, d. h. der Host kann Daten an den Endpunkt senden und Daten von ihr innerhalb einer Übertragung empfangen.
- Der Standardendpunkt ist auf Geräteebene verfügbar und wird nicht in einer Schnittstelle des Geräts definiert.
- Der Standardendpunkt ist aktiv, sobald eine Verbindung zwischen dem Host und dem Gerät hergestellt wird. Sie ist auch vor der Auswahl einer Konfiguration aktiv.
- Die maximale Paketgröße des Standardendpunkts hängt von der Busgeschwindigkeit des Geräts ab. Niedrige Geschwindigkeit, 8 Byte; volle und hohe Geschwindigkeit, 64 Bytes; SuperSpeed, 512 Bytes.
Layout einer Steuerelementübertragung
Da Kontrollübertragungen Übertragungen mit hoher Priorität sind, wird eine bestimmte Bandbreite auf dem Bus vom Host reserviert. Für Geräte mit niedriger und voller Geschwindigkeit, 10 % der Bandbreite; 20 % für High- und SuperSpeed-Übertragungsgeräte. Sehen wir uns nun das Layout einer Steuerelementübertragung an.
Eine Steuerungsübertragung ist in drei Transaktionen unterteilt: Setuptransaktion, Datentransaktion und Statustransaktion. Jede Transaktion enthält drei Arten von Paketen: Tokenpaket, Datenpaket und Handshake-Paket.
Bestimmte Felder sind für alle Pakete gemeinsam. Die Felder lauten:
- Synchronisierungsfeld, das den Anfang des Pakets angibt.
- Paketbezeichner (PID), der den Pakettyp, die Richtung der Transaktion und im Falle eines Handshake-Pakets angibt, gibt es Erfolg oder Fehler der Transaktion an.
- EOP-Feld gibt das Ende des Pakets an.
Andere Felder hängen vom Pakettyp ab.
Tokenpaket
Jede Setuptransaktion beginnt mit einem Tokenpaket. Dies ist die Struktur des Pakets. Der Host sendet immer das Tokenpaket.
Der PID-Wert gibt den Typ des Tokenpakets an. Die folgenden Werte sind möglich:
- SETUP: Gibt den Start einer Setuptransaktion in einer Steuerungsübertragung an.
- IN: Gibt an, dass der Host Daten vom Gerät anfordert (Lesefall).
- OUT: Gibt an, dass der Host Daten an das Gerät sendet (Schreibfall).
- SOF: Gibt den Anfang des Frames an. Dieser Tokenpakettyp enthält eine 11-Bit-Framenummer. Der Host sendet das SOF-Paket. Die Häufigkeit, mit der dieses Paket gesendet wird, hängt von der Busgeschwindigkeit ab. Für volle Geschwindigkeit sendet der Host das Paket alle 1millisekunden; alle 125 Mikrosekunden auf einem Hochgeschwindigkeitsbus.
Datenpaket
Unmittelbar nach dem Tokenpaket handelt es sich um das Datenpaket, das die Nutzlast enthält. Die Anzahl der Bytes, die jedes Datenpaket enthalten kann, hängt von der maximalen Paketgröße des Standardendpunkts ab. Das Datenpaket kann je nach Richtung der Übertragung vom Host oder vom Gerät gesendet werden.
Handshake-Paket
Unmittelbar nach dem Datenpaket handelt es sich um das Handshake-Paket. Die PID des Pakets gibt an, ob das Paket vom Host oder gerät empfangen wurde. Das Handshake-Paket kann je nach Richtung der Übertragung vom Host oder vom Gerät gesendet werden.
Sie können die Struktur von Transaktionen und Paketen mithilfe eines beliebigen USB-Analyzers sehen, z. B. Beagle, Ellisys, LeCroy USB-Protokollanalysatoren. Ein Analysegerät zeigt, wie Daten über das Kabel an ein USB-Gerät gesendet oder empfangen werden. In diesem Beispiel untersuchen wir einige Spuren, die von einem LeCroy-USB-Analysegerät erfasst wurden. Dieses Beispiel ist nur für Informationen vorgesehen. Dies ist keine Bestätigung durch Microsoft.
Setuptransaktion
Der Host initiiert immer eine Steuerelementübertragung. Dies geschieht durch Senden einer Setuptransaktion. Diese Transaktion enthält ein Tokenpaket, das als Setuptoken bezeichnet wird, gefolgt von einem 8-Byte-Datenpaket. Dieser Screenshot zeigt eine Beispiel-Setuptransaktion.
In der vorherigen Ablaufverfolgung initiiert der Host (angegeben durch H–) die Steuerungsübertragung durch Senden des Setuptokenpakets #434. Beachten Sie, dass die PID SETUP angibt, die ein Setuptoken angibt. Die PID folgt der Geräteadresse und der Adresse des Endpunkts. Bei Steuerungsübertragungen ist diese Endpunktadresse immer 0.
Als Nächstes sendet der Host das Datenpaket #435. Die PID ist DATA0 und dieser Wert wird für die Paketsequenzierung verwendet (zu besprechen). Auf die PID folgen 8 Byte, die die Hauptinformationen zu dieser Anforderung enthalten. Diese 8 Bytes geben den Anforderungstyp und die Größe des Puffers an, in dem das Gerät seine Antwort schreibt.
Alle Bytes werden in umgekehrter Reihenfolge empfangen. Wie in Abschnitt 9.3 beschrieben, werden die folgenden Felder und Werte angezeigt:
Feld | Größe | Wert | Beschreibung |
---|---|---|---|
bmRequestType (Siehe 9.3.1 bmRequestType) | 1 | 0x80 | Die Datenübertragungsrichtung ist vom Gerät zum Host (D7 ist 1) Die Anforderung ist eine Standardanforderung (D6... D5 ist 0) Der Empfänger der Anforderung ist DAS GERÄT (D4 ist 0) |
bRequest (Siehe Abschnitt 9.3.2 und Tabelle 9-4) | 1 | 0x06 | Der Anforderungstyp ist GET_DESCRIPTOR. |
wValue (Siehe Tabelle 9-5) | 2 | 0x0100 | Der Anforderungswert gibt an, dass der Deskriptortyp DEVICE ist. |
wIndex (Siehe Abschnitt 9.3.4) | 2 | 0x0000 | Die Richtung liegt vom Host zum Gerät (D7 ist 1) Die Endpunktnummer ist 0. |
wLength (Siehe Abschnitt 9.3.5) | 2 | 0x0012 | Die Anforderung besteht darin, 18 Bytes abzurufen. |
Daher können wir daraus schließen, dass der Host bei dieser Steuerungsübertragung eine Anforderung zum Abrufen des Gerätedeskriptors sendet und 18 Bytes als Übertragungslänge angibt, um diesen Deskriptor zu speichern. Die Art und Weise, wie das Gerät diese 18 Bytes sendet, hängt davon ab, wie viel Daten der Standardendpunkt in einer Transaktion senden kann. Diese Informationen sind in der Gerätebeschreibung enthalten, die vom Gerät in der Datentransaktion zurückgegeben wird.
Als Antwort sendet das Gerät ein Handshake-Paket (#436 angegeben durch D%).). Beachten Sie, dass der PID-Wert ACK (ACK-Paket) ist. Dies gibt an, dass das Gerät die Transaktion bestätigt hat.
Datentransaktion
Sehen wir uns nun an, was das Gerät als Reaktion auf die Anforderung zurückgibt. Die tatsächlichen Daten werden in einer Datentransaktion übertragen.
Dies ist die Ablaufverfolgung für die Datentransaktion.
Beim Empfangen des ACK-Pakets initiiert der Host die Datentransaktion. Um die Transaktion zu initiieren, sendet sie ein Tokenpaket (#450) mit Richtung als IN (als IN-Token bezeichnet).
Als Antwort sendet das Gerät ein Datenpaket (#451), das dem IN-Token folgt. Dieses Datenpaket enthält den tatsächlichen Gerätedeskriptor. Das erste Byte gibt die Länge des Gerätedeskriptors an, 18 Byte (0x12). Das letzte Byte in diesem Datenpaket gibt die maximale Paketgröße an, die vom Standardendpunkt unterstützt wird. In diesem Fall sehen wir, dass das Gerät jeweils 8 Byte über seinen Standardendpunkt senden kann.
Hinweis
Die maximale Paketgröße des Standardendpunkts hängt von der Geschwindigkeit des Geräts ab. Der Standardendpunkt eines Hochgeschwindigkeitsgeräts beträgt 64 Byte; Low-Speed-Gerät beträgt 8 Byte.
Der Host erkennt die Datentransaktion an, indem ein ACK-Paket (#452) an das Gerät gesendet wird.
Berechnen wir die zurückgegebene Datenmenge. Im wLength-Feld des Datenpakets (#435) in der Setuptransaktion hat der Host 18 Bytes angefordert. In der Datentransaktion sehen wir, dass nur die ersten 8 Byte des Gerätedeskriptors vom Gerät empfangen wurden. Wie empfängt der Host also Informationen, die in den verbleibenden 10 Bytes gespeichert sind? Das Gerät führt dies in zwei Transaktionen durch: 8 Byte und dann letzte 2 Bytes.
Da der Host nun die maximale Paketgröße des Standardendpunkts kennt, initiiert der Host eine neue Datentransaktion und fordert den nächsten Teil basierend auf der Paketgröße an.
Hier ist die nächste Datentransaktion:
Der Host initiiert die vorherige Datentransaktion, indem ein IN-Token (#463) gesendet und die nächsten 8 Bytes vom Gerät angefordert werden. Das Gerät antwortet mit einem Datenpaket (#464), das die nächsten 8 Byte des Gerätedeskriptors enthält.
Beim Empfang der 8 Bytes sendet der Host ein ACK-Paket (#465) an das Gerät.
Als Nächstes fordert der Host die letzten 2 Bytes in einer anderen Datentransaktion wie folgt an:
Daher sehen wir, dass der Host für die Übertragung von 18 Bytes vom Gerät an den Host die Anzahl der übertragenen Und initiierten drei Datentransaktionen nachverfolgt (8+8+2).
Hinweis
Beachten Sie die PID der Datenpakete in Datentransaktionen 19, 23, 26. Die PID wechselt zwischen DATA0 und DATA1. Diese Sequenz wird als Daten-Umschaltung bezeichnet. In Fällen, in denen mehrere Datentransaktionen vorhanden sind, wird die Datensteuerung verwendet, um die Paketsequenz zu überprüfen. Diese Methode stellt sicher, dass die Datenpakete nicht dupliziert oder verloren gehen.
Durch Zuordnen der konsolidierten Datenpakete zur Struktur des Gerätedeskriptors (siehe Tabelle 9-8) werden die folgenden Felder und Werte angezeigt:
Feld | Größe | Wert | Beschreibung |
---|---|---|---|
bLength | 1 | 0x12 | Länge des Gerätedeskriptors, der 18 Bytes beträgt. |
bDescriptorType | 1 | 0x01 | Der Deskriptortyp ist gerät. |
bcdUSB | 2 | 0x0100 | Die Versionsnummer der Spezifikation ist 1.00. |
bDeviceClass | 1 | 0x00 | Die Geräteklasse ist 0. Jede Schnittstelle in der Konfiguration weist die Klasseninformationen auf. |
bDeviceSubClass | 1 | 0x00 | Die Unterklasse ist 0, da die Geräteklasse 0 ist. |
bProtocol | 1 | 0x00 | Protokoll ist 0. Dieses Gerät verwendet keine klassenspezifischen Protokolle. |
bMaxPacketSize0 | 1 | 0x08 | Die maximale Paketgröße des Endpunkts beträgt 8 Bytes. |
idVendor | 2 | 0x0562 | Telex Communications. |
idProduct | 2 | 0x0002 | USB-Mikrofon. |
bcdDevice | 2 | 0x0100 | Gibt die Gerätefreigabenummer an. |
iManufacturer | 1 | 0x01 | Herstellerzeichenfolge. |
iProduct | 1 | 0x02 | Produktzeichenfolge. |
iSerialNumber | 1 | 0x03 | Seriennummer |
bNumConfigurations | 1 | 0x01 | Anzahl der Konfigurationen. |
Durch Die Untersuchung dieser Werte haben wir einige vorläufige Informationen über das Gerät. Das Gerät ist ein Usb-Mikrofon mit niedriger Geschwindigkeit. Die maximale Paketgröße des Standardendpunkts beträgt 8 Byte. Das Gerät unterstützt eine Konfiguration.
Statustransaktion
Schließlich schließt der Host die Steuerungsübertragung ab, indem die letzte Transaktion initiiert wird: Statustransaktion.
Der Host startet die Transaktion mit einem OUT-Tokenpaket (#481). Der Zweck dieses Pakets besteht darin, zu überprüfen, ob das Gerät alle angeforderten Daten gesendet hat. In dieser Statustransaktion werden keine Datenpakete gesendet. Das Gerät antwortet mit einem ACK-Paket. Wenn ein Fehler aufgetreten ist, konnte die PID entweder NAK oder STALL sein.
Treibermodelle
Voraussetzungen
Bevor der Clienttreiber Rohre aufzählen kann, stellen Sie sicher, dass diese Anforderungen erfüllt sind:
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 bereitgestellt werden, führt der Vorlagencode diese Aufgaben aus. Der Vorlagencode erhält das Handle zum Zielgeräteobjekt und speichert es im Gerätekontext.
KMDF-Clienttreiber
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).
UMDF-Clienttreiber
Ein UMDF-Clienttreiber muss einen IWDFUsbTargetDevice-Zeiger durch Abfragen des Framework-Zielgeräteobjekts abrufen. Weitere Informationen finden Sie unter "IPnpCallbackHardware-Implementierung und USB-spezifische Aufgaben" unter Grundlegendes zur USB-Clienttreibercodestruktur (UMDF).For more information, see "IPnpCallbackHardware implementation and USB-specific tasks" in Understanding the USB client driver code structure (UMDF).
Der wichtigste Aspekt für eine Steuerungsübertragung besteht darin, das Setuptoken entsprechend zu formatieren. Bevor Sie die Anforderung senden, sammeln Sie diese Gruppe von Informationen:
- Richtung der Anforderung: Host auf Gerät oder Gerät hosten.
- Empfänger der Anforderung: Gerät, Schnittstelle, Endpunkt oder andere.
- Anforderungskategorie: Standard, Klasse oder Lieferant.
- Anforderungstyp, z. B. eine GET_DESCRIPTPOR Anforderung. Weitere Informationen finden Sie unter Abschnitt 9.5 in der USB-Spezifikation.
- wValue - und wIndex-Werte . Diese Werte hängen vom Anforderungstyp ab.
Sie können alle diese Informationen aus der offiziellen USB-Spezifikation abrufen.
Wenn Sie einen UMDF-Treiber schreiben, rufen Sie die Headerdatei ab, Usb_hw.h vom UMDF-Beispieltreiber für OSR USB Fx2 Learning Kit. Diese Headerdatei enthält nützliche Makros und Struktur zum Formatieren des Setuppakets für die Steuerungsübertragung.
Alle UMDF-Treiber müssen mit einem Kernelmodustreiber kommunizieren, um Daten von Geräten zu senden und zu empfangen. Bei einem USB-UMDF-Treiber ist der Kernelmodustreiber immer der von Microsoft bereitgestellte Treiber WinUSB (Winusb.sys).
Wenn ein UMDF-Treiber eine Anforderung für den USB-Treiberstapel sendet, sendet der Windows-E/A-Manager die Anforderung an WinUSB. Nach erhalt der Anforderung verarbeitet WinUSB entweder die Anforderung oder leitet sie an den USB-Treiberstapel weiter.
Von Microsoft definierte Methoden zum Senden von Kontrollübertragungsanforderungen
Ein USB-Clienttreiber auf dem Host initiiert die meisten Steuerelementanforderungen, um Informationen über das Gerät abzurufen, das Gerät zu konfigurieren oder Anbietersteuerungsbefehle zu senden. Alle diese Anforderungen können kategorisiert werden in:
Standardanforderungen werden in der USB-Spezifikation definiert. Der Zweck des Sendens von Standardanforderungen besteht darin, Informationen über das Gerät, seine Konfigurationen, Schnittstellen und Endpunkte zu erhalten. Der Empfänger jeder Anforderung hängt vom Typ der Anforderung ab. Der Empfänger kann das Gerät, eine Schnittstelle oder ein Endpunkt sein.
Hinweis
Das Ziel jeder Steuerelementübertragung ist immer der Standardendpunkt. Der Empfänger ist die Entität des Geräts, deren Informationen (Deskriptor, Status usw.) der Host interessiert ist.
Anforderungen können weiter in klassifiziert werden: Konfigurationsanforderungen, Featureanforderungen und Statusanforderungen.
- Konfigurationsanforderungen werden gesendet, um Informationen vom Gerät abzurufen, damit der Host sie konfigurieren kann, z. B. eine GET_DESCRIPTOR Anforderung. Diese Anforderungen können auch Schreibanforderungen sein, die vom Host gesendet werden, um eine bestimmte Konfiguration oder alternative Einstellung auf dem Gerät festzulegen.
- Featureanforderungen werden vom Clienttreiber gesendet, um bestimmte vom Gerät, der Schnittstelle oder einem Endpunkt unterstützte boolesche Geräteeinstellungen zu aktivieren oder zu deaktivieren.
- Statusanforderungen ermöglichen dem Host das Abrufen oder Festlegen der USB-definierten Statusbits eines Geräts, Endpunkts oder einer Schnittstelle.
Weitere Informationen finden Sie in Abschnitt 9.4 in der USB-Spezifikation, Version 2.0. Die Standardanforderungstypen werden die Headerdatei Usbspec.h definiert.
Klassenanforderungen werden durch eine bestimmte Geräteklassenspezifikation definiert.
Lieferantenanforderungen werden vom Anbieter bereitgestellt und hängen von den vom Gerät unterstützten Anforderungen ab.
Der von Microsoft bereitgestellte USB-Stapel verarbeitet die gesamte Protokollkommunikation mit dem Gerät, wie in den vorherigen Ablaufverfolgungen gezeigt. Der Treiber macht Gerätetreiberschnittstellen (Device Driver Interfaces, DDIs) verfügbar, die es einem Clienttreiber ermöglichen, Steuerungsübertragungen auf vielfältige Weise zu senden. Wenn Ihr Clienttreiber ein Windows Driver Foundation (WDF)-Treiber ist, kann er Routinen direkt aufrufen, um die allgemeinen Typen von Steuerelementanforderungen zu senden. WDF unterstützt steuerungsinterne Übertragungen sowohl für KMDF als auch FÜR UMDF.
Bestimmte Arten von Steuerelementanforderungen werden nicht über WDF verfügbar gemacht. Für diese Anforderungen kann der Clienttreiber das WDF-Hybridmodell verwenden. Mit diesem Modell kann der Clienttreiber WDM-URB-Formatanforderungen erstellen und formatieren und diese Anforderungen dann mithilfe von WDF-Frameworkobjekten senden. Das Hybridmodell gilt nur für Kernelmodustreiber.
Für UMDF-Treiber:
Verwenden Sie die in usb_hw.h definierten Hilfsmakros und -struktur. Dieser Header ist im UMDF-Beispieltreiber für OSR USB Fx2 Learning Kit enthalten.
Verwenden Sie diese Tabelle, um die beste Methode zum Senden von Steuerelementanforderungen an den USB-Treiberstapel zu ermitteln. Wenn Sie diese Tabelle nicht anzeigen können, lesen Sie die Tabelle in diesem Artikel.
Wenn Sie eine Steuerelementanforderung senden möchten... | Für einen KMDF-Treiber... | Für einen UMDF-Treiber... | Erstellen Sie für einen WDM-Treiber eine URB-Struktur (Hilfsroutine) |
---|---|---|---|
CLEAR_FEATURE: Deaktivieren Sie bestimmte Featureeinstellungen im Gerät, deren Konfigurationen, Schnittstellen und Endpunkte. Siehe Abschnitt 9.4.1 in der USB-Spezifikation. |
|
|
_URB_CONTROL_FEATURE_REQUEST (UsbBuildFeatureRequest) URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT URB_FUNCTION_CLEAR_FEATURE_TO_OTHER |
GET_CONFIGURATION: Abrufen der aktuellen USB-Konfiguration. Siehe Abschnitt 9.4.2 in der USB-Spezifikation. | KMDF wählt standardmäßig die erste Konfiguration aus. So rufen Sie die vom Gerät definierte Konfigurationsnummer ab:
|
UMDF wählt standardmäßig die erste Konfiguration aus. So rufen Sie die vom Gerät definierte Konfigurationsnummer ab:
|
_URB_CONTROL_GET_CONFIGURATION_REQUEST URB_FUNCTION_GET_CONFIGURATION |
GET_DESCRIPTOR: Abrufen von Geräte-, Konfigurations-, Schnittstellen- und Endpunktdeskriptoren. Siehe Abschnitt 9.4.3 in der USB-Spezifikation. Weitere Informationen finden Sie unter USB-Deskriptoren. |
Rufen Sie die folgenden Methoden auf:
|
Rufen Sie die folgenden Methoden auf:
|
_URB_CONTROL_DESCRIPTOR_REQUEST (UsbBuildGetDescriptorRequest) URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE |
GET_INTERFACE: Abrufen der aktuellen alternativen Einstellung für eine Schnittstelle. Siehe Abschnitt 9.4.4 in der USB-Spezifikation. |
|
|
_URB_CONTROL_GET_INTERFACE_REQUEST URB_FUNCTION_GET_INTERFACE |
GET_STATUS: Abrufen von Statusbits von einem Gerät, einem Endpunkt oder einer Schnittstelle. Siehe Abschnitt 9.4.5. in der USB-Spezifikation. |
|
|
_URB_CONTROL_GET_STATUS_REQUEST (UsbBuildGetStatusRequest) URB_FUNCTION_GET_STATUS_FROM_DEVICE URB_FUNCTION_GET_STATUS_FROM_INTERFACE URB_FUNCTION_GET_STATUS_FROM_ENDPOINT URB_FUNCTION_GET_STATUS_FROM_OTHER. |
SET_ADDRESS: Siehe Abschnitt 9.4.6 in usb-Spezifikation. | Diese Anforderung wird vom USB-Treiberstapel verarbeitet. Der Clienttreiber kann diesen Vorgang nicht ausführen. | Diese Anforderung wird vom USB-Treiberstapel verarbeitet. Der Clienttreiber kann diesen Vorgang nicht ausführen. | Diese Anforderung wird vom USB-Treiberstapel verarbeitet. Der Clienttreiber kann diesen Vorgang nicht ausführen. |
SET_CONFIGURATION: Festlegen einer Konfiguration. Siehe Abschnitt 9.4.7 in usb-Spezifikation. Weitere Informationen finden Sie unter Auswählen einer Konfiguration für ein USB-Gerät. |
Standardmäßig wählt KMDF die Standardkonfiguration und erste alternative Einstellung in jeder Schnittstelle aus. Der Clienttreiber kann die Standardkonfiguration ändern, indem die WdfUsbTargetDeviceSelectConfigType-Methode aufgerufen und WdfUsbTargetDeviceSelectConfigTypeUrb als Anforderungsoption angegeben wird. Anschließend müssen Sie eine URB für diese Anforderung formatieren und an den USB-Treiberstapel übermitteln. | Standardmäßig wählt UMDF die Standardkonfiguration und die erste alternative Einstellung in jeder Schnittstelle aus. Der Clienttreiber kann die Konfiguration nicht ändern. | _URB_SELECT_CONFIGURATION (USBD_SelectConfigUrbAllocateAndBuild) URB_FUNCTION_SELECT_CONFIGURATION |
SET_DESCRIPTOR: Aktualisieren eines vorhandenen Geräts, einer Konfiguration oder eines Zeichenfolgendeskriptors. Siehe Abschnitt 9.4.8 in usb-Spezifikation. Diese Anforderung wird häufig nicht verwendet. Der USB-Treiberstapel akzeptiert jedoch eine solche Anforderung vom Clienttreiber. |
|
|
_URB_CONTROL_DESCRIPTOR_REQUEST URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE |
SET_FEATURE: Aktivieren Sie bestimmte Featureeinstellungen im Gerät, deren Konfigurationen, Schnittstellen und Endpunkte. Siehe Abschnitt 9.4.9 in der USB-Spezifikation. |
|
|
_URB_CONTROL_FEATURE_REQUEST (UsbBuildFeatureRequest) URB_FUNCTION_SET_FEATURE_TO_DEVICE URB_FUNCTION_SET_FEATURE_TO_INTERFACE URB_FUNCTION_SET_FEATURE_TO_ENDPOINT URB_FUNCTION_SET_FEATURE_TO_OTHER |
SET_INTERFACE: Ändert die alternative Einstellung in einer Schnittstelle. Siehe Abschnitt 9.4.9 in der USB-Spezifikation. Weitere Informationen finden Sie unter Auswählen einer alternativen Einstellung in einer USB-Schnittstelle. |
WdfUsbTargetDeviceSelectConfig
|
|
_URB_SELECT_INTERFACE (USBD_SelectInterfaceUrbAllocateAndBuild) URB_FUNCTION_SELECT_INTERFACE |
SYNC_FRAME: Festlegen und Abrufen und Abrufen der Synchronisierungsframenummer des Endpunkts. Siehe Abschnitt 9.4.10 in der USB-Spezifikation. | Diese Anforderung wird vom USB-Treiberstapel verarbeitet. Der Clienttreiber kann diesen Vorgang nicht ausführen. | Diese Anforderung wird vom USB-Treiberstapel verarbeitet. Der Clienttreiber kann diesen Vorgang nicht ausführen. | Diese Anforderung wird vom USB-Treiberstapel verarbeitet. Der Clienttreiber kann diesen Vorgang nicht ausführen. |
Für Geräteklassenspezifische Anforderungen und Anbieterbefehle. |
|
|
_URB_CONTROL_VENDOR_OR_CLASS_REQUEST (UsbBuildVendorRequest) URB_FUNCTION_VENDOR_DEVICE URB_FUNCTION_VENDOR_INTERFACE URB_FUNCTION_VENDOR_ENDPOINT URB_FUNCTION_VENDOR_OTHER URB_FUNCTION_CLASS_DEVICE URB_FUNCTION_CLASS_INTERFACE URB_FUNCTION_CLASS_ENDPOINT URB_FUNCTION_CLASS_OTHER |
Senden einer Steuerelementübertragung für Lieferantenbefehle – KMDF
Dieses Verfahren zeigt, wie ein Clienttreiber eine Steuerungsübertragung senden kann. In diesem Beispiel sendet der Clienttreiber einen Anbieterbefehl, der die Firmwareversion vom Gerät abruft.
Deklarieren Sie eine Konstante für den Lieferantenbefehl. Untersuchen Sie die Hardwarespezifikation, und bestimmen Sie den Anbieterbefehl, den Sie verwenden möchten.
Deklarieren Sie eine WDF_MEMORY_DESCRIPTOR Struktur, und initialisieren Sie sie, indem Sie das WDF_MEMORY_DESCRIPTOR_INIT_BUFFER-Makro aufrufen. Diese Struktur empfängt die Antwort vom Gerät, nachdem der USB-Treiber die Anforderung abgeschlossen hat.
Je nachdem, ob Sie die Anforderung synchron oder asynchron senden, geben Sie Die Sendeoptionen an:
Wenn Sie die Anforderung synchron senden, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronly aufrufen, geben Sie einen Timeoutwert an. Dieser Wert ist wichtig, da Sie den Thread ohne Timeout auf unbestimmte Zeit blockieren können.
Deklarieren Sie dazu eine WDF_REQUEST_SEND_OPTIONS Struktur, und initialisieren Sie sie durch Aufrufen des WDF_REQUEST_SEND_OPTIONS_INIT-Makros . Geben Sie die Option als WDF_REQUEST_SEND_OPTION_TIMEOUT an.
Legen Sie als Nächstes den Timeoutwert fest, indem Sie das makro WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT aufrufen.
Wenn Sie die Anforderung asynchron senden, implementieren Sie eine Abschlussroutine. Geben Sie alle zugeordneten Ressourcen in der Abschlussroutine frei.
Deklarieren Sie eine WDF_USB_CONTROL_SETUP_PACKET Struktur, um das Setuptoken zu enthalten und die Struktur zu formatieren. Rufen Sie dazu das WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR-Makro auf, um das Setuppaket zu formatieren. Geben Sie im Aufruf die Richtung der Anforderung, den Empfänger, die Optionen für die gesendete Anforderung (in Schritt3 initialisiert) und die Konstante für den Anbieterbefehl an.
Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronously oder WdfUsbTargetDeviceFormatRequestForControlTransfer aufrufen.
Überprüfen Sie den vom Framework zurückgegebenen NTSTATUS-Wert, und überprüfen Sie den empfangenen Wert.
In diesem Codebeispiel wird eine Steuerungsübertragungsanforderung an ein USB-Gerät gesendet, um die Firmwareversion abzurufen. Die Anforderung wird synchron gesendet, und der Clienttreiber gibt einen relativen Timeoutwert von 5 Sekunden an (in 100-Nanosekundeneinheiten). Der Treiber speichert die empfangene Antwort im vom Treiber definierten Gerätekontext.
enum {
USBFX2_GET_FIRMWARE_VERSION = 0x1,
....
} USBFX2_VENDOR_COMMANDS;
#define WDF_TIMEOUT_TO_SEC ((LONGLONG) 1 * 10 * 1000 * 1000) // defined in wdfcore.h
const __declspec(selectany) LONGLONG
DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC;
typedef struct _DEVICE_CONTEXT
{
...
union {
USHORT VersionAsUshort;
struct {
BYTE Minor;
BYTE Major;
} Version;
} Firmware; // Firmware version.
} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
__drv_requiresIRQL(PASSIVE_LEVEL)
VOID GetFirmwareVersion(
__in PDEVICE_CONTEXT DeviceContext
)
{
NTSTATUS status;
WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket;
WDF_REQUEST_SEND_OPTIONS sendOptions;
USHORT firmwareVersion;
WDF_MEMORY_DESCRIPTOR memoryDescriptor;
PAGED_CODE();
firmwareVersion = 0;
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, (PVOID) &firmwareVersion, sizeof(firmwareVersion));
WDF_REQUEST_SEND_OPTIONS_INIT(
&sendOptions,
WDF_REQUEST_SEND_OPTION_TIMEOUT
);
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
&sendOptions,
DEFAULT_CONTROL_TRANSFER_TIMEOUT
);
WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
BmRequestDeviceToHost, // Direction of the request
BmRequestToDevice, // Recipient
USBFX2_GET_FIRMWARE_VERSION, // Vendor command
0, // Value
0); // Index
status = WdfUsbTargetDeviceSendControlTransferSynchronously(
DeviceContext->UsbDevice,
WDF_NO_HANDLE, // Optional WDFREQUEST
&sendOptions,
&controlSetupPacket,
&memoryDescriptor, // MemoryDescriptor
NULL); // BytesTransferred
if (!NT_SUCCESS(status))
{
KdPrint(("Device %d: Failed to get device firmware version 0x%x\n", DeviceContext->DeviceNumber, status));
TraceEvents(DeviceContext->DebugLog,
TRACE_LEVEL_ERROR,
DBG_RUN,
"Device %d: Failed to get device firmware version 0x%x\n",
DeviceContext->DeviceNumber,
status);
}
else
{
DeviceContext->Firmware.VersionAsUshort = firmwareVersion;
TraceEvents(DeviceContext->DebugLog,
TRACE_LEVEL_INFORMATION,
DBG_RUN,
"Device %d: Get device firmware version : 0x%x\n",
DeviceContext->DeviceNumber,
firmwareVersion);
}
return;
}
So senden Sie eine Steuerungsübertragung für GET_STATUS – UMDF
Dieses Verfahren zeigt, wie ein Clienttreiber eine Steuerungsübertragung für einen GET_STATUS-Befehl senden kann. Der Empfänger der Anforderung ist das Gerät und die Anforderung ruft Informationen in Bits D1-D0 ab. Weitere Informationen finden Sie in Abbildung 9-4 in der USB-Spezifikation.
Schließen Sie die Headerdatei Usb_hw.h ein, die mit dem UMDF-Beispieltreiber für OSR USB Fx2 Learning Kit verfügbar ist.
Deklarieren Sie eine WINUSB_CONTROL_SETUP_PACKET Struktur.
Initialisieren Sie das Setuppaket, indem Sie das Hilfsmakro WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS aufrufen.
Geben Sie BmRequestToDevice als Empfänger an.
Geben Sie 0 im Indexwert an.
Rufen Sie die Hilfsmethode SendControlTransferSynchronously auf, um die Anforderung synchron zu senden.
Die Hilfsmethode erstellt die Anforderung, indem das initialisierte Setuppaket dem Framework-Anforderungsobjekt und dem Übertragungspuffer zugeordnet wird, indem IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufgerufen wird. Die Hilfsmethode sendet dann die Anforderung durch Aufrufen der IWDFIoRequest::Send-Methode . Überprüfen Sie nach dem Zurückgeben der Methode den zurückgegebenen Wert.
Um zu ermitteln, ob der Status selbstbetriebene Remote-Reaktivierung angibt, verwenden Sie die folgenden Werte, die in der WINUSB_DEVICE_TRAITS Enumeration definiert sind:
In diesem Codebeispiel wird eine Steuerelementübertragungsanforderung an den Status des Geräts gesendet. Im Beispiel wird die Anforderung synchron gesendet, indem eine Hilfsmethode namens "SendControlTransferSynchronously" aufgerufen wird.
HRESULT
CDevice::GetDeviceStatus ()
{
HRESULT hr = S_OK;
USHORT deviceStatus;
ULONG bytesTransferred;
TraceEvents(TRACE_LEVEL_INFORMATION,
DRIVER_ALL_INFO,
"%!FUNC!: entry");
// Setup the control packet.
WINUSB_CONTROL_SETUP_PACKET setupPacket;
WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(
&setupPacket,
BmRequestToDevice,
0);
hr = SendControlTransferSynchronously(
&(setupPacket.WinUsb),
& deviceStatus,
sizeof(USHORT),
&bytesReturned
);
if (SUCCEEDED(hr))
{
if (deviceStatus & USB_GETSTATUS_SELF_POWERED)
{
m_Self_Powered = true;
}
if (deviceStatus & USB_GETSTATUS_REMOTE_WAKEUP_ENABLED)
{
m_remote_wake-enabled = true;
}
}
return hr;
}
Das folgende Codebeispiel zeigt die Implementierung der Hilfsmethode "SendControlTransferSynchronously". Diese Methode sendet eine Anforderung synchron.
HRESULT
CDevice::SendControlTransferSynchronously(
_In_ PWINUSB_SETUP_PACKET SetupPacket,
_Inout_ PBYTE Buffer,
_In_ ULONG BufferLength,
_Out_ PULONG LengthTransferred
)
{
HRESULT hr = S_OK;
IWDFIoRequest *pWdfRequest = NULL;
IWDFDriver * FxDriver = NULL;
IWDFMemory * FxMemory = NULL;
IWDFRequestCompletionParams * FxComplParams = NULL;
IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;
*LengthTransferred = 0;
hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface
NULL, //pParentObject
&pWdfRequest);
if (SUCCEEDED(hr))
{
m_FxDevice->GetDriver(&FxDriver);
hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,
BufferLength,
NULL, //pCallbackInterface
pWdfRequest, //pParetObject
&FxMemory );
}
if (SUCCEEDED(hr))
{
hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest,
SetupPacket,
FxMemory,
NULL); //TransferOffset
}
if (SUCCEEDED(hr))
{
hr = pWdfRequest->Send( m_pIUsbTargetDevice,
WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
0); //Timeout
}
if (SUCCEEDED(hr))
{
pWdfRequest->GetCompletionParams(&FxComplParams);
hr = FxComplParams->GetCompletionStatus();
}
if (SUCCEEDED(hr))
{
HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams));
WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI));
WUDF_TEST_DRIVER_ASSERT( WdfUsbRequestTypeDeviceControlTransfer ==
FxUsbComplParams->GetCompletedUsbRequestType() );
FxUsbComplParams->GetDeviceControlTransferParameters( NULL,
LengthTransferred,
NULL,
NULL );
}
SAFE_RELEASE(FxUsbComplParams);
SAFE_RELEASE(FxComplParams);
SAFE_RELEASE(FxMemory);
pWdfRequest->DeleteWdfObject();
SAFE_RELEASE(pWdfRequest);
SAFE_RELEASE(FxDriver);
return hr;
}
Wenn Sie Winusb.sys als Funktionstreiber für Ihr Gerät verwenden, können Sie Steuerübertragungen von einer Anwendung senden. Verwenden Sie zum Formatieren des Setuppakets in WinUSB die in der Tabelle in diesem Artikel beschriebenen UMDF-Hilfsmakros und -strukturen. Rufen Sie WinUsb_ControlTransfer Funktion auf , um die Anforderung zu senden.