Come trasferire i dati agli endpoint isocroni USB
Questo argomento descrive come un driver client può creare un blocco di richieste USB per trasferire i dati da e verso endpoint isocroni in un dispositivo USB.
Un dispositivo USB (Universal Serial Bus) può supportare endpoint isocroni per trasferire dati dipendenti dal tempo a una velocità costante, ad esempio con lo streaming audio/video. Per trasferire i dati, il driver client invia una richiesta di lettura o scrittura di dati in un endpoint isocrono. Di conseguenza, il controller host avvia un trasferimento isocrono che invia o riceve dati eseguendo il polling del dispositivo a intervalli regolari.
Per i dispositivi ad alta velocità e a velocità completa, il polling viene eseguito usando pacchetti di token (IN/OUT). Quando l'endpoint è pronto per l'invio dei dati, il dispositivo risponde a uno dei pacchetti di token IN inviando i dati. Per scrivere nel dispositivo, il controller host invia un pacchetto di token OUT seguito da pacchetti di dati. Il controller host o il dispositivo non invia alcun pacchetto di handshake e pertanto non è garantito il recapito. Poiché il controller host non tenta di ripetere il trasferimento, è possibile che i dati vadano persi se si verifica un errore.
Per i trasferimenti isocroni il controller host riserva determinati periodi di tempo sul bus. Per gestire il tempo riservato per gli endpoint isocroni, il tempo viene diviso in blocchi logici consecutivi vengono chiamati intervalli di bus. L'unità di intervallo dell'autobus dipende dalla velocità dell'autobus.
Per la massima velocità, un intervallo di autobus è un frame. La lunghezza di un frame è di 1 millisecondo.
Per velocità elevata e SuperSpeed, l'intervallo dell'autobus è un microframe. La lunghezza di un microframe è di 125 microsecondi. Otto microframe consecutivi costituiscono un frame ad alta velocità o SuperSpeed.
I trasferimenti isocroni sono basati su pacchetti. Il termine pacchetto isochronous in questo argomento si riferisce alla quantità di dati trasferiti in un intervallo di bus. Le caratteristiche dell'endpoint determinano le dimensioni di ogni pacchetto sono fisse e determinate dalle caratteristiche dell'endpoint.
Il driver client avvia un trasferimento isocrono creando un'istanza DI PER LA RICHIESTA e inviando l'OGGETTO ALLO stack di driver USB. La richiesta viene gestita da uno dei driver inferiori nello stack di driver USB. Al momento della ricezione dell'OGGETTO, lo stack di driver USB esegue un set di convalide e pianifica le transazioni per la richiesta. Per la massima velocità, un pacchetto isocrono da trasferire in ogni intervallo di bus è contenuto in una singola transazione in transito. Alcuni dispositivi ad alta velocità consentono più transazioni in un intervallo di bus. In tal caso, il driver client può inviare o ricevere più dati nel pacchetto isochronous in una singola richiesta (ODBC). I dispositivi SuperSpeed supportano più transazioni e trasferimenti burst, consentendo un numero ancora maggiore di byte per intervallo di bus. Per altre informazioni sui trasferimenti burst, vedere la pagina delle specifiche USB 3.0 9-42.
Prima di iniziare
Prima di creare una richiesta per un trasferimento isocrono, è necessario disporre di informazioni sulla pipe aperta per l'endpoint isocrono.
Un driver client che usa routine WDM (Windows Driver Model) contiene le informazioni sulla pipe in una delle strutture USBD_PIPE_INFORMATION di una matrice di USBD_INTERFACE_LIST_ENTRY . Il driver client ha ottenuto tale matrice nella richiesta precedente del driver per selezionare una configurazione o un'interfaccia nel dispositivo.
Un driver client WDF (Windows Driver Framework) deve ottenere un riferimento all'oggetto pipe di destinazione del framework e chiamare WdfUsbTargetPipeGetInformation per ottenere informazioni sulla pipe in una struttura WDF_USB_PIPE_INFORMATION .
In base alle informazioni sulla pipe, determinare questo set di informazioni:
Quantità di dati che il controller host può inviare alla pipe in ogni pacchetto.
La quantità di dati che il driver client può inviare in una richiesta non può superare il numero massimo di byte che il controller host può inviare o ricevere da un endpoint. Il numero massimo di byte è indicato dal membro MaximumPacketSize delle strutture USBD_PIPE_INFORMATION e WDF_USB_PIPE_INFORMATION . Lo stack di driver USB imposta il valore MaximumPacketSize durante una richiesta select-configuration o select-interface.
Per i dispositivi a velocità completa, MaximumPacketSize deriva dai primi 11 bit del campo wMaxPacketSize del descrittore di endpoint, che indica il numero massimo di byte che l'endpoint può inviare o ricevere in una transazione. Per i dispositivi a velocità completa, il controller invia una transazione per intervallo di bus.
In un trasferimento isocrono ad alta velocità, il controller host può inviare transazioni aggiuntive in un intervallo di bus se l'endpoint li consente. Il numero di transazioni aggiuntive viene impostato dal dispositivo e indicato in bit 12..11 di wMaxPacketSize. Tale numero può essere 0, 1 o 2. Se 12..11 indica 0, le transazioni aggiuntive per microframe non sono supportate dall'endpoint. Se il numero è 1, il controller host può inviare una transazione aggiuntiva (totale di due transazioni per microframe); 2 indica due transazioni aggiuntive (totale di tre transazioni per microframe). Il valore MaximumPacketSize impostato dallo stack di driver USB include il numero di byte che possono essere inviati in transazioni aggiuntive.
Per il trasferimento isochronous di SuperSpeed, alcuni valori di USB_SUPERSPEED_ENDPOINT_COMPANION_DESCRIPTOR (vedere Usbspec.h) sono importanti. Lo stack di driver USB usa tali valori per calcolare il numero massimo di byte in un intervallo di bus.
Campo Isochronous.Mult del descrittore complementare dell'endpoint. Nei trasferimenti isocroni SuperSpeed, le transazioni aggiuntive (molto simili ai dispositivi ad alta velocità) vengono definite transazioni burst. Il valore Mult indica il numero massimo di transazioni burst supportate dall'endpoint. In un intervallo di servizio possono essere presenti fino a tre transazioni burst (indicizzate da 0 a 2).
bMaxBurst campo del descrittore complementare dell'endpoint. Questo valore indica il numero di blocchi di wMaxPacketSize che possono essere presenti in una singola transazione burst. In una transazione burst possono essere presenti fino a 16 blocchi (indicizzati da 0 a 15).
wBytesPerInterval indica il numero totale di byte che l'host può inviare o ricevere in un intervallo di bus. Anche se il numero massimo di byte per intervallo bus può essere calcolato come (bMaxBurst+1) * (Mult+1) * wMaxPacketSize, la specifica USB 3.0 consiglia invece di usare il valore wBytesPerInterval . Il valore wBytesPerInterval deve essere minore o uguale a quello calcolato.
Importante
Per un driver client, i valori descritti in precedenza sono solo per informazioni. Il driver deve sempre usare il valore MaximumPacketSize del descrittore dell'endpoint per determinare il layout del buffer di trasferimento.
Con quale frequenza l'endpoint invia o riceve i dati?
Il membro Interval viene usato per determinare la frequenza con cui l'endpoint può inviare o ricevere dati. Il dispositivo imposta tale valore e il driver client non può modificarlo. Lo stack di driver USB usa un altro numero per determinare la frequenza con cui inserisce pacchetti isocroni nel flusso di dati: il periodo di polling, derivato dal valore Interval .
Per le trasmissioni a velocità intera, i valori intervallo e periodo di polling sono sempre 1; lo stack di driver USB ignora altri valori.
La tabella seguente illustra Interval e il periodo di polling calcolato per i trasferimenti ad alta velocità e SuperSpeed:
Interval Periodo di polling (2Interval-1) 1 1; I dati vengono trasferiti a ogni intervallo di autobus. 2 2; I dati vengono trasferiti ogni secondo intervallo di bus. 3 4; I dati vengono trasferiti ogni quarto intervallo di autobus. 4 8; I dati vengono trasferiti ogni ottavo intervallo di autobus. Quali sono le restrizioni sul numero di pacchetti per ogni velocità del bus.
In un DISPOSITIVO a velocità intera è possibile inviare fino a 255 pacchetti isocroni; Pacchetti da 1024 in un'istanza di CLASSE per dispositivi ad alta velocità e SuperSpeed. Il numero di pacchetti inviati nell'OGGETTO DEVE essere un multiplo del numero di pacchetti in ogni frame.
Periodo di polling Numero di pacchetti per velocità elevata/SuperSpeed 1 Multiplo di 8 2 Multiplo di 4 3 Multiplo di 2 4 Qualsiasi
Si consideri un esempio di endpoint a velocità completa con wMaxPacketSize è 1.023. Per questo esempio, l'applicazione ha fornito il buffer di 25.575 byte. Il trasferimento per tale buffer richiede 25 pacchetti isocroni (25575/1023).
Si consideri un endpoint ad alta velocità di esempio con le caratteristiche seguenti indicate nel descrittore dell'endpoint.
- wMaxPacketSize è 1.024.
- I bit 12..11 indicano due transazioni aggiuntive.
- L'intervallo è 1.
Dopo che il driver client seleziona una configurazione, MaximumPacketSize per la pipe isochronous indica 3.072 byte (transazioni totali * wMaxPacketSize). Le transazioni aggiuntive consentono al driver client di trasferire 3.072 byte in ogni microframe e il totale di 24.576 byte in un frame. La figura seguente mostra la frequenza con cui un pacchetto isocrono viene trasferito in un microframe per le trasmissioni ad alta velocità.
Si consideri un esempio di endpoint SuperSpeed con queste caratteristiche indicate nei descrittori complementari endpoint e SuperSpeed:
- wMaxPacketSize è 1.024.
- bMaxBurst è 15.
- L'intervallo è 1.
- Isochronous.Mult è 2.
- wBytesPerInterval è 45000.
Nell'esempio precedente, anche se il numero massimo di byte può essere calcolato come wMaxPacketSize * (bMaxBurst +1) * (Mult + 1) risultante in 49.152 byte, il dispositivo limita il valore al valore wBytesPerInterval pari a 45.000 byte. Tale valore si riflette anche in MaximumPacketSize 45.000. Il driver client deve usare solo il valore MaximumPacketSize . In questo esempio la richiesta può essere suddivisa in tre transazioni burst. Le prime due transazioni burst contengono 16 blocchi di wMaxPacketSize. L'ultima transazione burst contiene 12 blocchi per contenere i byte rimanenti. Questa immagine mostra l'intervallo di polling e i byte trasferiti tramite un pacchetto isocrono per la trasmissione SuperSpeed.
Per compilare una richiesta per un trasferimento isocrono:
- Ottenere le dimensioni di ogni pacchetto isocrono.
- Determinare il numero di pacchetti isocroni per frame.
- Calcolare il numero di pacchetti isocroni necessari per contenere l'intero buffer di trasferimento.
- Allocare una strutturaRIPARTIZIONE per descrivere i dettagli del trasferimento.
- Specificare i dettagli di ogni pacchetto isocrono, ad esempio l'offset dei pacchetti.
Per un esempio di codice completo sull'invio di richieste di trasferimento isocrone, USBSAMP.
Questo esempio in questo argomento semplifica l'implementazione USBSAMP del trasferimento isocrono. Nell'esempio vengono calcolati i fotogrammi numerici totali necessari per il trasferimento. In base alla quantità di dati che possono essere inviati in un frame, il buffer di trasferimento viene diviso in byte di dimensioni ridotte.
La procedura seguente elabora i passaggi precedenti e illustra i calcoli e le routine che un driver client può usare per compilare e inviare una richiesta di trasferimento isocrona per un endpoint isocrono ad alta velocità. I valori usati nella procedura sono basati sulle caratteristiche dell'endpoint di esempio descritte in precedenza.
Passaggio 1: Ottenere le dimensioni di un pacchetto isocrono
Determinare le dimensioni di un pacchetto isocrono controllando il valore MaximumPacketSize della pipe.
Per le trasmissioni a velocità intera, la dimensione di un pacchetto isocrono è il numero di byte che è possibile trasferire in un frame. Per le trasmissioni ad alta velocità e SuperSpeed, le dimensioni di un pacchetto isocrono sono il numero totale di byte che possono essere trasferiti in un microframe. Tali valori sono indicati nella proprietà MaximumPacketSize della pipe.
Nell'esempio MaximumPacketSize è di 1023 byte per fotogramma (velocità intera); 3072 byte per microframe (alta velocità); 45.000 byte per microframe (SuperSpeed).
Nota
Il valore MaximumPacketSize indica la dimensione massima consentita del pacchetto isocrono. Il driver client può impostare le dimensioni di ogni pacchetto isocrono su qualsiasi valore minore del valore MaximumPacketSize .
Passaggio 2: Determinare il numero di pacchetti isocroni per frame
Per le trasmissioni a velocità intera, trasferisci un pacchetto isocrono in ogni fotogramma.
Per le trasmissioni ad alta velocità e SuperSpeed, questo valore deve essere derivato dal valore Interval. Nell'esempio Intervallo è 1. Pertanto, il numero di pacchetti isocroni deve essere otto per fotogramma. Per altri valori di intervallo, vedere la tabella nella sezione Prerequisiti.
Passaggio 3: Calcolare il numero di pacchetti isocroni necessari per contenere l'intero buffer di trasferimento
Calcolare il numero di pacchetti isocroni necessari per trasferire l'intero buffer. Questo valore può essere calcolato dividendo la lunghezza del buffer di trasferimento in base alle dimensioni di un pacchetto isocrono.
In questo esempio si presuppone che le dimensioni di ogni pacchetto isocrono siano MaximumPacketSize e che la lunghezza del buffer di trasferimento sia un multiplo di valore MaximumPacketSize .
Ad esempio, per il trasferimento a velocità intera un buffer fornito di 25.575 byte richiede 25 pacchetti isocroni (25575/1023). Per il trasferimento ad alta velocità, un buffer di dimensioni pari a 24.576 è suddiviso in otto pacchetti isocroni (24576 /3072) per il trasferimento. Per SuperSpeed, un buffer di dimensioni pari a 360.000 byte si adatta a otto pacchetti isocroni (360000/45000).
Il driver client deve convalidare questi requisiti:
- Il numero di pacchetti isocroni deve essere un multiplo del numero di pacchetti per frame.
- Il numero massimo di pacchetti isocroni necessari per effettuare il trasferimento non deve superare 255 per il dispositivo a velocità intera; 1024 per un dispositivo ad alta velocità o SuperSpeed.
Passaggio 4: Allocare unastrutturaae per descrivere i dettagli del trasferimento
Allocare una struttura BLOB in un pool non di paging.
Se il driver client usa routine WDM, il driver deve chiamare il USBD_IsochUrbAllocate se si dispone di Windows Driver Kit (WDK) per Windows 8. Un driver client può usare la routine per specificare Come destinazione Windows Vista e versioni successive del sistema operativo Windows. Se non si dispone di WDK per Windows 8 o se il driver client è destinato a una versione precedente del sistema operativo, è possibile allocare la struttura nello stack o nel pool non di paging chiamando ExAllocatePoolWithTag.
Un driver client WDF può chiamare il metodo WdfUsbTargetDeviceCreateIsochUrb per allocare memoria per la struttura DELL'OGGETTO .
Il membro Dell'Oggetto TypeIsochronousTransfer della struttura DELL'OGGETTO POINT punta a una struttura _URB_ISOCH_TRANSFER che descrive i dettagli di un trasferimento isocrono. Inizializzare i membri seguenti di TypeIsochronousTransfer come indicato di seguito:
Impostare il membro TypeIsochronousTransfer.Hdr.Length sulla dimensione dell'oggetto WSUS. Per ottenere le dimensioni dell'OGGETTO, chiamare GET_ISO_URB_SIZE macro e specificare il numero di pacchetti.
Impostare ilmembrooee di Di Azure.Hdr.Function su
URB_FUNCTION_ISOCH_TRANSFER
.Impostare il membro TroppaIsochronousTransfer.NumberOfPackets sul numero di pacchetti isocroni.
Impostare Il valore DiLosronousTransfer.PipeHandle sull'handle opaco per la pipe associata all'endpoint. Assicurarsi che l'handle della pipe sia l'handle di pipe USBD usato dallo stack di driver USB (Universal Serial Bus).
Per ottenere l'handle della pipe USBD, un driver client WDF può chiamare il metodo WdfUsbTargetPipeWdmGetPipeHandle e specificare l'handle WDFUSBPIPE per l'oggetto pipe del framework. Un driver client WDM deve usare lo stesso handle ottenuto nel membro PipeHandle della struttura USBD_PIPE_INFORMATION .
Specificare la direzione del trasferimento. Impostare TroppaIsochronousTransfer.TransferFlags su USBD_TRANSFER_DIRECTION_IN per un trasferimento IN isochronous (lettura dal dispositivo); USBD_TRANSFER_DIRECTION_OUT per un trasferimento OUT isocrono (scrittura nel dispositivo).
Specificare il flag di USBD_START_ISO_TRANSFER_ASAP inPrecisareIsochronousTransfer. TransferFlags. Il flag indica allo stack di driver USB di inviare il trasferimento nel frame appropriato successivo. Per la prima volta che il driver client invia un'interfaccia ISOCRONA PER questa pipe, lo stack di driver invia i pacchetti isocroni nel DISPOSITIVO appena possibile. Lo stack di driver USB tiene traccia del frame successivo da usare per gli URL successivi su tale pipe. Se si verifica un ritardo nell'invio di un successivo oggetto ODBC isocrono che utilizza il flag di USBD_START_ISO_TRANSFER_ASAP, lo stack di driver considera alcuni o tutti i pacchetti di TALE ELEMENTO ESSERE in ritardo e non trasferisce tali pacchetti.
Lo stack di driver USB reimposta la sua USBD_START_ISO_TRANSFER_ASAP rilevamento dei frame di avvio, se lo stack non riceve un'immagine ISOcrona PER 1024 frame dopo aver completato la precedente ISTRUZIONE PER tale pipe. Anziché specificare il flag di USBD_START_ISO_TRANSFER_ASAP, è possibile specificare il frame di inizio. Per altre informazioni, vedere la sezione Osservazioni.
Specificare il buffer di trasferimento e le relative dimensioni. È possibile impostare un puntatore al buffer in AttestazionIsochronousTransfer.TransferBuffer o MDL che descrive il buffer in DlIsochronousTransfer.TransferBufferMDL.
Per recuperare il MDL per il buffer di trasferimento, un driver client WDF può chiamare WdfRequestRetrieveOutputWdmMdl o WdfRequestRetrieveInputWdmMdl, a seconda della direzione del trasferimento.
Passaggio 5: Specificare i dettagli di ogni pacchetto isocrono nel trasferimento
Lo stack di driver USB alloca la nuova struttura DELL'OGGETTO che è sufficientemente grande da contenere informazioni su ogni pacchetto isocrono, ma non i dati contenuti nel pacchetto. Nella struttura DELL'OGGETTO , il membro DelisisochronousTransfer.IsoPacket è una matrice di USBD_ISO_PACKET_DESCRIPTOR che descrive i dettagli di ogni pacchetto isocrono nel trasferimento. I pacchetti devono essere contigui. Il numero di elementi nella matrice deve essere il numero di pacchetti isochronous specificati nel membro TypeIsochronousTransfer.NumberOfPackets del CRITERIO.
Per un trasferimento ad alta velocità, ogni elemento della matrice è correlato a un pacchetto isocrono in un microframe. Per la velocità completa, ogni elemento è correlato a un pacchetto isocrono trasferito in un frame.
Per ogni elemento, specificare l'offset di byte di ogni pacchetto isocrono dall'inizio dell'intero buffer di trasferimento per la richiesta. È possibile specificare tale valore impostando l'oggetto TroppaIsochronousTransfer.IsoPacket[i]. Membro offset . Lo stack di driver USB usa il valore specificato per tenere traccia della quantità di dati da inviare o ricevere.
Impostazione dell'offset per un trasferimento Full-Speed
Ad esempio, si tratta delle voci di matrice per il buffer di trasferimento a velocità completa. In piena velocità, il driver client ha un frame per trasferire un pacchetto isocrono fino a 1.023 byte. Un buffer di trasferimento di 25.575 byte può contenere 25 pacchetti isocroni, ogni 1.023 byte. Per l'intero buffer sono necessari un totale di 25 fotogrammi.
Frame 1 IsoPacket [0].Offset = 0 (start address)
Frame 2 IsoPacket [1].Offset = 1023
Frame 3 IsoPacket [2].Offset = 2046
Frame 4 IsoPacket [3].Offset = 3069
...
Frame 25 IsoPacket [24].Offset = 24552
Total length transferred is 25,575 bytes.
Impostazione dell'offset per un trasferimento High-Speed
Ad esempio, si tratta delle voci di matrice per un buffer di trasferimento ad alta velocità. L'esempio presuppone che il buffer sia di 24.576 byte e che il driver client abbia un frame per trasferire otto pacchetti isocroni, ogni 3.072 byte di lunghezza.
Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 3072
Microframe 3 IsoPacket [2].Offset = 6144
Microframe 4 IsoPacket [3].Offset = 9216
Microframe 5 IsoPacket [4].Offset = 12288
Microframe 6 IsoPacket [5].Offset = 15360
Microframe 7 IsoPacket [6].Offset = 18432
Microframe 8 IsoPacket [7].Offset = 21504
Total length transferred is 24,576 bytes.
Impostazione dell'offset per un trasferimento SuperSpeed
Ad esempio, si tratta dell'offset di matrice per SuperSpeed. È possibile trasferire fino a 45.000 byte in un frame. Il buffer di trasferimento di dimensioni 360.000 rientra in otto microframe.
Microframe 1 IsoPacket [0].Offset = 0 (start address)
Microframe 2 IsoPacket [1].Offset = 45000
Microframe 3 IsoPacket [2].Offset = 90000
Microframe 4 IsoPacket [3].Offset = 135000
Microframe 5 IsoPacket [4].Offset = 180000
Microframe 6 IsoPacket [5].Offset = 225000
Microframe 7 IsoPacket [6].Offset = 270000
Microframe 8 IsoPacket [7].Offset = 315000
Total length transferred is 360,000 bytes.
L'Elemento TroppaIsochronousTransfer.IsoPacket[i]. Il membro di lunghezza non implica la lunghezza di ogni pacchetto dell'oggetto TYPE isocrono. IsoPacket[i]. La lunghezza viene aggiornata dallo stack di driver USB per indicare il numero effettivo di byte ricevuti dal dispositivo per trasferimenti IN isocroni. Per i trasferimenti OUT isochronous, lo stack di driver ignora il valore impostato in IsoPacket[i]. Lunghezza.
Specificare il numero di frame USB iniziale per il trasferimento
Il membro Dell'oggetto GatewayIsochronousTransfer.StartFrame dell'OGGETTO CONSENTE di specificare il numero di fotogramma USB iniziale per il trasferimento. C'è sempre la latenza tra il tempo in cui il driver client invia un'eccezione ODBC e l'ora in cui lo stack di driver USB elabora l'OGGETTO. Pertanto, il driver client deve sempre specificare un frame di avvio successivo al fotogramma corrente quando il driver invia IL FILE. Per recuperare il numero di frame corrente, il driver client può inviare la richiesta di URB_FUNCTION_GET_CURRENT_FRAME_NUMBER allo stack di driver USB (_URB_GET_CURRENT_FRAME_NUMBER).
Per i trasferimenti isocroni, la differenza assoluta tra il frame corrente e il valore StartFrame deve essere minore di USBD_ISO_START_FRAME_RANGE. Se StartFrame non è compreso nell'intervallo appropriato, lo stack di driver USB imposta il membro Status dell'intestazione ODBC (vedere _URB_HEADER) su USBD_STATUS_BAD_START_FRAME e rimuove l'intero OGGETTO.
Il valore StartFrame specificato nell'OGGETTO CRITERI indica il numero di fotogramma in cui viene trasferito il primo pacchetto isocrono dell'OGGETTO. Il numero di frame per i pacchetti successivi dipende dalla velocità del bus e dai valori del periodo di polling dell'endpoint. Ad esempio, per una trasmissione ad alta velocità, il primo pacchetto viene trasferito in StartFrame; il secondo pacchetto viene trasferito in StartFrame+1 e così via. Il modo in cui lo stack di driver USB trasferisce pacchetti isocroni, per la massima velocità, nei fotogrammi viene mostrato come segue:
Frame (StartFrame) IsoPacket [0]
Frame (StartFrame+1) IsoPacket [1]
Frame (StartFrame+2) IsoPacket [2]
Frame (StartFrame+3) IsoPacket [3]
...
Per il dispositivo ad alta velocità con valore Intervallo pari a 1, il numero di fotogrammi cambia ogni ottavo microframe. Il modo in cui lo stack di driver USB trasferisce pacchetti isocroni, per velocità elevata, nei fotogrammi viene mostrato come segue:
Frame (StartFrame) Microframe 1 IsoPacket [0]
...
Frame (StartFrame) Microframe 8 IsoPacket [7]
Frame (StartFrame+1) Microframe 1 IsoPacket [8]
...
Frame (StartFrame+1) Microframe 8 IsoPacket [15]
Frame (StartFrame+2) Microframe 1 IsoPacket [16]
...
Frame (StartFrame+2) Microframe 8 IsoPacket [23]
Quando lo stack di driver USB elabora l'OGGETTO CRITERI, il driver rimuove tutti i pacchetti isocroni nell'oggetto DHCP i cui numeri di fotogramma sono inferiori al numero di fotogramma corrente. Lo stack di driver imposta il membro Status del descrittore di pacchetti per ogni pacchetto rimosso su USBD_STATUS_ISO_NA_LATE_USBPORT, USBD_STATUS_ISO_NOT_ACCESSED_BY_HW o USBD_STATUS_ISO_NOT_ACCESSED_LATE. Anche se alcuni pacchetti nell'OGGETTO VENGONO eliminati, lo stack di driver tenta di trasmettere solo i pacchetti i cui numeri di frame sono superiori al numero di frame corrente.
Il controllo di un membro StartFrame valido è leggermente più complicato nelle trasmissioni ad alta velocità perché lo stack di driver USB carica ogni pacchetto isocrono in un microframe ad alta velocità; Tuttavia, il valore in StartFrame si riferisce al numero di fotogramma di 1 millisecondo (a velocità intera) e non al microframe. Se, ad esempio, il valore startframe registrato in ODBC è minore del frame corrente, lo stack di driver può eliminare fino a otto pacchetti. Il numero esatto di pacchetti eliminati dipende dal periodo di polling associato alla pipe isocrona.
Esempio di trasferimento isocrono
Nell'esempio di codice riportato di seguito viene illustrato come creare un OGGETTO COMMAND per un trasferimento isocrono per la trasmissione a velocità massima, ad alta velocità e SuperSpeed.
#define MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED 1024
#define MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED 255
NTSTATUS CreateIsochURB ( PDEVICE_OBJECT DeviceObject,
PUSBD_PIPE_INFORMATION PipeInfo,
ULONG TotalLength,
PMDL RequestMDL,
PURB Urb)
{
PDEVICE_EXTENSION deviceExtension;
ULONG numberOfPackets;
ULONG numberOfFrames;
ULONG isochPacketSize = 0;
ULONG transferSizePerFrame;
ULONG currentFrameNumber;
size_t urbSize;
ULONG index;
NTSTATUS ntStatus;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
isochPacketSize = PipeInfo->MaximumPacketSize;
// For high-speed transfers
if (deviceExtension->IsDeviceHighSpeed || deviceExtension->IsDeviceSuperSpeed)
{
// Ideally you can pre-calculate numberOfPacketsPerFrame for the Pipe and
// store it in the pipe context.
switch (PipeInfo->Interval)
{
case 1:
// Transfer period is every microframe (eight times a frame).
numberOfPacketsPerFrame = 8;
break;
case 2:
// Transfer period is every 2 microframes (four times a frame).
numberOfPacketsPerFrame = 4;
break;
case 3:
// Transfer period is every 4 microframes (twice in a frame).
numperOfPacketsPerFrame = 2;
break;
case 4:
default:
// Transfer period is every 8 microframes (once in a frame).
numberOfPacketsPerFrame = 1;
break;
}
//Calculate the number of packets.
numberOfPackets = TotalLength / isochPacketSize;
if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_HIGH_OR_SUPER_SPEED)
{
// Number of packets cannot be greater than 1021.
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (numberOfPackets % numberOfPacketsPerFrame != 0)
{
// Number of packets should be a multiple of numberOfPacketsPerFrame
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
}
else if (deviceExtension->IsDeviceFullSpeed)
{
//For full-speed transfers
// Microsoft USB stack only supports bInterval value of 1 for
// full-speed isochronous endpoints.
//Calculate the number of packets.
numberOfPacketsPerFrame = 1;
numberOfPackets = TotalLength / isochPacketSize;
if (numberOfPackets > MAX_SUPPORTED_PACKETS_FOR_FULL_SPEED)
{
// Number of packets cannot be greater than 255.
ntStatus = STATUS_INVALID_PARAMETER;
goto Exit;
}
}
// Allocate an isochronous URB for the transfer
ntStatus = USBD_IsochUrbAllocate (deviceExtension->UsbdHandle,
numberOfPackets,
&Urb);
if (!NT_SUCCESS(ntStatus))
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
urbSize = GET_ISO_URB_SIZE(numberOfPackets);
Urb->UrbIsochronousTransfer.Hdr.Length = (USHORT) urbSize;
Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
Urb->UrbIsochronousTransfer.PipeHandle = PipeInfo->PipeHandle;
if (USB_ENDPOINT_DIRECTION_IN(PipeInfo->EndpointAddress))
{
Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
}
else
{
Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
}
Urb->UrbIsochronousTransfer.TransferBufferLength = TotalLength;
Urb->UrbIsochronousTransfer.TransferBufferMDL = RequestMDL;
Urb->UrbIsochronousTransfer.NumberOfPackets = numberOfPackets;
Urb->UrbIsochronousTransfer.UrbLink = NULL;
// Set the offsets for every packet for reads/writes
for (index = 0; index < numberOfPackets; index++)
{
Urb->UrbIsochronousTransfer.IsoPacket[index].Offset = index * isochPacketSize;
}
// Length is a return value for isochronous IN transfers.
// Length is ignored by the USB driver stack for isochronous OUT transfers.
Urb->UrbIsochronousTransfer.IsoPacket[index].Length = 0;
Urb->UrbIsochronousTransfer.IsoPacket[index].Status = 0;
// Set the USBD_START_ISO_TRANSFER_ASAP. The USB driver stack will calculate the start frame.
// StartFrame value set by the client driver is ignored.
Urb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
Exit:
return ntStatus;
}