Écrire un pilote client du contrôleur de fonction
Cet article décrit les différentes tâches qu’un pilote client de contrôleur de fonction effectue lors de l’interaction avec l’extension de contrôleur de fonction USB (UFX).
API importantes
Décrit les différentes tâches qu’un pilote client de contrôleur de fonction effectue lors de l’interaction avec l’extension de contrôleur de fonction USB (UFX). UFX et le pilote client communiquent entre eux à l’aide de méthodes d’exportation et de fonctions de rappel d’événement. Les méthodes d’exportation ( nommées UfxDeviceXxx ou UfxEndpointXxx) sont exportées par UFX et appelées par le pilote client. Les fonctions de rappel ( nommées EVT_UFX_Xxx) sont implémentées dans le pilote client et appelées par UFX.
UFX appelle toutes les fonctions de rappel du pilote client de manière asynchrone, et un rappel à la fois par objet. Par exemple, il existe un objet périphérique USB et trois objets de point de terminaison. Quatre fonctions de rappel maximum (une pour l’appareil et une pour chaque point de terminaison) peuvent être appelées à la fois. Pour chaque méthode de rappel, UFX attend que le pilote client appelle UfxDeviceEventComplete pour indiquer que le pilote a terminé la demande. La seule autre méthode d’exportation que UFX écoute pendant l’attente de ces exportations est UfxDeviceNotifyHardwareFailure. De nombreuses fonctions de rappel client sont facultatives. Les fonctions requises sont les suivantes :
- EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD
- EVT_UFX_DEVICE_ENDPOINT_ADD
- EVT_UFX_DEVICE_HOST_CONNECT
- EVT_UFX_DEVICE_HOST_DISCONNECT
- EVT_UFX_DEVICE_ADDRESSED
Initialisation
- Le pilote client du contrôleur de fonction démarre le processus d’initialisation lorsque Windows Driver Foundation (WDF) appelle l’implémentation du pilote client du rappel EVT_WDF_DRIVER_DEVICE_ADD . Dans cette implémentation, le pilote client est censé appeler UfxFdoInit , puis créer l’objet d’appareil en appelant WdfDeviceCreate.
- Le pilote client appelle UfxDeviceCreate pour créer l’objet de périphérique USB et récupérer le handle UFXDEVICE.
- Le pilote client appelle UfxDeviceNotifyHardwareReady pour indiquer à UFX qu’il peut désormais appeler les fonctions de rappel du pilote client.
- UFX effectue des tâches d’initialisation telles que :
- UFX appelle l’implémentation EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD du pilote client pour créer le point de terminaison par défaut.
- UFX crée des objets d’appareil physique enfants pour les interfaces prises en charge par l’appareil.
- UFX attend l’activation du pilote de classe de périphérique lorsqu’il envoie la demande IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS . Il attend également que le pilote client appelle UfxDeviceNotifyAttach qui indique que l’appareil a été attaché.
Notification du pilote de classe
Pour être informé des paquets d’installation et des status du bus, un pilote de classe doit envoyer une IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS requêtes. UFX met en file d’attente ces demandes dans des files d’attente de notification spécifiques au pilote de classe. Lors de la réception d’une notification concernant un événement de bus de la part du pilote client, UFX s’affiche dans chaque file d’attente appropriée et termine la demande. Pour éviter que les pilotes de classe ne manquent des notifications, UFX conserve une file d’attente de notifications de taille fixe pour le pilote de classe.
Événements d’attachement et de détachement d’appareil
UFX suppose que l’appareil est détaché jusqu’à ce que le pilote client du contrôleur de fonction appelle UfxDeviceNotifyAttach.
Après cet appel, UFX définit l’état de l’appareil sur Alimenté comme défini dans la spécification USB. Pour informer le pilote client d’un changement d’état, UFX appelle l’implémentation EVT_UFX_DEVICE_USB_STATE_CHANGE du pilote client.
UFX avertit le pilote de chargeur (Cad.sys) de l’aider à charger l’appareil. UFX avertit également les pilotes de classe en effectuant IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION requêtes envoyées précédemment par les pilotes de classe.
Le pilote client doit appeler UfxDeviceNotifyDetach lorsque le bus est détaché. Le client ne doit appeler detach qu’une seule fois après chaque appel à UfxDeviceNotifyAttach. Après l’appel UfxDeviceNotifyDetach , UFX appelle EVT_UFX_DEVICE_HOST_DISCONNECT (s’il ne s’agit pas d’un changement d’interface). UFX procède ensuite à toutes les tâches propre telles que le vidage de toutes les files d’attente de point de terminaison et le démarrage de la file d’attente de point de terminaison par défaut. Les appels UFX EVT_UFX_DEVICE_USB_STATE_CHANGE et notifient les pilotes de classe en effectuant IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION demandes.
Défaillance matérielle
Si une erreur matérielle se produit, le pilote client est censé appeler UfxDeviceNotifyHardwareFailure. En réponse, UFX va détruire la pile des appareils et peut essayer de récupérer de cette situation en appelant le EVT_UFX_DEVICE_CONTROLLER_RESET du pilote client. Le client doit rétablir l’état initial du contrôleur. Si une autre défaillance matérielle se produit, le client doit appeler à nouveau UfxDeviceNotifyHardwareFailure. Lors du deuxième appel, UFX enregistre son état et son case activée de bogues.
Détection des ports
La détection de port est effectuée par UFX. Il appelle la fonction de rappel EVT_UFX_DEVICE_PORT_DETECT du pilote client du contrôleur de fonction pour déterminer le type de port auquel l’appareil est attaché. Le client répond en appelant UfxDevicePortDetectComplete ou UfxDevicePortDetectCompleteEx avec l’un des types de port définis dans USBFN_PORT_TYPE.
Si le client ne peut pas déterminer le type de port, il doit signaler UsbfnUnknownPort. Si le port est inconnu ou un port en aval, UFX appelle la fonction EVT_UFX_DEVICE_HOST_CONNECT du pilote client. UFX écoute le bus pendant un certain temps. Si le port est inconnu, mais qu’il y a du trafic, tel qu’un paquet d’installation, UFX suppose UsbfnStandardDownstreamPort. Sinon, UFX affecte le port à UsbfnInvalidDedicatedChargingPort. Une fois qu’un type de port a été déterminé, UFX avertit Cad.sys et appelle la fonction EVT_UFX_DEVICE_PORT_CHANGE du pilote client. Dans la fonction , le pilote client doit modifier l’état du matériel pour qu’il corresponde au type de port UFX.
Création de point de terminaison
UFX crée le point de terminaison par défaut (point de terminaison 0) en appelant le EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD du pilote client afin qu’il puisse gérer les paquets d’installation envoyés par l’hôte. UFX crée d’autres points de terminaison en appelant EVT_UFX_DEVICE_ENDPOINT_ADD. UFX crée des points de terminaison uniquement après que le pilote client a appelé UfxDeviceNotifyHardwareReady. Dans ces fonctions de rappel, le pilote client est censé appeler UfxEndpointCreate à l’objet de point de terminaison et obtenir son handle UFXENDPOINT. UFX définit le parent sur le PDO du pilote de classe associé à l’interface à laquelle appartient le point de terminaison. Le parent du point de terminaison par défaut est l’objet périphérique USB. Un point de terminaison contient deux objets de file d’attente d’infrastructure : une file d’attente de transfert et une file d’attente de commande, qui ne sont accessibles que lorsque l’appareil est à l’état Configuré (à l’exception du point de terminaison 0, accessible après les appels UFX EVT_UFX_DEVICE_HOST_CONNECT).
- Demandes de file d’attente de commandes
- IOCTL_INTERNAL_USBFN_GET_PIPE_STATE
- IOCTL_INTERNAL_USBFN_SET_PIPE_STATE
- IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE
- Demandes de file d’attente de transfert
- IOCTL_INTERNAL_USBFN_TRANSFER_IN
- IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT
- IOCTL_INTERNAL_USBFN_TRANSFER_OUT
- IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN
- IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT
Énumération de l’appareil
Le pilote client ne doit pas autoriser les connexions à un hôte avant qu’UFX appelle le EVT_UFX_DEVICE_HOST_CONNECT du pilote. L’énumération de l’appareil commence lorsque le pilote client appelle UfxDeviceNotifyReset. Dans l’état Par défaut , UFX gère les paquets d’installation standard.
Réinitialiser
UFX vide toutes les files d’attente de point de terminaison et envoie une demande de IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE au pilote client pour mettre à jour le wMaxPacketSize du point de terminaison 0. UFX démarre la file d’attente du point de terminaison par défaut et définit l’état sur Par défaut.
Default
UFX appelle la fonction EVT_UFX_DEVICE_USB_STATE_CHANGE du pilote client. Il avertit également les pilotes de classe de l’état. Une fois qu’UFX a reçu le paquet d’installation standard SET_ADDRESS, UFX définit l’état sur Adresse.
Adressée
UFX appelle la fonction EVT_UFX_DEVICE_ADDRESSED du pilote client pour indiquer au client l’adresse qu’il doit utiliser. - Si l’adresse est 0, UFX rétablit l’état sur Default et appelle EVT_UFX_DEVICE_USB_STATE_CHANGE et avertit les pilotes de classe. Lors de la réception du paquet d’installation standard SET_CONFIGURATION, UFX définit l’état sur Configuré.
Configuré
Si la configuration sélectionnée est 0, UFX vide les points de terminaison d’interface et définit l’état sur Addressed. UFX envoie une demande de IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE au pilote client pour mettre à jour le wMaxPacketSize des points de terminaison d’interface. UFX s’assure que toutes les files d’attente de point de terminaison d’interface ont fini de purger et de démarrer les files d’attente de point de terminaison d’interface. Si le type de port n’est pas UsbfnStandardDownstreamPort ou UsbfnChargingDownstreamPort, UFX remplace le type de port par UsbfnStandardDownstreamPort et informe Cad.sys ; le pilote client en appelant EVT_UFX_DEVICE_PORT_CHANGE et EVT_UFX_DEVICE_USB_STATE_CHANGE pour mettre à jour l’état ; les pilotes de classe de l’état configuré.
Transferts de contrôle standard
UFX peut gérer les transferts de contrôle sur le point de terminaison par défaut à tout moment après avoir appelé EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD, dans lequel le pilote client crée le point de terminaison par défaut à l’aide de . Tous les transferts de contrôle commencent par un paquet d’installation de 8 octets. Pour envoyer un paquet d’installation à l’hôte, le pilote client doit appeler UfxEndpointNotifySetup. Les transferts de contrôle standard sont effectués par UFX. Si des données sont associées au transfert de contrôle, UFX lit et écrit dans le point de terminaison de contrôle par défaut le cas échéant.
Transferts de contrôle non standard
Si UFX ne peut pas gérer un transfert de contrôle, le transfert est transféré au pilote de classe approprié en effectuant une demande de IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION . Les transferts de contrôle peuvent se produire sur n’importe quel point de terminaison défini comme point de terminaison de contrôle dans le descripteur de point de terminaison. Les transferts de contrôle sur des points de terminaison autres que le point de terminaison de contrôle par défaut sont toujours des transferts de contrôle non standard. Si le point de terminaison de contrôle est le point de terminaison de contrôle par défaut, UFX informe les pilotes de classe des paquets d’installation marqués comme des demandes de classe pour ce pilote de classe. Si le point de terminaison de contrôle appartient à une interface, UFX avertit le pilote de classe associé à cette interface. Si nécessaire, les pilotes de classe sont censés lire et écrire dans le point de terminaison de contrôle.
Transfert de données
Les transferts de données sont initiés par les pilotes de classe en envoyant des requêtes IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT ou IOCTL_INTERNAL_USBFN_TRANSFER_OUT . Après avoir validé chacune de ces demandes, UFX la transfère à la file d’attente de point de terminaison appropriée pour être gérée par le pilote client. Le pilote client est censé effectuer une validation supplémentaire. Le pilote client reçoit les demandes de transfert sur les files d’attente du point de terminaison. Le pilote client peut récupérer autant de requêtes de cette file d’attente que nécessaire pour optimiser l’utilisation du bus. Le pilote client doit exécuter les demandes réussies avec STATUS_SUCCESS. Le conducteur doit faire tout son possible pour tenter d’annuler les demandes et terminer les demandes annulées avec STATUS_CANCELLED si elles sont annulées. Si des paramètres non valides sont transmis, le pilote client termine la demande avec STATUS_INVALID_PARAMETER.
Transferts de contrôle
Les transferts de contrôle commencent par un paquet d’installation de 8 octets. Pour envoyer un paquet d’installation à l’hôte, le pilote client doit appeler UfxEndpointNotifySetup. UFX avertit les pilotes de classe des transferts de contrôle non standard en effectuant des demandes de notification. Les clients et UFX utilisent IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT ou IOCTL_INTERNAL_USBFN_TRANSFER_OUT pour lire et écrire sur le point de terminaison de contrôle par défaut. Toutefois, une interface peut définir d’autres points de terminaison de contrôle, que seul le pilote de classe correspondant peut utiliser. Les points de terminaison de contrôle peuvent être bloqués en réponse à un paquet d’installation. Les pilotes de classe envoient la IOCTL_INTERNAL_USBFN_SET_PIPE_STATE demande de blocage du point de terminaison. Le matériel ou le pilote client est censé reprendre immédiatement le trafic sur le point de terminaison après l’envoi du décrochage. Les points de terminaison de contrôle peuvent également envoyer et recevoir des paquets de longueur zéro (ZLP) sans données préalables. Le pilote client et UFX peuvent le faire en utilisant IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN et IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT.
Transferts en bloc et interruptions
Les transferts en bloc garantissent la remise des données et sont utilisés pour envoyer de grandes quantités de données. Les transferts peuvent être envoyés sur un point de terminaison en bloc à l’aide de IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT ou IOCTL_INTERNAL_USBFN_TRANSFER_OUT. Les points de terminaison en bloc peuvent être bloqués de la même façon que les points de terminaison de contrôle à l’aide de IOCTL_INTERNAL_USBFN_SET_PIPE_STATE. Le pilote client doit envoyer un paquet STALL en réponse à toutes les requêtes de l’hôte et contenir les requêtes IOCTL. Contrairement aux points de terminaison de contrôle, un point de terminaison en bloc bloqué reste bloqué jusqu’à ce que l’état de décrochage soit explicitement effacé.
Les transferts d’interruption sont similaires aux transferts en bloc, mais ont une latence garantie. Les transferts d’interruption ont la même interface que les transferts en bloc, mais ils ne disposent pas de fonctionnalités de streaming.
Transferts isochronous
Le pilote client n’est pas censé prendre en charge les transferts isochronieux dans cette version.
Gestion de l'alimentation
Le pilote client possède tous les aspects de la gestion de l’alimentation. Étant donné que les fonctions de rappel sont asynchrones, le pilote client est censé revenir à un état d’alimentation approprié et terminer la demande avant d’appeler la fonction d’exportation d’exécution d’événements appropriée, telle qu’UfxDeviceEventComplete.
UFX est dans un état de fonctionnement si l’état de l’appareil (défini dans USBFN_DEVICE_STATE) est UsbfnDeviceStateSuspended et UsbfnDeviceStateAttached, et n’a pas signalé de type de port. Par ailleurs, UFX a signalé le type de port (défini dans USBFN_PORT_TYPE) UsbfnStandardDownstreamPort ou UsbfnChargingDownstreamPort.
UFX entre et quitte un état De travail en appelant des implémentations EVT_UFX_DEVICE_USB_STATE_CHANGE ou EVT_UFX_DEVICE_PORT_CHANGE . La transition vers ou à partir d’un état Working est terminée lorsque le pilote client appelle UfxDeviceEventComplete.
Dans un état De travail, UFX peut appeler n’importe quel rappel. Alors qu’il n’est pas à l’état Working, UFX appelle uniquement EVT_UFX_DEVICE_USB_STATE_CHANGE pour entrer un état opérationnel ; EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL d’émettre une veille à distance pendant la suspension (si prise en charge).
Interruption de l’appareil
La suspension de l’appareil se produit lorsqu’il n’y a pas de trafic sur le bus pendant 3 millisecondes. Dans ce cas, le pilote client doit informer UFX lorsqu’il détecte la suspension et la reprise en appelant UfxDeviceNotifySuspend et UfxDeviceNotifyResume. Lors de la réception de ces appels, UFX appelle EVT_UFX_DEVICE_USB_STATE_CHANGE et avertit les pilotes de classe en effectuant IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION requêtes. Si la veille à distance est prise en charge par l’appareil et activée par l’hôte, UFX peut appeler des appels EVT_UFX_DEVICE_USB_STATE_CHANGE pendant la suspension pour émettre un signal de veille à distance.