Share via


Escritura de un controlador de puerto USB de tipo C

Debe escribir un controlador de puerto USB type-C si el hardware USB type-C implementa la capa física usb type-C o power delivery (PD), pero no implementa las máquinas de estado necesarias para la entrega de energía.

En Windows 10, versión 1703, la arquitectura usb type-C se ha mejorado para admitir diseños de hardware que implementan la capa física usb type-C o power delivery (PD), pero no tienen una implementación de capa de protocolo o motor de directivas pd correspondiente. Para estos diseños, Windows 10 versión 1703 proporciona un motor de directivas pd basado en software y un administrador de directivas de dispositivos a través de una nueva extensión de clase denominada "Extensión de clase de interfaz de controlador de puerto type-C del Administrador de conectores USB" (UcmTcpciCx). Un controlador de cliente escrito por un IHV o OEM/ODM se comunica con UcmTcpciCx para proporcionar información sobre los eventos de hardware necesarios para el motor de directivas pd y el administrador de directivas de dispositivos en UcmTcpciCx para funcionar. Esa comunicación se habilita a través de un conjunto de interfaces de programación que se describen en este artículo y en la sección de referencia.

Diagrama del administrador de conectores USB.

La extensión de clase UcmTcpciCx es un controlador cliente de UcmCx. Las decisiones de directiva sobre contratos de energía, roles de datos, se toman en UcmCx y se reenvía a UcmTcpciCx. UcmTcpciCx implementa esas directivas y administra las máquinas de estado type-C y PD, mediante la interfaz del controlador de puerto proporcionada por el controlador de cliente UcmTcpciCx.

Resumen

  • Servicios proporcionados por la extensión de clase UcmTcpci
  • Comportamiento esperado del controlador de cliente

Especificaciones oficiales

API importantes

Referencia de extensiones de clase de controlador de controlador de interfaz de controlador de controlador usb type-C

Plantilla de controlador de cliente UcmTcpciCx

Plantilla de controlador de cliente UcmTcpciCx

Antes de empezar

  • Determine el tipo de controlador que necesita escribir en función de si el hardware o el firmware implementa la máquina de estado pd. Para obtener más información, vea Developing Windows drivers for USB Type-C connectors (Desarrollo de controladores de Windows para conectores usb de tipo C).

  • Instale Windows 10 para ediciones de escritorio (Home, Pro, Enterprise y Education) en el equipo de destino o Windows 10 Mobile con un conector USB Type-C.

  • Instale el Kit de controladores de Windows (WDK) más reciente en el equipo de desarrollo. El kit tiene los archivos y bibliotecas de encabezado necesarios para escribir el controlador de cliente, en concreto, necesita:

    • La biblioteca de código auxiliar (UcmTcpciCxStub.lib). La biblioteca traduce las llamadas realizadas por el controlador cliente y las pasa a la extensión de clase.
    • El archivo de encabezado, UcmTcpciCx.h.

    El controlador cliente se ejecuta en modo kernel y se enlaza a la biblioteca KMDF 1.15.

    Captura de pantalla de la configuración de Visual Studio para UCM.

  • Decida si el controlador de cliente admite alertas.

  • No es necesario que el controlador de puerto sea compatible con TCPCI. La interfaz captura las funciones de cualquier controlador de puerto type-C. Escribir un controlador de cliente UcmTcpciCx para hardware que no sea compatible con TCPCI implica asignar los significados de los registros y comandos de la especificación TCPCI a los del hardware.

  • La mayoría de los controladores TCPCI están conectados a I2C. El controlador cliente usa un recurso de conexión de bus periférico serie (SPB) y una línea de interrupción para comunicarse con el hardware. El controlador usa la interfaz de programación spb Framework Extension (SpbCx). Familiarícese con SpbCx leyendo estos artículos:

    • [Guía de diseño de controladores de bus periférico simple (SPB) ]
    • [Referencia de programación del controlador SPB]
  • Familiarícese con Windows Driver Foundation (WDF). Lectura recomendada: Desarrollar controladores con Windows Driver Foundation, escrita por Penny Orwick y Guy Smith.

Comportamiento de la extensión de clase UcmTcpci

  • Como parte de la ejecución de la máquina de estado, UcmTcpciCx envía solicitudes IOCTL al controlador de puerto. Por ejemplo, en la mensajería pd, envía una solicitud de IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT_BUFFER para establecer el búfer de transmisión. Esa solicitud (TRANSMIT_BUFFER) se entrega al controlador cliente. A continuación, el controlador establece el búfer de transmisión con los detalles proporcionados por la extensión de clase.

  • UcmTcpciCx implementa directivas sobre contratos de energía, roles de datos, etc.

