Schreiben eines Funktionscontroller-Clienttreibers

In diesem Artikel werden die verschiedenen Aufgaben beschrieben, die ein Funktionscontroller-Clienttreiber während der Interaktion mit der USB-Funktionscontrollererweiterung (UFX) ausführt.

Wichtige APIs

Beschreibt die verschiedenen Aufgaben, die ein Funktionscontrollerclienttreiber während der Interaktion mit der USB-Funktionscontrollererweiterung (UFX) ausführt. UFX und der Clienttreiber kommunizieren miteinander über Exportmethoden und Ereignisrückruffunktionen. Exportmethoden (mit dem Namen UfxDeviceXxx oder UfxEndpointXxx) werden von UFX exportiert und vom Clienttreiber aufgerufen. Rückruffunktionen (EVT_UFX_Xxx) werden im Clienttreiber implementiert und von UFX aufgerufen.

UFX ruft alle Rückruffunktionen des Clienttreibers asynchron und jeweils einen Rückruf pro Objekt auf. Beispielsweise gibt es ein USB-Geräteobjekt und drei Endpunktobjekte. Es können maximal vier Rückruffunktionen (eine für das Gerät und eine für jeden Endpunkt) gleichzeitig aufgerufen werden. Für jede Rückrufmethode wartet UFX, bis der Clienttreiber UfxDeviceEventComplete aufruft , um anzugeben, dass der Treiber die Anforderung abgeschlossen hat. Die einzige andere Exportmethode, auf die UFX beim Warten auf diese Exporte lauscht, ist UfxDeviceNotifyHardwareFailure. Viele Clientrückruffunktionen sind optional. Die erforderlichen Funktionen sind wie folgt:

Initialisierung

  1. Der Clienttreiber des Funktionscontrollers startet den Initialisierungsprozess, wenn Windows Driver Foundation (WDF) die Implementierung des EVT_WDF_DRIVER_DEVICE_ADD Rückrufs durch den Clienttreiber aufruft. In dieser Implementierung wird erwartet, dass der Clienttreiber UfxFdoInit aufruft und dann das Geräteobjekt durch Aufrufen von WdfDeviceCreate erstellt.
  2. Der Clienttreiber ruft UfxDeviceCreate auf, um das USB-Geräteobjekt zu erstellen und das UFXDEVICE-Handle abzurufen.
  3. Der Clienttreiber ruft UfxDeviceNotifyHardwareReady auf, um UFX mitzuteilen, dass er jetzt die Rückruffunktionen des Clienttreibers aufrufen kann.
  4. UFX führt Initialisierungsaufgaben aus, z. B.:
    • UFX ruft die EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD Implementierung des Clienttreibers auf, um den Standardendpunkt zu erstellen.
    • UFX erstellt untergeordnete physische Geräteobjekte (PDOs) für schnittstellen, die vom Gerät unterstützt werden.
    • UFX wartet auf die Aktivierung des Geräteklassentreibers, wenn die IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS Anforderung gesendet wird. Außerdem wird gewartet, bis der Clienttreiber UfxDeviceNotifyAttach aufruft, was angibt, dass das Gerät angefügt wurde.

Klassentreiberbenachrichtigung

Um über Setuppakete und die status des Busses benachrichtigt zu werden, sollte ein Klassentreiber eine IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS Anforderungen senden. UFX stellt diese Anforderungen in Klassentreiberspezifische Benachrichtigungswarteschlangen bereit. Wenn sie eine Benachrichtigung über ein Busereignis vom Clienttreiber erhalten, wird UFX aus jeder entsprechenden Warteschlange angezeigt und schließt die Anforderung ab. Um zu verhindern, dass Klassentreiber Benachrichtigungen fehlen, behält UFX eine Warteschlange mit Benachrichtigungen mit fester Größe für den Klassentreiber bei.

Geräteanfügen und Trennen von Ereignissen

