Partilhar via


Como selecionar uma configuração alternativa em uma interface USB

Este tópico descreve as etapas para emitir uma solicitação de interface selecionada para ativar uma configuração alternativa em uma interface USB. O driver do cliente deve emitir essa solicitação depois de selecionar uma configuração USB. A seleção de uma configuração, por padrão, também ativa a primeira configuração alternativa em cada interface nessa configuração.

Cada configuração USB deve suportar uma ou mais interfaces USB múltiplas. Cada interface expõe um ou mais pontos de extremidade que são usados para transferir dados de e para o dispositivo. As interfaces USB devem ter um índice de interface definido pelo dispositivo que é usado para identificar a interface. A interface também deve ter uma ou mais configurações alternativas que agrupam os pontos de extremidade da interface. Como parte da configuração do dispositivo, o driver do cliente deve selecionar uma das configurações alternativas na interface. Como os pontos de extremidade podem ser compartilhados entre configurações alternativas, apenas uma configuração pode estar ativa em um determinado momento. Depois que a configuração alternativa estiver ativa, seus pontos de extremidade ficarão disponíveis para transferências de dados.

Para um dispositivo de interface múltipla, duas interfaces podem estar ativas em um determinado momento. O driver do cliente deve ativar uma configuração alternativa em cada interface. Os pontos finais não são compartilhados entre interfaces e, portanto, cada transferência de dados simultânea pode ser realizada em cada interface.

As configurações alternativas são definidas pelo dispositivo e identificadas com um número chamado índice de configuração. A configuração alternativa no índice 0 é chamada de configuração alternativa padrão neste conjunto de documentação. Uma configuração alternativa é descrita em uma estrutura USB_INTERFACE_DESCRIPTOR . A estrutura contém o índice de interface ao qual a configuração está associada e o número de pontos de extremidade definidos pela configuração. Ele também contém informações sobre a especificação de classe à qual a funcionalidade da interface está em conformidade. A forma, na qual os pontos finais são agrupados, depende da funcionalidade do dispositivo.

Por exemplo, uma interface expõe dois pontos finais isócronos e dois pontos finais em massa através de três configurações alternativas (índice 0, 1, 2). A Configuração Alternativa 0 não define nenhum ponto de extremidade; A Configuração Alternativa 1 define os pontos de extremidade em massa; A configuração alternativa 2 define os pontos finais isócronos. Como a Configuração Alternativa 0 não tem ponto de extremidade, o driver do cliente pode selecionar essa configuração para desabilitar a transferência de dados a fim de conservar a largura de banda. Quando qualquer uma das outras configurações está ativa, o dispositivo está pronto para transferências de dados. A Configuração Alternativa 1 pode ser usada para transferir dados em massa. A configuração alternativa 2 pode ser selecionada quando o dispositivo está no modo de streaming. Portanto, as configurações alternativas dão ao driver do cliente a flexibilidade de alterar a configuração do dispositivo como e quando necessário. Neste exemplo, o driver do cliente pode alternar a funcionalidade do dispositivo de uma transferência em massa para streaming, apenas selecionando uma configuração alternativa.

Configurações alternativas também podem ser usadas para definir requisitos de largura de banda. Para obter um exemplo, consulte o layout do dispositivo USB.

Windows Driver Foundation (WDF) fornece métodos no Kernel-Mode Driver Framework e noUser-Mode Driver Framework que o driver do cliente pode chamar para selecionar uma configuração alternativa diferente. O driver do cliente KMDF pode selecionar uma configuração especificando o índice de configuração, o descritor de interface da configuração ou enviando um URB que contenha a solicitação. O driver de cliente UMDF só pode selecionar uma configuração alternativa especificando seu índice de configuração.

Depois que uma solicitação de configuração selecionada for concluída com êxito, a configuração alternativa ativa anteriormente será desativada.

O que precisa de saber

Este artigo utiliza as seguintes estruturas:

Antes de começar

