Écrire un pilote de contrôleur de port USB Type-C

Vous devez écrire un pilote de contrôleur de port USB Type-C si votre matériel USB Type-C implémente la couche physique USB Type-C ou Power Delivery (PD), mais n’implémente pas les machines d’état requises pour power Delivery.

Dans Windows 10 version 1703, l’architecture USB Type-C a été améliorée pour prendre en charge les conceptions matérielles qui implémentent la couche physique USB Type-C ou Power Delivery (PD), mais qui n’ont pas de moteur de stratégie de pdd ou d’implémentation de la couche protocole correspondante. Pour ces conceptions, Windows 10 version 1703 fournit un moteur de stratégie de pdD basé sur un logiciel et un gestionnaire de stratégie de périphérique via une nouvelle extension de classe appelée « USB Connector Manager Type-C Port Controller Interface Extension » (UcmTcpciCx). Un pilote client écrit par un IHV ou OEM/ODM communique avec UcmTcpciCx pour fournir des informations sur les événements matériels nécessaires au fonctionnement du moteur de stratégie de pds et du gestionnaire de stratégies de périphérique dans UcmTcpciCx. Cette communication est activée par le biais d’un ensemble d’interfaces de programmation décrites dans cet article et dans la section de référence.

Diagramme du gestionnaire de connecteurs USB.

L’extension de classe UcmTcpciCx est elle-même un pilote client d’UcmCx. Les décisions de stratégie concernant les contrats d’alimentation et les rôles de données sont prises dans UcmCx et transférées à UcmTcpciCx. UcmTcpciCx implémente ces stratégies et gère les machines à état Type-C et PD, à l’aide de l’interface de contrôleur de port fournie par votre pilote client UcmTcpciCx.

Résumé

  • Services fournis par l’extension de classe UcmTcpci
  • Comportement attendu du pilote client

Spécifications officielles

API importantes

Informations de référence sur les extensions de la classe de pilote de l’interface du contrôleur de port USB Type-C

Modèle de pilote client UcmTcpciCx

Modèle de pilote client UcmTcpciCx

Avant de commencer

  • Déterminez le type de pilote que vous devez écrire selon que votre matériel ou microprogramme implémente la machine à état PD. Pour plus d’informations, consultez Développement de pilotes Windows pour les connecteurs USB Type-C.

  • Installez Windows 10 pour les éditions de bureau (Famille, Professionnel, Entreprise et Éducation) sur votre ordinateur cible ou Windows 10 Mobile avec un connecteur USB Type-C.

  • Installez la dernière version du Kit de pilotes Windows (WDK) sur votre ordinateur de développement. Le kit contient les fichiers d’en-tête et les bibliothèques requis pour l’écriture du pilote client. En particulier, vous avez besoin des éléments suivants :

    • Bibliothèque stub, (UcmTcpciCxStub.lib). La bibliothèque traduit les appels effectués par le pilote client et les transmet à l’extension de classe.
    • Fichier d’en-tête UcmTcpciCx.h.

    Le pilote client s’exécute en mode noyau et se lie à la bibliothèque KMDF 1.15.

    Capture d’écran de la configuration de Visual Studio pour UCM.

  • Déterminez si le pilote client prend en charge les alertes.

  • Votre contrôleur de port n’a pas besoin d’être conforme à TCPCI. L’interface capture les fonctionnalités de n’importe quel contrôleur de port de type C. L’écriture d’un pilote client UcmTcpciCx pour du matériel qui n’est pas conforme à TCPCI implique de mapper les significations des registres et des commandes dans la spécification TCPCI à celles du matériel.

  • La plupart des contrôleurs TCPCI sont connectés à I2C. Votre pilote client utilise une ressource de connexion SPB (Serial Peripheral Bus) et une ligne d’interruption pour communiquer avec le matériel. Le pilote utilise l’interface de programmation SPB Framework Extension (SpbCx). Familiarisez-vous avec SpbCx en lisant ces articles :

    • [Guide de conception du pilote SPB (Simple Peripheral Bus)]
    • [Référence de programmation du pilote SPB]
  • Familiarisez-vous avec Windows Driver Foundation (WDF). Lecture recommandée : Développement de pilotes avec Windows Driver Foundation, écrit par Penny Orwick et Guy Smith.

Comportement de l’extension de classe UcmTcpci

  • Dans le cadre de l’exécution de la machine à états, UcmTcpciCx envoie des requêtes IOCTL au contrôleur de port. Par exemple, dans la messagerie PD, elle envoie une demande IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT_BUFFER pour définir la mémoire tampon de transmission. Cette demande (TRANSMIT_BUFFER) est transmise au pilote client. Le pilote définit ensuite la mémoire tampon de transmission avec les détails fournis par l’extension de classe.

  • UcmTcpciCx implémente des stratégies sur les contrats d’alimentation, les rôles de données, etc.