UFX geht davon aus, dass das Gerät getrennt wird, bis der Clienttreiber des Funktionscontrollers UfxDeviceNotifyAttach aufruft.

Nach diesem Aufruf legt UFX den Gerätestatus auf "Stromversorgung" fest, wie in der USB-Spezifikation definiert. Um den Clienttreiber über Zustandsänderungen zu benachrichtigen, ruft UFX die EVT_UFX_DEVICE_USB_STATE_CHANGE Implementierung des Clienttreibers auf.

UFX benachrichtigt den Ladegerättreiber (Cad.sys), um das Aufladen des Geräts zu unterstützen. UFX benachrichtigt auch die Klassentreiber, indem IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION Anforderungen abgeschlossen werden, die zuvor von Klassentreibern gesendet wurden.

Der Clienttreiber muss UfxDeviceNotifyDetach aufrufen, wenn der Bus getrennt wird. Der Client darf detach nur einmal nach jedem Aufruf von UfxDeviceNotifyAttach aufrufen. Nach dem UfxDeviceNotifyDetach-Aufruf ruft UFX EVT_UFX_DEVICE_HOST_DISCONNECT auf (wenn dies keine Schnittstellenänderung ist). UFX fährt dann mit allen sauber-Up-Aufgaben fort, z. B. das Bereinigen aller Endpunktwarteschlangen und das Starten der Standardendpunktwarteschlange. UFX ruft EVT_UFX_DEVICE_USB_STATE_CHANGE auf und benachrichtigt die Klassentreiber, indem IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION Anforderungen ausgeführt werden.

Hardwarefehler

Wenn ein Hardwarefehler auftritt, wird erwartet, dass der Clienttreiber UfxDeviceNotifyHardwareFailure aufruft. Als Reaktion reißt UFX den Gerätestapel ab und versucht möglicherweise, diese Situation zu beheben, indem der EVT_UFX_DEVICE_CONTROLLER_RESET des Clienttreibers aufgerufen wird. Der Client sollte den Controller auf seinen Ursprünglichen Zustand zurücksetzen. Wenn ein weiterer Hardwarefehler auftritt, sollte der Client UfxDeviceNotifyHardwareFailure erneut aufrufen. Beim zweiten Aufruf zeichnet UFX den Zustand und die Fehlerüberprüfung auf.

Porterkennung

Die Porterkennung wird von UFX durchgeführt. Es ruft die EVT_UFX_DEVICE_PORT_DETECT Rückruffunktion des Clienttreibers des Funktionscontrollers auf, um den Porttyp zu bestimmen, an den das Gerät angefügt ist. Der Client antwortet, indem er UfxDevicePortDetectComplete oder UfxDevicePortDetectCompleteEx mit einem der in USBFN_PORT_TYPE definierten Porttypen aufruft.

Wenn der Client den Porttyp nicht ermitteln kann, sollte der Client UsbfnUnknownPort melden. Wenn der Port unbekannt oder ein Downstreamport ist, ruft UFX die EVT_UFX_DEVICE_HOST_CONNECT-Funktion des Clienttreibers auf. UFX lauscht seit einiger Zeit auf den Bus. Wenn der Port unbekannt ist, aber Datenverkehr vorhanden ist, z. B. ein Setuppaket, geht UFX von UsbfnStandardDownstreamPort aus. Andernfalls weist UFX den Port UsbfnInvalidDedicatedChargingPort zu. Nachdem ein Porttyp ermittelt wurde, benachrichtigt UFX Cad.sys und ruft die EVT_UFX_DEVICE_PORT_CHANGE-Funktion des Clienttreibers auf. In der Funktion wird erwartet, dass der Clienttreiber den Hardwarezustand so ändert, dass er dem UFX-Porttyp entspricht.

Endpunkterstellung

