Compartir a través de


Recuperación de errores de canalización USB

Nota:

Este artículo es para desarrolladores de controladores de dispositivos. Si tiene dificultades con un dispositivo USB, consulte Corrección de problemas de USB-C en Windows.

En este artículo se proporciona información sobre los pasos que puede probar cuando se produce un error en una transferencia de datos a una canalización USB. En los mecanismos descritos en este artículo se tratan las operaciones de anulación, restablecimiento y ciclo de puertos en canalizaciones masivas, interrumpidas e isocrónicas.

Un controlador cliente USB se comunica con su dispositivo enviando transferencias de control al punto de conexión predeterminado; transferencias de datos a puntos de conexión masivos, de interrupción e isócronos del dispositivo. A veces, esas transferencias de datos pueden generar un error por varios motivos, como una condición de bloqueo en el punto de conexión. Si se produce un error en la transferencia, la canalización asociada no puede procesar las solicitudes hasta que se borre la condición de error.

Para las transferencias de control, la pila del controlador USB borra automáticamente las condiciones de error. Para las transferencias de datos, el cliente debe realizar los pasos adecuados para recuperarse de la condición de error. Cuando se produce un error en una transferencia de datos, la pila del controlador USB notifica el error al controlador cliente a través de códigos de estado USBD con errores. En función del código de estado, el controlador puede proporcionar un mecanismo de recuperación de errores.

En este artículo se proporcionan instrucciones sobre la recuperación de errores a través de estas operaciones.

  • Restablecimiento de la canalización USB
  • Restablecimiento del puerto USB al que está conectado el dispositivo
  • Ciclo del puerto USB para volver a enumerar la pila de dispositivos para el controlador de cliente

Para borrar una condición de error, comience con la operación de restablecimiento de la canalización y realice operaciones más complejas, como el restablecimiento y ciclo de puertos, solo si es necesario.

Acerca de la coordinación de varios mecanismos de recuperación:

El controlador cliente debe coordinar las distintas operaciones para la recuperación y asegurarse de que solo se usa un método en un momento dado. Por ejemplo, considere un dispositivo con dos puntos de conexión: una interrupción masiva y otra. Después de enviar algunas solicitudes de transferencia de datos al dispositivo, el controlador observa que las solicitudes producen un error en la canalización masiva. Para recuperarse de esos errores, el controlador restablece la canalización masiva. Sin embargo, esa operación no resuelve los errores de transferencia y las transferencias masivas siguen fallando. Por lo tanto, el controlador emite una solicitud para restablecer el puerto USB. Mientras tanto, las transferencias comienzan a producir un error en la canalización de interrupción y, a continuación, una solicitud de restablecimiento del dispositivo. Para recuperarse de los errores de transferencia de interrupciones, el controlador emite una solicitud de restablecimiento de canalización en la canalización de interrupción. Si esas dos operaciones no están coordinadas, el controlador puede iniciar dos operaciones de restablecimiento de dispositivo simultáneamente, debido a errores en ambas canalizaciones. Esas operaciones simultáneas pueden ser problemáticas.

El controlador cliente debe asegurarse de que, en un momento dado, el controlador solo realiza una operación de restablecimiento o de ciclo de puerto. Durante esas operaciones, una operación de restablecimiento de canalización no debe estar en curso en ninguna canalización y el controlador no debe emitir una nueva solicitud de restablecimiento de canalización.

Lo que necesitas saber

En este artículo se usa el marco de controladores en modo kernel (KMDF).

Requisitos previos

  • El controlador cliente debe haber creado el objeto de dispositivo de destino USB del marco.

    Si usa las plantillas USB que se proporcionan con Microsoft Visual Studio Professional 2012, el código de plantilla realiza esas tareas. El código de plantilla obtiene el identificador del objeto de dispositivo de destino y almacena en el contexto del dispositivo.

    Un controlador cliente KMDF debe obtener un identificador WDFUSBDEVICE llamando al método WdfUsbTargetDeviceCreateWithParameters. Para obtener más información, consulte "Código fuente del dispositivo" en Descripción de la estructura de código del controlador de cliente USB (KMDF).

  • El controlador cliente debe tener un identificador para el objeto de canalización de destino del marco. Para obtener más información, consulte Cómo enumerar canalizaciones USB.

Paso 1: Determinar la causa de la condición de error

El controlador cliente inicia una transferencia de datos mediante un bloque de solicitud USB (URB). Una vez completada la solicitud, la pila del controlador USB devuelve un código de estado USBD que indica si la transferencia se realizó correctamente o si se produjo un error. Si hay un error, el código USBD indica el motivo del error.