Comportement attendu du pilote client

Le pilote client pour UcmTcpciCx est censé :

  • Être le propriétaire de la stratégie d’alimentation. UcmTcpciCx ne participe pas à la gestion de l’alimentation du contrôleur de port.

  • Traduisez les requêtes reçues d’UcmTcpciCx en commandes de lecture ou d’écriture matérielles. Les commandes doivent être asynchrones, car DPM ne peut pas bloquer l’attente d’un transfert matériel.

  • Fournissez un objet de file d’attente d’infrastructure qui contient des objets de demande d’infrastructure. Pour chaque requête que l’extension de classe UcmTcpci souhaite envoyer au pilote client, l’extension ajoute un objet de requête dans l’objet file d’attente du pilote. Lorsque le pilote a terminé de traiter la requête, il appelle WdfRequestComplete. Il incombe au conducteur du client de compléter les demandes en temps opportun.

  • Découvrez et signalez les fonctionnalités du contrôleur de port. Ces fonctionnalités incluent des informations telles que les rôles dans lesquels le contrôleur de port peut fonctionner (par exemple, Source uniquement, Récepteur uniquement, DRP). Toutefois, il existe d’autres fonctionnalités du connecteur (voir la Note sur le magasin de fonctionnalités) et du système dans son ensemble, que le DPM doit connaître pour implémenter correctement la stratégie USB Type-C et PD. Pour instance, le DPM doit connaître les fonctionnalités sources du système/connecteur pour le publier auprès du partenaire de port.

    Magasin de fonctionnalités

    En plus des fonctionnalités liées au pilote client, des informations supplémentaires proviennent d’un emplacement global du système appelé magasin de capacités. Ce magasin de capacités global du système est stocké dans ACPI. Il s’agit d’une description statique des fonctionnalités du système et de chacun de ses connecteurs USB Type-C que le DPM utilise pour déterminer les stratégies à implémenter.

    En séparant la description des fonctionnalités système du pilote client pour le ou les contrôleurs de port, la conception permet d’utiliser un pilote sur différents systèmes de différentes fonctionnalités. UcmCx, et non UcmTcpciCx, s’interface avec le magasin de capacités. UcmTcpciCx (ou son pilote client) n’interagit pas avec le magasin de fonctionnalités.

    Le cas échéant, les informations du magasin de capacités remplacent les informations provenant directement du pilote client du contrôleur de port. Par instance, un contrôleur de port est capable d’une opération récepteur uniquement et le pilote client signale ces informations. Toutefois, le reste du système peut ne pas être configuré correctement pour l’opération récepteur uniquement. Dans ce cas, le fabricant du système peut signaler que les connecteurs sont capables d’une opération source uniquement dans le magasin de capacités. Le paramètre dans le magasin de fonctionnalités est prioritaire sur les informations signalées par le pilote.

  • Informez UcmTcpciCx avec toutes les données pertinentes liées aux alertes.

  • facultatif. Effectuez un traitement supplémentaire après l’entrée/la sortie d’un autre mode. Le pilote est informé de ces états par l’extension de classe par le biais de requêtes IOCTL.

Inscrire le pilote client avec UcmTcpciCx

Exemple de référence : voir EvtPrepareHardware dans Device.cpp.

  1. Dans votre implémentation EVT_WDF_DRIVER_DEVICE_ADD, appelez UcmTcpciDeviceInitInitialize pour initialiser la structure opaque WDFDEVICE_INIT. L’appel associe le pilote client à l’infrastructure.

  2. Après avoir créé l’objet d’appareil d’infrastructure (WDFDEVICE), appelez UcmTcpciDeviceInitialize pour inscrire le diver client auprès de UcmTcpciCx.

Initialiser le canal de communication I2C vers le matériel du contrôleur de port

Exemple de référence : voir EvtCreateDevice dans Device.cpp.

Dans votre implémentation EVT_WDF_DEVICE_PREPARE_HARDWARE, lisez les ressources matérielles pour ouvrir un canal de communication. Cela est nécessaire pour récupérer les fonctionnalités de pdD et être averti des alertes.

La plupart des contrôleurs TCPCI sont connectés à I2C. Dans l’exemple de référence, le pilote client ouvre un canal I2 à l’aide de l’interface de programmation SPB Framework Extension (SpbCx).

Le pilote client énumère les ressources matérielles en appelant WdfCmResourceListGetDescriptor.

Les alertes sont reçues en tant qu’interruptions. Par conséquent, le pilote crée un objet d’interruption d’infrastructure et inscrit l’ISR qui gère les alertes. L’ISR effectue des opérations de lecture et d’écriture matérielles, qui se bloquent jusqu’à ce que l’accès au matériel soit terminé. Étant donné que l’attente est inacceptable au niveau de DIRQL, le pilote effectue l’ISR à PASSIVE_LEVEL.