UFX erstellt den Standardendpunkt (Endpunkt 0), indem der EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD des Clienttreibers aufgerufen wird, damit er Setuppakete verarbeiten kann, die vom Host gesendet werden. UFX erstellt andere Endpunkte, indem EVT_UFX_DEVICE_ENDPOINT_ADD aufgerufen wird. UFX erstellt nur Endpunkte, nachdem der Clienttreiber UfxDeviceNotifyHardwareReady aufgerufen hat. In diesen Rückruffunktionen wird erwartet, dass der Clienttreiber UfxEndpointCreate für das Endpunktobjekt aufruft und dessen UFXENDPOINT-Handle abruft. UFX legt das übergeordnete Element auf den Klassentreiber-PDO fest, der der Schnittstelle zugeordnet ist, zu der der Endpunkt gehört. Übergeordnetes Element des Standardendpunkts ist das USB-Geräteobjekt. Ein Endpunkt enthält zwei Frameworkwarteschlangenobjekte: eine Übertragungswarteschlange und einen Befehl Warteschlange, auf die nur zugegriffen werden kann, wenn sich das Gerät im Zustand Konfiguriert befindet (mit Ausnahme von Endpunkt 0, auf den nach UFX-Aufrufen EVT_UFX_DEVICE_HOST_CONNECT zugegriffen werden kann).

Geräteenumeration

Der Clienttreiber sollte keine Verbindungen mit einem Host zulassen, bevor UFX den EVT_UFX_DEVICE_HOST_CONNECT des Treibers aufruft. Die Geräteaufzählung beginnt, wenn der Clienttreiber UfxDeviceNotifyReset aufruft. Im Standardzustand verarbeitet UFX Standardsetuppakete.

Reset

UFX löscht alle Endpunktwarteschlangen und sendet eine IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE Anforderung an den Clienttreiber, um die wMaxPacketSize von Endpunkt 0 zu aktualisieren. UFX startet die Warteschlange des Standardendpunkts und legt den Status auf Standard fest.

Standard

UFX ruft die EVT_UFX_DEVICE_USB_STATE_CHANGE-Funktion des Clienttreibers auf. Außerdem werden Klassentreiber des Zustands benachrichtigt. Nachdem UFX das SET_ADDRESS Standardsetuppaket empfangen hat, legt UFX den Status auf Adressiert fest.

Adressiert

UFX ruft die EVT_UFX_DEVICE_ADDRESSED-Funktion des Clienttreibers auf, um dem Client anzugeben, welche Adresse er verwenden soll. - Wenn die Adresse 0 ist, legt UFX den Zustand wieder auf Standard fest, ruft EVT_UFX_DEVICE_USB_STATE_CHANGE auf und benachrichtigt Klassentreiber. Beim Empfang des SET_CONFIGURATION Standardsetuppakets legt UFX den Status auf Konfiguriert fest.

Konfiguriert

Wenn die ausgewählte Konfiguration 0 ist, löscht UFX die Schnittstellenendpunkte und legt den Status auf Adressiert fest. UFX sendet eine IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE-Anforderung an den Clienttreiber, um wMaxPacketSize der Schnittstellenendpunkte zu aktualisieren. UFX stellt sicher, dass alle Schnittstellenendpunktwarteschlangen das Bereinigen und Starten von Schnittstellenendpunktwarteschlangen abgeschlossen haben. Wenn der Porttyp nicht UsbfnStandardDownstreamPort oder UsbfnChargingDownstreamPort ist, ändert UFX den Porttyp in UsbfnStandardDownstreamPort und informiert Cad.sys. den Clienttreiber durch Aufrufen von EVT_UFX_DEVICE_PORT_CHANGE und EVT_UFX_DEVICE_USB_STATE_CHANGE , um den Zustand zu aktualisieren; die Klassentreiber des konfigurierten Zustands.

Standard-Steuerungsübertragungen