Los errores de transferencia pueden deberse a un error de dispositivo, como USBD_STATUS_STALL_PID o USBD_STATUS_BABBLE_DETECTED. También pueden producirse debido a un error notificado por el controlador de host, como USBD_STATUS_XACT_ERROR.

Paso 2: Determinar si el dispositivo está conectado al puerto

Antes de emitir cualquier solicitud que restablezca la canalización o el dispositivo, asegúrese de que el dispositivo está conectado. Puede determinar el estado de conexión del dispositivo llamando al método WdfUsbTargetDeviceIsConnectedSynchronous.

Paso 3: Cancelar todas las transferencias pendientes a la canalización

Antes de enviar cualquier solicitud que restablezca la canalización o el puerto, cancele todas las solicitudes de transferencia pendientes a la canalización que la pila del controlador USB aún no haya completado. Puede cancelar las solicitudes de una de estas maneras:

  • Detenga el destino de E/S llamando al método WdfIoTargetStop.

    Para detener el destino de E/S, primero obtenga el identificador WDFIOTARGET asociado al objeto de canalización del marco llamando al método WdfUsbTargetPipeGetIoTarget. Mediante el identificador, llame a WdfIoTargetStop. En la llamada, establezca la acción en WdfIoTargetCancelSentIo (consulte WDF_IO_TARGET_SENT_IO_ACTION)** para indicar al marco que cancele todas las solicitudes que no ha completado la pila del controlador USB. Para las solicitudes que se han completado, el controlador cliente debe esperar a que el marco invoque su devolución de llamada de finalización.

  • Envíe una solicitud de anulación de canalización. Puede enviar la solicitud llamando a uno de estos métodos:

    • Llame al método WdfUsbTargetPipeAbortSynchronously.

      La llamada es sincrónica y solo devuelve después de cancelar todas las solicitudes pendientes. WdfUsbTargetPipeAbortSynchronously toma un parámetro Request opcional. Se recomienda pasar un identificador WDFREQUEST a un objeto de solicitud de marco asignado previamente. El parámetro habilita el marco de uso del objeto de solicitud especificado en lugar de un objeto de solicitud interno al que el controlador no puede acceder. Este valor de parámetro garantiza que WdfUsbTargetPipeAbortSynchronously no produce un error debido a una memoria insuficiente.

    • Llame al método WdfUsbTargetPipeFormatRequestForAbort para dar formato a un objeto de solicitud para una solicitud de anulación de canalización y, a continuación, envíe la solicitud llamando al método WdfRequestSend.

      Si el controlador envía la solicitud de forma asincrónica, debe especificar un puntero a EVT_WDF_REQUEST_COMPLETION_ROUTINE del controlador que implementa el controlador. Para especificar el puntero, llame al método WdfRequestSetCompletionRoutine.

      El controlador puede enviar la solicitud de forma sincrónica especificando WDF_REQUEST_SEND_OPTION_SYNCHRONOUS como una de las opciones de solicitud en WdfRequestSend. Si envía la solicitud de forma sincrónica, llame a WdfUsbTargetPipeAbortSynchronously en su lugar.

Paso 4: Restablecer la canalización USB

Inicie la recuperación de errores restableciendo la canalización. Puede enviar una solicitud de restablecimiento de canalización llamando a uno de estos métodos:

  • Llame a WdfUsbTargetPipeResetSynchronously para enviar una solicitud de restablecimiento de canalización sincrónicamente.

  • Llame al método WdfUsbTargetPipeFormatRequestForReset para dar formato a un objeto de solicitud para una solicitud de restablecimiento de canalización y, a continuación, envíe la solicitud llamando al método WdfRequestSend. Esas llamadas son similares a las de la solicitud de anulación de canalización, como se describe en el paso 3.

Nota:

No envíe ninguna solicitud de transferencia nueva hasta que se complete la operación de restablecimiento de canalización.

La solicitud de restablecimiento de canalización borra la condición de error en el dispositivo y el hardware del controlador de host. Para borrar el error del dispositivo, la pila del controlador USB envía una solicitud de control CLEAR_FEATURE al dispositivo mediante el selector de características de ENDPOINT_HALT. El destinatario de la solicitud es el punto de conexión asociado a la canalización. Si se produjo la condición de error en una canalización isocrónica, la pila del controlador no realiza ninguna acción para borrar el dispositivo porque, en caso de errores, los puntos de conexión isócronos se borran automáticamente.