Comportamiento esperado del controlador de cliente

Se espera que el controlador de cliente a UcmTcpciCx:

  • Ser el propietario de la directiva de energía. UcmTcpciCx no participa en la administración de energía del controlador de puerto.

  • Traducir solicitudes, recibidas de UcmTcpciCx, en comandos de lectura o escritura de hardware. Los comandos deben ser asincrónicos porque DPM no puede bloquear la espera de que se complete una transferencia de hardware.

  • Proporcione un objeto de cola de marco que contenga objetos de solicitud de marco. Para cada solicitud que la extensión de clase UcmTcpci desea enviar al controlador de cliente, la extensión agrega un objeto de solicitud en el objeto de cola del controlador. Cuando el controlador termina de procesar la solicitud, llama a WdfRequestComplete. Es responsabilidad del controlador de cliente completar las solicitudes de forma oportuna.

  • Descubra e informe de las funcionalidades del controlador de puerto. Estas funcionalidades incluyen información como los roles en los que el controlador de puerto puede funcionar (por ejemplo, solo origen, solo receptor, DRP). Sin embargo, hay otras funcionalidades del conector (consulte la nota sobre el almacén de funcionalidades) y del sistema en su conjunto, que se requiere DPM para poder implementar correctamente la directiva usb type-C y PD. Por ejemplo, DPM debe conocer las funcionalidades de origen del sistema o conector para anunciarlo al asociado de puerto.

    Almacén de funcionalidades

    Además de las funcionalidades relacionadas con el controlador cliente, la información adicional procede de una ubicación global del sistema denominada Almacén de funcionalidades. Este almacén de funcionalidades global del sistema se almacena en ACPI. Se trata de una descripción estática de las funcionalidades del sistema y de cada uno de sus conectores USB de tipo C que usa DPM para determinar las directivas que se van a implementar.

    Al separar la descripción de las funcionalidades del sistema del controlador cliente para los controladores de puerto, el diseño permite usar un controlador en diferentes sistemas de distintas funcionalidades. UcmCx, no UcmTcpciCx, interfaces con el almacén de funcionalidades. UcmTcpciCx (o su controlador de cliente) no interactúa con el almacén de funcionalidades.

    Siempre que corresponda, la información del almacén de funcionalidades invalida la información procedente directamente del controlador de cliente del controlador de puerto. Por ejemplo, un controlador de puerto es capaz de realizar operaciones de solo receptor y el controlador cliente informa de esa información. Sin embargo, es posible que el resto del sistema no esté configurado correctamente para la operación solo receptor. En ese caso, el fabricante del sistema puede informar de que los conectores son capaces de realizar operaciones de solo origen en el almacén de funcionalidades. La configuración del almacén de funcionalidades tiene prioridad sobre la información notificada del controlador.

  • Notifique a UcmTcpciCx todos los datos relevantes relacionados con las alertas.

  • Opcional. Realice algún procesamiento adicional después de entrar o salir de un modo alternativo. El controlador se informa sobre esos estados por la extensión de clase a través de solicitudes IOCTL.

Registro del controlador de cliente con UcmTcpciCx

Referencia de ejemplo: vea EvtPrepareHardware en Device.cpp.

  1. En la implementación de EVT_WDF_DRIVER_DEVICE_ADD, llame a UcmTcpciDeviceInitInitialize para inicializar la estructura WDFDEVICE_INIT opaca. La llamada asocia el controlador cliente con el marco de trabajo.

  2. Después de crear el objeto de dispositivo de marco (WDFDEVICE), llame a UcmTcpciDeviceInitialize para registrar el buzón de cliente con UcmTcpciCx.

Inicialización del canal de comunicaciones I2C en el hardware del controlador de puerto

Referencia de ejemplo: vea EvtCreateDevice en Device.cpp.

En la implementación de EVT_WDF_DEVICE_PREPARE_HARDWARE, lea los recursos de hardware para abrir un canal de comunicación. Esto es necesario para recuperar las funcionalidades de pd y recibir notificaciones sobre las alertas.

La mayoría de los controladores TCPCI están conectados a I2C. En el ejemplo de referencia, el controlador cliente abre un canal I2 mediante la interfaz de programación spb Framework Extension (SpbCx).

El controlador cliente enumera los recursos de hardware mediante una llamada a WdfCmResourceListGetDescriptor.

Las alertas se reciben como interrupciones. Por lo tanto, el controlador crea un objeto de interrupción de marco y registra el ISR que controla las alertas. El ISR realiza operaciones de lectura y escritura de hardware, que bloquean hasta que se completa el acceso de hardware. Dado que la espera es inaceptable en DIRQL, el controlador realiza el ISR en PASSIVE_LEVEL.

