Share via


Escritura de un controlador de conector usb type-C

Debe escribir un controlador del conector USB Type-C en estos escenarios:

  • Si el hardware USB Type-C tiene la capacidad de controlar la máquina de estado de entrega de energía (PD). De lo contrario, considere la posibilidad de escribir un controlador de puerto usb de tipo C. Para obtener más información, vea Escribir un controlador de puerto usb de tipo C.

  • Si el hardware no tiene un controlador incrustado. De lo contrario, cargue el controlador in-box proporcionado por Microsoft, UcmUcsi.sys. (Véase el controlador UCSI) para transportes ACPI o escribir un controlador de cliente UCSI para transportes que no son ACPI.

Resumen

  • Objeto UCM usado por la extensión de clase y el controlador de cliente
  • Servicios proporcionados por la extensión de clase UCM
  • Comportamiento esperado del controlador de cliente

Especificaciones oficiales

Se aplica a

  • Windows 10

Versión de WDF

  • KMDF versión 1.15
  • UMDF versión 2.15

API importantes

Describe el administrador de conectores USB (UCM) que administra un conector USB Type-C y el comportamiento esperado de un controlador de conector.

UCM está diseñado mediante el modelo de controlador de extensión de cliente de clase WDF. La extensión de clase (UcmCx) es un controlador WDF proporcionado por Microsoft que proporciona interfaces a las que el controlador cliente puede llamar para informar sobre la información sobre el conector. El controlador de cliente UCM usa las interfaces de hardware del conector y mantiene la extensión de clase al tanto de los eventos que se producen en el conector. Por el contrario, la extensión de clase invoca funciones de devolución de llamada implementadas por el controlador cliente en respuesta a eventos del sistema operativo.

Para habilitar un conector USB Type-C en un sistema, debe escribir el controlador cliente.

administrador de conectores usb.

Antes de empezar

  • 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 un controlador de cliente UCM, en concreto, necesitará:

    • La biblioteca de código auxiliar (UcmCxstub.lib). La biblioteca traduce las llamadas realizadas por el controlador cliente y las pasa a UcmCx.

    • El archivo de encabezado, UcmCx.h.

      Puede escribir un controlador de cliente UCM que se ejecute en modo de usuario o modo kernel. Para el modo de usuario, se enlaza con la biblioteca UMDF 2.x; para el modo kernel es KMDF 1.15. Las interfaces de programación son idénticas para cualquiera de los modos.

      Configuración de Visual Studio para ucm.

  • Decida si el controlador cliente admitirá características avanzadas del conector USB Type-C y la entrega de energía USB.

    Esta compatibilidad le permite crear dispositivos Windows con conectores USB type-C, soportes y accesorios USB Type-C y cargadores USB Type-C. El controlador cliente notifica eventos de conector que permiten al sistema operativo implementar directivas en torno al consumo de energía y USB en el sistema.

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

  • Familiarícese con UCM y cómo interactúa con otros controladores de Windows. Consulta Arquitectura: Diseño de tipo USB-C para un sistema Windows.

  • Familiarícese con Windows Driver Foundation (WDF). Lectura recomendada: Desarrollar controladores con Windows Driver Foundation, escrito por Penny Orwick y Guy Smith.

Resumen de los servicios proporcionados por la extensión de clase UCM

La extensión de clase UCM mantiene informado al sistema operativo sobre los cambios en los datos y el rol de energía, los niveles de carga y el contrato de PD negociado. Mientras el controlador cliente interactúa con el hardware, debe notificar a la extensión de clase cuando se produzcan esos cambios. La extensión de clase proporciona un conjunto de métodos que el controlador cliente puede usar para enviar las notificaciones (que se describen en este tema). Estos son los servicios proporcionados:

Configuración del rol de datos

