Gravar um driver de conector USB Tipo C

Você precisa escrever um driver de conector USB Tipo C nestes cenários:

  • Se o hardware USB Tipo C tiver a capacidade de lidar com o computador de estado de entrega de energia (PD). Caso contrário, considere escrever um driver de controlador de porta USB Tipo C. Para obter mais informações, consulte Gravar um driver de controlador de porta TIPO C USB.

  • Se o hardware não tiver um controlador inserido. Caso contrário, carregue o driver in-box fornecido pela Microsoft, UcmUcsi.sys. (Consulte Driver UCSI) para transportes ACPI ou escreva um driver de cliente UCSI para transportes não ACPI.

Resumo

  • Objeto UCM usado pela extensão de classe e pelo driver cliente
  • Serviços fornecidos pela extensão de classe UCM
  • Comportamento esperado do driver do cliente

Especificações oficiais

Aplica-se a

  • Windows 10

Versão do WDF

  • KMDF versão 1.15
  • UMDF versão 2.15

APIs importantes

Descreve o UCM (gerenciador de conector USB) que gerencia um conector USB Tipo C e o comportamento esperado de um driver de conector.

O UCM foi projetado usando o modelo de driver de cliente de extensão da classe WDF. A extensão de classe (UcmCx) é um driver WDF fornecido pela Microsoft que fornece interfaces que o driver cliente pode chamar para relatar informações sobre o conector. O driver cliente UCM usa as interfaces de hardware do conector e mantém a extensão de classe ciente dos eventos que ocorrem no conector. Por outro lado, a extensão de classe invoca funções de retorno de chamada implementadas pelo driver cliente em resposta a eventos do sistema operacional.

Para habilitar um conector USB Tipo C em um sistema, você deve gravar o driver do cliente.

gerenciador de conectores usb.

Antes de começar

  • Instale o WDK (Windows Driver Kit) mais recente em seu computador de desenvolvimento. O kit tem os arquivos e bibliotecas de cabeçalho necessários para escrever um driver de cliente UCM, especificamente, você precisará:

    • A biblioteca stub , (UcmCxstub.lib). A biblioteca converte chamadas feitas pelo driver cliente e as passa para o UcmCx.

    • O arquivo de cabeçalho, UcmCx.h.

      Você pode escrever um driver cliente UCM executado no modo de usuário ou no modo kernel. Para o modo de usuário, ele se associa à biblioteca UMDF 2.x; para o modo kernel, é KMDF 1.15. As interfaces de programação são idênticas para qualquer um dos modos.

      configuração do Visual Studio para ucm.

  • Decida se o driver cliente dará suporte a recursos avançados do conector USB Tipo C e da Entrega de Energia USB.

    Esse suporte permite que você crie dispositivos Windows com conectores USB Tipo C, encaixes e acessórios USB Tipo C e carregadores USB Type-C. O driver do cliente relata eventos de conector que permitem que o sistema operacional implemente políticas em torno do consumo de ENERGIA e USB no sistema.

  • Instale Windows 10 para edições da área de trabalho (Home, Pro, Enterprise e Education) em seu computador de destino ou Windows 10 Mobile com um conector USB Type-C.

  • Familiarize-se com o UCM e como ele interage com outros drivers do Windows. Consulte Arquitetura: design usb tipo C para um sistema Windows.

  • Familiarize-se com o WDF (Windows Driver Foundation). Leitura recomendada: Desenvolvendo drivers com o Windows Driver Foundation, escrito por Penny Orwick e Guy Smith.

Resumo dos serviços fornecidos pela extensão de classe UCM

A extensão de classe UCM mantém o sistema operacional informado sobre as alterações na função de dados e energia, níveis de carregamento e o contrato de PD negociado. Embora o driver cliente interaja com o hardware, ele deve notificar a extensão de classe quando essas alterações ocorrerem. A extensão de classe fornece um conjunto de métodos que o driver cliente pode usar para enviar as notificações (discutidas neste tópico). Estes são os serviços fornecidos:

Configuração da função de dados

Em sistemas USB Tipo C, a função de dados (host ou função) depende do status dos pinos CC do conector. O driver do cliente lê a linha CC (consulte Arquitetura: design usb tipo C para um sistema Windows) status do controlador de porta para determinar se a porta foi resolvida para uma UFP (Porta Voltada para Upstream) ou UFP (Porta Voltada para Downstream). Ele relata essas informações para a extensão de classe para que ela possa relatar a função atual aos drivers de comutador de função USB.

Observação

