Compartir a través de


Envío de una transferencia de control USB

En este artículo se explica la estructura de una transferencia de control y cómo un controlador cliente debe enviar una solicitud de control al dispositivo.

Acerca del punto de conexión predeterminado

Todos los dispositivos USB deben admitir al menos un punto de conexión denominado punto de conexión predeterminado. Cualquier transferencia que tenga como destino el punto de conexión predeterminado se denomina transferencia de control. El propósito de una transferencia de control es permitir que el host obtenga información del dispositivo, configure el dispositivo o realice operaciones de control únicas para el dispositivo.

Empecemos estudiando estas características del punto de conexión predeterminado.

  • La dirección del punto de conexión predeterminado es 0.
  • El punto de conexión predeterminado es bidireccional, es decir, el host puede enviar datos al punto de conexión y recibir datos de él dentro de una transferencia.
  • El punto de conexión predeterminado está disponible en el nivel de dispositivo y no está definido en ninguna interfaz del dispositivo.
  • El punto de conexión predeterminado está activo en cuanto se establece una conexión entre el host y el dispositivo. Está activo incluso antes de seleccionar una configuración.
  • El tamaño máximo del paquete del punto de conexión predeterminado depende de la velocidad del bus del dispositivo. Baja velocidad, 8 bytes; full y alta velocidad, 64 bytes; SuperSpeed, 512 bytes.

Diseño de una transferencia de control

Dado que las transferencias de control son transferencias de alta prioridad, el host reserva cierta cantidad de ancho de banda en el bus. Para dispositivos de velocidad baja y completa, el 10 % del ancho de banda; 20% para dispositivos de transferencia alta y SuperSpeed. Ahora, echemos un vistazo al diseño de una transferencia de control.

Diagrama de una transferencia de control USB.

Una transferencia de control se divide en tres transacciones: configuración de transacción, transacción de datos y transacción de estado. Cada transacción contiene tres tipos de paquetes: paquete de token, paquete de datos y paquete de protocolo de enlace.

Algunos campos son comunes a todos los paquetes. Estos campos son:

  • Campo de sincronización que indica el inicio del paquete.
  • Identificador de paquete (PID) que indica el tipo de paquete, la dirección de la transacción y, en el caso de un paquete de protocolo de enlace, indica que la transacción se ha realizado correctamente o no.
  • El campo EOP indica el final del paquete.

Otros campos dependen del tipo de paquete.

Paquete de token

Cada transacción de instalación comienza con un paquete de token. Esta es la estructura del paquete. El host siempre envía el paquete de token.

Diagrama de un diseño de paquete de token.

El valor de PID indica el tipo del paquete de token. Estos son los valores posibles:

  • SETUP: indica el inicio de una transacción de instalación en una transferencia de control.
  • IN: indica que el host solicita datos del dispositivo (caso de lectura).
  • OUT: indica que el host envía datos al dispositivo (caso de escritura).
  • SOF: indica el inicio del marco. Este tipo de paquete de token contiene un número de fotograma de 11 bits. El host envía el paquete SOF. La frecuencia con la que se envía este paquete depende de la velocidad del autobús. Para la velocidad completa, el host envía el paquete cada 1 milisegundos; cada 125 microsegundos en un autobús de alta velocidad.

Paquete de datos

Inmediatamente después del paquete de token se encuentra el paquete de datos que contiene la carga. El número de bytes que puede contener cada paquete de datos depende del tamaño máximo del paquete del punto de conexión predeterminado. El paquete de datos se puede enviar mediante el host o el dispositivo, dependiendo de la dirección de la transferencia.

Diagrama de un diseño de paquete de datos.

Paquete de protocolo de enlace

Inmediatamente después del paquete de datos se encuentra el paquete de protocolo de enlace. El PID del paquete indica si el host o el dispositivo recibieron o no el paquete. El paquete de protocolo de enlace puede ser enviado por el host o el dispositivo, dependiendo de la dirección de la transferencia.

Diagrama de un diseño de paquete de protocolo de enlace.

Puede ver la estructura de transacciones y paquetes mediante cualquier analizador USB, como Beagle, Ellisys, analizadores del protocolo USB LeCroy. Un dispositivo analizador muestra cómo se envían o reciben los datos de un dispositivo USB a través de la conexión. En este ejemplo, vamos a examinar algunos seguimientos capturados por un analizador USB LeCroy. Este ejemplo es solo para información. No es una aprobación de Microsoft.

Configuración de la transacción

El host siempre inicia una transferencia de control. Para ello, envía una transacción de configuración. Esta transacción contiene un paquete de token denominado token de instalación seguido de un paquete de datos de 8 bytes. Esta captura de pantalla muestra una transacción de configuración de ejemplo.

Captura de pantalla de un seguimiento de una transacción de configuración.

En el seguimiento anterior, el host inicia (indicado por H}) la transferencia de control mediante el envío del paquete de token de instalación n.º 434. Observe que el PID especifica SETUP que indica un token de configuración. El PID va seguido de la dirección del dispositivo y la dirección del punto de conexión. Para las transferencias de control, esa dirección del punto de conexión siempre es 0.

A continuación, el host envía el paquete de datos #435. El PID es DATA0 y ese valor se usa para la secuenciación de paquetes (que se va a analizar). El PID va seguido de 8 bytes que contiene la información principal sobre esta solicitud. Esos 8 bytes indican el tipo de solicitud y el tamaño del búfer en el que el dispositivo escribirá su respuesta.