En los sistemas USB Type-C, el rol de datos (host o función) depende del estado de las patillas CC del conector. El controlador cliente lee la línea CC (consulte Arquitectura: diseño de tipo USB-C para un sistema Windows) estado del controlador de puerto para determinar si el puerto se ha resuelto en un puerto orientado ascendente (UFP) o en un puerto de bajada (UFP). Informa de esa información a la extensión de clase para que pueda notificar el rol actual a los controladores de conmutador de rol USB.

Nota:

Los controladores de conmutador de rol USB se usan en sistemas Windows 10 Mobile. En Windows 10 para los sistemas de ediciones de escritorio, la comunicación entre la extensión de clase y los controladores de conmutador de rol es opcional. Es posible que estos sistemas no usen un controlador de rol dual, en cuyo caso no se usan los controladores de conmutador de rol.

Rol de energía y carga

El controlador cliente lee el anuncio actual del tipo USB-C o negocia un contrato de alimentación pd con el conector asociado.

  • En un sistema Windows 10 Mobile, la decisión de elegir el cargador adecuado es asistido por software. El conductor cliente informa de la información del contrato a la extensión de clase para que pueda enviar los niveles de carga al controlador de arbitraje de carga (CAD.sys). CAD selecciona el nivel actual para usar y reenvía la información del nivel de carga al subsistema de la batería.
  • En un Windows 10 para el sistema de ediciones de escritorio, el hardware selecciona el cargador adecuado. El controlador cliente puede elegir obtener esa información y reenviarla a la extensión de clase. Como alternativa, esa lógica se puede implementar mediante un controlador diferente.

Cambios en los datos y el rol de energía

Una vez negociado un contrato de PD, los roles de datos y los roles de energía pueden cambiar. Ese cambio puede iniciarse mediante el controlador de cliente o el conector del asociado. El controlador de cliente informa de esa información a la extensión de clase para que pueda volver a configurar las cosas en consecuencia.

Actualización de datos o rol de energía

El sistema operativo puede decidir que el rol de datos actual no es correcto. En ese caso, la extensión de clase llama a la función de devolución de llamada del controlador para realizar las operaciones de intercambio de roles necesarias.

El Administrador de directivas usb de tipo C proporcionado por Microsoft supervisa las actividades de los conectores USB type-C. Windows, versión 1809, presenta un conjunto de interfaces de programación que puede usar para escribir un controlador cliente en el Administrador de directivas. El controlador cliente puede participar en las decisiones de directiva de los conectores USB Type-C. Con este conjunto, puede elegir escribir un controlador de exportación en modo kernel o un controlador en modo de usuario. Para obtener más información, vea Escribir un controlador de cliente del Administrador de directivas de tipo C USB.

Comportamiento esperado del controlador de cliente

El controlador de cliente es responsable de estas tareas:

  • Detecte cambios en la línea CC y determine el tipo de asociado, como UFP, DFP y otros. Para ello, el controlador debe implementar la máquina de estado tipo C completa tal y como se define en la especificación USB Type-C.
  • Configure mux según la orientación detectada en la línea CC. Esto incluye activar el transmisor/receptor de PD y controlar y responder a los mensajes de PD. Para ello, el controlador debe implementar el receptor de PD completo y las máquinas de estado del transmisor, tal como se define en la especificación USB Power Delivery 2.0.
  • Tome decisiones de directiva de PD, como negociar un contrato (como origen o receptor), intercambios de roles y otros. El controlador cliente es responsable de determinar el contrato más adecuado.
  • Anuncie y negocie modos alternativos y configure mux si se detecta un modo alternativo. El controlador cliente es responsable de decidir el modo alternativo para negociar.
  • Control de VBus/VConn sobre el conector.

1. Inicializar el objeto del conector UCM (UCMCONNECTOR)

El objeto de conector UCM (UCMCONNECTOR) representa el conector USB Type-C y es el identificador principal entre la extensión de clase UCM y el controlador de cliente. El objeto realiza un seguimiento de los modos de funcionamiento del conector y las funcionalidades de aprovisionamiento de energía.

