Partilhar via


Como se recuperar de erros de pipe USB

Observação

Este artigo é para desenvolvedores de driver de dispositivo. Se você estiver tendo dificuldades com um dispositivo USB, confira Solucionar problemas comuns de USB

Este artigo fornece informações sobre as etapas que você pode tentar quando uma transferência de dados para um pipe USB falha. Os mecanismos descritos neste artigo abrangem operações de anulação, redefinição e porta de ciclo em pipes em massa, interrupção e isócronos.

Um driver cliente USB se comunica com seu dispositivo enviando transferências de controle para o ponto de extremidade padrão; transferências de dados para pontos de extremidade em massa, de interrupção e isócronos do dispositivo. Às vezes, essas transferências podem falhar devido a vários motivos, como uma condição de parada no ponto de extremidade. Se a transferência falhar, o pipe associado não poderá processar solicitações até que a condição de erro seja limpa.

Para transferências de controle, a pilha de driver USB limpa as condições de erro automaticamente. Para transferências de dados, o cliente deve tomar as etapas apropriadas para se recuperar da condição de erro. Quando uma transferência de dados falha, a pilha de driver USB relata o erro ao driver cliente por meio de códigos de status USBD com falha. Com base no código status, o driver pode fornecer um mecanismo de recuperação de erro.

Este artigo fornece diretrizes sobre a recuperação de erros por meio dessas operações.

  • Redefinir o pipe USB
  • Redefinir a porta USB à qual o dispositivo está conectado
  • Ciclo da porta USB para renumerar a pilha de dispositivos para o driver cliente

Para limpar uma condição de erro, comece com a operação de pipe de redefinição e execute operações mais complexas, como reset-port e cycle-port, somente se necessário.

Sobre a coordenação de vários mecanismos de recuperação:

O driver do cliente deve coordenar as diferentes operações de recuperação e garantir que apenas um método seja usado em um determinado momento. Por exemplo, considere um dispositivo com dois pontos de extremidade: um em massa e uma interrupção. Depois de enviar algumas solicitações de transferência de dados para o dispositivo, o driver percebe que as solicitações falham no pipe em massa. Para se recuperar desses erros, o driver redefine o pipe em massa. No entanto, essa operação não resolve os erros de transferência e as transferências em massa continuam falhando. Portanto, o driver emite uma solicitação para redefinir a porta USB. Enquanto isso, as transferências começam a falhar no pipe de interrupção e, em seguida, uma solicitação de redefinição de dispositivo. Para se recuperar das falhas de transferência de interrupção, o driver emite uma solicitação de pipe de redefinição no pipe de interrupção. Se essas duas operações não forem coordenadas, o driver poderá iniciar duas operações de redefinição de dispositivo simultaneamente, devido a falhas em ambos os pipes. Essas operações simultâneas podem ser problemáticas.

O driver cliente deve garantir que, em um determinado momento, o driver execute apenas uma operação de porta de redefinição ou porta de ciclo. Durante essas operações, uma operação de pipe de redefinição não deve estar em andamento em nenhum pipe e o driver não deve emitir uma nova solicitação de pipe de redefinição.

O que você precisa saber

Este artigo usa o KMDF (Kernel-Mode Driver Framework).

Pré-requisitos

  • O driver cliente deve ter criado o objeto de dispositivo de destino USB da estrutura.

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

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

  • O driver cliente deve ter um identificador para o objeto de pipe de destino da estrutura. Para obter mais informações, consulte Como enumerar pipes USB.

Etapa 1: Determinar a causa da condição de erro

O driver cliente inicia uma transferência de dados usando um URB (Bloco de Solicitação USB). Após a conclusão da solicitação, a pilha de driver USB retorna um código USBD status que indica se a transferência foi bem-sucedida ou se falhou. Em uma falha, o código USBD indica o motivo da falha.

Falhas de transferência podem resultar de um erro de dispositivo, como USBD_STATUS_STALL_PID ou USBD_STATUS_BABBLE_DETECTED. Eles também podem resultar devido a um erro relatado pelo controlador de host, como USBD_STATUS_XACT_ERROR.

Etapa 2: Determinar se o dispositivo está conectado à porta