Todos los bytes se reciben en orden inverso. Como se describe en la sección 9.3, vemos estos campos y valores:

Campo Size Value Descripción
bmRequestType (vea 9.3.1 bmRequestType) 1 0x80 La dirección de transferencia de datos es desde el dispositivo al host (D7 es 1)

La solicitud es una solicitud estándar (D6... D5 es 0)

El destinatario de la solicitud es EL DISPOSITIVO (D4 es 0)
bRequest (consulte la sección 9.3.2 y la tabla 9-4) 1 0x06 El tipo de solicitud es GET_DESCRIPTOR.
wValue (vea la tabla 9-5) 2 0x0100 El valor de solicitud indica que el tipo de descriptor es DEVICE.
wIndex (consulte la sección 9.3.4) 2 0x0000 La dirección es del host al dispositivo (D7 es 1)

El número de punto de conexión es 0.
wLength (consulte la sección 9.3.5) 2 0x0012 La solicitud es recuperar 18 bytes.

Por lo tanto, podemos concluir que en esta transferencia de control (lectura), el host envía una solicitud para recuperar el descriptor de dispositivo y especifica 18 bytes como longitud de transferencia para contener ese descriptor. La forma en que el dispositivo envía esos 18 bytes depende de la cantidad de datos que el punto de conexión predeterminado puede enviar en una transacción. Esa información se incluye en el descriptor de dispositivo devuelto por el dispositivo en la transacción de datos.

