Senden einer USB-Steuerübertragung

In diesem Artikel wird die Struktur einer Steuerungsübertragung erläutert und erläutert, wie ein Clienttreiber eine Steuerungsanforderung 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 Steuerungsübertragung bezeichnet. Der Zweck einer Steuerungsübertragung besteht darin, dem Host zu ermöglichen, Geräteinformationen abzurufen, das Gerät zu konfigurieren oder Steuerungsvorgänge auszuführen, die für das Gerät eindeutig sind.

Beginnen wir mit der Untersuchung dieser Merkmale des Standardendpunkts.

  • Die Adresse des Standardendpunkts ist 0.
  • Der Standardendpunkt ist bidirektional, d. h. der Host kann Daten an den Endpunkt senden und daten von diesem innerhalb einer Übertragung empfangen.
  • Der Standardendpunkt ist auf Geräteebene verfügbar und in keiner Schnittstelle des Geräts definiert.
  • Der Standardendpunkt ist aktiv, sobald eine Verbindung zwischen dem Host und dem Gerät hergestellt wird. Er ist bereits aktiv, bevor eine Konfiguration ausgewählt wird.
  • Die maximale Paketgröße des Standardendpunkts hängt von der Busgeschwindigkeit des Geräts ab. Niedrige Geschwindigkeit, 8 Bytes; volle und hohe Geschwindigkeit, 64 Bytes; SuperSpeed, 512 Bytes.

Layout einer Steuerelementübertragung

Da Steuerungsübertragungen Übertragungen mit hoher Priorität sind, wird eine bestimmte Bandbreite auf dem Bus vom Host reserviert. Bei Geräten mit niedriger und voller Geschwindigkeit 10 % der Bandbreite; 20 % für High- und SuperSpeed-Transfergeräte. Sehen wir uns nun das Layout einer Steuerelementübertragung an.

Diagramm einer USB-Steuerübertragung.

Eine Steuerungsübertragung ist in drei Transaktionen unterteilt: Setuptransaktion, Datentransaktion und status Transaktion. Jede Transaktion enthält drei Pakettypen: Tokenpaket, Datenpaket und Handshakepaket.

Bestimmte Felder sind für alle Pakete gemeinsam. Die Felder lauten:

  • Synchronisierungsfeld, das den Start des Pakets angibt.
  • Packet Identifier (PID), der den Pakettyp, die Richtung der Transaktion und im Falle eines Handshakepakets den Erfolg oder Fehler der Transaktion angibt.
  • EOP-Feld gibt das Ende des Pakets an.

Andere Felder hängen vom Pakettyp ab.

Tokenpaket

Jede Setuptransaktion beginnt mit einem Tokenpaket. Hier sehen Sie die Struktur des Pakets. Der Host sendet immer das Tokenpaket.

Diagramm eines Tokenpaketlayouts.

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 Typ von Tokenpaket 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. Bei voller Geschwindigkeit sendet der Host das Paket alle 1 Millisekunden; alle 125 Mikrosekunden auf einem Hochgeschwindigkeitsbus.

Datenpaket

Unmittelbar nach dem Tokenpaket befindet sich 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 Übertragungsrichtung entweder vom Host oder vom Gerät gesendet werden.

Diagramm eines Datenpaketlayouts.

Handshakepaket

Unmittelbar nach dem Datenpaket befindet sich das Handshakepaket. Die PID des Pakets gibt an, ob das Paket vom Host oder vom Gerät empfangen wurde. Das Handshakepaket kann je nach Übertragungsrichtung entweder vom Host oder vom Gerät gesendet werden.

Diagramm eines Handshakepaketlayouts.

Sie können die Struktur von Transaktionen und Paketen mithilfe eines beliebigen USB-Analysetools wie Beagle, Ellisys und LeCroy USB-Protokollanalysetools anzeigen. Ein Analysegerät zeigt an, wie Daten über das Kabel an ein USB-Gerät gesendet oder von diesem empfangen werden. In diesem Beispiel untersuchen wir einige Ablaufverfolgungen, die von einem LeCroy-USB-Analysetool erfasst wurden. Dieses Beispiel dient nur für Informationen. Dies ist keine Bestätigung durch Microsoft.

Einrichten der Transaktion

Der Host initiiert immer eine Steuerungsübertragung. Dazu wird eine Setuptransaktion gesendet. Diese Transaktion enthält ein Tokenpaket namens Setuptoken , gefolgt von einem 8-Byte-Datenpaket. Dieser Screenshot zeigt ein Beispiel für eine Setuptransaktion.