Antes de emitir qualquer solicitação que redefina o pipe ou o dispositivo, verifique se o dispositivo está conectado. Você pode determinar o estado conectado do dispositivo chamando o método WdfUsbTargetDeviceIsConnectedSynchronous .

Etapa 3: Cancelar todas as transferências pendentes para o pipe

Antes de enviar solicitações que redefinam o pipe ou a porta, cancele todas as solicitações de transferência pendentes para o pipe, que a pilha de driver USB ainda não concluiu. Você pode cancelar solicitações de uma destas maneiras:

  • Pare o destino de E/S chamando o método WdfIoTargetStop .

    Para interromper o destino de E/S, primeiro, obtenha o identificador WDFIOTARGET associado ao objeto de pipe da estrutura chamando o método WdfUsbTargetPipeGetIoTarget . Usando o identificador , chame WdfIoTargetStop. Na chamada, defina a ação como WdfIoTargetCancelSentIo (consulte WDF_IO_TARGET_SENT_IO_ACTION)** para instruir a estrutura a cancelar todas as solicitações que a pilha de driver USB não concluiu. Para solicitações que foram concluídas, o driver cliente deve aguardar o retorno de chamada de conclusão ser invocado pela estrutura.

  • Enviar uma solicitação de pipe de anulação. Você pode enviar a solicitação chamando um destes métodos:

    • Chame o método WdfUsbTargetPipeAbortSynchronously .

      A chamada é síncrona e retorna somente depois que todas as solicitações pendentes são canceladas. WdfUsbTargetPipeAbortSynchronously usa um parâmetro Request opcional. Recomendamos que você passe um identificador WDFREQUEST para um objeto de solicitação de estrutura pré-alocado. O parâmetro habilita a estrutura de usar o objeto de solicitação especificado em vez de um objeto de solicitação interno que o driver não pode acessar. Esse valor de parâmetro garante que WdfUsbTargetPipeAbortSynchronously não falhe devido à memória insuficiente.

    • Chame o método WdfUsbTargetPipeFormatRequestForAbort para formatar um objeto de solicitação para uma solicitação de pipe de anulação e, em seguida, envie a solicitação chamando o método WdfRequestSend .

      Se o driver enviar a solicitação de forma assíncrona, ele deverá especificar um ponteiro para o EVT_WDF_REQUEST_COMPLETION_ROUTINE do driver que o driver implementa. Para especificar o ponteiro, chame o método WdfRequestSetCompletionRoutine .

      O driver pode enviar a solicitação de forma síncrona especificando WDF_REQUEST_SEND_OPTION_SYNCHRONOUS como uma das opções de solicitação em WdfRequestSend. Se você enviar a solicitação de forma síncrona, chame WdfUsbTargetPipeAbortSynchronously .

Etapa 4: Redefinir o pipe USB

Inicie a recuperação de erro redefinindo o pipe. Você pode enviar uma solicitação de pipe de redefinição chamando um destes métodos:

  • Chame o WdfUsbTargetPipeResetSynchronously para enviar uma solicitação de pipe de redefinição de forma síncrona.

  • Chame o método WdfUsbTargetPipeFormatRequestForReset para formatar um objeto de solicitação para uma solicitação de pipe de redefinição e envie a solicitação chamando o método WdfRequestSend . Essas chamadas são semelhantes às da solicitação de pipe de anulação, conforme descrito na etapa 3.

Observação

Não envie novas solicitações de transferência até que a operação de pipe de redefinição seja concluída.

A solicitação de pipe de redefinição limpa a condição de erro no dispositivo e no hardware do controlador de host. Para limpar o erro do dispositivo, a pilha de driver USB envia uma solicitação de controle de CLEAR_FEATURE para o dispositivo usando o seletor de recursos ENDPOINT_HALT. O destinatário da solicitação é o ponto de extremidade associado ao pipe. Se a condição de erro ocorreu em um pipe isócrono, a pilha de driver não executa nenhuma ação para limpar o dispositivo porque, no caso de erros, os pontos de extremidade isócronos são limpos automaticamente.

Para limpar o erro do controlador de host, a pilha do driver limpa o estado HALT do pipe e redefine a alternância de dados do pipe para 0.