Initialiser les fonctionnalités type C et PD du contrôleur de port

Exemple de référence : voir EvtDeviceD0Entry dans Device.cpp.

Dans votre implémentation EVT_WDF_DEVICE_D0_EXIT,

  1. Communiquez avec le matériel du contrôleur de port et récupérez l’identification et les fonctionnalités de l’appareil en lisant différents registres.

  2. Initialisez UCMTCPCI_PORT_CONTROLLER_IDENTIFICATION et UCMTCPCI_PORT_CONTROLLER_CAPABILITIES avec les informations récupérées.

  3. Initialisez UCMTCPCI_PORT_CONTROLLER_CONFIG structure avec les informations précédentes en passant les structures initialisées à UCMTCPCI_PORT_CONTROLLER_CONFIG_INIT.

  4. Appelez UcmTcpciPortControllerCreate pour créer l’objet contrôleur de port et récupérer le handle UCMTCPCIPORTCONTROLLER.

Configurer un objet de file d’attente d’infrastructure pour recevoir des requêtes à partir d’UcmTcpciCx

Exemple de référence : consultez EvtDeviceD0Entry dans Device.cpp et HardwareRequestQueueInitialize dans Queue.cpp.

  1. Dans votre implémentation EVT_WDF_DEVICE_D0_EXIT, créez un objet de file d’attente d’infrastructure en appelant WdfIoQueueCreate. Dans cet appel, vous devez inscrire votre implémentation de rappel pour gérer les demandes IOCTL envoyées par UcmTpciCx. Le pilote client peut utiliser une file d’attente gérée par l’alimentation.

    Pendant l’exécution des machines d’état Type-C et PD, UcmTpciCx envoie des commandes au pilote client à exécuter. UcmTcpciCx garantit au maximum une demande de contrôleur de port en suspens à tout moment.

  2. Appelez UcmTcpciPortControllerSetHardwareRequestQueue pour inscrire le nouvel objet de file d’attente de framework avec UcmTpciCx. Une fois cet appel réussi, UcmTcpciCx place des objets de file d’attente d’infrastructure (WDFREQUEST) dans cette file d’attente quand il nécessite une action du pilote.

  3. Implémentez la fonction de rappel EvtIoDeviceControl pour gérer ces IOCTL.

Code de contrôle Description
IOCTL_UCMTCPCI_PORT_CONTROLLER_GET_STATUS Obtient les valeurs de tous les enregistrements status conformément à la spécification de l’interface du contrôleur de port de type C du bus série universel. Le pilote client doit récupérer les valeurs des registres CC_STATUS, POWER_STATUS et FAULT_STATUS.
IOCTL_UCMTCPCI_PORT_CONTROLLER_GET_CONTROL Obtient les valeurs de tous les registres de contrôle définis conformément à la spécification de l’interface du contrôleur de port De type C de bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_CONTROL Définit la valeur d’un registre de contrôles défini conformément à la spécification de l’interface du contrôleur de port C de type de bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT Définit le registre TRANSMIT défini conformément à la spécification de l’interface du contrôleur de port C de type de bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT_BUFFER Définit le TRANSMIT_BUFER Register défini conformément à la spécification de l’interface du contrôleur de port C de type de bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_RECEIVE_DETECT Définit le RECEIVE_DETECT Register défini conformément à la spécification de l’interface du contrôleur de port de type C de bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_CONFIG_STANDARD_OUTPUT Définit le CONFIG_STANDARD_OUTPUT Register défini conformément à la spécification de l’interface du contrôleur de port C de type de bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_COMMAND Définit la valeur d’un registre de commandes défini conformément à la spécification de l’interface du contrôleur de port de type C du bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_MESSAGE_HEADER_INFO Définit la valeur de l’MESSAGE_HEADER_INFO Register définie conformément à la spécification de l’interface du contrôleur de port de type C de bus série universel.
IOCTL_UCMTCPCI_PORT_CONTROLLER_ALTERNATE_MODE_ENTERED Avertit le pilote client qu’un autre mode est entré afin qu’il puisse effectuer d’autres tâches.
IOCTL_UCMTCPCI_PORT_CONTROLLER_ALTERNATE_MODE_EXITED Avertit le pilote client qu’un autre mode est arrêté afin qu’il puisse effectuer d’autres tâches.
IOCTL_UCMTCPCI_PORT_CONTROLLER_DISPLAYPORT_CONFIGURED Avertit le pilote client que le mode DisplayPort de remplacement sur l’appareil partenaire a été configuré avec l’attribution de broche afin que le pilote puisse effectuer d’autres tâches.
IOCTL_UCMTCPCI_PORT_CONTROLLER_DISPLAYPORT_HPD_STATUS_CHANGED Avertit le pilote client que le hot-plug detect status de la connexion DisplayPort a changé afin que le pilote puisse effectuer d’autres tâches.
  1. Appelez UcmTcpciPortControllerStart pour indiquer à UcmTcpciCx de démarrer le contrôleur de port. UcmTcpciCx assume le contrôle d’USB Type-C et power Delivery. Une fois le contrôleur de port démarré, UcmTcpciCx peut commencer à placer des requêtes dans la file d’attente des requêtes matérielles.