Este es el resumen de la secuencia en la que el controlador cliente recupera un identificador UCMCONNECTOR para el conector. Realizar estas tareas en el controlador

  1. Llame a UcmInitializeDevice pasando la referencia a una estructura de UCM_MANAGER_CONFIG . El controlador debe llamar a este método en la función de devolución de llamada EVT_WDF_DRIVER_DEVICE_ADD antes de llamar a WdfDeviceCreate.

  2. Especifique los parámetros de inicialización para el conector USB Type-C en una estructura de UCM_CONNECTOR_TYPEC_CONFIG . Esto incluye el modo de funcionamiento del conector, ya sea un puerto orientado hacia abajo, un puerto ascendente o es compatible con el rol dual. También especifica los niveles de corriente usb type-C cuando el conector es una fuente de alimentación. Un conector USB type-C se puede diseñar de forma que pueda actuar con un conector de audio de 3,5 mm. Si el hardware admite la característica, el objeto del conector debe inicializarse en consecuencia.

    En la estructura , también debe registrar la función de devolución de llamada del controlador cliente para controlar los roles de datos.

    Esta función de devolución de llamada está asociada al objeto de conector, que se invoca mediante la extensión de clase UCM. El controlador cliente debe implementar esta función.

    EVT_UCM_CONNECTOR_SET_DATA_ROLE Intercambia el rol de datos del conector al rol especificado cuando se adjunta a un conector asociado.

  3. Si el controlador cliente quiere ser compatible con PD, es decir, controlar la implementación de hardware de Power Delivery 2.0 del conector, también debe inicializar una estructura de UCM_CONNECTOR_PD_CONFIG que especifique los parámetros de inicialización de PD. Esto incluye el flujo de alimentación, tanto si el conector es un receptor de alimentación como una fuente.

    En la estructura, también debe registrar la función de devolución de llamada del controlador cliente para controlar los roles de energía.

    Esta función de devolución de llamada está asociada al objeto de conector, que se invoca mediante la extensión de clase UCM. El controlador cliente debe implementar esta función.

    EVT_UCM_CONNECTOR_SET_POWER_ROLE Establece el rol de potencia del conector en el rol especificado cuando se adjunta a un conector asociado.

  4. Llame a UcmConnectorCreate y recupere un identificador UCMCONNECTOR para el conector. Asegúrese de llamar a este método después de que el controlador cliente haya creado el objeto de dispositivo de marco llamando a WdfDeviceCreate. Un lugar adecuado para esta llamada puede estar en el EVT_WDF_DEVICE_PREPARE_HARDWARE del controlador o EVT_WDF_DEVICE_D0_ENTRY.

EVT_UCM_CONNECTOR_SET_DATA_ROLE     EvtSetDataRole;

