Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
En dispositivos USB 2.0 y anteriores, un punto final masivo puede enviar o recibir un único flujo de datos a través del punto final. En los dispositivos USB 3.0, el punto final masivo es capaz de enviar y recibir múltiples flujos de datos a través del punto final.
La pila de controladores USB proporcionada por Microsoft en Windows admite múltiples transmisiones. Esto permite que los controladores del cliente envíen solicitudes de E/S independientes a cada secuencia asociada con un punto final masivo en un dispositivo USB 3.0, sin serializar solicitudes a diferentes secuencias.
Para un controlador de cliente, una secuencia representa múltiples puntos finales lógicos con el mismo conjunto de características. Para enviar una solicitud a una secuencia específica, el controlador del cliente necesita un identificador para esa secuencia (similar al identificador de canalización de un punto final). La URB para solicitudes de E/S de transmisión es similar a la URB para solicitudes de E/S para puntos finales masivos. La única diferencia es el mango del tubo. Para enviar una solicitud de E/S a una secuencia, el controlador especifica un identificador de tubería en la secuencia.
Durante la configuración del dispositivo, el controlador del cliente envía una solicitud de configuración seleccionada y, opcionalmente, una solicitud de interfaz seleccionada. Estas solicitudes recuperan un conjunto de identificadores de canalización para los puntos finales definidos en la configuración de actividad de la interfaz. Para los puntos finales que reconocen la transmisión, el identificador de canalización del punto final se puede usar para enviar solicitudes de E/S a la secuencia predeterminada (la primera secuencia) hasta que el controlador abra la secuencia.
Si un controlador de cliente desea enviar solicitudes a secuencias distintas a la secuencia predeterminada, el controlador debe abrir y obtener identificadores para todas las secuencias. Para hacer esto, el controlador del cliente envía una solicitud de transmisión abierta especificando la cantidad de transmisiones a abrir. Una vez que un controlador de cliente ha terminado de usar transmisiones, el controlador puede optar por cerrarlas enviando una solicitud de cierre de transmisión.
Kernel Mode Driver Framework (KMDF) no admite de forma nativa transmisiones estáticas. Los controladores de cliente deben utilizar el modelo de controlador de Windows (WDM) para abrir y cerrar transmisiones. Los controladores de cliente de User-mode Driver Framework (UMDF) no pueden utilizar la función de transmisión estática.
Lo siguiente puede contener algunos comentarios denominados Controladores WDM. Estas instrucciones describen rutinas para un controlador de cliente USB basado en WDM que desea enviar solicitudes de transmisión.
Antes de que un controlador de cliente pueda abrir o cerrar una transmisión, el controlador debe tener:
1. Llame al método WdfUsbTargetDeviceCreateWithParameters. El método requiere la versión del protocolo del cliente USBD_CLIENT_CONTRACT_VERSION_602. Al especificar esta versión, el controlador del cliente debe cumplir con un conjunto de reglas.
Llame para recuperar el identificador WDFUSBDEVICE del objeto de dispositivo de destino USB del marco. El identificador es necesario para llamadas posteriores a la secuencia abierta. Normalmente, un controlador de cliente se registra en la rutina de devolución de llamada del evento EVT_WDF_DEVICE_PREPARE_HARDWARE del controlador.
Controlador WDM: llame a la rutina USBD_CreateHandle y obtenga el identificador USBD registrado por el controlador en la pila del controlador USB.
2. Configuró el dispositivo y obtuvo el identificador de tubería WDFUSBPIPE para el punto final masivo que admite la transmisión. Para obtener un identificador de tubería, llame al método WdfUsbInterfaceGetConfiguredPipe en la configuración alternativa actual de la interfaz en la configuración seleccionada.
Controlador WDM: obtiene el identificador de tubería USBD enviando una solicitud de configuración de selección o de interfaz de selección.
1. Determine si la pila de controladores USB subyacente y el controlador de host admiten la función de transmisión estática llamando al método WdfUsbTargetDeviceQueryUsbCapability. Normalmente, los controladores del cliente llaman a rutinas en la rutina de devolución de llamada del evento EVT_WDF_DEVICE_PREPARE_HARDWARE del controlador.
Controlador WDM: llama a la rutina USBD_QueryUsbCapability. Normalmente, un controlador consulta la función que se utilizará en la rutina del dispositivo de inicio del controlador (IRP_MN_START_DEVICE).
Provee la siguiente informacion:
Controlador WDM: pase el identificador USBD recuperado en la llamada anterior a USBD_CreateHandle.
Si un controlador cliente desea utilizar una función específica, primero debe consultar la pila de controladores USB subyacente para determinar si la pila de controladores y el controlador host admiten la función. Si la función es compatible, solo entonces el conductor debe enviar una solicitud para utilizarla. Ciertas solicitudes requieren URB, como la funcionalidad de transmisión que se analiza en el Paso 5. Para estas solicitudes, asegúrese de utilizar el mismo identificador para consultar la función y asignar la URB. Esto se debe a que la pila de controladores utiliza identificadores para realizar un seguimiento de las funciones compatibles que el controlador puede utilizar.
Por ejemplo, si se obtuvo USBD_HANDLE llamando a USBD_CreateHandle, la pila del controlador se consulta llamando a USBD_QueryUsbCapability y la URB se asigna llamando a USBD_UrbAllocate. Pase el mismo USBD_HANDLE en ambas llamadas.
Si llama a los métodos KMDF, WdfUsbTargetDeviceQueryUsbCapability y WdfUsbTargetDeviceCreateUrb, especifique el mismo identificador WDFUSBDEVICE para el objeto de destino del marco en estas llamadas a métodos.
2. Evalúe el valor NTSTATUS devuelto. Si la rutina se completa correctamente, se devuelve STATUS_SUCCESS y se admite la funcionalidad de transmisión estática. De lo contrario, el método devuelve el código de error apropiado.
3. Determine la cantidad de transmisiones que se abrirán. El número máximo de transmisiones que se pueden abrir está limitado por:
Para determinar la cantidad máxima de flujos, elija el menor de los dos valores admitidos por el controlador del host y el punto final.
4. Asigne una matriz de estructuras USBD_STREAM_INFORMATION de n elementos, donde n es el número de secuencias que se abrirán. El controlador del cliente es responsable de liberar esta matriz una vez que el controlador termina de usar la transmisión.
5. Asigne una URB para la solicitud de transmisión abierta llamando al método WdfUsbTargetDeviceCreateUrb. Si la llamada se completa correctamente, el método recupera el objeto de memoria WDF y la dirección de la estructura URB asignada por la pila del controlador USB.
Controlador WDM: llama a la rutina USBD_UrbAllocate.
6. Configure el formato URB de la solicitud de transmisión abierta. URB utiliza la estructura _URB_OPEN_STATIC_STREAMS para definir solicitudes. Para formatear una URB, necesita:
Para formatear una URB, llame a UsbBuildOpenStaticStreamsRequest y pase la información requerida como valores de parámetros. Asegúrese de que la cantidad de transmisiones especificadas en UsbBuildOpenStaticStreamsRequest no exceda la cantidad máxima de transmisiones admitidas.
7. Envíe la URB como un objeto de solicitud WDF llamando al método WdfRequestSend. Para enviar la solicitud de forma sincrónica, llame al método WdfUsbTargetDeviceSendUrbSynchronfully.
Controlador WDM: asocia la URB con el IRP y envía el IRP a la pila del controlador USB.
8. Una vez completada la solicitud, verifique el estado de la solicitud.Si falla la solicitud de la pila del controlador USB, el estado de la URB contiene el código de error relevante.
Si el estado de la solicitud (objeto de solicitud IRP o WDF) indica USBD_STATUS_SUCCESS, la solicitud se completó correctamente. Conjunto de estructuras USBD_STREAM_INFORMATION recibidas cuando se completa la verificación. La matriz se completa con información sobre la secuencia solicitada. La pila del controlador USB completa cada estructura de la matriz con información de flujo, como el identificador de recepción USBD_PIPE_HANDLE, el identificador de flujo y el tamaño máximo de transferencia numérica. La transmisión ahora puede transferir datos.
Para solicitudes de transmisión abierta, es necesario asignar URB y matrices. Una vez completada la solicitud de transmisión abierta, el controlador del cliente debe liberar la URB llamando al método WdfObjectDelete en el objeto de memoria WDF asociado. Si el controlador envía la solicitud de forma sincrónica llamando a WdfUsbTargetDeviceSendUrbSynchronfully, el objeto de memoria WDF debe liberarse después de que regrese el método. Si un controlador de cliente envía una solicitud de forma asincrónica llamando a WdfRequestSend, el controlador debe liberar el objeto de memoria WDF en la rutina de finalización implementada por el controlador asociada con la solicitud.
La matriz de flujo se puede liberar después de que el controlador del cliente haya terminado de usar el flujo, o se puede almacenar para solicitudes de E/S. En el ejemplo de código que se incluye a continuación, el controlador almacena una matriz de flujo en el contexto del dispositivo. El controlador libera el contexto del dispositivo antes de liberar el objeto del dispositivo.
Cómo transferir datos a una secuencia específica
Para enviar una solicitud de transferencia de datos a una secuencia específica, se requiere un objeto de solicitud WDF. Normalmente, los controladores del cliente no necesitan asignar objetos de solicitud WDF. Cuando el administrador de E/S recibe una solicitud de una aplicación, crea un IRP para la solicitud. El IRP fue interceptado por el marco. Luego, el marco asigna un objeto de solicitud WDF para representar el IRP. Luego, el marco pasa el objeto de solicitud WDF al controlador del cliente. Luego, el controlador del cliente puede asociar el objeto de solicitud con la URB de transferencia de datos y enviarlo a la pila del controlador USB.
Si un controlador de cliente no recibe un objeto de solicitud WDF del marco y desea enviar la solicitud de forma asincrónica, el controlador debe asignar un objeto de solicitud WDF llamando al método WdfRequestCreate. Formatee el nuevo objeto llamando a WdfUsbTargetPipeFormatRequestForUrb y envíe la solicitud llamando a WdfRequestSend.
En el caso síncrono, pasar el objeto de solicitud WDF es opcional.
Para transferir datos a una secuencia, se debe utilizar URB. La URB se debe formatear llamando a WdfUsbTargetPipeFormatRequestForUrb.
Las transmisiones no admiten los siguientes métodos WDF:
El siguiente procedimiento supone que el controlador del cliente recibe el objeto de solicitud del marco.
Controlador WDM: asigna una URB llamando a USBD_UrbAllocate y la formatea para transferencia masiva (consulte _URB_BULK_OR_INTERRUPT_TRANSFER). Para formatear una URB, puede llamar a UsbBuildInterruptOrBulkTransferRequest o formatear manualmente la estructura URB. Especifique el identificador de la secuencia en el miembro UrbBulkOrInterruptTransfer.PipeHandle de la URB.
El controlador del cliente puede cerrar la transmisión una vez que haya terminado de usarla. Sin embargo, cerrar la solicitud de transmisión es opcional. La pila del controlador USB cierra todas las transmisiones cuando el punto final asociado con la transmisión no está configurado. Los puntos finales se desconfiguran al seleccionar una configuración o interfaz alternativa, eliminar un dispositivo, etc. Si el controlador del cliente desea abrir una cantidad diferente de transmisiones, debe cerrarlas. Enviar una solicitud de cierre de transmisión:
1. Asigne la estructura URB llamando a WdfUsbTargetDeviceCreateUrb.
2. Configure el formato URB para cerrar la solicitud de transmisión. El miembro UrbPipeRequest de la estructura URB es la estructura _URB_PIPE_REQUEST. Complete sus miembros de la siguiente manera:
3. Envíe la URB como una solicitud WDF llamando a WdfRequestSend o WdfUsbTargetDeviceSendUrbSynchronfully.
El controlador de cierre solicita el cierre de todas las secuencias abiertas previamente por el controlador del cliente. El controlador del cliente no puede utilizar solicitudes para cerrar una secuencia específica en el punto final.
La pila del controlador USB realiza la verificación en la URB recibida. Para evitar errores de validación, haga lo siguiente:
En ocasiones, las transferencias hacia o desde un punto final pueden fallar. Estas fallas pueden deberse a condiciones de error en el punto final o en el controlador del host, como una condición de detención o detención. Para borrar la condición de error, el controlador del cliente primero cancela la transferencia pendiente y luego restablece la tubería asociada con el punto final. Para cancelar una transferencia pendiente, el controlador del cliente puede enviar una solicitud de cancelación de canalización. Para restablecer una tubería, el controlador del cliente debe enviar una solicitud de reinicio de tubería.
Para la transmisión, las solicitudes de cancelación y reinicio de canalización no se admiten para transmisiones individuales asociadas con el punto final masivo. Si falla una transferencia en una tubería de flujo específica, el controlador del host detendrá las transferencias en todas las demás tuberías para otras transmisiones. Para recuperarse de la condición de error, el controlador del cliente debe cancelar manualmente la transferencia a cada transmisión. un identificador de tubería para enviar una solicitud de reinicio de tubería al punto final masivo. Para esta solicitud, el controlador del cliente debe especificar el identificador de tubería del punto final en la estructura _URB_PIPE_REQUEST y configurar la función URB (Hdr.Function) en URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL.
El siguiente ejemplo de código demuestra cómo abrir una secuencia.
- NTSTATUS
- OpenStreams (
- _In_ WDFDEVICE Device,
- _In_ WDFUSBPIPE Pipe)
- {
- NTSTATUS status;
- PDEVICE_CONTEXT deviceContext;
- PPIPE_CONTEXT pipeContext;
- USHORT cStreams = 0;
- USBD_PIPE_HANDLE usbdPipeHandle;
- WDFMEMORY urbMemory = NULL;
- PURB urb = NULL;
-
- PAGED_CODE();
-
- deviceContext =GetDeviceContext(Device);
- pipeContext = GetPipeContext (Pipe);
-
- if (deviceContext->MaxStreamsController == 0)
- {
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Static streams are not supported.");
-
- status = STATUS_NOT_SUPPORTED;
- goto Exit;
- }
-
- // If static streams are not supported, number of streams supported is zero.
-
- if (pipeContext->MaxStreamsSupported == 0)
- {
- status = STATUS_DEVICE_CONFIGURATION_ERROR;
-
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Static streams are not supported by the endpoint.");
-
- goto Exit;
- }
-
- // Determine the number of streams to open.
- // Compare the number of streams supported by the endpoint with the
- // number of streams supported by the host controller, and choose the
- // lesser of the two values. The deviceContext->MaxStreams value was
- // obtained in a previous call to WdfUsbTargetDeviceQueryUsbCapability
- // that determined whether or not static streams is supported and
- // retrieved the maximum number of streams supported by the
- // host controller. The device context stores the values for IN and OUT
- // endpoints.
-
- // Allocate an array of USBD_STREAM_INFORMATION structures to store handles to streams.
- // The number of elements in the array is the number of streams to open.
- // The code snippet stores the array in its device context.
-
- cStreams = min(deviceContext->MaxStreamsController, pipeContext->MaxStreamsSupported);
-
- // Allocate an array of streams associated with the IN bulk endpoint
- // This array is released in CloseStreams.
-
- pipeContext->StreamInfo = (PUSBD_STREAM_INFORMATION) ExAllocatePoolWithTag (
- NonPagedPool,
- sizeof (USBD_STREAM_INFORMATION) * cStreams,
- USBCLIENT_TAG);
-
- if (pipeContext->StreamInfo == NULL)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
-
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Could not allocate stream information array.");
-
- goto Exit;
- }
-
- RtlZeroMemory (pipeContext->StreamInfo,
- sizeof (USBD_STREAM_INFORMATION) * cStreams);
-
- // Get USBD pipe handle from the WDF target pipe object. The client driver received the
- // endpoint pipe handles during device configuration.
-
- usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle (Pipe);
-
- // Allocate an URB for the open streams request.
- // WdfUsbTargetDeviceCreateUrb returns the address of the
- // newly allocated URB and the WDFMemory object that
- // contains the URB.
-
- status = WdfUsbTargetDeviceCreateUrb (
- deviceContext->UsbDevice,
- NULL,
- &urbMemory,
- &urb);
-
- if (status != STATUS_SUCCESS)
- {
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Could not allocate URB for an open-streams request.");
-
- goto Exit;
- }
-
- // Format the URB for the open-streams request.
- // The UsbBuildOpenStaticStreamsRequest inline function formats the URB by specifying the
- // pipe handle to the entire bulk endpoint, number of streams to open, and the array of stream structures.
-
- UsbBuildOpenStaticStreamsRequest (
- urb,
- usbdPipeHandle,
- (USHORT)cStreams,
- pipeContext->StreamInfo);
-
- // Send the request synchronously.
- // Upon completion, the USB driver stack populates the array of with handles to streams.
-
- status = WdfUsbTargetPipeSendUrbSynchronously (
- Pipe,
- NULL,
- NULL,
- urb);
-
- if (status != STATUS_SUCCESS)
- {
- goto Exit;
- }
-
- Exit:
- if (urbMemory)
- {
- WdfObjectDelete (urbMemory);
- }
-
- return status;
- }