Inicialización de las funcionalidades type-C y PD del controlador de puerto

Referencia de ejemplo: vea EvtDeviceD0Entry en Device.cpp.

En la implementación de EVT_WDF_DEVICE_D0_EXIT,

  1. Comunicarse con el hardware del controlador de puerto y recuperar la identificación y las funcionalidades del dispositivo mediante la lectura de varios registros.

  2. Inicialice UCMTCPCI_PORT_CONTROLLER_IDENTIFICATION y UCMTCPCI_PORT_CONTROLLER_CAPABILITIES con la información recuperada.

  3. Inicialice UCMTCPCI_PORT_CONTROLLER_CONFIG estructura con la información anterior pasando las estructuras inicializadas a UCMTCPCI_PORT_CONTROLLER_CONFIG_INIT.

  4. Llame a UcmTcpciPortControllerCreate para crear el objeto de controlador de puerto y recuperar el identificador UCMTCPCIPORTCONTROLLER.

Configuración de un objeto de cola de marco para recibir solicitudes de UcmTcpciCx

Referencia de ejemplo: vea EvtDeviceD0Entry en Device.cpp y HardwareRequestQueueInitialize en Queue.cpp.

  1. En la implementación de EVT_WDF_DEVICE_D0_EXIT, cree un objeto de cola de marco mediante una llamada a WdfIoQueueCreate. En esa llamada, deberá registrar la implementación de devolución de llamada para controlar las solicitudes IOCTL enviadas por UcmTpciCx. El controlador cliente puede usar una cola administrada por energía.

    Durante la ejecución de las máquinas de estado type-C y PD, UcmTpciCx envía comandos al controlador cliente para que se ejecute. UcmTcpciCx garantiza como máximo una solicitud de controlador de puerto pendiente en un momento dado.

  2. Llame a UcmTcpciPortControllerSetHardwareRequestQueue para registrar el nuevo objeto de cola de marco con UcmTpciCx. Después de que la llamada se realice correctamente, UcmTcpciCx coloca objetos de cola de marco (WDFREQUEST) en esta cola cuando requiere una acción del controlador.

  3. Implemente la función de devolución de llamada EvtIoDeviceControl para controlar estas IOCTLs.

Código de control Descripción
IOCTL_UCMTCPCI_PORT_CONTROLLER_GET_STATUS Obtiene los valores de todos los registros de estado según la especificación de interfaz del controlador de puerto de tipo C del bus serie universal. El controlador cliente debe recuperar los valores de los registros de CC_STATUS, POWER_STATUS y FAULT_STATUS.
IOCTL_UCMTCPCI_PORT_CONTROLLER_GET_CONTROL Obtiene los valores de todos los registros de control definidos según la especificación de interfaz del controlador de puerto de tipo C de bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_CONTROL Establece el valor de un registro de control definido según la especificación de interfaz del controlador de puerto de tipo C de bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT Establece el registro TRANSMIT definido según la especificación de interfaz del controlador de puerto de tipo C del bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_TRANSMIT_BUFFER Establece el TRANSMIT_BUFER Registro definido según la especificación de interfaz del controlador de puerto de tipo C del bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_RECEIVE_DETECT Establece el RECEIVE_DETECT Register definido según la especificación de interfaz del controlador de puerto de tipo C del bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_CONFIG_STANDARD_OUTPUT Establece el CONFIG_STANDARD_OUTPUT Register definido según la especificación de interfaz del controlador de puerto de tipo C del bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_COMMAND Establece el valor de un registro de comandos definido según la especificación de interfaz del controlador de puerto de tipo C del bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_SET_MESSAGE_HEADER_INFO Establece el valor del MESSAGE_HEADER_INFO Register definido según la especificación de interfaz del controlador de puerto de tipo C de bus serie universal.
IOCTL_UCMTCPCI_PORT_CONTROLLER_ALTERNATE_MODE_ENTERED Notifica al controlador cliente que se especifica un modo alternativo para que el controlador pueda realizar otras tareas.
IOCTL_UCMTCPCI_PORT_CONTROLLER_ALTERNATE_MODE_EXITED Notifica al controlador cliente que se sale de un modo alternativo para que el controlador pueda realizar otras tareas.
IOCTL_UCMTCPCI_PORT_CONTROLLER_DISPLAYPORT_CONFIGURED Notifica al controlador cliente que se ha configurado el modo alternativo DisplayPort en el dispositivo asociado con la asignación de patillas para que el controlador pueda realizar otras tareas.
IOCTL_UCMTCPCI_PORT_CONTROLLER_DISPLAYPORT_HPD_STATUS_CHANGED Notifica al controlador de cliente que el estado de detección del enchufe activo de la conexión displayPort ha cambiado para que el controlador pueda realizar otras tareas.
  1. Llame a UcmTcpciPortControllerStart para indicar a UcmTcpciCx que inicie el controlador de puerto. UcmTcpciCx asume el control de USB Type-C y Power Delivery. Una vez iniciado el controlador de puerto, UcmTcpciCx puede empezar a poner solicitudes en la cola de solicitudes de hardware.