Drivers de comutador de função USB são usados em sistemas Windows 10 Mobile. Em Windows 10 para sistemas de edições da área de trabalho, a comunicação entre a extensão de classe e os drivers de comutador de função é opcional. Esses sistemas podem não usar um controlador de função dupla, nesse caso, os drivers de comutador de função não são usados.

Função de energia e carregamento

O driver do cliente lê o anúncio atual do TIPO C USB ou negocia um contrato de energia PD com o conector do parceiro.

  • Em um sistema Windows 10 Mobile, a decisão de escolher o carregador apropriado é assistida por software. O driver do cliente relata as informações do contrato para a extensão de classe para que ele possa enviar os níveis de carregamento para o driver de arbitragem de cobrança (CAD.sys). O CAD seleciona o nível atual a ser usado e encaminha as informações de nível de carregamento para o subsistema da bateria.
  • Em um Windows 10 para o sistema de edições da área de trabalho, o carregador apropriado é selecionado pelo hardware. O driver do cliente pode optar por obter essas informações e encaminhá-la para a extensão de classe. Como alternativa, essa lógica pode ser implementada por um driver diferente.

Alterações de função de energia e dados

Depois que um contrato PD for negociado, as funções de dados e as funções de energia poderão ser alteradas. Essa alteração pode ser iniciada pelo driver cliente ou pelo conector do parceiro. O driver do cliente relata essas informações para a extensão de classe, para que ela possa reconfigurar as coisas adequadamente.

Atualização de função de energia e/ou dados

O sistema operacional pode decidir que a função de dados atual não está correta. Nesse caso, a extensão de classe chama a função de retorno de chamada do driver para executar as operações de troca de função necessárias.

O Gerenciador de Políticas USB Tipo C fornecido pela Microsoft monitora as atividades dos conectores USB Type-C. O Windows, versão 1809, apresenta um conjunto de interfaces de programação que você pode usar para gravar um driver de cliente no Gerenciador de Políticas. O driver cliente pode participar das decisões de política para conectores USB Type-C. Com esse conjunto, você pode optar por escrever um driver de exportação no modo kernel ou um driver de modo de usuário. Para obter mais informações, consulte Escrever um driver de cliente do Gerenciador de Políticas do Tipo C USB.

Comportamento esperado do driver do cliente

O driver do cliente é responsável por essas tarefas:

  • Detecte alterações na linha CC e determine o tipo de parceiro, como UFP, DFP e outros. Para fazer isso, o driver deve implementar o computador de estado tipo C completo, conforme definido na especificação USB Type-C.
  • Configure o Mux com base na orientação detectada na linha CC. Isso inclui ativar o transmissor/receptor PD e manipular e responder a mensagens PD. Para fazer isso, o driver deve implementar o receptor PD completo e os computadores de estado do transmissor, conforme definido na especificação do USB Power Delivery 2.0.
  • Tome decisões de política de PD, como negociar um contrato (como origem ou coletor), trocas de função e outros. O driver do cliente é responsável por determinar o contrato mais apropriado.
  • Anuncie e negocie modos alternativos e configure o Mux se um modo alternativo for detectado. O driver do cliente é responsável por decidir o modo alternativo a ser negociado.
  • Controle do VBus/VConn sobre o conector.

1. Inicializar o objeto do conector UCM (UCMCONNECTOR)

O objeto do conector UCM (UCMCONNECTOR) representa o conector USB Type-C e é o identificador main entre a extensão de classe UCM e o driver cliente. O objeto rastreia os modos operacionais do conector e os recursos de fornecimento de energia.