Gérer les alertes à partir du matériel du contrôleur de port

Exemple de référence : voir ProcessAndSendAlerts dans Alert.cpp

Le pilote client doit gérer les alertes (ou événements) reçues du matériel du contrôleur de port et les envoyer à UcmTcpciCx avec des données liées à l’événement.

Lorsqu’une alerte matérielle se produit, le matériel du contrôleur de port pilote la broche ALERT haute. Cela entraîne l’appel de l’ISR du pilote client (inscrit à l’étape 2). La routine prend en compte l’interruption matérielle à PASSIVE_LEVEL. La routine détermine si une interruption est une alerte provenant du matériel du contrôleur de port ; si c’est le cas, il termine le traitement de l’alerte et avertit UcmTcpciCx en appelant UcmTcpciPortControllerAlert.

Avant d’appeler UcmTcpciPortControllerAlert, le client est chargé d’inclure toutes les données pertinentes liées à l’alerte dans une structure de UCMTCPCI_PORT_CONTROLLER_ALERT_DATA. Le client fournit un tableau de toutes les alertes actives, car il est possible que le matériel puisse déclarer plusieurs alertes simultanément.

Voici un exemple de flux de tâches à signaler dans l’état CC.

  1. Le client reçoit une alerte matérielle.

  2. Le client lit le registre ALERT et détermine les alertes de type actives.

  3. Le client lit le registre CC STATUS et décrit le contenu du registre CC STATUS dans UCMTCPCI_PORT_CONTROLLER_ALERT_DATA. Le pilote définit le membre AlertType sur UcmTcpciPortControllerAlertCCStatus et le membre CCStatus du registre.

  4. Le client appelle UcmPortControllerAlert pour envoyer les alertes matérielles du tableau à UcmTcpciCx.

  5. Le client efface l’alerte (cela peut se produire à tout moment après que le client a récupéré les informations d’alerte)

Traiter les demandes reçues d’UcmTcpciCx

Exemple de référence : voir PortControllerInterface.cpp

Dans le cadre de l’exécution de la machine d’état, UcmTcpciCx doit envoyer des requêtes au contrôleur de port. Par exemple, il doit définir le TRANSMIT_BUFFER. Cette demande est transmise au pilote client. Le pilote définit la mémoire tampon de transmission avec les détails fournis par UcmTcpciCx. La plupart de ces requêtes se traduisent par une lecture ou une écriture matérielle par le pilote client. Les commandes doivent être asynchrones, car le DPM ne peut pas bloquer l’attente d’un transfert matériel.

UcmTcpciCx envoie les commandes en tant que code de contrôle d’E/S décrivant l’opération get/set requise à partir du pilote client. Dans la configuration de file d’attente du pilote client, le pilote a inscrit sa file d’attente auprès d’UcmTcpciCx. UcmTcpciCx commence à placer des objets de requête d’infrastructure dans la file d’attente, il nécessite une opération à partir du pilote. Les codes de contrôle d’E/S sont répertoriés dans le tableau de l’étape 4.

Il incombe au conducteur du client de remplir les demandes en temps opportun.

Le pilote client appelle WdfRequestComplete sur l’objet de demande d’infrastructure avec une status d’achèvement lorsqu’il a terminé l’opération demandée.

Le pilote client peut avoir besoin d’envoyer une demande d’E/S à un autre pilote pour effectuer l’opération matérielle. Par exemple, dans l’exemple, le pilote envoie une requête SPB au contrôleur de port connecté à I2C. Dans ce cas, le pilote ne peut pas transférer l’objet de demande d’infrastructure qu’il a reçu d’UcmTcpciCx, car l’objet de requête peut ne pas avoir le nombre correct d’emplacements de pile dans l’IRP WDM. Le pilote client doit créer un autre objet de requête d’infrastructure et le transférer à un autre pilote. Le pilote client peut préallouer les objets de requête dont il a besoin lors de l’initialisation, au lieu d’en créer un chaque fois qu’il reçoit une requête à partir d’UcmTcpciCx. Cela est possible, car UcmTcpciCx garantit qu’il n’y aura qu’une seule demande en attente à un moment donné.

Voir aussi