Partilhar via


Escrever um driver de cliente para controlador de funções

Este artigo descreve as várias tarefas que um driver de cliente do controlador de função executa ao interagir com a extensão do controlador de função USB (UFX).

APIs importantes

Descreve as várias tarefas que um driver cliente do controlador de função executa ao interagir com a extensão do controlador de função USB (UFX). UFX e o driver cliente se comunicam entre si usando métodos de exportação e funções de retorno de chamada de eventos. Os métodos de exportação (chamados UfxDeviceXxx ou UfxEndpointXxx) são exportados pelo UFX e invocados pelo driver do cliente. As funções de retorno de chamada (chamadas EVT_UFX_Xxx) são implementadas no driver do cliente e invocadas pela UFX.

O UFX chama todas as funções de retorno de chamada do driver cliente de forma assíncrona, executando um retorno de chamada de cada vez para cada objeto. Por exemplo, existe um objeto de dispositivo USB e três objetos de endpoint. No máximo, quatro funções de retorno de chamada (uma para o dispositivo e uma para cada ponto de extremidade) podem ser chamadas de cada vez. Para cada método de retorno de chamada, o UFX aguarda até que o driver cliente chame UfxDeviceEventComplete para indicar que o driver concluiu a solicitação. O único outro método de exportação que o UFX escuta enquanto aguarda essas exportações é UfxDeviceNotifyHardwareFailure. Muitas funções de retorno de chamada do cliente são opcionais. As funções necessárias são as seguintes:

Inicialização

  1. O driver cliente do controlador de função inicia o processo de inicialização quando o Windows Driver Foundation (WDF) invoca a implementação do driver cliente do callback EVT_WDF_DRIVER_DEVICE_ADD. Nessa implementação, espera-se que o driver do cliente chame UfxFdoInit e, em seguida, crie o objeto de dispositivo chamando WdfDeviceCreate.
  2. O driver do cliente chama UfxDeviceCreate para criar o objeto de dispositivo USB e recuperar o identificador UFXDEVICE.
  3. O driver do cliente chama UfxDeviceNotifyHardwareReady para indicar ao UFX que agora ele pode invocar as funções de retorno de chamada do driver do cliente.
  4. O UFX executa tarefas de inicialização, tais como:

Notificação do controlador de classe

Para ser notificado sobre os pacotes de configuração e o status do barramento, um driver de classe deve enviar um pedido IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS. O UFX enfileira estas solicitações em filas de notificação específicas da classe de drivers. Ao receber uma notificação sobre um evento de ônibus do motorista cliente, a UFX aparece de cada fila apropriada e conclui a solicitação. Para evitar que os drivers de classe percam notificações, a UFX mantém uma fila de notificações de tamanho fixo para o driver de classe.

Eventos de anexação e desanexação de dispositivos

UFX assume que o dispositivo está desligado até que o driver cliente do controlador de funções chame UfxDeviceNotifyAttach.

Após essa chamada, o UFX define o estado do dispositivo como Alimentado , conforme definido na especificação USB. Para notificar o driver do cliente sobre a alteração de estado, o UFX invoca a implementação EVT_UFX_DEVICE_USB_STATE_CHANGE do driver do cliente.

UFX notifica o condutor do carregador (Cad.sys) para ajudar no carregamento do dispositivo. A UFX também notifica os drivers de classe ao concluir as solicitações de IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION enviadas anteriormente pelos drivers de classe.

O driver do cliente deve chamar UfxDeviceNotifyDetach quando o barramento é desanexado. O cliente deve chamar o método "desanexar" apenas uma vez após cada chamada para UfxDeviceNotifyAttach. Após a chamada UfxDeviceNotifyDetach , UFX chama EVT_UFX_DEVICE_HOST_DISCONNECT (se esta não for uma alteração de interface). Em seguida, o UFX prossegue com todas as tarefas de limpeza, como purgar todas as filas de pontos de extremidade e iniciar a fila de ponto de extremidade padrão. A UFX chama EVT_UFX_DEVICE_USB_STATE_CHANGE e notifica os controladores de classe ao concluir solicitações de IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION.