Aqui está o resumo da sequência na qual o driver do cliente recupera um identificador UCMCONNECTOR para o conector. Executar essas tarefas no driver

  1. Chame UcmInitializeDevice passando a referência para uma estrutura UCM_MANAGER_CONFIG . O driver deve chamar esse método na função de retorno de chamada EVT_WDF_DRIVER_DEVICE_ADD antes de chamar WdfDeviceCreate.

  2. Especifique os parâmetros de inicialização para o conector USB Type-C em uma estrutura UCM_CONNECTOR_TYPEC_CONFIG . Isso inclui o modo de operação do conector, seja uma porta voltada para downstream, uma porta voltada para upstream ou com capacidade de função dupla. Ele também especifica os níveis atuais do Tipo C USB quando o conector é uma fonte de energia. Um conector USB Tipo C pode ser projetado de modo que ele possa atuar em uma tomada de áudio de 3,5 mm. Se o hardware der suporte ao recurso, o objeto do conector deverá ser inicializado adequadamente.

    Na estrutura , você também deve registrar a função de retorno de chamada do driver cliente para lidar com funções de dados.

    Essa função de retorno de chamada está associada ao objeto do conector, que é invocado pela extensão de classe UCM. Essa função deve ser implementada pelo driver do cliente.

    EVT_UCM_CONNECTOR_SET_DATA_ROLE Troca a função de dados do conector pela função especificada quando anexada a um conector de parceiro.

  3. Se o driver cliente quiser ser compatível com PD, ou seja, manipular a implementação de hardware do power delivery 2.0 do conector, você também deverá inicializar uma estrutura UCM_CONNECTOR_PD_CONFIG que especifica os parâmetros de inicialização de PD. Isso inclui o fluxo de energia, seja o conector como um coletor de energia ou uma fonte.

    Na estrutura , você também deve registrar a função de retorno de chamada do driver cliente para lidar com funções de energia.

    Essa função de retorno de chamada está associada ao objeto do conector, que é invocado pela extensão de classe UCM. Essa função deve ser implementada pelo driver do cliente.

    EVT_UCM_CONNECTOR_SET_POWER_ROLE Define a função de energia do conector para a função especificada quando anexada a um conector de parceiro.

  4. Chame UcmConnectorCreate e recupere um identificador UCMCONNECTOR para o conector. Certifique-se de chamar esse método depois que o driver do cliente tiver criado o objeto de dispositivo de estrutura chamando WdfDeviceCreate. Um local apropriado para essa chamada pode estar no EVT_WDF_DEVICE_PREPARE_HARDWARE ou no EVT_WDF_DEVICE_D0_ENTRY do driver.

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. Relatar o evento de anexação do conector do parceiro

O driver cliente deve chamar UcmConnectorTypeCAttach quando uma conexão com um conector de parceiro é detectada. Essa chamada notifica a extensão de classe UCM, que notifica ainda mais o sistema operacional. Neste ponto, o sistema pode começar a carregar em níveis USB Tipo C.

A extensão de classe UCM também notifica os URS (drivers de comutador de função) USB. Com base no tipo de parceiro, o URS configura o controlador na função de host ou função de função. Antes de chamar esse método, verifique se o Mux em seu sistema está configurado corretamente. Caso contrário, se o sistema estiver na função de função, ele se conectará a uma velocidade incorreta (alta velocidade em vez 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. Relatar alterações de anúncio usb tipo C

No evento de anexação inicial, o conector do parceiro envia um anúncio atual. Se o anúncio especificar o nível atual do conector do parceiro quando o parceiro for uma porta voltada para downstream tipo C USB. Caso contrário, o anúncio especifica o nível atual do conector local, representado pelo identificador UCMCONNECTOR (conector local). Esse anúncio inicial pode ser alterado durante o tempo de vida da conexão. Essas alterações devem ser monitoradas pelo driver do cliente.

Se o conector local for o coletor de energia e o anúncio atual for alterado, o driver do cliente deverá detectar alterações no anúncio atual e reportá-las à extensão de classe. Em sistemas Windows 10 Mobile, essas informações são usadas pelo CAD.sys e pelo subsistema de bateria para ajustar a quantidade de corrente que está extraindo da origem. Para relatar a alteração no nível atual para a extensão de classe, o driver cliente deve chamar UcmConnectorTypeCCurrentAdChanged.

4. Relatar o novo contrato de PD negociado

Se o conector der suporte a PD, após o evento de anexação inicial, haverá mensagens PD transferidas entre o conector e seu conector de parceiro. Entre ambos os parceiros, um contrato de PD é negociado que determina os níveis atuais que o conector pode desenhar ou permitir que o parceiro desenhe. Sempre que o contrato PD for alterado, o driver do cliente deverá chamar esses métodos para relatar a alteração para a extensão de classe.

  • O driver cliente deve chamar esses métodos sempre que receber um anúncio de recursos de origem (não solicitado ou não) do parceiro. O conector local (coletor) obtém um anúncio não solicitado do parceiro somente quando o parceiro é a origem. Além disso, o conector local pode solicitar explicitamente recursos de origem do parceiro que é capaz de ser a origem (mesmo quando o parceiro é atualmente o coletor). Isso é feito enviando uma mensagem Get_Source_Caps ao parceiro.
  • Por outro lado, o driver cliente deve chamar esses métodos sempre que o conector local (origem) anunciar recursos de origem para o parceiro. Além disso, quando o conector local recebe uma mensagem Get_Source_Caps do parceiro, ele deve responder com os recursos de origem do conector local.

5. Relatar status de carregamento de bateria

O driver cliente poderá notificar a extensão de classe UCM se o nível de carregamento não for adequado. A extensão de classe relata essas informações ao sistema operacional. O sistema usa essas informações para mostrar uma notificação do usuário de que o carregador não está carregando o sistema de maneira ideal. Os status de carregamento podem ser relatados por estes métodos:

Esses métodos especificam o estado de carregamento. Se os níveis relatados forem UcmChargingStateSlowCharging ou UcmChargingStateTrickleCharging (consulte UCM_CHARGING_STATE),o sistema operacional mostrará a notificação do usuário.

6. Relatar eventos de PR_Swap/DR_Swap

Se o conector receber uma mensagem de troca de função de energia (PR_Swap) ou função de dados (DR_Swap) do parceiro, o driver cliente deverá notificar a extensão de classe UCM.

  • UcmConnectorDataDirectionChanged

    Chame esse método depois que uma mensagem de DR_Swap PD tiver sido processada. Após essa chamada, o sistema operacional relata a nova função para URS, que rasga os drivers de função existentes e carrega drivers para a nova função.

  • UcmConnectorPowerDirectionChanged

    Chame esse método depois que uma mensagem de PR_Swap PD tiver sido processada. Após uma PR_Swap, o contrato do PD precisa ser renegociado. O driver cliente deve relatar que a negociação de contrato PD chamando os métodos descritos na etapa 4.

7. Implementar funções de retorno de chamada para lidar com solicitações de troca de função de dados e energia

A extensão de classe UCM pode receber solicitações para alterar dados ou direção de energia do conector. Nesse caso, ele invoca a implementação do driver cliente de funções de retorno de chamada EVT_UCM_CONNECTOR_SET_DATA_ROLE e EVT_UCM_CONNECTOR_SET_POWER_ROLE (se o conector implementar pd). O driver cliente registrou anteriormente essas funções em sua chamada para UcmConnectorCreate.

O driver cliente executa operações de troca de função usando interfaces de hardware.

  • EVT_UCM_CONNECTOR_SET_DATA_ROLE

    Na implementação do retorno de chamada, espera-se que o driver do cliente:

    1. Envie uma mensagem de DR_Swap PD para o parceiro de porta.
    2. Chame UcmConnectorDataDirectionChanged para notificar a extensão de classe de que a sequência de mensagens foi concluída com êxito ou sem ê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

    Na implementação do retorno de chamada, espera-se que o driver do cliente:

    1. Envie uma mensagem de PR_Swap PD para o parceiro de porta.
    2. Chame UcmConnectorPowerDirectionChanged para notificar a extensão de classe de que a sequência de mensagens foi concluída com êxito ou sem ê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;
    }
    