UFX kann Steuerungsübertragungen auf dem Standardendpunkt jederzeit verarbeiten, nachdem EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD aufgerufen wurde, in dem der Clienttreiber den Standardendpunkt mit erstellt. Alle Steuerungsübertragungen beginnen mit einem 8-Byte-Setuppaket. Um ein Setuppaket an den Host zu senden, sollte der Clienttreiber UfxEndpointNotifySetup aufrufen. Standardmäßige Steuerungsübertragungen werden von UFX abgeschlossen. Wenn der Steuerungsübertragung Daten zugeordnet sind, liest UFX nach Bedarf aus dem Standardendpunkt der Steuerung und schreibt es in diesen.

Nicht standardmäßige Steuerungsübertragungen

Wenn UFX eine Steuerungsübertragung nicht verarbeiten kann, wird die Übertragung an den entsprechenden Klassentreiber weitergeleitet, indem eine IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION-Anforderung abgeschlossen wird. Steuerungsübertragungen können auf jedem Endpunkt erfolgen, der im Endpunktdeskriptor als Steuerungsendpunkt definiert ist. Steuerungsübertragungen auf anderen Endpunkten als dem standardgesteuerten Endpunkt sind immer nicht standardmäßige Steuerungsübertragungen. Wenn der Steuerungsendpunkt der Standardendpunkt für die Steuerung ist, benachrichtigt UFX einen Klassentreiber über Setuppakete, die als Klassenanforderungen für diesen Klassentreiber gekennzeichnet sind. Wenn der Steuerungsendpunkt zu einer Schnittstelle gehört, benachrichtigt UFX den klassentreiber, der dieser Schnittstelle zugeordnet ist. Bei Bedarf wird erwartet, dass Klassentreiber aus dem Steuerungsendpunkt lesen und in diesen schreiben.

Datenübertragungen

Datenübertragungen werden von Klassentreibern initiiert, indem IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT oder IOCTL_INTERNAL_USBFN_TRANSFER_OUT Anforderungen gesendet werden. Nach der Validierung jeder dieser Anforderungen leitet UFX sie an die entsprechende Endpunktwarteschlange weiter, die vom Clienttreiber verarbeitet werden soll. Es wird erwartet, dass der Clienttreiber eine zusätzliche Überprüfung durchführt. Der Clienttreiber empfängt Übertragungsanforderungen für Endpunktwarteschlangen. Der Clienttreiber kann so viele Anforderungen aus dieser Warteschlange abrufen, wie er benötigt, um die Busauslastung zu maximieren. Der Clienttreiber sollte erfolgreiche Anforderungen mit STATUS_SUCCESS abschließen. Der Treiber sollte nach besten Kräften versuchen, Anforderungen abzubrechen und abgebrochene Anforderungen mit STATUS_CANCELLED abzuschließen, wenn sie abgebrochen werden. Wenn ungültige Parameter übergeben werden, schließt der Clienttreiber die Anforderung mit STATUS_INVALID_PARAMETER ab.

Steuern von Übertragungen

Steuerungsübertragungen beginnen mit einem 8-Byte-Setuppaket. Um ein Setuppaket an den Host zu senden, sollte der Clienttreiber UfxEndpointNotifySetup aufrufen. UFX benachrichtigt Klassentreiber über nicht standardmäßige Steuerungsübertragungen, indem Benachrichtigungsanforderungen abgeschlossen werden. Sowohl Clients als auch UFX verwenden IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT oder IOCTL_INTERNAL_USBFN_TRANSFER_OUT , um aus dem Standard-Steuerelementendpunkt zu lesen und in diesen zu schreiben. Eine Schnittstelle kann jedoch andere Steuerungsendpunkte definieren, die nur der entsprechende Klassentreiber verwenden kann. Steuerungsendpunkte können als Reaktion auf ein Setuppaket angehalten werden. Klassentreiber senden die IOCTL_INTERNAL_USBFN_SET_PIPE_STATE-Anforderung , um den Endpunkt zu stagnieren. Die Hardware oder der Clienttreiber wird erwartet, dass der Datenverkehr auf dem Endpunkt sofort fortgesetzt wird, nachdem die Verzögerung gesendet wurde. Steuerungsendpunkte können auch Pakete der Länge Null (ZLP) ohne vorherige Daten senden und empfangen. Der Clienttreiber und UFX können dies mithilfe von IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN und IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT.

