le mie informazioni di contatto
Posta[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Nei dispositivi USB 2.0 e precedenti, un endpoint in blocco può inviare o ricevere un singolo flusso di dati attraverso l'endpoint. Nei dispositivi USB 3.0, l'endpoint in blocco è in grado di inviare e ricevere più flussi di dati attraverso l'endpoint.
Lo stack di driver USB fornito da Microsoft in Windows supporta più flussi. Ciò consente ai driver client di inviare richieste I/O indipendenti a ciascun flusso associato a un endpoint in blocco in un dispositivo USB 3.0, senza serializzare le richieste a flussi diversi.
Per un driver client, un flusso rappresenta più endpoint logici con lo stesso insieme di caratteristiche. Per inviare una richiesta a un flusso specifico, il driver client necessita di un handle per quel flusso (simile all'handle della pipe di un endpoint). L'URB per le richieste di I/O in streaming è simile all'URB per le richieste di I/O per endpoint in blocco. L'unica differenza è la maniglia del tubo. Per inviare una richiesta I/O a un flusso, il driver specifica un handle di pipe nel flusso.
Durante la configurazione del dispositivo, il driver client invia una richiesta di configurazione selezionata e facoltativamente una richiesta di interfaccia selezionata. Queste richieste recuperano una serie di handle di pipe per gli endpoint definiti nelle impostazioni dell'attività dell'interfaccia. Per gli endpoint in grado di riconoscere il flusso, l'handle della pipe dell'endpoint può essere utilizzato per inviare richieste I/O al flusso predefinito (il primo flusso) finché il driver non apre il flusso.
Se un driver client desidera inviare richieste a flussi diversi da quello predefinito, il driver deve aprire e ottenere gli handle per tutti i flussi. Per fare ciò, il driver client invia una richiesta di flusso aperto specificando il numero di flussi da aprire. Dopo che un driver client ha finito di utilizzare i flussi, il driver può scegliere di chiuderli inviando una richiesta di chiusura del flusso.
Kernel Mode Driver Framework (KMDF) non supporta in modo nativo i flussi statici. I driver client devono utilizzare Windows Driver Model (WDM) per aprire e chiudere i flussi. I driver client UMDF (user-mode Driver Framework) non possono utilizzare la funzionalità di streaming statico.
Quanto segue potrebbe contenere alcuni commenti etichettati Driver WDM. Queste istruzioni descrivono le routine per un driver client USB basato su WDM che desidera inviare richieste di streaming.
Prima che un driver client possa aprire o chiudere un flusso, il driver deve disporre di:
1. Chiamare il metodo WdfUsbTargetDeviceCreateWithParameters. Il metodo richiede la versione del protocollo client USBD_CLIENT_CONTRACT_VERSION_602. Specificando questa versione, il driver client deve rispettare una serie di regole.
Chiamata per recuperare l'handle WDFUSBDEVICE dell'oggetto dispositivo di destinazione USB del framework. L'handle è necessario per le chiamate successive al flusso aperto. In genere, un driver client si registra nella routine di callback dell'evento EVT_WDF_DEVICE_PREPARE_HARDWARE del driver.
Driver WDM: richiama la routine USBD_CreateHandle e ottiene l'handle USBD registrato dal driver nello stack dei driver USB.
2. Configurato il dispositivo e ottenuto l'handle della pipe WDFUSBPIPE per l'endpoint in blocco che supporta lo streaming. Per ottenere un handle di pipe, chiamare il metodo WdfUsbInterfaceGetConfiguredPipe sulle impostazioni alternative correnti dell'interfaccia nella configurazione selezionata.
Driver WDM: ottiene l'handle della pipe USBD inviando una richiesta di configurazione o selezione dell'interfaccia.
1. Determinare se lo stack di driver USB sottostante e il controller host supportano la funzionalità di streaming statico chiamando il metodo WdfUsbTargetDeviceQueryUsbCapability. In genere, i driver client chiamano le routine nella routine di callback dell'evento EVT_WDF_DEVICE_PREPARE_HARDWARE del driver.
Driver WDM: richiama la routine USBD_QueryUsbCapability. In genere, un driver interroga la funzione da utilizzare nella routine del dispositivo di avvio del driver (IRP_MN_START_DEVICE).
Fornire le seguenti informazioni:
Driver WDM: passa l'handle USBD recuperato nella chiamata precedente a USBD_CreateHandle.
Se un driver client desidera utilizzare una funzionalità specifica, il driver deve prima interrogare lo stack di driver USB sottostante per determinare se lo stack di driver e il controller host supportano la funzionalità. Se la funzionalità è supportata, solo allora il conducente dovrà inviare una richiesta per utilizzare la funzionalità. Alcune richieste richiedono URB, come la funzionalità di streaming discussa nel passaggio 5. Per queste richieste, assicurati di utilizzare lo stesso handle per interrogare la funzione e allocare l'URB. Questo perché lo stack dei driver utilizza gli handle per tenere traccia delle funzionalità supportate che il driver può utilizzare.
Ad esempio, se USBD_HANDLE è stato ottenuto chiamando USBD_CreateHandle, lo stack di driver viene interrogato chiamando USBD_QueryUsbCapability e l'URB viene allocato chiamando USBD_UrbAllocate. Passa lo stesso USBD_HANDLE in entrambe le chiamate.
Se chiami i metodi KMDF, WdfUsbTargetDeviceQueryUsbCapability e WdfUsbTargetDeviceCreateUrb, specifica lo stesso handle WDFUSBDEVICE per l'oggetto di destinazione del framework in queste chiamate al metodo.
2. Valutare il valore NTSTATUS restituito. Se la routine viene completata correttamente, viene restituito STATUS_SUCCESS e la funzionalità di streaming statico è supportata. In caso contrario, il metodo restituisce il codice di errore appropriato.
3. Determinare il numero di flussi da aprire. Il numero massimo di flussi che possono essere aperti è limitato da:
Per determinare il numero massimo di flussi, scegli il più piccolo dei due valori supportati dal controller host e dall'endpoint.
4. Assegnare un array di strutture USBD_STREAM_INFORMATION di n elementi, dove n è il numero di flussi da aprire. Il driver client è responsabile della liberazione di questo array dopo che il driver ha terminato di utilizzare il flusso.
5. Assegnare un URB per la richiesta di flusso aperto chiamando il metodo WdfUsbTargetDeviceCreateUrb. Se la chiamata viene completata con successo, il metodo recupera l'oggetto memoria WDF e l'indirizzo della struttura URB allocata dallo stack dei driver USB.
Driver WDM: richiama la routine USBD_UrbAllocate.
6. Imposta il formato URB della richiesta di flusso aperto. URB utilizza la struttura _URB_OPEN_STATIC_STREAMS per definire le richieste. Per formattare un URB, è necessario:
Per formattare un URB, chiama UsbBuildOpenStaticStreamsRequest e passa le informazioni richieste come valori dei parametri. Assicurati che il numero di flussi specificati in UsbBuildOpenStaticStreamsRequest non superi il numero massimo di flussi supportati.
7. Invia l'URB come oggetto di richiesta WDF chiamando il metodo WdfRequestSend. Per inviare la richiesta in modo sincrono, chiamare invece il metodo WdfUsbTargetDeviceSendUrbSynchronously.
Driver WDM: associa l'URB all'IRP e invia l'IRP allo stack di driver USB.
8. Una volta completata la richiesta, verificare lo stato della richiesta.Se la richiesta dello stack del driver USB fallisce, lo stato URB contiene il relativo codice di errore.
Se lo stato della richiesta (oggetto richiesta IRP o WDF) indica USBD_STATUS_SUCCESS, la richiesta è stata completata correttamente. Array di strutture USBD_STREAM_INFORMATION ricevute al termine del controllo. L'array viene popolato con le informazioni sul flusso richiesto. Lo stack di driver USB popola ciascuna struttura nell'array con informazioni sul flusso, come l'handle ricevuto USBD_PIPE_HANDLE, l'identificatore del flusso e la dimensione numerica massima del trasferimento. Il flusso ora può trasferire i dati.
Per le richieste di flusso aperto, è necessario allocare URB e array. Una volta completata la richiesta di flusso aperto, il driver client deve rilasciare l'URB chiamando il metodo WdfObjectDelete sull'oggetto di memoria WDF associato. Se il driver invia la richiesta in modo sincrono chiamando WdfUsbTargetDeviceSendUrbSynchronously, l'oggetto memoria WDF deve essere rilasciato dopo la restituzione del metodo. Se un driver client invia una richiesta in modo asincrono chiamando WdfRequestSend, il driver deve rilasciare l'oggetto memoria WDF nella routine di completamento implementata dal driver associata alla richiesta.
L'array del flusso può essere rilasciato dopo che il driver client ha terminato di utilizzare il flusso oppure può essere archiviato per le richieste I/O. Nell'esempio di codice incluso di seguito, il driver archivia un array di flussi nel contesto del dispositivo. Il driver rilascia il contesto di dispositivo prima di rilasciare l'oggetto dispositivo.
Come trasferire i dati a un flusso specifico
Per inviare una richiesta di trasferimento dati a un flusso specifico, è richiesto un oggetto di richiesta WDF. In genere, i driver client non necessitano di allocare oggetti di richiesta WDF. Quando il gestore I/O riceve una richiesta da un'applicazione, crea un IRP per la richiesta. L'IRP è stato intercettato dal framework. Il framework quindi alloca un oggetto di richiesta WDF per rappresentare l'IRP. Successivamente, il framework passa l'oggetto della richiesta WDF al driver client. Il driver client può quindi associare l'oggetto richiesta all'URB di trasferimento dati e inviarlo allo stack del driver USB.
Se un driver client non riceve un oggetto di richiesta WDF dal framework e desidera inviare la richiesta in modo asincrono, il driver deve allocare un oggetto di richiesta WDF chiamando il metodo WdfRequestCreate. Formatta il nuovo oggetto chiamando WdfUsbTargetPipeFormatRequestForUrb e invia la richiesta chiamando WdfRequestSend.
Nel caso sincrono, il passaggio dell'oggetto richiesta WDF è facoltativo.
Per trasferire i dati a un flusso, è necessario utilizzare URB. L'URB deve essere formattato chiamando WdfUsbTargetPipeFormatRequestForUrb.
I flussi non supportano i seguenti metodi WDF:
La procedura seguente presuppone che il driver client riceva l'oggetto richiesta dal framework.
Driver WDM: assegna un URB chiamando USBD_UrbAllocate e lo formatta per il trasferimento di massa (vedi _URB_BULK_OR_INTERRUPT_TRANSFER). Per formattare un URB, puoi chiamare UsbBuildInterruptOrBulkTransferRequest o formattare manualmente la struttura URB. Specificare l'handle del flusso nel membro UrbBulkOrInterruptTransfer.PipeHandle dell'URB.
Il driver client può chiudere il flusso una volta terminato di utilizzarlo. Tuttavia, la chiusura della richiesta di streaming è facoltativa. Lo stack di driver USB chiude tutti i flussi quando l'endpoint associato al flusso non è configurato. Gli endpoint non vengono configurati quando si seleziona una configurazione o un'interfaccia alternativa, si elimina un dispositivo, ecc. Se il driver client desidera aprire un numero diverso di flussi, deve chiuderli. Invia una richiesta di chiusura dello streaming:
1. Assegnare la struttura URB chiamando WdfUsbTargetDeviceCreateUrb.
2. Imposta il formato URB per chiudere la richiesta di flusso. Il membro UrbPipeRequest della struttura URB è la struttura _URB_PIPE_REQUEST. Compila i suoi membri come segue:
3. Invia l'URB come richiesta WDF chiamando WdfRequestSend o WdfUsbTargetDeviceSendUrbSynchronously.
L'handle di chiusura richiede la chiusura di tutti i flussi precedentemente aperti dal driver client. Il driver client non può utilizzare le richieste per chiudere un flusso specifico nell'endpoint.
Lo stack di driver USB esegue la verifica sull'URB ricevuto. Per evitare errori di convalida, procedere come segue:
Occasionalmente, i trasferimenti da o verso un endpoint potrebbero non riuscire. Tali errori possono essere causati da condizioni di errore sull'endpoint o sul controller host, ad esempio una condizione di arresto o di arresto. Per eliminare la condizione di errore, il driver client annulla innanzitutto il trasferimento in sospeso e quindi reimposta la pipe associata all'endpoint. Per annullare un trasferimento in sospeso, il driver client può inviare una richiesta di pipe di interruzione. Per reimpostare una pipe, il driver client deve inviare una richiesta di reimpostazione della pipe.
Per lo streaming, le richieste di abort-pipe e reset-pipe non sono supportate per i singoli flussi associati all'endpoint in blocco. Se un trasferimento su una pipe di flusso specifica non riesce, il controller host interromperà i trasferimenti su tutte le altre pipe per gli altri flussi. Per ripristinare la condizione di errore, il driver client deve annullare manualmente il trasferimento su ciascun flusso un handle di pipe per inviare una richiesta di reimpostazione della pipe all'endpoint in blocco. Per questa richiesta, il driver client deve specificare l'handle della pipe dell'endpoint nella struttura _URB_PIPE_REQUEST e impostare la funzione URB (Hdr.Function) su URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL.
Nell'esempio di codice seguente viene illustrato come aprire un flusso.
- 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;
- }