Práticas recomendadas: usando URBs
Este tópico descreve as práticas recomendadas para um driver de cliente para alocar, compilar e enviar um URB para a pilha de driver USB incluída com Windows 8.
Windows 8 inclui uma nova pilha de driver USB para dar suporte a dispositivos USB (Barramento Serial Universal) 3.0. A nova pilha de drivers USB 3.0 implementa várias novas funcionalidades, de acordo com a especificação USB 3.0. Além disso, a pilha de driver inclui outros recursos que permitem que um driver de cliente execute tarefas comuns com eficiência. Por exemplo, a nova pilha de driver aceita MDLs encadeadas que permitem ao driver cliente enviar um buffer de transferência em páginas descoloridas na memória física.
Antes que um driver cliente possa usar os novos recursos da pilha de drivers USB para Windows 8, o driver deve registrar-se com a pilha de driver USB subjacente que é carregada pelo Windows para o dispositivo. Para registrar o driver cliente, chame USBD_CreateHandle e especifique uma versão do contrato. Se o driver do cliente se destina a compilar, executar e usar as melhorias e os novos recursos no Windows 8, a versão do contrato do cliente será USBD_CLIENT_CONTRACT_VERSION_602.
Para um driver de cliente USBD_CLIENT_CONTRACT_VERSION_602 versão, a pilha de driver USB pressupõe que o driver cliente está em conformidade com o seguinte conjunto de regras:
- Não enviar solicitações de E/S usando identificadores de pipe obsoletos ou inválidos
- Alocar URBs chamando rotinas de alocação no Windows 8
- Não reutilizar URBs ativos associados a solicitações pendentes
- Não use o período de sondagem maior que 8 para alta velocidade e transferências isócronas superSpeed
- Verifique se o número de pacotes isócronos que é um número múltiplo de pacotes por quadro
- Chamar a rotina no nível de IRQL documentado
- Tópicos relacionados
A pilha de driver USB executa validações nas solicitações recebidas e lida com as violações sempre que possível. Não fazer isso pode levar a um comportamento indefinido.
Não enviar solicitações de E/S usando identificadores de pipe obsoletos ou inválidos
O driver cliente não deve usar identificadores de pipe obsoletos para enviar solicitações de E/S para a pilha de driver USB. Um identificador de pipe obsoleto refere-se a um identificador de pipe obtido em uma solicitação para selecionar uma configuração, uma interface ou uma configuração alternativa que não está mais selecionada no dispositivo. Para evitar identificadores de pipe obsoletos, sempre que o driver do cliente seleciona uma configuração ou uma interface, o driver deve atualizar seu cache de identificadores de pipe (geralmente armazenados no contexto do dispositivo). Determinadas condições de corrida também podem resultar em alças de pipe obsoletas. Por exemplo, o driver cliente envia uma solicitação de E/S usando um identificador de pipe na interface selecionada. Antes da conclusão da solicitação, o driver do cliente seleciona uma configuração alternativa que não usa o mesmo ponto de extremidade associado ao identificador de pipe em uso. Ambas as solicitações pendentes podem causar uma condição de corrida tornando a alça de pipe inválida.
Alocar URBs chamando rotinas de alocação no Windows 8
Windows 8 fornece novas rotinas para alocar, compilar e liberar URBs (Blocos de Solicitação USB). Para alocar URBs, um driver de cliente WDM (Modelo de Driver do Windows) sempre deve usar as novas rotinas mostradas na lista a seguir:
- USBD_UrbAllocate
- USBD_IsochUrbAllocate
- USBD_SelectConfigUrbAllocateAndBuild
- USBD_SelectInterfaceUrbAllocateAndBuild
- USBD_UrbFree
- USBD_AssignUrbToIoStackLocation
As rotinas na lista anterior podem anexar um contexto URB opaco à URB alocada para melhorar o acompanhamento e o processamento. O driver cliente não pode exibir ou modificar o conteúdo do contexto URB. Para obter mais informações sobre a alocação de URB em Windows 8, consulte Alocando e criando URBs.
Se um driver de cliente WDF (Windows Driver Framework) que identifica sua versão como USBD_CLIENT_CONTRACT_VERSION_602 durante o registro (consulte WdfUsbTargetDeviceCreateWithParameters), a pilha de driver USB espera que o driver cliente aloque memória para o URB chamando o novo WdfUsbTargetDeviceCreateUrb.
Não reutilizar URBs ativos associados a solicitações pendentes
A pilha de driver USB verifica deliberadamente se detecta que um URB ativo foi reenviado antes da solicitação associada ao URB. Um URB está ativo desde que a solicitação esteja pendente e a rotina de conclusão do IRP do driver cliente não tenha sido chamada. Não execute as tarefas a seguir em um URB ativo.
- Não reenvie um URB ativo para outra solicitação (associe o URB a outro IRP).
- Não modifique o conteúdo de um URB ativo.
- Não libere um URB ativo.
Depois que a rotina de conclusão do driver cliente for chamada, os drivers poderão reenviar URBs para determinados tipos de solicitação dentro da rotina de conclusão. As seguintes regras se aplicam a reenvios:
O driver cliente não deve reutilizar um URB alocado por USBD_SelectConfigUrbAllocateAndBuild para qualquer tipo de solicitação que não seja uma solicitação de configuração de seleção para selecionar a mesma configuração.
O driver cliente não deve reutilizar um URB alocado por USBD_SelectInterfaceUrbAllocateAndBuild para qualquer tipo de solicitação que não seja uma solicitação select-interface para selecionar a mesma configuração alternativa em uma interface. Para obter um exemplo, consulte Comentários em USBD_SelectInterfaceUrbAllocateAndBuild.
Um URB alocado por USBD_IsochUrbAllocate deve ser reutilizado somente para solicitações de transferência isócronas. Por outro lado, um URB alocado para outros tipos de solicitações de E/S (controle, em massa ou interrupção) não deve ser usado para uma solicitação isócrona.
Por exemplo, um driver de cliente aloca e cria uma estrutura URB para uma solicitação de transferência em massa. O driver cliente também deseja enviar dados para pontos de extremidade isócronos no dispositivo. Depois que uma solicitação de transferência em massa for concluída, o driver do cliente não deverá reformatar e enviar o URB para uma solicitação isócrona. Isso ocorre porque um URB associado a uma solicitação isócrona tem um comprimento variável, dependendo do número de pacotes. Além disso, os pacotes são necessários para iniciar e terminar em um limite de quadro. O URB alocado (para a transferência em massa) pode não se ajustar ao layout de buffer necessário para uma transferência isócrona e a solicitação pode falhar.
Um URB alocado por USBD_UrbAllocate não deve ser reutilizado para um isócrono, uma seleção de configuração ou uma solicitação select-interface. O URB pode ser reutilizado para selecionar uma configuração NULL para desabilitar a configuração selecionada no dispositivo. O URB não deve estar ativo e o driver cliente deve reformatar o URB chamando a macro UsbBuildSelectConfigurationRequest e passando NULL no parâmetro ConfigurationDescriptor .
Antes de reenviar um URB, o driver cliente deve reformatar o URB usando a macro UsbBuildXxx apropriada definida para o tipo de solicitação. É importante que o driver formate a URB, pois a pilha USB pode ter alterado parte de seu conteúdo.
Por exemplo, suponha que um driver chame UsbBuildInterruptOrBulkTransferRequest para inicializar um URB para uma solicitação de transferência em massa (consulte _URB_BULK_OR_INTERRUPT_TRANSFER). Se o driver inicializar o membro TransferBufferMDL da estrutura URB para NULL, a pilha de driver USB usará o buffer de transferência, especificado TransferBuffer, para trocar dados com o dispositivo em vez de um MDL. No entanto, internamente, a pilha de driver USB pode criar um MDL, armazenar um ponteiro para o MDL em TransferBufferMDL e usar o MDL para passar dados para baixo na pilha. Embora a pilha de driver USB libere a memória MDL, TransferBufferMDL pode não ser NULL quando o driver cliente está processando a URB na rotina de conclusão. Para garantir que os membros do URB estejam formatados corretamente, o driver deve chamar UsbBuildInterruptOrBulkTransferRequest novamente para reformatar o URB antes de enviar a solicitação,
Não use o período de sondagem maior que 8 para alta velocidade e transferências isócronas superSpeed
A pilha de drivers USB dá suporte a pipes isócronos de alta velocidade e SuperSpeed com um período de sondagem de números de 1, 2, 4 ou 8. Um driver cliente não deve enviar E/S para um ponto de extremidade que tenha um período maior que 8. Isso pode levar a uma verificação de bugs.
Verifique se o número de pacotes isócronos que é um número múltiplo de pacotes por quadro
Para transferências isócronas de alta velocidade e SuperSpeed, o número de pacotes isócronos por quadro é calculado como 8/período de sondagem. O driver cliente deve verificar se o valor NumberOfPackets especificado no URB (consulte _URB_ISOCH_TRANSFER) é um número múltiplo de pacotes por quadro.
A pilha de driver USB não dá suporte a URBs de transferência isócrona nas quais o NumberOfPackets não é um número múltiplo de pacotes por quadro.
Chamar a rotina no nível de IRQL documentado
Se você registrar o driver cliente com USBD_CLIENT_CONTRACT_VERSION_602 como a versão do contrato, a pilha de driver USB pressupõe que o driver cliente enviou a solicitação no nível IRQL apropriado. Se um driver cliente enviar uma solicitação em DISPATCH_LEVEL, que deve ser enviada em PASSIVE_LEVEL. Ao receber a solicitação, em alguns casos, a pilha de driver USB valida o valor irql e falha na solicitação. No entanto, em outros casos, a pilha de driver USB pode gerar uma verificação de bugs.