Antes que o driver do cliente possa selecionar uma configuração alternativa, verifique se estes requisitos são atendidos:

  • O driver do cliente deve ter criado o objeto de dispositivo USB de destino do framework.

    • Um driver de cliente KMDF deve obter um identificador WDFUSBDEVICE chamando o método WdfUsbTargetDeviceCreateWithParameters. Para obter mais informações, consulte "Código-fonte do dispositivo" em Noções básicas sobre a estrutura de código do driver do cliente USB (KMDF).

    • Um driver de cliente UMDF deve obter um ponteiro IWDFUsbTargetDevice consultando o objeto de dispositivo de destino estrutural. Para obter mais informações, consulte "implementação de IPnpCallbackHardware e tarefas específicas de USB" em "Compreender a estrutura de código do driver de cliente USB (UMDF)"

      Se você estiver usando os modelos USB fornecidos com o Microsoft Visual Studio Professional 2012, o código do modelo executa essas tarefas. O código do modelo obtém o identificador para o objeto de dispositivo de destino e armazena-o no contexto do dispositivo.

  • O dispositivo deve ter uma configuração ativa.

    • Um driver de cliente KMDF deve chamar o método WdfUsbTargetDeviceSelectConfig.

    • Para um driver de cliente UMDF, a estrutura seleciona a primeira configuração e a configuração alternativa padrão para cada interface nessa configuração.

      Se você estiver usando modelos USB, o código selecionará a primeira configuração e a configuração alternativa padrão em cada interface.

Selecione uma configuração alternativa em um driver de cliente KMDF

  1. Obtenha um identificador WDFUSBINTERFACE para a interface que tem a configuração alternativa.

    Para obter o identificador, primeiro obtenha o número das interfaces da configuração selecionada chamando WdfUsbTargetDeviceGetNumInterfaces e, em seguida, enumere as interfaces em um loop. Em cada iteração, chame o método WdfUsbTargetDeviceGetInterface e incremente o índice (começando em zero).

    Observação Durante a enumeração de dispositivos, a stack de drivers USB atribui números aos parâmetros alternativos. Os números de interface são baseados em zero e sequenciais. Esses números podem ser diferentes do índice de configuração definido pelo dispositivo. Para obter o índice de configuração definido pelo dispositivo, chame o método WdfUsbInterfaceGetInterfaceNumber .

  2. Inicie uma solicitação de interface selecionada chamando o método WdfUsbInterfaceSelectSetting . No parâmetro Params da chamada, escolha uma destas opções:

    • Especifique o número de configuração alternativo atribuído pela stack de drivers USB. Normalmente, você passa o mesmo índice que você usou na etapa 1 para enumerar as configurações.

    • Especifique um ponteiro para o descritor da interface que descreve a configuração alternativa. O driver pode então obter descritores de interface ao enumerar configurações alternativas na interface chamando o método WdfUsbInterfaceGetDescriptor . Após a conclusão da enumeração, o driver obtém informações sobre todas as configurações alternativas enumeradas na estrutura USB_INTERFACE_DESCRIPTOR .

    • Especifique um ponteiro para um URB que contenha todas as informações necessárias para o pedido de seleção de interface.

      1. Aloque uma matriz de estruturas USBD_INTERFACE_LIST_ENTRY . O número de elementos nessa matriz depende do número de interfaces na configuração selecionada. Para obter informações sobre como inicializar essa matriz, consulte Como selecionar uma configuração para um dispositivo USB.
      2. Aloque um URB para a solicitação de interface selecionada, chamando a rotina USBD_SelectInterfaceUrbAllocateAndBuild. Nesta chamada, especifique o array da lista de interfaces e o identificador de configuração que foi obtido após selecionar uma configuração. Você pode obter esse identificador chamando o método WdfUsbTargetDeviceWdmGetConfigurationHandle .
      3. Chame WdfUsbInterfaceSelectSetting e especifique o URB.

      **Drivers WDM:**Para enviar o URB, associe o URB a um IRP e envie o IRP para a pilha de drivers USB. Para obter mais informações, consulte Como enviar um URB.

    As opções na lista fornecem ao driver do cliente a flexibilidade para especificar os critérios de seleção. Se você já estiver ciente dos recursos de ponto de extremidade da configuração alternativa, escolha a primeira opção (com o número de configuração alternativo) na lista. Caso contrário, escolha a segunda opção que especifica o descritor de interface. Inspecione as estruturas USB_INTERFACE_DESCRIPTOR para todas as configurações alternativas. Para cada configuração, enumere seus pontos de extremidade e suas características, como o tipo de ponto de extremidade, o tamanho máximo do pacote e assim por diante. Quando encontrar o conjunto de pontos de extremidade necessários para transferências de dados, chame WdfUsbInterfaceSelectSetting especificando um ponteiro para esse descritor de interface. Normalmente, você não precisará da terceira opção, a menos que seja um driver de cliente baseado em WDM que só pode enviar solicitações para a pilha de drivers USB enviando URBs.

    Com base nas informações fornecidas pelo driver do cliente, a pilha de driver USB cria uma solicitação de controle padrão (SET INTERFACE) e a envia para o dispositivo. Se a solicitação for concluída com êxito, a pilha de drivers USB obterá alças de tubos para os pontos finais da configuração alternativa.

    Depois de selecionar uma configuração alternativa, o driver cliente deve sempre obter as alças de tubo para pontos de extremidade na nova configuração. Se isso não for feito, o driver poderá enviar solicitações de transferência de dados usando alças de tubo obsoletas. Para obter informações sobre como recuperar alças de tubo, consulte Como enumerar pipes USB.