Screenshot einer Ablaufverfolgung einer Setuptransaktion.

In der vorherigen Ablaufverfolgung initiiert der Host (angegeben durch H)die Steuerungsübertragung, indem er das Setuptokenpaket #434 sendet. Beachten Sie, dass die PID SETUP angibt und ein Setuptoken angibt. Auf die PID folgen die Geräteadresse und die 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 diskutieren). Auf die PID folgen 8 Bytes, die die Standard Informationen zu dieser Anforderung enthält. Diese 8 Bytes geben den Typ der Anforderung und die Größe des Puffers an, in den 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 Size 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 device (D4 ist 0).
bRequest (siehe Abschnitt siehe 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 ist 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 in dieser Steuerelementübertragung (Lese-)Übertragung eine Anforderung zum Abrufen des Gerätedeskriptors sendet und 18 Bytes als Übertragungslänge angibt, um diesen Deskriptor zu halten. Wie das Gerät diese 18 Bytes sendet, hängt davon ab, wie viele Daten der Standardendpunkt in einer Transaktion senden kann. Diese Informationen sind im Gerätedeskriptor enthalten, der vom Gerät in der Datentransaktion zurückgegeben wird.

Als Antwort sendet das Gerät ein Handshakepaket (#436, die von D)angegeben wird. Beachten Sie, dass der PID-Wert ACK (ACK-Paket) ist. Dies gibt an, dass das Gerät die Transaktion bestätigt hat.

Datentransaktion

Nun sehen wir uns an, was das Gerät als Antwort auf die Anforderung zurückgibt. Die tatsächlichen Daten werden in einer Datentransaktion übertragen.

Hier ist die Ablaufverfolgung für die Datentransaktion.

Screenshot: Ablaufverfolgung einer Beispieldatentransaktion

Beim Empfang des ACK-Pakets initiiert der Host die Datentransaktion. Um die Transaktion zu initiieren, sendet sie ein Tokenpaket (#450) mit der Richtung ALS IN (sogenanntes IN-Token).

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 Bytes (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 8 Bytes gleichzeitig ü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 ist 64 Bytes. Low-Speed-Gerät ist 8 Bytes.

Der Host bestätigt die Datentransaktion, indem er ein ACK-Paket (#452) an das Gerät sendet.

Berechnen wir die Menge der zurückgegebenen Daten. Im Feld wLength des Datenpakets (#435) in der Setuptransaktion hat der Host 18 Bytes angefordert. In der Datentransaktion sehen wir, dass nur die ersten 8 Bytes 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 tut dies in zwei Transaktionen: 8 Bytes und dann die letzten 2 Bytes.

Nachdem der Host nun die maximale Paketgröße des Standardendpunkts kennt, initiiert der Host eine neue Datentransaktion und fordert basierend auf der Paketgröße den nächsten Teil an.

Hier ist die nächste Datentransaktion:

Screenshot: Ablaufverfolgung der neuen Datentransaktion

Der Host initiiert die vorherige Datentransaktion, indem er ein IN-Token (#463) sendet und die nächsten 8 Bytes vom Gerät anfordert. Das Gerät antwortet mit einem Datenpaket (#464), das die nächsten 8 Bytes 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:

Screenshot: Ablaufverfolgung der neuen Beispieldatentransaktion, in der der Host die letzten 2 Bytes anfordert

Daher sehen wir, dass der Host, um 18 Bytes vom Gerät auf den Host zu übertragen, die Anzahl der übertragenen Bytes nachverfolgt und drei Datentransaktionen (8+8+2) initiiert hat.

Hinweis

Beachten Sie die PID der Datenpakete in Datentransaktionen 19, 23, 26. Die PID wechselt zwischen DATA0 und DATA1. Diese Sequenz wird als Datenschalter bezeichnet. In Fällen, in denen mehrere Datentransaktionen vorhanden sind, wird die Datenschaltung 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 Size Wert BESCHREIBUNG
bLength 1 0x12 Die Länge des Gerätedeskriptors beträgt 18 Bytes.
bDescriptorType 1 0x01 Der Deskriptortyp ist Gerät.
bcdUSB 2 0x0100 Die Spezifikationsversionsnummer ist 1.00.
bDeviceClass 1 0x00 Die Geräteklasse ist 0. Jede Schnittstelle in der Konfiguration verfügt über die Klasseninformationen.
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 Fernkommunikation.
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 Bytes. Das Gerät unterstützt eine Konfiguration.

Statustransaktion

Schließlich schließt der Host die Steuerungsübertragung ab, indem er die letzte Transaktion initiiert: status Transaktion.

Screenshot: Ablaufverfolgung einer Beispieldatentransaktion

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 status Transaktion wird kein Datenpaket gesendet. Das Gerät antwortet mit einem ACK-Paket. Wenn ein Fehler aufgetreten ist, könnte die PID entweder NAK oder STALL sein.

Treibermodelle

Voraussetzungen

Bevor der Clienttreiber Pipes aufzählen kann, stellen Sie sicher, dass diese Anforderungen erfüllt sind:

  • 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.

KMDF-Clienttreiber

Ein KMDF-Clienttreiber muss ein WDFUSBDEVICE-Handle abrufen, indem die WdfUsbTargetDeviceCreateWithParameters-Methode aufgerufen wird. Weitere Informationen finden Sie unter "Gerätequellcode" unter Grundlegendes zur Codestruktur des USB-Clienttreibers (KMDF).

UMDF-Clienttreiber

Ein UMDF-Clienttreiber muss einen IWDFUsbTargetDevice-Zeiger abrufen, indem das Framework-Zielgerätobjekt abfragt. Weitere Informationen finden Sie unter "IPnpCallbackHardware-Implementierung und USB-spezifische Aufgaben" unter Grundlegendes zur Codestruktur des USB-Clienttreibers (UMDF).

Der wichtigste Aspekt für eine Steuerungsübertragung besteht darin, das Setuptoken entsprechend zu formatieren. Sammeln Sie vor dem Senden der Anforderung die folgenden Informationen:

  • Richtung der Anforderung: Hosten zu Gerät oder Gerät zum Hosten.
  • Empfänger der Anforderung: Gerät, Schnittstelle, Endpunkt oder andere.
  • Anforderungskategorie: Standard, Klasse oder Anbieter.
  • Anforderungstyp, z. B. eine GET_DESCRIPTPOR Anforderung. Weitere Informationen finden Sie in Abschnitt 9.5 der USB-Spezifikation.
  • wValue - und wIndex-Werte . Diese Werte hängen vom Typ der Anforderung ab.

Sie können alle diese Informationen aus der offiziellen USB-Spezifikation abrufen.

Wenn Sie einen UMDF-Treiber schreiben, rufen Sie die Headerdatei Usb_hw.h aus dem UMDF-Beispieltreiber für OSR USB Fx2 Learning Kit ab. Diese Headerdatei enthält nützliche Makros und Struktur zum Formatieren des Setuppakets für die Steuerelementübertragung.

Alle UMDF-Treiber müssen mit einem Kernelmodustreiber kommunizieren, um Daten von Geräten senden und empfangen zu können. 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 dem Empfang der Anforderung verarbeitet WinUSB entweder die Anforderung oder leitet sie an den USB-Treiberstapel weiter.

Von Microsoft definierte Methoden zum Senden von Steuerungsübertragungsanforderungen

Ein USB-Clienttreiber auf dem Host initiiert die meisten Steuerungsanforderungen, um Informationen zum Gerät abzurufen, das Gerät zu konfigurieren oder Anbietersteuerungsbefehle zu senden. Alle diese Anforderungen können in folgende Kategorien unterteilt werden:

  • Standardanforderungen sind 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 einer beliebigen Steuerungsübertragung ist immer der Standardendpunkt. Der Empfänger ist die Entität des Geräts, für deren Informationen (Deskriptor, status usw.) der Host interessiert ist.

    Anforderungen können weiter unterteilt werden in: Konfigurationsanforderungen, Featureanforderungen und status Anforderungen.

    • Konfigurationsanforderungen werden gesendet, um Informationen vom Gerät abzurufen, damit der Host es 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 eine alternative Einstellung im Gerät festzulegen.
    • Featureanforderungen werden vom Clienttreiber gesendet, um bestimmte boolesche Geräteeinstellungen zu aktivieren oder zu deaktivieren, die vom Gerät, der Schnittstelle oder einem Endpunkt unterstützt werden.
    • Statusanforderungen ermöglichen es dem Host, die usb-definierten status Bits eines Geräts, Endpunkts oder einer Schnittstelle abzurufen oder festzulegen.

    Weitere Informationen finden Sie in Abschnitt 9.4 der USB-Spezifikation, Version 2.0. Die Standardanforderungstypen werden in der Headerdatei Usbspec.h definiert.

  • Klassenanforderungen werden durch eine bestimmte Geräteklassenspezifikation definiert.

  • Anbieteranforderungen werden vom Anbieter bereitgestellt und hängen von den anforderungen ab, die vom Gerät unterstützt werden.

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 viele Arten zu senden. Wenn es sich bei Ihrem Clienttreiber um einen WDF-Treiber (Windows Driver Foundation) handelt, können Routinen direkt aufgerufen werden, um die gängigen 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. Dieses Modell ermöglicht es dem Clienttreiber, Anforderungen im WDM-URB-Stil zu erstellen und zu formatieren und diese Anforderungen dann mithilfe von WDF-Frameworkobjekten zu 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 zu ermitteln, wie Sie Steuerungsanforderungen am besten an den USB-Treiberstapel senden können. Wenn Sie diese Tabelle nicht anzeigen können, lesen Sie die Tabelle in diesem Artikel.

Wenn Sie eine Steuerungsanforderung an... 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, dessen Konfigurationen, Schnittstellen und Endpunkten. Siehe Abschnitt 9.4.1 in der USB-Spezifikation.
  1. Deklarieren Sie ein Setuppaket. Weitere Informationen finden Sie in der WDF_USB_CONTROL_SETUP_PACKET-Struktur .
  2. Initialisieren Sie das Setuppaket, indem Sie WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE aufrufen.
  3. Geben Sie einen in WDF_USB_BMREQUEST_RECIPIENT definierten Empfängerwert an.
  4. Geben Sie den Featureauswahlor (wValue) an. Siehe USB_FEATURE_XXX Konstanten in Usbspec.h. Siehe tabelle 9-6 in der USB-Spezifikation.
  5. Legen Sie SetFeature auf FALSE fest.
  6. Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronously oder WdfUsbTargetDeviceFormatRequestForControlTransfer aufrufen.
  1. Deklarieren Sie ein Setuppaket. Siehe die WINUSB_CONTROL_SETUP_PACKET-Struktur , die in usb_hw.h deklariert wurde.
  2. Initialisieren Sie das Setuppaket, indem Sie das in usb_hw.h definierte Hilfsmakro WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE aufrufen.
  3. Geben Sie einen in WINUSB_BMREQUEST_RECIPIENT definierten Empfängerwert an.
  4. Geben Sie den Featureauswahlor (wValue) an. Siehe USB_FEATURE_XXX Konstanten in Usbspec.h. Siehe tabelle 9-6 in der USB-Spezifikation.
  5. Legen Sie SetFeature auf FALSE fest.
  6. Erstellen Sie die Anforderung, indem Sie das initialisierte Setuppaket dem Frameworkanforderungsobjekt und dem Übertragungspuffer zuordnen, indem Sie die IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufrufen.
  7. Senden Sie die Anforderung, indem Sie die IWDFIoRequest::Send-Methode aufrufen.
_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: Rufen Sie die aktuelle USB-Konfiguration ab. Siehe Abschnitt 9.4.2 in der USB-Spezifikation. KMDF wählt standardmäßig die erste Konfiguration aus. So rufen Sie die gerätedefinierte Konfigurationsnummer ab:

  1. Formatieren Sie einen WDF_USB_CONTROL_SETUP_PACKET , und legen Sie sein bRequest-Element auf USB_REQUEST_GET_CONFIGURATION fest.
  2. Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronously oder WdfUsbTargetDeviceFormatRequestForControlTransfer aufrufen.
UMDF wählt standardmäßig die erste Konfiguration aus. So rufen Sie die gerätedefinierte Konfigurationsnummer ab:

  1. Deklarieren Sie ein Setuppaket. Siehe die WINUSB_CONTROL_SETUP_PACKET-Struktur , die in usb_hw.h deklariert wurde.
  2. Initialisieren Sie das Setuppaket, indem Sie das in usb_hw.h definierte Hilfsmakro WINUSB_CONTROL_SETUP_PACKET_INIT aufrufen.
  3. Geben Sie bmRequestToDevice als Richtung, BmRequestToDevice als Empfänger und USB_REQUEST_GET_CONFIGURATION als Anforderung an.
  4. Erstellen Sie die Anforderung, indem Sie das initialisierte Setuppaket dem Frameworkanforderungsobjekt und dem Übertragungspuffer zuordnen, indem Sie die IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufrufen.
  5. Senden Sie die Anforderung, indem Sie die IWDFIoRequest::Send-Methode aufrufen.
  6. Erhalten Sie die Konfigurationsnummer im Übertragungspuffer. Greifen Sie auf diesen Puffer zu, indem Sie IWDFMemory-Methoden aufrufen.
_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: Rufen Sie die aktuelle alternative Einstellung für eine Schnittstelle ab. Siehe Abschnitt 9.4.4 in der USB-Spezifikation.

  1. Rufen Sie ein WDFUSBINTERFACE-Handle für das Zielschnittstellenobjekt ab, indem Sie die WdfUsbTargetDeviceGetInterface-Methode aufrufen.
  2. Rufen Sie die WdfUsbInterfaceGetConfiguredSettingIndex-Methode auf.
  1. Rufen Sie einen IWDFUsbInterface-Zeiger auf das Zielschnittstellenobjekt ab.
  2. Rufen Sie die IWDFUsbInterface::GetConfiguredSettingIndex-Methode auf.
_URB_CONTROL_GET_INTERFACE_REQUEST

URB_FUNCTION_GET_INTERFACE
GET_STATUS: Abrufen status Bits von einem Gerät, Endpunkt oder einer Schnittstelle. Siehe Abschnitt 9.4.5. in der USB-Spezifikation.
  1. Deklarieren Sie ein Setuppaket. Weitere Informationen finden Sie in der WDF_USB_CONTROL_SETUP_PACKET-Struktur .
  2. Initialisieren Sie das Setuppaket, indem Sie WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS aufrufen.
  3. Geben Sie den in WDF_USB_BMREQUEST_RECIPIENT definierten Empfängerwert an.
  4. Geben Sie an, welche status Sie abrufen möchten: Gerät, Schnittstelle oder Endpunkt (wIndex).
  5. Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronously oder WdfUsbTargetDeviceFormatRequestForControlTransfer aufrufen.
  1. Deklarieren Sie ein Setuppaket. Siehe die WINUSB_CONTROL_SETUP_PACKET-Struktur , die in usb_hw.h deklariert wurde.
  2. Initialisieren Sie das Setuppaket, indem Sie das in usb_hw.h definierte Hilfsmakro WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS aufrufen.
  3. Geben Sie einen in WINUSB_BMREQUEST_RECIPIENT definierten Empfängerwert an.
  4. Geben Sie an, welche status Sie abrufen möchten: Gerät, Schnittstelle oder Endpunkt (wIndex).
  5. Erstellen Sie die Anforderung, indem Sie das initialisierte Setuppaket dem Frameworkanforderungsobjekt und dem Übertragungspuffer zuordnen, indem Sie die IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufrufen.
  6. Senden Sie die Anforderung, indem Sie die IWDFIoRequest::Send-Methode aufrufen.
  7. Erhalten Sie den status Wert im Übertragungspuffer. Greifen Sie auf diesen Puffer zu, indem Sie IWDFMemory-Methoden aufrufen.
  8. Verwenden Sie die in der WINUSB_DEVICE_TRAITS-Enumeration definierten Werte, um zu bestimmen, ob der status eine selbstgesteuerte Remoteaktivierung angibt:
_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 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.
SET_CONFIGURATION: Legen Sie eine Konfiguration fest. Siehe Abschnitt 9.4.7 der 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 die erste alternative Einstellung in jeder Schnittstelle aus. Der Clienttreiber kann die Standardkonfiguration ändern, indem er die WdfUsbTargetDeviceSelectConfigType-Methode aufruft und WdfUsbTargetDeviceSelectConfigTypeUrb als Anforderungsoption angibt. 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 Sie ein vorhandenes Gerät, eine vorhandene Konfiguration oder einen Zeichenfolgendeskriptor. Siehe Abschnitt 9.4.8 unter USB-Spezifikation.

Diese Anforderung wird häufig nicht verwendet. Der USB-Treiberstapel akzeptiert jedoch eine solche Anforderung vom Clienttreiber.
  1. Ordnen Sie eine URB für die Anforderung zu, und erstellen Sie sie.
  2. Geben Sie die Übertragungsinformationen in einer _URB_CONTROL_DESCRIPTOR_REQUEST-Struktur an.
  3. Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceFormatRequestForUrb oder WdfUsbTargetDeviceSendUrbSynchronously aufrufen.
  1. Deklarieren Sie ein Setuppaket. Weitere Informationen finden Sie in der in usb_hw.h deklarierten WINUSB_CONTROL_SETUP_PACKET-Struktur.
  2. Geben Sie die Übertragungsinformationen gemäß der USB-Spezifikation an.
  3. Erstellen Sie die Anforderung, indem Sie das initialisierte Setuppaket dem Frameworkanforderungsobjekt und dem Übertragungspuffer zuordnen, indem Sie die IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufrufen.
  4. Senden Sie die Anforderung, indem Sie die IWDFIoRequest::Send-Methode aufrufen.
_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, seinen Konfigurationen, Schnittstellen und Endpunkten. Siehe Abschnitt 9.4.9 in der USB-Spezifikation.
  1. Deklarieren Sie ein Setuppaket. Weitere Informationen finden Sie in der WDF_USB_CONTROL_SETUP_PACKET-Struktur.
  2. Initialisieren Sie das Setuppaket, indem Sie WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE aufrufen.
  3. Geben Sie den in WDF_USB_BMREQUEST_RECIPIENT definierten Empfängerwert (Gerät, Schnittstelle, Endpunkt) an.
  4. Geben Sie die Featureauswahl (wValue) an. Weitere Informationen finden Sie unter USB_FEATURE_XXX Konstanten in Usbspec.h. Siehe auch Tabelle 9-6 in der USB-Spezifikation.
  5. SetFeature auf TRUE festlegen
  6. Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronously oder WdfUsbTargetDeviceFormatRequestForControlTransfer aufrufen.
  1. Deklarieren Sie ein Setuppaket. Weitere Informationen finden Sie in der in usb_hw.h deklarierten WINUSB_CONTROL_SETUP_PACKET-Struktur.
  2. Initialisieren Sie das Setuppaket, indem Sie das in usb_hw.h definierte Hilfsmakro WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE aufrufen.
  3. Geben Sie einen in WINUSB_BMREQUEST_RECIPIENT definierten Empfängerwert an.
  4. Geben Sie die Featureauswahl (wValue) an. Siehe USB_FEATURE_XXX Konstanten in Usbspec.h. Siehe auch Tabelle 9-6 in der USB-Spezifikation.
  5. Legen Sie SetFeature auf TRUE fest.
  6. Erstellen Sie die Anforderung, indem Sie das initialisierte Setuppaket dem Frameworkanforderungsobjekt und dem Übertragungspuffer zuordnen, indem Sie die IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufrufen.
  7. Senden Sie die Anforderung, indem Sie die IWDFIoRequest::Send-Methode aufrufen.
_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
  1. Rufen Sie ein WDFUSBINTERFACE-Handle für das Zielschnittstellenobjekt ab.
  2. Rufen Sie die WdfUsbInterfaceSelectSetting-Methode auf .
  1. Rufen Sie einen IWDFUsbInterface-Zeiger auf das Zielschnittstellenobjekt ab.
  2. Rufen Sie die IWDFUsbInterface::SelectSetting-Methode auf .
_URB_SELECT_INTERFACE

(USBD_SelectInterfaceUrbAllocateAndBuild)

URB_FUNCTION_SELECT_INTERFACE
SYNC_FRAME: Legen Sie die Synchronisierungsrahmennummer des Endpunkts fest, und rufen Sie sie ab. 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.
  1. Deklarieren Sie ein Setuppaket. Weitere Informationen finden Sie in der WDF_USB_CONTROL_SETUP_PACKET-Struktur.
  2. Initialisieren Sie das Setuppaket, indem Sie WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS spezifische Anforderungen oder WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR für Anbieterbefehle aufrufen.
  3. Geben Sie den in WDF_USB_BMREQUEST_RECIPIENT definierten Empfängerwert (Gerät, Schnittstelle, Endpunkt) an.
  4. Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronously oder WdfUsbTargetDeviceFormatRequestForControlTransfer aufrufen.
  1. Deklarieren Sie ein Setuppaket. Weitere Informationen finden Sie in der in usb_hw.h deklarierten WINUSB_CONTROL_SETUP_PACKET-Struktur.
  2. Initialisieren Sie das Setuppaket, indem Sie das in usb_hw.h definierte Hilfsmakro WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS oder WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR aufrufen.
  3. Geben Sie die Richtung (siehe WINUSB_BMREQUEST_DIRECTION-Enumeration ), den Empfänger (siehe WINUSB_BMREQUEST_RECIPIENT-Enumeration ) und die Anforderung an, wie in der Klasse oder der Hardwarespezifikation beschrieben.
  4. Erstellen Sie die Anforderung, indem Sie das initialisierte Setuppaket dem Frameworkanforderungsobjekt und dem Übertragungspuffer zuordnen, indem Sie die IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufrufen.
  5. Senden Sie die Anforderung, indem Sie die IWDFIoRequest::Send-Methode aufrufen.
  6. Empfangen der Informationen vom Gerät im Übertragungspuffer. Greifen Sie auf diesen Puffer zu, indem Sie IWDFMemory-Methoden aufrufen.
_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 Steuerungsübertragung für Anbieterbefehle – 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.

  1. Deklarieren Sie eine Konstante für den Vendor-Befehl. Untersuchen Sie die Hardwarespezifikation, und ermitteln Sie den gewünschten Anbieterbefehl.

  2. Deklarieren Sie eine WDF_MEMORY_DESCRIPTOR-Struktur , und initialisieren Sie sie, indem Sie das makro WDF_MEMORY_DESCRIPTOR_INIT_BUFFER aufrufen. Diese Struktur erhält die Antwort vom Gerät, nachdem der USB-Treiber die Anforderung abgeschlossen hat.

  3. Je nachdem, ob Sie die Anforderung synchron oder asynchron senden, geben Sie Ihre Sendeoptionen an:

  4. Deklarieren Sie eine WDF_USB_CONTROL_SETUP_PACKET Struktur, die das Setuptoken enthält, und formatieren Sie die Struktur. Rufen Sie hierzu das Makro WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR auf, um das Setuppaket zu formatieren. Geben Sie im Aufruf die Richtung der Anforderung, den Empfänger, die Optionen für die gesendete Anforderung (initialisiert in Schritt 3) und die Konstante für den Vendor-Befehl an.

  5. Senden Sie die Anforderung, indem Sie WdfUsbTargetDeviceSendControlTransferSynchronously oder WdfUsbTargetDeviceFormatRequestForControlTransfer aufrufen.

  6. Ü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 dessen Firmwareversion abzurufen. Die Anforderung wird synchron gesendet, und der Clienttreiber gibt einen relativen Timeoutwert von 5 Sekunden (in 100 Nanosekundeneinheiten) an. 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;
}

Senden einer 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 den Bits D1-D0 ab. Weitere Informationen finden Sie unter Abbildung 9-4 in der USB-Spezifikation.

  1. Schließen Sie die Headerdatei Usb_hw.h ein, die mit dem UMDF-Beispieltreiber für OSR USB Fx2 Learning Kit verfügbar ist.

  2. Deklarieren Sie eine WINUSB_CONTROL_SETUP_PACKET-Struktur .

  3. Initialisieren Sie das Setuppaket, indem Sie das Hilfsmakro aufrufen, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.

  4. Geben Sie BmRequestToDevice als Empfänger an.

  5. Geben Sie 0 im Indexwert an.

  6. Rufen Sie die Hilfsmethode SendControlTransferSynchronously auf, um die Anforderung synchron zu senden.

    Die Hilfsmethode erstellt die Anforderung, indem das initialisierte Setuppaket dem Frameworkanforderungsobjekt und dem Übertragungspuffer zugeordnet wird, indem die IWDFUsbTargetDevice::FormatRequestForControlTransfer-Methode aufgerufen wird. Die Hilfsmethode sendet dann die Anforderung durch Aufrufen der IWDFIoRequest::Send-Methode . Überprüfen Sie nach der Rückgabe der Methode den zurückgegebenen Wert.

  7. Verwenden Sie die folgenden Werte, die in der WINUSB_DEVICE_TRAITS-Enumeration definiert sind, um festzustellen, ob die status auf eine selbstgesteuerte Remotereaktivierung hinweist:

In diesem Codebeispiel wird eine Steuerungsübertragungsanforderung an ein get the 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 Steuerungsübertragungen von einer Anwendung senden. Verwenden Sie zum Formatieren des Setuppakets in WinUSB die INDF-Hilfsmakros und -Strukturen, die in der Tabelle in diesem Artikel beschrieben werden. Um die Anforderung zu senden, rufen Sie WinUsb_ControlTransfer-Funktion auf.