Falha de hardware

Se ocorrer um erro de hardware, espera-se que o driver do cliente chame UfxDeviceNotifyHardwareFailure. Em resposta, UFX desmontará a pilha de dispositivos e poderá tentar recuperar-se dessa situação chamando o controlador do cliente EVT_UFX_DEVICE_CONTROLLER_RESET. O cliente deve redefinir o controlador para seu estado inicial. Se ocorrer outra falha de hardware, o cliente deve chamar UfxDeviceNotifyHardwareFailure novamente. Na segunda chamada, a UFX registrará o seu estado e a verificação de erros.

Deteção de porta

A deteção de portas é realizada pela UFX. Esta chama a função de retorno de chamada do driver do controlador de função EVT_UFX_DEVICE_PORT_DETECT para determinar o tipo de porta à qual o dispositivo está conectado. O cliente responde chamando UfxDevicePortDetectComplete ou UfxDevicePortDetectCompleteEx com um dos tipos de porta definidos em USBFN_PORT_TYPE.

Se o cliente não puder determinar o tipo de porta, o cliente deverá relatar UsbfnUnknownPort. Se a porta for desconhecida ou for uma porta a jusante, a UFX chamará a função EVT_UFX_DEVICE_HOST_CONNECT do driver cliente. A UFX ouve o ônibus há algum tempo. Se a porta for desconhecida, mas houver tráfego, como um pacote de configuração, o UFX assumirá UsbfnStandardDownstreamPort. Caso contrário, o UFX atribui a porta como UsbfnInvalidDedicatedChargingPort. Depois que um tipo de porta é determinado, o UFX notifica Cad.sys e chama a função EVT_UFX_DEVICE_PORT_CHANGE do driver do cliente. Na função, espera-se que o driver do cliente altere o estado do hardware para corresponder ao tipo de porta UFX.

Criação de pontos finais

O UFX cria o ponto de extremidade padrão (ponto de extremidade 0) chamando o EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD do driver do cliente para que ele possa lidar com pacotes de configuração enviados pelo host. A UFX cria outros pontos finais chamando EVT_UFX_DEVICE_ENDPOINT_ADD. UFX só cria pontos de extremidade depois de o driver do cliente chamar UfxDeviceNotifyHardwareReady. Nessas funções de retorno de chamada, espera-se que o driver do cliente chame UfxEndpointCreate para o objeto de ponto de extremidade e obtenha seu identificador UFXENDPOINT. O UFX define o pai para o driver de classe DOP associado à interface à qual o ponto de extremidade pertence. O pai do ponto de extremidade padrão é o objeto de dispositivo USB. Um ponto de extremidade contém dois objetos de fila de estrutura: uma fila de transferência e uma fila de comando, que só podem ser acessados quando o dispositivo está no estado Configurado (com exceção do ponto de extremidade 0, que pode ser acessado após chamadas UFX EVT_UFX_DEVICE_HOST_CONNECT).

Enumeração de dispositivos

O controlador do cliente não deve permitir conexões com um host antes que o UFX chame o EVT_UFX_DEVICE_HOST_CONNECT do controlador. A enumeração de dispositivo começa quando o driver do cliente chama UfxDeviceNotifyReset. No estado Padrão , o UFX lida com pacotes de configuração padrão.

Reiniciar

O UFX limpa todas as filas de endpoint e envia uma solicitação de IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE ao driver do cliente para atualizar o wMaxPacketSize do endpoint 0. O UFX inicia a fila do ponto de extremidade padrão e define o estado como Padrão.

Predefinido

A UFX chama a função de EVT_UFX_DEVICE_USB_STATE_CHANGE do motorista cliente. Também notifica os motoristas de classe do estado. Depois que o UFX recebe o pacote de configuração padrão SET_ADDRESS, o UFX define o estado como endereçado.