Observação

O driver cliente pode chamar UcmConnectorDataDirectionChanged e UcmConnectorPowerDirectionChanged de forma assíncrona, que não é do thread de retorno de chamada. Em uma implementação típica, a extensão de classe invoca as funções de retorno de chamada, fazendo com que o driver cliente inicie uma transação de hardware para enviar a mensagem. Quando a transação for concluída, o hardware notificará o driver. O driver chama esses métodos para notificar a extensão de classe.

8. Relatar o evento de desanexação do conector do parceiro

O driver cliente deve chamar UcmConnectorTypeCDetach quando a conexão com um conector de parceiro terminar. Essa chamada notifica a extensão de classe UCM, que notifica ainda mais o sistema operacional.

Exemplo de caso de uso: dispositivo móvel conectado a um computador

Quando um dispositivo que executa Windows 10 Mobile está conectado a um computador que executa Windows 10 para edições da área de trabalho por meio de uma conexão USB Tipo C, o sistema operacional garante que o dispositivo móvel seja a UFP (Porta Voltada para Upstream), pois o MTP é funcional apenas nessa direção. Nesse cenário, aqui está a sequência de correção de função de dados:

  1. O driver cliente, em execução no dispositivo móvel, relata um evento de anexação chamando UcmConnectorTypeCAttach e relata o conector do parceiro como a UFP (Porta Voltada para Downstream).
  2. O driver cliente relata o contrato PD chamando UcmConnectorPdPartnerSourceCaps e UcmConnectorPdConnectionStateChanged.
  3. A extensão de classe UCM notifica os drivers usb do lado do dispositivo, fazendo com que esses drivers respondam à enumeração do host. As informações do sistema operacional são trocadas por USB.
  4. A extensão de classe UCM UcmCx invoca as funções de retorno de chamada do driver cliente para alterar funções: EVT_UCM_CONNECTOR_SET_DATA_ROLE e EVT_UCM_CONNECTOR_SET_POWER_ROLE.

Observação

Se dois dispositivos Windows 10 Mobile estiverem conectados um ao outro, uma troca de função não será executada e o usuário será notificado de que a conexão não é uma conexão válida.