En respuesta, el dispositivo envía un paquete de protocolo de enlace (#436 indicado por D)*). Observe que el valor piD es ACK (paquete ACK). Esto indica que el dispositivo reconoció la transacción.

Transacción de datos

Ahora, veamos lo que devuelve el dispositivo en respuesta a la solicitud. Los datos reales se transfieren en una transacción de datos.

Este es el seguimiento de la transacción de datos.

Captura de pantalla que muestra un seguimiento de una transacción de datos de ejemplo.

Al recibir el paquete ACK, el host inicia la transacción de datos. Para iniciar la transacción, envía un paquete de token (#450) con dirección como IN (denominado token IN).

En respuesta, el dispositivo envía un paquete de datos (451) que sigue al token IN. Este paquete de datos contiene el descriptor de dispositivo real. El primer byte indica la longitud del descriptor de dispositivo, 18 bytes (0x12). El último byte de este paquete de datos indica el tamaño máximo de paquete admitido por el punto de conexión predeterminado. En este caso, vemos que el dispositivo puede enviar 8 bytes a la vez a través de su punto de conexión predeterminado.

Nota:

El tamaño máximo del paquete del punto de conexión predeterminado depende de la velocidad del dispositivo. El punto de conexión predeterminado de un dispositivo de alta velocidad es de 64 bytes; El dispositivo de baja velocidad es de 8 bytes.

El host confirma la transacción de datos enviando un paquete ACK (#452) al dispositivo.

Vamos a calcular la cantidad de datos devueltos. En el campo wLength del paquete de datos (435) en la transacción de instalación, el host solicitó 18 bytes. En la transacción de datos, vemos que solo se recibieron los primeros 8 bytes del descriptor de dispositivo del dispositivo. Por lo tanto, ¿cómo recibe el host la información almacenada en los 10 bytes restantes? El dispositivo lo hace en dos transacciones: 8 bytes y, a continuación, dura 2 bytes.

Ahora que el host conoce el tamaño máximo de paquete del punto de conexión predeterminado, el host inicia una nueva transacción de datos y solicita la siguiente parte en función del tamaño del paquete.

Esta es la siguiente transacción de datos:

Captura de pantalla que muestra un seguimiento de la nueva transacción de datos.

El host inicia la transacción de datos anterior enviando un token IN (#463) y solicitando los siguientes 8 bytes desde el dispositivo. El dispositivo responde con un paquete de datos (464) que contiene los siguientes 8 bytes del descriptor de dispositivo.

Al recibir los 8 bytes, el host envía un paquete ACK (#465) al dispositivo.

A continuación, el host solicita los últimos 2 bytes en otra transacción de datos de la siguiente manera:

Captura de pantalla que muestra un seguimiento de la nueva transacción de datos de ejemplo en la que el host solicita los últimos 2 bytes.

Por lo tanto, vemos que para transferir 18 bytes desde el dispositivo al host, el host realiza un seguimiento del número de bytes transferidos e iniciados tres transacciones de datos (8+8+2).

Nota:

Observe el PID de los paquetes de datos en las transacciones de datos 19, 23, 26. El PID se alterna entre DATA0 y DATA1. Esta secuencia se denomina alternancia de datos. En los casos en los que hay varias transacciones de datos, la alternancia de datos se usa para comprobar la secuencia de paquetes. Este método garantiza que los paquetes de datos no están duplicados ni perdidos.

Al asignar los paquetes de datos consolidados a la estructura del descriptor de dispositivo (consulte la tabla 9-8), vemos estos campos y valores:

Campo Size Value Descripción
BLength 1 0x12 Longitud del descriptor de dispositivo, que es de 18 bytes.
bDescriptorType 1 0x01 El tipo de descriptor es device.
bcdUSB 2 0x0100 El número de versión de especificación es 1.00.
bDeviceClass 1 0x00 La clase de dispositivo es 0. Cada interfaz de la configuración tiene la información de clase.
bDeviceSubClass 1 0x00 La subclase es 0 porque la clase de dispositivo es 0.
bProtocol 1 0x00 El protocolo es 0. Este dispositivo no usa ningún protocolo específico de clase.
bMaxPacketSize0 1 0x08 El tamaño máximo de paquete del punto de conexión es de 8 bytes.
idVendor 2 0x0562 Telex Communications.
idProduct 2 0x0002 Micrófono USB.
bcdDevice 2 0x0100 Indica el número de versión del dispositivo.
iManufacturer 1 0x01 Cadena del fabricante.
iProduct 1 0x02 Cadena del producto.
iSerialNumber 1 0x03 Número de serie.
bNumConfigurations 1 0x01 Número de configuraciones.

Al examinar esos valores, tenemos información preliminar sobre el dispositivo. El dispositivo es un micrófono USB de baja velocidad. El tamaño máximo del paquete del punto de conexión predeterminado es de 8 bytes. El dispositivo admite una configuración.

Transacción de estado

Por último, el host completa la transferencia de control iniciando la última transacción: transacción de estado.

Captura de pantalla de un seguimiento de una transacción de datos de ejemplo.

El host inicia la transacción con un paquete de token OUT (#481). El propósito de este paquete es comprobar que el dispositivo envió todos los datos solicitados. No hay ningún paquete de datos enviado en esta transacción de estado. El dispositivo responde con un paquete ACK. Si se produce un error, el PID podría haber sido NAK o STALL.

Modelos de controladores

Requisitos previos

Antes de que el controlador cliente pueda enumerar canalizaciones, asegúrese de que se cumplen estos requisitos:

  • El controlador cliente debe haber creado el objeto de dispositivo de destino USB de 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.

Controlador cliente kmdf

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

Controlador de cliente UMDF

Un controlador de cliente UMDF debe obtener un puntero IWDFUsbTargetDevice consultando el objeto de dispositivo de destino de la plataforma. Para obtener más información, consulte "IPnpCallbackHardware implementation and USB-specific tasks" (Implementación de IPnpCallbackHardware y tareas específicas de USB) en Descripción de la estructura de código del controlador de cliente USB (UMDF).

El aspecto más importante para una transferencia de control es dar formato al token de instalación de forma adecuada. Antes de enviar la solicitud, recopile este conjunto de información:

  • Dirección de la solicitud: host al dispositivo o dispositivo que se va a hospedar.
  • Destinatario de la solicitud: dispositivo, interfaz, punto de conexión u otro.
  • Categoría de solicitud: estándar, clase o proveedor.
  • Tipo de solicitud, como una solicitud de GET_DESCRIPTPOR. Para obtener más información, consulte la sección 9.5 en la especificación USB.
  • valores wValue y wIndex . Esos valores dependen del tipo de solicitud.

Puede obtener toda esa información de la especificación USB oficial.

Si va a escribir un controlador UMDF, obtenga el archivo de encabezado, Usb_hw.h del controlador de ejemplo umDF para el kit de aprendizaje USB Fx2 de OSR. Este archivo de encabezado contiene macros y estructura útiles para dar formato al paquete de instalación para la transferencia de control.

Todos los controladores UMDF deben comunicarse con un controlador en modo kernel para enviar y recibir datos de los dispositivos. En el caso de un controlador UMDF USB, el controlador en modo kernel siempre es el controlador proporcionado por Microsoft WinUSB (Winusb.sys).

Cada vez que un controlador UMDF realiza una solicitud para la pila de controladores USB, el administrador de E/S de Windows envía la solicitud a WinUSB. Después de recibir la solicitud, WinUSB procesa la solicitud o la reenvía a la pila del controlador USB.

Métodos definidos por Microsoft para enviar solicitudes de transferencia de control

Un controlador de cliente USB en el host inicia la mayoría de las solicitudes de control para obtener información sobre el dispositivo, configurar el dispositivo o enviar comandos de control de proveedor. Todas esas solicitudes se pueden clasificar en:

  • Las solicitudes estándar se definen en la especificación USB. El propósito de enviar solicitudes estándar es obtener información sobre el dispositivo, sus configuraciones, interfaces y puntos de conexión. El destinatario de cada solicitud depende del tipo de solicitud. El destinatario puede ser el dispositivo, una interfaz o un punto de conexión.

    Nota:

    El destino de cualquier transferencia de control siempre es el punto de conexión predeterminado. El destinatario es la entidad del dispositivo cuya información (descriptor, estado, etc.) está interesado en el host.

    Las solicitudes se pueden clasificar aún más en: solicitudes de configuración, solicitudes de características y solicitudes de estado.

    • Las solicitudes de configuración se envían para obtener información del dispositivo para que el host pueda configurarla, como una solicitud de GET_DESCRIPTOR. Estas solicitudes también pueden escribir solicitudes enviadas por el host para establecer una configuración determinada o una configuración alternativa en el dispositivo.
    • El controlador cliente envía solicitudes de características para habilitar o deshabilitar determinadas configuraciones de dispositivo booleanas compatibles con el dispositivo, la interfaz o un punto de conexión.
    • Las solicitudes de estado permiten que el host obtenga o establezca los bits de estado definidos por USB de un dispositivo, punto de conexión o interfaz.

    Para obtener más información, vea sección 9.4 en especificación USB, versión 2.0. Los tipos de solicitud estándar se definen el archivo de encabezado, Usbspec.h.

  • Las solicitudes de clase se definen mediante una especificación de clase de dispositivo específica.

  • El proveedor proporciona solicitudes de proveedor y dependen de las solicitudes admitidas por el dispositivo.

La pila USB proporcionada por Microsoft controla toda la comunicación de protocolo con el dispositivo, como se muestra en los seguimientos anteriores. El controlador expone interfaces de controlador de dispositivo (DDIs) que permiten a un controlador cliente enviar transferencias de control de muchas maneras. Si el controlador cliente es un controlador de Windows Driver Foundation (WDF), puede llamar a rutinas directamente para enviar los tipos comunes de solicitudes de control. WDF admite transferencias de control intrínsecamente para KMDF y UMDF.

Ciertos tipos de solicitudes de control no se exponen a través de WDF. Para esas solicitudes, el controlador cliente puede usar el modelo híbrido de WDF. Este modelo permite al controlador de cliente compilar y dar formato a las solicitudes de estilo URB de WDM y, a continuación, enviar esas solicitudes mediante objetos de marco de WDF. El modelo híbrido solo se aplica a los controladores en modo kernel.

Para los controladores UMDF:

Use las macros auxiliares y la estructura definidas en usb_hw.h. Este encabezado se incluye con el controlador de ejemplo UMDF para el kit de aprendizaje USB Fx2 de OSR.

Use esta tabla para determinar la mejor manera de enviar solicitudes de control a la pila de controladores USB. Si no puede ver esta tabla, consulte la tabla de este artículo.

Si desea enviar una solicitud de control a... Para un controlador KMDF... Para un controlador UMDF... Para un controlador WDM, cree una estructura URB (rutina auxiliar)
CLEAR_FEATURE: deshabilite ciertas opciones de características en el dispositivo, sus configuraciones, interfaces y puntos de conexión. Consulte la sección 9.4.1 en la especificación USB.
  1. Declare un paquete de instalación. Consulte la estructura WDF_USB_CONTROL_SETUP_PACKET .
  2. Inicialice el paquete de instalación llamando a WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE.
  3. Especifique un valor de destinatario definido en WDF_USB_BMREQUEST_RECIPIENT.
  4. Especifique el selector de características (wValue). Consulte USB_FEATURE_XXX constantes en Usbspec.h. Consulte también la tabla 9-6 en la especificación USB.
  5. Establezca SetFeature enFALSE.
  6. Envíe la solicitud llamando a WdfUsbTargetDeviceSendControlTransferSynchronously o WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Declare un paquete de instalación. Consulte la estructura de WINUSB_CONTROL_SETUP_PACKET declarada en usb_hw.h.
  2. Inicialice el paquete de instalación llamando a la macro auxiliar, WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE, definida en usb_hw.h.
  3. Especifique un valor de destinatario definido en WINUSB_BMREQUEST_RECIPIENT.
  4. Especifique el selector de características (wValue). Consulte USB_FEATURE_XXX constantes en Usbspec.h. Consulte también la tabla 9-6 en la especificación USB.
  5. Establezca SetFeature enFALSE.
  6. Compile la solicitud asociando el paquete de instalación inicializado con el objeto de solicitud de marco y el búfer de transferencia llamando al método IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  7. Envíe la solicitud llamando al método IWDFIoRequest::Send .
_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE

URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE

URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT

URB_FUNCTION_CLEAR_FEATURE_TO_OTHER
GET_CONFIGURATION: obtenga la configuración USB actual. Consulte la sección 9.4.2 en la especificación USB. KMDF selecciona la primera configuración de forma predeterminada. Para recuperar el número de configuración definido por el dispositivo:

  1. Dé formato a un WDF_USB_CONTROL_SETUP_PACKET y establezca su miembro bRequesten USB_REQUEST_GET_CONFIGURATION.
  2. Envíe la solicitud llamando a WdfUsbTargetDeviceSendControlTransferSynchronously o WdfUsbTargetDeviceFormatRequestForControlTransfer.
UMDF selecciona la primera configuración de forma predeterminada. Para recuperar el número de configuración definido por el dispositivo:

  1. Declare un paquete de instalación. Consulte la estructura de WINUSB_CONTROL_SETUP_PACKET declarada en usb_hw.h.
  2. Inicialice el paquete de instalación llamando a la macro auxiliar, WINUSB_CONTROL_SETUP_PACKET_INIT, definida en usb_hw.h.
  3. Especifique BmRequestToDevice como dirección, BmRequestToDevice como destinatario y USB_REQUEST_GET_CONFIGURATION como solicitud.
  4. Compile la solicitud asociando el paquete de instalación inicializado con el objeto de solicitud de marco y el búfer de transferencia llamando al método IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  5. Envíe la solicitud llamando al método IWDFIoRequest::Send .
  6. Reciba el número de configuración en el búfer de transferencia. Acceda a ese búfer mediante una llamada a métodos IWDFMemory .
_URB_CONTROL_GET_CONFIGURATION_REQUEST

URB_FUNCTION_GET_CONFIGURATION
GET_DESCRIPTOR: obtener descriptores de dispositivo, configuración, interfaz y punto de conexión. Consulte la sección 9.4.3 en la especificación USB.

Para obtener más información, consulte Descriptores USB.
Llame a estos métodos:

Llame a estos métodos:

_URB_CONTROL_DESCRIPTOR_REQUEST

(UsbBuildGetDescriptorRequest)

URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE

URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT

URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE
GET_INTERFACE: obtener la configuración alternativa actual de una interfaz. Consulte la sección 9.4.4 en la especificación USB.

  1. Obtenga un identificador WDFUSBINTERFACE para el objeto de interfaz de destino llamando al método WdfUsbTargetDeviceGetInterface .
  2. Llame al método WdfUsbInterfaceGetConfiguredSettingIndex .
  1. Obtiene un puntero IWDFUsbInterface al objeto de interfaz de destino.
  2. Llame al método IWDFUsbInterface::GetConfiguredSettingIndex .
_URB_CONTROL_GET_INTERFACE_REQUEST

URB_FUNCTION_GET_INTERFACE
GET_STATUS: obtiene los bits de estado de un dispositivo, un punto de conexión o una interfaz. Consulte la sección 9.4.5. en la especificación USB.
  1. Declare un paquete de instalación. Consulte la estructura WDF_USB_CONTROL_SETUP_PACKET .
  2. Inicialice el paquete de instalación llamando a WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.
  3. Especifique el valor del destinatario definido en WDF_USB_BMREQUEST_RECIPIENT.
  4. Especifique el estado que desea obtener: dispositivo, interfaz o punto de conexión (wIndex).
  5. Envíe la solicitud llamando a WdfUsbTargetDeviceSendControlTransferSynchronously o WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Declare un paquete de instalación. Consulte la estructura de WINUSB_CONTROL_SETUP_PACKET declarada en usb_hw.h.
  2. Inicialice el paquete de instalación llamando a la macro auxiliar, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS, definida en usb_hw.h.
  3. Especifique un valor de destinatario definido en WINUSB_BMREQUEST_RECIPIENT.
  4. Especifique el estado que desea obtener: dispositivo, interfaz o punto de conexión (wIndex).
  5. Compile la solicitud asociando el paquete de instalación inicializado con el objeto de solicitud de marco y el búfer de transferencia llamando al método IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  6. Envíe la solicitud llamando al método IWDFIoRequest::Send .
  7. Reciba el valor de estado en el búfer de transferencia. Acceda a ese búfer mediante una llamada a métodos IWDFMemory .
  8. Para determinar si el estado indica la reactivación remota autopropulsado, use los valores definidos en la enumeración WINUSB_DEVICE_TRAITS :
_URB_CONTROL_GET_STATUS_REQUEST

(UsbBuildGetStatusRequest)

URB_FUNCTION_GET_STATUS_FROM_DEVICE

URB_FUNCTION_GET_STATUS_FROM_INTERFACE

URB_FUNCTION_GET_STATUS_FROM_ENDPOINT

URB_FUNCTION_GET_STATUS_FROM_OTHER.
SET_ADDRESS: consulte la sección 9.4.6 en especificación USB. Esta solicitud se controla mediante la pila del controlador USB; el controlador cliente no puede realizar esta operación. Esta solicitud se controla mediante la pila del controlador USB; el controlador cliente no puede realizar esta operación. Esta solicitud se controla mediante la pila del controlador USB; el controlador cliente no puede realizar esta operación.
SET_CONFIGURATION: establezca una configuración. Consulte la sección 9.4.7 en especificación USB.

Para obtener más información, consulte Cómo seleccionar una configuración para un dispositivo USB.
De forma predeterminada, KMDF selecciona la configuración predeterminada y la primera opción alternativa en cada interfaz. El controlador cliente puede cambiar la configuración predeterminada llamando al método WdfUsbTargetDeviceSelectConfigType y especificando WdfUsbTargetDeviceSelectConfigTypeUrb como opción de solicitud. A continuación, debe dar formato a un URB para esta solicitud y enviarlo a la pila de controladores USB. De forma predeterminada, UMDF selecciona la configuración predeterminada y la primera configuración alternativa en cada interfaz. El controlador cliente no puede cambiar la configuración. _URB_SELECT_CONFIGURATION

(USBD_SelectConfigUrbAllocateAndBuild)

URB_FUNCTION_SELECT_CONFIGURATION
SET_DESCRIPTOR: actualice un dispositivo, una configuración o un descriptor de cadena existentes. Consulte la sección 9.4.8 en especificación USB.

Esta solicitud no se usa normalmente. Sin embargo, la pila del controlador USB acepta dicha solicitud del controlador cliente.
  1. Asigne y compile un URB para la solicitud.
  2. Especifique la información de transferencia en una estructura de _URB_CONTROL_DESCRIPTOR_REQUEST .
  3. Envíe la solicitud llamando a WdfUsbTargetDeviceFormatRequestForUrb o WdfUsbTargetDeviceSendUrbSynchronously .
  1. Declare un paquete de instalación. Consulte la estructura de WINUSB_CONTROL_SETUP_PACKET declarada en usb_hw.h.
  2. Especifique la información de transferencia según la especificación USB.
  3. Compile la solicitud asociando el paquete de instalación inicializado con el objeto de solicitud de marco y el búfer de transferencia llamando al método IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  4. Envíe la solicitud llamando al método IWDFIoRequest::Send .
_URB_CONTROL_DESCRIPTOR_REQUEST

URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE

URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT

URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE
SET_FEATURE: habilite ciertas opciones de características en el dispositivo, sus configuraciones, interfaces y puntos de conexión. Consulte la sección 9.4.9 en la especificación USB.
  1. Declare un paquete de instalación. Consulte la estructura WDF_USB_CONTROL_SETUP_PACKET .
  2. Inicialice el paquete de instalación llamando a WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE.
  3. Especifique el valor del destinatario (dispositivo, interfaz, punto de conexión) definido en WDF_USB_BMREQUEST_RECIPIENT.
  4. Especifique el selector de características (wValue). Consulte USB_FEATURE_XXX constantes en Usbspec.h. Consulte también la tabla 9-6 en la especificación USB.
  5. Establezca SetFeature en TRUE.
  6. Envíe la solicitud llamando a WdfUsbTargetDeviceSendControlTransferSynchronously o WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Declare un paquete de instalación. Consulte la estructura de WINUSB_CONTROL_SETUP_PACKET declarada en usb_hw.h.
  2. Inicialice el paquete de instalación llamando a la macro auxiliar, WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE, definida en usb_hw.h.
  3. Especifique un valor de destinatario definido en WINUSB_BMREQUEST_RECIPIENT.
  4. Especifique el selector de características (wValue). Consulte USB_FEATURE_XXX constantes en Usbspec.h. Consulte también la tabla 9-6 en la especificación USB.
  5. Establezca SetFeature en TRUE.
  6. Compile la solicitud asociando el paquete de instalación inicializado con el objeto de solicitud de marco y el búfer de transferencia llamando al método IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  7. Envíe la solicitud llamando al método IWDFIoRequest::Send .
_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

URB_FUNCTION_SET_FEATURE_TO_DEVICE

URB_FUNCTION_SET_FEATURE_TO_INTERFACE

URB_FUNCTION_SET_FEATURE_TO_ENDPOINT

URB_FUNCTION_SET_FEATURE_TO_OTHER
SET_INTERFACE: cambia la configuración alternativa en una interfaz. Consulte la sección 9.4.9 en la especificación USB.

Para obtener más información, vea Cómo seleccionar una configuración alternativa en una interfaz USB.
WdfUsbTargetDeviceSelectConfig
  1. Obtenga un identificador WDFUSBINTERFACE para el objeto de interfaz de destino.
  2. Llame al método WdfUsbInterfaceSelectSetting .
  1. Obtiene un puntero IWDFUsbInterface al objeto de interfaz de destino.
  2. Llame al método IWDFUsbInterface::SelectSetting .
_URB_SELECT_INTERFACE

(USBD_SelectInterfaceUrbAllocateAndBuild)

URB_FUNCTION_SELECT_INTERFACE
SYNC_FRAME: establezca y obtenga y el número de fotograma de sincronización del punto de conexión. Consulte la sección 9.4.10 en la especificación USB. Esta solicitud se controla mediante la pila de controladores USB; el controlador cliente no puede realizar esta operación. Esta solicitud se controla mediante la pila de controladores USB; el controlador cliente no puede realizar esta operación. Esta solicitud se controla mediante la pila de controladores USB; el controlador cliente no puede realizar esta operación.
Para las solicitudes específicas de clase de dispositivo y los comandos de proveedor.
  1. Declare un paquete de instalación. Consulte la estructura WDF_USB_CONTROL_SETUP_PACKET .
  2. Inicialice el paquete de instalación llamando a solicitudes específicas de WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS o WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR para comandos de proveedor.
  3. Especifique el valor del destinatario (dispositivo, interfaz, punto de conexión) definido en WDF_USB_BMREQUEST_RECIPIENT.
  4. Envíe la solicitud llamando a WdfUsbTargetDeviceSendControlTransferSynchronously o WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Declare un paquete de instalación. Consulte la estructura de WINUSB_CONTROL_SETUP_PACKET declarada en usb_hw.h.
  2. Inicialice el paquete de instalación llamando a la macro auxiliar, WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS o WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR, definida en usb_hw.h.
  3. Especifique la dirección (vea la enumeración WINUSB_BMREQUEST_DIRECTION ), el destinatario ( vea la enumeración WINUSB_BMREQUEST_RECIPIENT ) y la solicitud, como se describe en la clase o en la especificación de hardware.
  4. Compile la solicitud asociando el paquete de instalación inicializado con el objeto de solicitud de marco y el búfer de transferencia llamando al método IWDFUsbTargetDevice::FormatRequestForControlTransfer .
  5. Envíe la solicitud llamando al método IWDFIoRequest::Send .
  6. Reciba la información del dispositivo en el búfer de transferencia. Acceda a ese búfer mediante una llamada a los métodos IWDFMemory .
_URB_CONTROL_VENDOR_OR_CLASS_REQUEST

(UsbBuildVendorRequest)

URB_FUNCTION_VENDOR_DEVICE

URB_FUNCTION_VENDOR_INTERFACE

URB_FUNCTION_VENDOR_ENDPOINT

URB_FUNCTION_VENDOR_OTHER

URB_FUNCTION_CLASS_DEVICE

URB_FUNCTION_CLASS_INTERFACE

URB_FUNCTION_CLASS_ENDPOINT

URB_FUNCTION_CLASS_OTHER

Cómo enviar una transferencia de control para comandos de proveedor: KMDF

Este procedimiento muestra cómo un controlador cliente puede enviar una transferencia de control. En este ejemplo, el controlador cliente envía un comando de proveedor que recupera la versión de firmware del dispositivo.

  1. Declare una constante para el comando de proveedor. Estudie la especificación de hardware y determine el comando de proveedor que desea usar.

  2. Declare una estructura de WDF_MEMORY_DESCRIPTOR e inicialícela llamando a la macro WDF_MEMORY_DESCRIPTOR_INIT_BUFFER . Esta estructura recibirá la respuesta del dispositivo después de que el controlador USB complete la solicitud.

  3. En función de si envía la solicitud de forma sincrónica o asincrónica, especifique las opciones de envío:

    • Si envía la solicitud de forma sincrónica llamando a WdfUsbTargetDeviceSendControlTransferSynchronously, especifique un valor de tiempo de espera. Ese valor es importante porque sin un tiempo de espera, puede bloquear el subproceso indefinidamente.

      Para ello, declare una estructura de WDF_REQUEST_SEND_OPTIONS e inicialícela llamando a la macro WDF_REQUEST_SEND_OPTIONS_INIT . Especifique la opción como WDF_REQUEST_SEND_OPTION_TIMEOUT.

      A continuación, establezca el valor de tiempo de espera llamando a la macro WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT .

    • Si va a enviar la solicitud de forma asincrónica, implemente una rutina de finalización. Libere todos los recursos asignados en la rutina de finalización.

  4. Declare una estructura de WDF_USB_CONTROL_SETUP_PACKET para que contenga el token de instalación y dé formato a la estructura. Para ello, llame a la macro WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR para dar formato al paquete de instalación. En la llamada, especifique la dirección de la solicitud, el destinatario, las opciones de solicitud enviadas (inicializadas en el paso3) y la constante del comando vendor.

  5. Envíe la solicitud llamando a WdfUsbTargetDeviceSendControlTransferSynchronously o WdfUsbTargetDeviceFormatRequestForControlTransfer.

  6. Compruebe el valor NTSTATUS devuelto por el marco e inspeccione el valor recibido.

Este ejemplo de código envía una solicitud de transferencia de control a un dispositivo USB para recuperar su versión de firmware. La solicitud se envía de forma sincrónica y el controlador cliente especifica un valor de tiempo de espera relativo de 5 segundos (en unidades de 100 nanosegundos). El controlador almacena la respuesta recibida en el contexto del dispositivo definido por el controlador.

enum {
    USBFX2_GET_FIRMWARE_VERSION = 0x1,
....

} USBFX2_VENDOR_COMMANDS; 

#define WDF_TIMEOUT_TO_SEC              ((LONGLONG) 1 * 10 * 1000 * 1000)  // defined in wdfcore.h

const __declspec(selectany) LONGLONG
            DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; 


typedef struct _DEVICE_CONTEXT
{

    ...
       union {
        USHORT      VersionAsUshort;
        struct {
            BYTE Minor;
            BYTE Major;
        } Version;
    } Firmware; // Firmware version.

} DEVICE_CONTEXT, *PDEVICE_CONTEXT;


__drv_requiresIRQL(PASSIVE_LEVEL)
VOID  GetFirmwareVersion(
    __in PDEVICE_CONTEXT DeviceContext
)
{
    NTSTATUS                        status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    USHORT                          firmwareVersion;
    WDF_MEMORY_DESCRIPTOR           memoryDescriptor;

    PAGED_CODE();

    firmwareVersion = 0;

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, (PVOID) &firmwareVersion, sizeof(firmwareVersion));

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );

    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestDeviceToHost,       // Direction of the request
                                        BmRequestToDevice,           // Recipient
                                        USBFX2_GET_FIRMWARE_VERSION, // Vendor command
                                        0,                           // Value
                                        0);                          // Index 

    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                        DeviceContext->UsbDevice,
                                        WDF_NO_HANDLE,               // Optional WDFREQUEST
                                        &sendOptions,
                                        &controlSetupPacket,
                                        &memoryDescriptor,           // MemoryDescriptor
                                        NULL);                       // BytesTransferred 

    if (!NT_SUCCESS(status)) 
    {
        KdPrint(("Device %d: Failed to get device firmware version 0x%x\n", DeviceContext->DeviceNumber, status));
        TraceEvents(DeviceContext->DebugLog,
                    TRACE_LEVEL_ERROR,
                    DBG_RUN,
                    "Device %d: Failed to get device firmware version 0x%x\n",
                    DeviceContext->DeviceNumber,
                    status);
    }
    else 
    {
        DeviceContext->Firmware.VersionAsUshort = firmwareVersion;
        TraceEvents(DeviceContext->DebugLog,
                    TRACE_LEVEL_INFORMATION,
                    DBG_RUN,
                    "Device %d: Get device firmware version : 0x%x\n",
                    DeviceContext->DeviceNumber,
                    firmwareVersion);
    }

    return;
}

Cómo enviar una transferencia de control para GET_STATUS: UMDF

Este procedimiento muestra cómo un controlador cliente puede enviar una transferencia de control para un comando GET_STATUS. El destinatario de la solicitud es el dispositivo y la solicitud obtiene información en bits D1-D0. Para obtener más información, vea la figura 9-4 en la especificación USB.

  1. Incluya el archivo de encabezado Usb_hw.h disponible con el controlador de ejemplo UMDF para OSR USB Fx2 Learning Kit.

  2. Declare una estructura de WINUSB_CONTROL_SETUP_PACKET .

  3. Inicialice el paquete de instalación llamando a la macro auxiliar WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.

  4. Especifique BmRequestToDevice como destinatario.

  5. Especifique 0 en el valor índice .

  6. Llame al método auxiliar SendControlTransferSynchronousmente para enviar la solicitud de forma sincrónica.

    El método auxiliar compila la solicitud asociando el paquete de instalación inicializado con el objeto de solicitud de marco y el búfer de transferencia llamando al método IWDFUsbTargetDevice::FormatRequestForControlTransfer . A continuación, el método auxiliar envía la solicitud llamando al método IWDFIoRequest::Send . Una vez devuelto el método, inspeccione el valor devuelto.

  7. Para determinar si el estado indica la activación remota automática, use estos valores definidos en la enumeración WINUSB_DEVICE_TRAITS :

En este ejemplo de código se envía una solicitud de transferencia de control para obtener el estado del dispositivo. En el ejemplo se envía la solicitud de forma sincrónica llamando a un método auxiliar denominado SendControlTransferSynchronousmente.

HRESULT
CDevice::GetDeviceStatus ()
{

    HRESULT hr = S_OK;

    USHORT deviceStatus;
    ULONG bytesTransferred;

    TraceEvents(TRACE_LEVEL_INFORMATION,
                DRIVER_ALL_INFO,
                "%!FUNC!: entry");

    // Setup the control packet.

    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(
                                      &setupPacket,
                                      BmRequestToDevice,
                                      0);

    hr = SendControlTransferSynchronously(
                 &(setupPacket.WinUsb),
                 & deviceStatus,
                 sizeof(USHORT),
                 &bytesReturned
                );

     if (SUCCEEDED(hr))
    {
        if (deviceStatus & USB_GETSTATUS_SELF_POWERED)
        {
             m_Self_Powered = true;
        } 
        if (deviceStatus & USB_GETSTATUS_REMOTE_WAKEUP_ENABLED)
        {
             m_remote_wake-enabled = true;
        }
    }

    return hr;
 }

En el ejemplo de código siguiente se muestra la implementación del método auxiliar denominado SendControlTransferSynchronously. Este método envía una solicitud de forma sincrónica.

HRESULT
CDevice::SendControlTransferSynchronously(
    _In_ PWINUSB_SETUP_PACKET SetupPacket,
    _Inout_ PBYTE Buffer,
    _In_ ULONG BufferLength,
    _Out_ PULONG LengthTransferred
    )
{
    HRESULT hr = S_OK;
    IWDFIoRequest *pWdfRequest = NULL;
    IWDFDriver * FxDriver = NULL;
    IWDFMemory * FxMemory = NULL;
    IWDFRequestCompletionParams * FxComplParams = NULL;
    IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;

    *LengthTransferred = 0;

    hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface
                                    NULL, //pParentObject
                                    &pWdfRequest);

    if (SUCCEEDED(hr))
    {
        m_FxDevice->GetDriver(&FxDriver);

        hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,
                                                    BufferLength,
                                                    NULL,        //pCallbackInterface
                                                    pWdfRequest, //pParetObject
                                                    &FxMemory );
    }

    if (SUCCEEDED(hr))
    {
        hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest,
                                                                   SetupPacket,
                                                                   FxMemory,
                                                                   NULL); //TransferOffset
    }

    if (SUCCEEDED(hr))
    {
        hr = pWdfRequest->Send( m_pIUsbTargetDevice,
                                WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
                                0); //Timeout
    }

    if (SUCCEEDED(hr))
    {
        pWdfRequest->GetCompletionParams(&FxComplParams);

        hr = FxComplParams->GetCompletionStatus();
    }

    if (SUCCEEDED(hr))
    {
        HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams));
        WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI));

        WUDF_TEST_DRIVER_ASSERT( WdfUsbRequestTypeDeviceControlTransfer ==
                            FxUsbComplParams->GetCompletedUsbRequestType() );

        FxUsbComplParams->GetDeviceControlTransferParameters( NULL,
                                                             LengthTransferred,
                                                             NULL,
                                                             NULL );
    }

    SAFE_RELEASE(FxUsbComplParams);
    SAFE_RELEASE(FxComplParams);
    SAFE_RELEASE(FxMemory);

    pWdfRequest->DeleteWdfObject(); 
    SAFE_RELEASE(pWdfRequest);

    SAFE_RELEASE(FxDriver);

    return hr;
}

Si usa Winusb.sys como controlador de función para el dispositivo, puede enviar transferencias de control desde una aplicación. Para dar formato al paquete de instalación en WinUSB, use las macros y estructuras auxiliares de UMDF, que se describen en la tabla de este artículo. Para enviar la solicitud, llame a WinUsb_ControlTransfer función.