Endereçado

UFX chama a função EVT_UFX_DEVICE_ADDRESSED do driver do cliente para indicar ao cliente qual endereço o cliente deve usar. - Se o endereço for 0, UFX restabelece o estado para Padrão e chama EVT_UFX_DEVICE_USB_STATE_CHANGE, notificando os drivers de classe. Ao receber o pacote de configuração padrão SET_CONFIGURATION, o UFX define o estado como Configurado.

Configurado

Se a configuração selecionada for 0, o UFX limpa os pontos de extremidade da interface e define o estado como endereçado. UFX envia uma solicitação de IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE para o driver cliente para atualizar o wMaxPacketSize dos pontos de extremidade da interface. O UFX garante que todas as filas de pontos finais de interface tenham terminado de purgar e inicia as filas de pontos de extremidade de interface. Se o tipo de porta não for UsbfnStandardDownstreamPort ou UsbfnChargingDownstreamPort, UFX alterará o tipo de porta para UsbfnStandardDownstreamPort e informará Cad.syso driver do cliente, chamando EVT_UFX_DEVICE_PORT_CHANGE e EVT_UFX_DEVICE_USB_STATE_CHANGE para atualizar o estado dos drivers de classe configurados.

Transferências de controlo normalizadas

O UFX pode lidar com transferências de controle no ponto de extremidade padrão a qualquer momento após chamar EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD, no qual o driver do cliente cria o ponto de extremidade padrão usando. Todas as transferências de controle começam com um pacote de instalação de 8 bytes. Para enviar um pacote de instalação para o host, o driver do cliente deve chamar UfxEndpointNotifySetup. As transferências de controle padrão são concluídas pela UFX. Se houver dados associados à transferência de controle, o UFX lê e grava no ponto de extremidade de controle padrão, conforme apropriado.

Transferências de controlo não normalizadas

Se a UFX não puder lidar com uma transferência de controlo, a transferência será encaminhada para o driver de classe apropriado ao completar uma solicitação IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION. As transferências de controlo podem ocorrer em qualquer ponto final que seja definido como um ponto final de controlo no descritor do ponto final. As transferências de controle em pontos de extremidade diferentes do ponto de extremidade de controle padrão são sempre transferências de controle não padrão. Se o ponto de extremidade de controlo for o ponto de extremidade de controlo padrão, o UFX notificará os drivers de classe acerca dos pacotes de configuração marcados como pedidos de classe para esse driver de classe. Se o ponto de extremidade de controle pertencer a uma interface, o UFX notificará o driver de classe associado a essa interface. Se necessário, espera-se que os drivers de classe leiam e gravem no endpoint de controlo.

Transferências de dados

As transferências de dados são iniciadas pelos drivers de classe que enviam solicitações IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT ou IOCTL_INTERNAL_USBFN_TRANSFER_OUT. Depois de validar cada uma dessas requisições, a UFX encaminha-a para a fila de ponto final apropriada para ser processada pelo driver do cliente. Espera-se que o driver do cliente execute validação adicional. O driver do cliente recebe solicitações de transferência em filas de endpoints. O controlador do cliente pode recuperar quantas solicitações desta fila forem necessárias para maximizar a utilização do barramento. O driver do cliente deve concluir as solicitações bem-sucedidas com STATUS_SUCCESS. O motorista deve fazer a melhor tentativa possível para cancelar as solicitações e concluir as solicitações canceladas com STATUS_CANCELADO se forem canceladas. Se parâmetros inválidos forem passados, o driver do cliente concluirá a solicitação com STATUS_INVALID_PARAMETER.

Controlar transferências