NTSTATUS
EvtDevicePrepareHardware(
    WDFDEVICE Device,
    WDFCMRESLIST ResourcesRaw,
    WDFCMRESLIST ResourcesTranslated
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PDEVICE_CONTEXT devCtx;
    UCM_MANAGER_CONFIG ucmCfg;
    UCM_CONNECTOR_CONFIG connCfg;
    UCM_CONNECTOR_TYPEC_CONFIG typeCConfig;
    UCM_CONNECTOR_PD_CONFIG pdConfig;
    WDF_OBJECT_ATTRIBUTES attr;
    PCONNECTOR_CONTEXT connCtx;

    UNREFERENCED_PARAMETER(ResourcesRaw);
    UNREFERENCED_PARAMETER(ResourcesTranslated);

    TRACE_FUNC_ENTRY();

    devCtx = GetDeviceContext(Device);

    if (devCtx->Connector)
    {
        goto Exit;
    }

    //
    // Initialize UCM Manager
    //
    UCM_MANAGER_CONFIG_INIT(&ucmCfg);

    status = UcmInitializeDevice(Device, &ucmCfg);
    if (!NT_SUCCESS(status))
    {
        TRACE_ERROR(
            "UcmInitializeDevice failed with %!STATUS!.",
            status);
        goto Exit;
    }

    TRACE_INFO("UcmInitializeDevice() succeeded.");

    //
    // Create a USB Type-C connector #0 with PD
    //
    UCM_CONNECTOR_CONFIG_INIT(&connCfg, 0);

    UCM_CONNECTOR_TYPEC_CONFIG_INIT(
        &typeCConfig,
        UcmTypeCOperatingModeDrp,
        UcmTypeCCurrentDefaultUsb | UcmTypeCCurrent1500mA | UcmTypeCCurrent3000mA);

    typeCConfig.EvtSetDataRole = EvtSetDataRole;

    UCM_CONNECTOR_PD_CONFIG_INIT(&pdConfig, UcmPowerRoleSink | UcmPowerRoleSource);

    connCfg.TypeCConfig = &typeCConfig;
    connCfg.PdConfig = &pdConfig;

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attr, CONNECTOR_CONTEXT);

    status = UcmConnectorCreate(Device, &connCfg, &attr, &devCtx->Connector);
    if (!NT_SUCCESS(status))
    {
        TRACE_ERROR(
            "UcmConnectorCreate failed with %!STATUS!.",
            status);
        goto Exit;
    }

    connCtx = GetConnectorContext(devCtx->Connector);

    UcmEventInitialize(&connCtx->EventSetDataRole);

    TRACE_INFO("UcmConnectorCreate() succeeded.");

Exit:

    TRACE_FUNC_EXIT();
    return status;
}

2. Notificar el evento de asociación del conector asociado

El controlador cliente debe llamar a UcmConnectorTypeCAttach cuando se detecta una conexión a un conector asociado. Esta llamada notifica a la extensión de clase UCM, que notifica aún más al sistema operativo. En este momento, el sistema puede empezar a cargarse en los niveles usb type-C.

La extensión de clase UCM también notifica a los controladores de conmutador de rol (URS) USB. En función del tipo de asociado, URS configura el controlador en el rol de host o el rol de función. Antes de llamar a este método, asegúrese de que mux en el sistema está configurado correctamente. De lo contrario, si el sistema está en el rol de función, se conectará a una velocidad incorrecta (alta velocidad en lugar de SuperSpeed).

        UCM_CONNECTOR_TYPEC_ATTACH_PARAMS attachParams;

        UCM_CONNECTOR_TYPEC_ATTACH_PARAMS_INIT(
            &attachParams,
            UcmTypeCPortStateDfp);
        attachParams.CurrentAdvertisement = UcmTypeCCurrent1500mA;

        status = UcmConnectorTypeCAttach(
                    Connector,
                    &attachParams);
        if (!NT_SUCCESS(status))
        {
            TRACE_ERROR(
                "UcmConnectorTypeCAttach() failed with %!STATUS!.",
                status);
            goto Exit;
        }

        TRACE_INFO("UcmConnectorTypeCAttach() succeeded.");

3. Notificar cambios de anuncio de tipo C usb

En el evento de asociación inicial, el conector del asociado envía un anuncio actual. Si el anuncio especifica el nivel actual del conector asociado cuando el asociado es un puerto usb de tipo C de bajada. De lo contrario, el anuncio especifica el nivel actual del conector local, representado por el identificador UCMCONNECTOR (conector local). Este anuncio inicial puede cambiar durante la duración de la conexión. El controlador cliente debe supervisar esos cambios.

Si el conector local es el receptor de energía y cambia el anuncio actual, el controlador cliente debe detectar los cambios en el anuncio actual y notificarlos a la extensión de clase. En Windows 10 Mobile sistemas, esa información se usa en CAD.sys y el subsistema de batería para ajustar la cantidad de corriente que se dibuja a partir de la fuente. Para notificar el cambio en el nivel actual a la extensión de clase, el controlador cliente debe llamar a UcmConnectorTypeCCurrentAdChanged.