Control de alertas desde el hardware del controlador de puerto

Referencia de ejemplo: consulte ProcessAndSendAlerts en Alert.cpp

El controlador cliente debe controlar las alertas (o eventos) recibidos del hardware del controlador de puerto y enviarlos a UcmTcpciCx con datos relacionados con el evento.

Cuando se produce una alerta de hardware, el hardware del controlador de puerto controla el pin ALERT alto. Esto hace que el ISR del controlador cliente (registrado en el paso 2) se invoque. La rutina atiende la interrupción del hardware en PASSIVE_LEVEL. La rutina determina si una interrupción es una alerta del hardware del controlador de puerto; Si es así, completa el procesamiento de la alerta y notifica a UcmTcpciCx mediante una llamada a UcmTcpciPortControllerAlert.

Antes de llamar a UcmTcpciPortControllerAlert, el cliente es responsable de incluir todos los datos relevantes relacionados con la alerta en una estructura de UCMTCPCI_PORT_CONTROLLER_ALERT_DATA. El cliente proporciona una matriz de todas las alertas que están activas porque existe la posibilidad de que el hardware pueda declarar varias alertas simultáneamente.

Este es un flujo de ejemplo de tareas para notificar el cambio en estado CC.

  1. El cliente recibe una alerta de hardware.

  2. El cliente lee el registro ALERT y determina las alertas de tipo que están activas.

  3. El cliente lee el registro CC STATUS y describe el contenido del registro CC STATUS en UCMTCPCI_PORT_CONTROLLER_ALERT_DATA. El controlador establece el miembro AlertType en UcmTcpciPortControllerAlertCCStatus y el miembro CCStatus del registro.

  4. El cliente llama a UcmPortControllerAlert para enviar las alertas de hardware de matriz a UcmTcpciCx.

  5. El cliente borra la alerta (esto puede ocurrir en cualquier momento después de que el cliente recupere la información de alerta).

Solicitudes de proceso recibidas de UcmTcpciCx

Referencia de ejemplo: consulte PortControllerInterface.cpp

Como parte de la ejecución de la máquina de estado, UcmTcpciCx debe enviar solicitudes al controlador de puerto. Por ejemplo, debe establecer el TRANSMIT_BUFFER. Esta solicitud se entrega al controlador cliente. El controlador establece el búfer de transmisión con los detalles proporcionados por UcmTcpciCx. La mayoría de esas solicitudes se traducen en una lectura o escritura de hardware por parte del controlador cliente. Los comandos deben ser asincrónicos porque DPM no puede bloquear la espera de que se complete una transferencia de hardware.

UcmTcpciCx envía los comandos como código de control de E/S que describe la operación get/set necesaria del controlador cliente. En la configuración de la cola del controlador cliente, el controlador registró su cola con UcmTcpciCx. UcmTcpciCx comienza a colocar objetos de solicitud de marco en la cola que requiere la operación desde el controlador. Los códigos de control de E/S se enumeran en la tabla del paso 4.

Es responsabilidad del controlador de cliente completar las solicitudes a tiempo.

El controlador cliente llama a WdfRequestComplete en el objeto de solicitud de marco con un estado de finalización cuando ha finalizado la operación solicitada.

Es posible que el controlador cliente tenga que enviar una solicitud de E/S a otro controlador para realizar la operación de hardware. Por ejemplo, en el ejemplo, el controlador envía una solicitud SPB al controlador de puerto conectado a I2C. En ese caso, el controlador no puede reenviar el objeto de solicitud de marco que recibió de UcmTcpciCx porque es posible que el objeto de solicitud no tenga el número correcto de ubicaciones de pila en el IRP de WDM. El controlador cliente debe crear otro objeto de solicitud de marco y reenviarlo a otro controlador. El controlador cliente puede asignar previamente objetos de solicitud que necesita durante la inicialización, en lugar de crear uno cada vez que obtiene una solicitud de UcmTcpciCx. Esto es posible porque UcmTcpciCx garantiza que solo habrá una solicitud pendiente en un momento dado.

Consulte también