Massen- und Unterbrechungsübertragungen

Massenübertragungen garantieren die Datenübermittlung und werden zum Senden großer Datenmengen verwendet. Übertragungen können mithilfe von IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKToder IOCTL_INTERNAL_USBFN_TRANSFER_OUT an einen Massenendpunkt gesendet werden. Massenendpunkte können ähnlich wie Steuerungsendpunkte mithilfe von IOCTL_INTERNAL_USBFN_SET_PIPE_STATE angehalten werden. Vom Clienttreiber wird erwartet, dass er als Antwort auf alle Hostanforderungen ein STALL-Paket sendet und IOCTL-Anforderungen vorhält. Im Gegensatz zu Steuerungsendpunkten bleibt ein blockierter Massenendpunkt so lange angehalten, bis der Status des Sperrvorgangs explizit gelöscht wird.

Interruptübertragungen Interruptübertragungen sind wie Massenübertragungen, weisen jedoch eine garantierte Latenz auf. Interruptübertragungen verfügen über die gleiche Schnittstelle wie Massenübertragungen, verfügen aber nicht über Streamingfunktionen.

Isochrone Übertragungen

Es wird nicht erwartet, dass der Clienttreiber isochrone Übertragungen in dieser Version unterstützt.

Energieverwaltung

Der Clienttreiber besitzt alle Aspekte der Energieverwaltung. Da Rückruffunktionen asynchron sind, wird erwartet, dass der Clienttreiber zu einem geeigneten Energiezustand zurückkommt und die Anforderung abschließt, bevor die entsprechende Event-Complete-Exportfunktion wie UfxDeviceEventComplete aufgerufen wird.

UFX befindet sich im Betriebszustand, wenn der Gerätestatus (in USBFN_DEVICE_STATE definiert) UsbfnDeviceStateSuspended und UsbfnDeviceStateAttached lautet und keinen Porttyp gemeldet hat. Alternativ hat UFX den Porttyp (definiert in USBFN_PORT_TYPE) UsbfnStandardDownstreamPort oder UsbfnChargingDownstreamPort gemeldet.

UFX wechselt in den Arbeitszustand und beendet diese, indem EVT_UFX_DEVICE_USB_STATE_CHANGE - oder EVT_UFX_DEVICE_PORT_CHANGE-Implementierungen aufgerufen werden. Der Übergang zu oder von einem Arbeitsstatus ist abgeschlossen, wenn der Clienttreiber UfxDeviceEventComplete aufruft.

In einem funktionierenden Zustand kann UFX jeden Rückruf aufrufen. Während sich UFX nicht im Arbeitszustand befindet, ruft UFX nur EVT_UFX_DEVICE_USB_STATE_CHANGE auf, um in einen Funktionierenden Zustand zu wechseln. EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL beim Anhalten eine Remotereaktivierung aus (sofern unterstützt).

Angehaltenes Gerät

Das Anhalten des Geräts tritt auf, wenn 3 Millisekunden lang kein Datenverkehr im Bus vorhanden ist. In diesem Fall muss der Clienttreiber UFX informieren, wenn er das Anhalten und Fortsetzen erkennt, indem er UfxDeviceNotifySuspend und UfxDeviceNotifyResume aufruft. Beim Empfang dieser Anrufe ruft UFX EVT_UFX_DEVICE_USB_STATE_CHANGE auf und benachrichtigt Klassentreiber, indem IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION Anforderungen abgeschlossen werden. Wenn die Remotereaktivierung vom Gerät unterstützt und vom Host aktiviert wird, kann UFX Aufrufe EVT_UFX_DEVICE_USB_STATE_CHANGE angehalten aufrufen, um ein Remotereaktivierungssignal auszusetzen.