NTSTATUS  FX3SelectInterfaceSetting(  
    _In_ WDFDEVICE Device,
    _In_ UCHAR SettingIndex)

{
    NTSTATUS                 status;  
    PDEVICE_CONTEXT          pDeviceContext;  
    WDF_OBJECT_ATTRIBUTES               pipeAttributes;

    WDF_USB_INTERFACE_SELECT_SETTING_PARAMS settingParams;

    PAGED_CODE();  

    pDeviceContext = GetDeviceContext(Device);

    if (pDeviceContext->UsbInterface == NULL)
    {
        status = USBD_STATUS_BAD_NUMBER_OF_INTERFACES;
        goto Exit;
    }

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pipeAttributes, PIPE_CONTEXT);  

    pipeAttributes.EvtCleanupCallback = FX3EvtPipeContextCleanup;

    WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING (&settingParams, SettingIndex);

    status = WdfUsbInterfaceSelectSetting (
        pDeviceContext->UsbInterface,
        &pipeAttributes,
        &settingParams);

    if (status != STATUS_SUCCESS)
    {
        goto Exit;
    }

    if (WdfUsbInterfaceGetNumConfiguredPipes (pDeviceContext->UsbInterface) > 0)
    {
        status = FX3EnumeratePipes (Device);

        if (status != STATUS_SUCCESS)
        {
            goto Exit;
        }
    }

Exit:
    return status;
}

Selecione uma configuração alternativa em um driver de cliente UMDF

  1. Obtenha o número de interfaces USB suportadas pela configuração ativa chamando o método IWDFUsbTargetDevice::GetNumInterfaces .

  2. Obtenha um ponteiro IWDFUsbInterface para cada interface na configuração.

    Enumere todas as interfaces chamando o método IWDFUsbTargetDevice::RetrieveUsbInterface em um loop até que a função retorne NULL. A cada iteração, incremente o índice de membros (baseado em zero). O loop recupera ponteiros IWDFUsbInterface para todas as interfaces enumeradas.

  3. Para cada interface, obtenha o identificador WinUSB chamando IWDFUsbInterface::GetWinUsbHandle. Este identificador é necessário para a próxima etapa.

  4. Chame WinUsb_GetAssociatedInterface para obter um identificador para a interface. No parâmetro AssociatedInterfaceIndex , especifique o índice na etapa 2.

  5. Determine o número de configurações alternativas na interface.

    Chame a função WinUsb_QueryInterfaceSettings em um loop e incremente o índice (baseado em zero) em cada iteração. Quando todas as configurações são enumeradas, a função retorna ERROR_NO_MORE_ITEMS. A função também retorna descritores de interface para cada configuração.

  6. Usando o valor recebido no membro bNumEndpoints de cada descritor de interface e enumere seus pontos de extremidade. Inspecione os descritores de ponto final e determine qual configuração atende às suas necessidades.

  7. Inicie uma solicitação de interface selecionada chamando a função WinUsb_SetCurrentAlternateSetting . Na chamada, especifique o número de configuração alternativo associado ao índice na etapa 4.

  8. Solte o identificador de interface obtido na etapa 4 chamando a função WinUsb_Free .

  9. Solte o identificador WinUSB obtido na etapa 3 chamando a função WinUsb_Free .

  10. Se você terminar de usar os métodos IWDFUsbInterface , libere todos os ponteiros de interface recuperados na etapa 2.

Observações

Para um driver cliente KMDF, durante a sua chamada de WdfUsbInterfaceSelectSetting, o driver pode fornecer um ponteiro para um contexto de pipe definido pelo próprio driver. O driver do cliente pode armazenar informações sobre tubos no contexto do pipe. Para obter mais informações sobre pipes, consulte Como enumerar pipes USB.