As transferências de controle começam com um pacote de configuração de 8 bytes. Para enviar um pacote de instalação para o host, o driver do cliente deve chamar UfxEndpointNotifySetup. A UFX notifica os motoristas de classe de transferências de controle fora do padrão, completando solicitações de notificação. Os clientes e o UFX usam IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT ou IOCTL_INTERNAL_USBFN_TRANSFER_OUT para ler e escrever no ponto final de controlo padrão. No entanto, uma interface pode definir outros pontos de extremidade de controle, que somente o driver de classe correspondente pode usar. Os pontos de extremidade de controlo podem ser bloqueados em resposta a um pacote de configuração. Os drivers de classe enviam a solicitação IOCTL_INTERNAL_USBFN_SET_PIPE_STATE para suspender o ponto de extremidade. É esperado que o hardware ou o driver do cliente retome imediatamente o tráfego no endpoint após o envio da interrupção. Os pontos de extremidade de controle também podem enviar e receber pacotes de comprimento zero (ZLP) sem dados anteriores. O driver cliente e UFX podem fazer isso usando IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN e IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT.

Transferências em massa e interrompidas

As transferências em massa garantem a entrega de dados e são usadas para enviar grandes quantidades de dados. As transferências podem ser enviadas em um endpoint em massa usando IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT ou IOCTL_INTERNAL_USBFN_TRANSFER_OUT. Os pontos de extremidade em massa podem ser paralisados da mesma forma que os pontos de extremidade de controle usando IOCTL_INTERNAL_USBFN_SET_PIPE_STATE. Espera-se que o controlador do cliente envie um pacote STALL em resposta a todas as solicitações do host e mantenha as solicitações IOCTL. Ao contrário dos pontos de extremidade de controle, um ponto de extremidade em massa paralisado permanece parado até que o estado de parada seja explicitamente limpo.

As transferências de interrupção são como transferências em massa, mas têm uma latência garantida. As transferências de interrupção têm a mesma interface que as transferências em massa, mas não têm recursos de streaming.

Transferências isócronas

Não se espera que o driver do cliente suporte transferências isócronas nesta versão.

Gestão de energia

O motorista do cliente possui todos os aspetos do gerenciamento de energia. Como as funções de retorno de chamada são assíncronas, espera-se que o driver do cliente volte a um estado de energia apropriado e conclua a solicitação antes de chamar a função de exportação de evento completo apropriada, como UfxDeviceEventComplete.

UFX está em um estado de trabalho se o estado do dispositivo (definido em USBFN_DEVICE_STATE) é UsbfnDeviceStateSuspended e UsbfnDeviceStateAttached, e não relatou um tipo de porta. Como alternativa, a UFX informou o tipo de porta (definido em USBFN_PORT_TYPE) UsbfnStandardDownstreamPort ou UsbfnChargingDownstreamPort.

UFX entra e sai de um estado de trabalho chamando EVT_UFX_DEVICE_USB_STATE_CHANGE ou EVT_UFX_DEVICE_PORT_CHANGE implementações. A transição de ou para um estado de trabalho é concluída quando o driver do cliente chama UfxDeviceEventComplete.

Num estado operacional, UFX pode chamar qualquer retorno de chamada. Embora não esteja no estado de trabalho, a UFX apenas invoca EVT_UFX_DEVICE_USB_STATE_CHANGE para entrar em um estado de trabalho e EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL para emitir um despertar remoto durante a suspensão (se suportado).

Suspensão do dispositivo

A suspensão do dispositivo ocorre quando não há tráfego no barramento por três milissegundos. Nesse caso, o driver do cliente deve informar a UFX quando detetar suspensão e retomada chamando UfxDeviceNotifySuspend e UfxDeviceNotifyResume. Ao receber essas chamadas, o UFX chama EVT_UFX_DEVICE_USB_STATE_CHANGE e notifica os controladores de classe ao concluir os pedidos de IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION. Se o despertar remoto for suportado pelo dispositivo e ativado pelo host, o UFX poderá chamar chamadas EVT_UFX_DEVICE_USB_STATE_CHANGE enquanto estiver suspenso para emitir um sinal de despertar remoto.