Para borrar el error del controlador de host, la pila del controlador borra el estado HALT de la canalización y restablece el botón de alternancia de datos de la canalización a 0.

Paso 5: Restablecer el puerto USB

Si una operación de restablecimiento de canalización no borra la condición de error y las transferencias de datos siguen fallando, envíe una solicitud de restablecimiento de puerto.

  1. Cancele todas las transferencias al dispositivo. Para ello, enumere todas las canalizaciones de la configuración actual y cancele las solicitudes pendientes programadas para cada canalización.

  2. Detenga el destino de E/S para el dispositivo.

    Llame al método WdfUsbTargetDeviceGetIoTarget para obtener un identificador WDFIOTARGET asociado al objeto de dispositivo de destino de marco. A continuación, llame a WdfIoTargetStop y especifique el identificador WDFIOTARGET. En la llamada, establezca la acción en WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).

  3. Envíe una solicitud de restablecimiento de puerto llamando al método WdfUsbTargetDeviceResetPortSynchronously.

Una operación de restablecimiento de puerto hace que el dispositivo se vuelva a enumerar en el bus USB. La pila del controlador USB conserva la configuración del dispositivo después de la enumeración. El controlador cliente puede usar los identificadores de canalización obtenidos anteriormente porque la pila del controlador garantiza que los identificadores de canalización existentes sigan siendo válidos.

No se puede restablecer una función individual de un dispositivo compuesto. Para un dispositivo compuesto, cuando el controlador cliente de una función determinada envía una solicitud de puerto de restablecimiento, se restablece todo el dispositivo. Si el dispositivo USB mantiene el estado, esa solicitud de restablecimiento de puerto puede afectar a los controladores de cliente de otras funciones. Por lo tanto, es importante que el controlador cliente intente restablecer la canalización antes de restablecer el puerto.

Paso 6: Ciclo del puerto USB

Una operación de ciclo de puerto es similar al dispositivo que se desconecta y se vuelve a conectar al puerto, excepto que el dispositivo no está desconectado eléctricamente. El dispositivo se desconecta y se vuelve a conectar en el software. Esta operación conduce al restablecimiento y enumeración del dispositivo. Como resultado, el Administrador de PnP vuelve a generar el nodo del dispositivo.

Si una operación de restablecimiento de puerto no borra la condición de error y las transferencias de datos siguen fallando, envíe una solicitud de ciclo de puerto.

  1. Cancele todas las transferencias al dispositivo. Asegúrese de cancelar la solicitud pendiente programada para cada canalización en la configuración actual (consulte el paso 3).

  2. Detenga el destino de E/S para el dispositivo.

    Llame al método WdfUsbTargetDeviceGetIoTarget para obtener un identificador WDFIOTARGET asociado al objeto de dispositivo de destino de marco. A continuación, llame a WdfIoTargetStop y especifique el identificador WDFIOTARGET. En la llamada, establezca la acción en WdfIoTargetCancelSentIo (WDF_IO_TARGET_SENT_IO_ACTION).

  3. Envíe una solicitud de ciclo de puerto llamando a uno de estos métodos:

El controlador cliente puede enviar solicitudes de transferencia al dispositivo solo después de que se haya completado la solicitud de ciclo de puerto. Esto se debe a que el nodo del dispositivo se quita mientras la pila del controlador USB procesa la solicitud de ciclo de puerto.

La solicitud de ciclo de puerto hace que el dispositivo se vuelva a enumerar. La pila del controlador USB informa al Administrador de PnP de que el dispositivo se ha desconectado. El Administrador de PnP desmonta la pila de dispositivos asociada al controlador cliente. La pila del controlador restablece el dispositivo, lo vuelve a enumerar en el bus USB e informa al Administrador de PnP de que se ha conectado un dispositivo. El Administrador de PnP vuelve a generar la pila de dispositivos para el dispositivo USB.

Como resultado de la operación de ciclo de puerto, cualquier aplicación que tenga un identificador abierto al dispositivo obtiene una notificación de eliminación de dispositivos (si la aplicación se registró para dicha notificación). En respuesta, la aplicación podría notificar un mensaje de dispositivo desconectado al usuario. Dado que afecta a la experiencia del usuario, el controlador cliente debe optar por una solicitud de ciclo de puerto solo si otros mecanismos de recuperación no resuelven la condición de error.

De forma similar a la operación de restablecimiento de puerto (descrita en el paso 6), para un dispositivo compuesto, la operación de ciclo de puerto afecta a todo el dispositivo y no a las funciones individuales del dispositivo.