4. Informe del nuevo contrato de PD negociado

Si el conector admite PD, después del evento de asociación inicial, hay mensajes pd transferidos entre el conector y su conector asociado. Entre ambos asociados, se negocia un contrato de PD que determina los niveles actuales que el conector puede dibujar o permitir que el asociado dibuje. Cada vez que cambia el contrato pd, el controlador cliente debe llamar a estos métodos para notificar el cambio a la extensión de clase.

  • El controlador de cliente debe llamar a estos métodos siempre que obtenga un anuncio de funcionalidades de origen (no solicitado o de otro modo) del asociado. El conector local (receptor) obtiene un anuncio no solicitado del asociado solo cuando el asociado es el origen. Además, el conector local puede solicitar explícitamente funcionalidades de origen del asociado que sea capaz de ser el origen (incluso cuando el asociado es actualmente el receptor). Ese intercambio se realiza enviando un mensaje Get_Source_Caps al asociado.
  • Por el contrario, el controlador cliente debe llamar a estos métodos cada vez que el conector local (origen) anuncia las funcionalidades de origen para el asociado. Además, cuando el conector local recibe un mensaje de Get_Source_Caps del asociado, debe responder con las funcionalidades de origen del conector local.

5. Informe del estado de carga de la batería

El controlador cliente puede notificar a la extensión de clase UCM si el nivel de carga no es adecuado. La extensión de clase notifica esta información al sistema operativo. El sistema utiliza esa información para mostrar una notificación del usuario de que el cargador no está cargando el sistema de forma óptima. Estos métodos pueden notificar el estado de carga:

Esos métodos especifican el estado de carga. Si los niveles notificados son UcmChargingStateSlowCharging o UcmChargingStateTrickleCharging (consulte UCM_CHARGING_STATE), el sistema operativo muestra la notificación del usuario.

6. Notificar eventos de PR_Swap/DR_Swap

Si el conector recibe un mensaje de intercambio de rol de energía (PR_Swap) o de rol de datos (DR_Swap) del asociado, el controlador cliente debe notificar a la extensión de clase UCM.

  • UcmConnectorDataDirectionChanged

    Llame a este método después de que se haya procesado un mensaje de DR_Swap PD. Después de esta llamada, el sistema operativo informa del nuevo rol a URS, que elimina los controladores de rol existentes y carga los controladores para el nuevo rol.

  • UcmConnectorPowerDirectionChanged

    Llame a este método después de que se haya procesado un mensaje de PR_Swap PD. Después de un PR_Swap, el contrato de PD debe renegociarse. El controlador cliente debe notificar esa negociación del contrato de PD llamando a los métodos descritos en el paso 4.

7. Implementación de funciones de devolución de llamada para controlar las solicitudes de intercambio de roles de datos y energía

La extensión de clase UCM puede obtener solicitudes para cambiar los datos o la dirección de energía del conector. En ese caso, invoca la implementación del controlador de cliente de EVT_UCM_CONNECTOR_SET_DATA_ROLE y EVT_UCM_CONNECTOR_SET_POWER_ROLE funciones de devolución de llamada (si el conector implementa PD). El controlador cliente registró previamente esas funciones en su llamada a UcmConnectorCreate.