Etapa 5: Redefinir a porta USB

Se uma operação de redefinição de pipe não limpar a condição de erro e as transferências de dados continuarem falhando, envie uma solicitação de redefinição de porta.

  1. Cancele todas as transferências para o dispositivo. Para fazer isso, enumere todos os pipes na configuração atual e cancele solicitações pendentes agendadas para cada pipe.

  2. Interrompa o destino de E/S do dispositivo.

    Chame o método WdfUsbTargetDeviceGetIoTarget para obter um identificador WDFIOTARGET associado ao objeto de dispositivo de destino da estrutura. Em seguida, chame WdfIoTargetStop e especifique o identificador WDFIOTARGET. Na chamada, defina a ação como WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).

  3. Envie uma solicitação de porta de redefinição chamando o método WdfUsbTargetDeviceResetPortSynchronously .

Uma operação de redefinição de porta faz com que o dispositivo seja renumerado no barramento USB. A pilha de driver USB preserva a configuração do dispositivo após a enumeração . O driver cliente pode usar as alças de pipe obtidas anteriormente porque a pilha de driver garante que as alças de pipe existentes permaneçam válidas.

Não é possível redefinir uma função individual de um dispositivo composto. Para um dispositivo composto, quando o driver de cliente de uma função específica envia uma solicitação de porta de redefinição, todo o dispositivo é redefinido. Se o dispositivo USB mantiver o estado, essa solicitação de porta de redefinição poderá afetar os drivers de cliente de outras funções. Portanto, é importante que o driver do cliente tente redefinir o pipe antes de redefinir a porta.

Etapa 6: Percorrer a porta USB

Uma operação de porta de ciclo é semelhante ao dispositivo que está desconectado e conectado de volta à porta, exceto que o dispositivo não está desconectado eletricamente. O dispositivo é desconectado e reconectado no software. Essa operação leva à redefinição e à enumeração do dispositivo. Como resultado, o Gerenciador de PnP recria o nó do dispositivo.

Se uma operação de redefinição de porta não limpar a condição de erro e as transferências de dados continuarem falhando, envie uma solicitação de porta de ciclo.

  1. Cancele todas as transferências para o dispositivo. Cancele a solicitação pendente agendada para cada pipe na configuração atual (consulte a etapa 3).

  2. Interrompa o destino de E/S do dispositivo.

    Chame o método WdfUsbTargetDeviceGetIoTarget para obter um identificador WDFIOTARGET associado ao objeto de dispositivo de destino da estrutura. Em seguida, chame WdfIoTargetStop e especifique o identificador WDFIOTARGET. Na chamada, defina a ação como WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).

  3. Envie uma solicitação de porta de ciclo chamando um destes métodos:

O driver cliente pode enviar solicitações de transferência para o dispositivo somente após a conclusão da solicitação de porta de ciclo. Isso ocorre porque o nó do dispositivo é removido enquanto a pilha de driver USB processa a solicitação de porta de ciclo.

A solicitação de porta de ciclo faz com que o dispositivo seja renumerado. A pilha de driver USB informa ao Gerenciador de PnP que o dispositivo foi desconectado. O Gerenciador PnP desativa a pilha de dispositivos associada ao driver do cliente. A pilha do driver redefine o dispositivo, renumera-o no barramento USB e informa ao Gerenciador PnP que um dispositivo foi conectado. Em seguida, o Gerenciador de PnP recria a pilha de dispositivos para o dispositivo USB.

Como resultado da operação de porta de ciclo, qualquer aplicativo que tenha um identificador aberto no dispositivo receberá uma notificação de remoção de dispositivo (se o aplicativo tiver sido registrado para essa notificação). Em resposta, o aplicativo pode relatar uma mensagem desconectada do dispositivo ao usuário. Como isso afeta a experiência do usuário, o driver do cliente deve optar por uma solicitação de porta de ciclo somente se outros mecanismos de recuperação não resolve a condição de erro.

Semelhante à operação de redefinição de porta (descrita na etapa 6), para um dispositivo composto, a operação de porta de ciclo afeta todo o dispositivo e não as funções individuais do dispositivo.