El controlador cliente realiza operaciones de intercambio de roles mediante interfaces de hardware.

  • EVT_UCM_CONNECTOR_SET_DATA_ROLE

    En la implementación de devolución de llamada, se espera que el controlador de cliente:

    1. Envíe un mensaje pd DR_Swap al asociado de puerto.
    2. Llame a UcmConnectorDataDirectionChanged para notificar a la extensión de clase que la secuencia de mensajes se ha completado correctamente o sin éxito.
    EVT_UCM_CONNECTOR_SET_DATA_ROLE     EvtSetDataRole;
    
    NTSTATUS
    EvtSetDataRole(
        UCMCONNECTOR  Connector,
        UCM_TYPE_C_PORT_STATE DataRole
        )
    {
        PCONNECTOR_CONTEXT connCtx;
    
        TRACE_INFO("EvtSetDataRole(%!UCM_TYPE_C_PORT_STATE!) Entry", DataRole);
    
        connCtx = GetConnectorContext(Connector);
    
        TRACE_FUNC_EXIT();
    
        return STATUS_SUCCESS;
    }
    
  • EVT_UCM_CONNECTOR_SET_POWER_ROLE

    En la implementación de devolución de llamada, se espera que el controlador de cliente:

    1. Envíe un mensaje pd PR_Swap al asociado de puerto.
    2. Llame a UcmConnectorPowerDirectionChanged para notificar a la extensión de clase que la secuencia de mensajes se ha completado correctamente o sin éxito.
    EVT_UCM_CONNECTOR_SET_POWER_ROLE     EvtSetPowerRole;
    
    NTSTATUS
    EvtSetPowerRole(
        UCMCONNECTOR Connector,
        UCM_POWER_ROLE PowerRole
        )
    {
        PCONNECTOR_CONTEXT connCtx;
    
        TRACE_INFO("EvtSetPowerRole(%!UCM_POWER_ROLE!) Entry", PowerRole);
    
        connCtx = GetConnectorContext(Connector);
    
        //PR_Swap operation.
    
        TRACE_FUNC_EXIT();
    
        return STATUS_SUCCESS;
    }
    

Nota:

El controlador cliente puede llamar a UcmConnectorDataDirectionChanged y UcmConnectorPowerDirectionChanged de forma asincrónica, que no procede del subproceso de devolución de llamada. En una implementación típica, la extensión de clase invoca las funciones de devolución de llamada que hacen que el controlador de cliente inicie una transacción de hardware para enviar el mensaje. Cuando se completa la transacción, el hardware notifica al controlador. El controlador llama a esos métodos para notificar a la extensión de clase.

8. Notificar el evento de desasociación del conector asociado

El controlador cliente debe llamar a UcmConnectorTypeCDetach cuando finaliza la conexión a un conector asociado. Esta llamada notifica a la extensión de clase UCM, que notifica aún más al sistema operativo.

Ejemplo de caso de uso: dispositivo móvil conectado a un equipo

Cuando un dispositivo que ejecuta Windows 10 Mobile está conectado a un equipo que ejecuta Windows 10 para las ediciones de escritorio a través de una conexión USB type-C, el sistema operativo se asegura de que el dispositivo móvil sea el puerto de acceso ascendente (UFP) porque MTP solo funciona en esa dirección. En este escenario, esta es la secuencia para la corrección de roles de datos:

  1. El controlador cliente, que se ejecuta en el dispositivo móvil, notifica un evento de asociación mediante una llamada a UcmConnectorTypeCAttach e informa del conector asociado como puerto orientado a bajada (UFP).
  2. El controlador cliente informa del contrato de PD llamando a UcmConnectorPdPartnerSourceCaps y UcmConnectorPdConnectionStateChanged.
  3. La extensión de clase UCM notifica a los controladores del lado del dispositivo USB que hacen que esos controladores respondan a la enumeración del host. La información del sistema operativo se intercambia a través de USB.
  4. La extensión de clase UCM UcmCx invoca las funciones de devolución de llamada del controlador cliente para cambiar los roles: EVT_UCM_CONNECTOR_SET_DATA_ROLE y EVT_UCM_CONNECTOR_SET_POWER_ROLE.

Nota:

Si dos dispositivos Windows 10 Mobile están conectados entre sí, no se realiza un intercambio de roles y se notifica al usuario que la conexión no es una conexión válida.