Uso della routine MapTransferEx
La routine MapTransferEx inizializza un set di risorse DMA assegnate in precedenza e avvia un trasferimento DMA. Questa routine è disponibile nella versione 3 dell'interfaccia delle operazioni DMA. La versione 3 di questa interfaccia è supportata a partire da Windows 8. Per altre informazioni sull'interfaccia delle operazioni DMA, vedere DMA_OPERATIONS.
Confronto tra MapTransferEx e MapTransfer
MapTransferEx è una versione migliorata della routine MapTransfer . MapTransfer è disponibile in tutte le versioni dell'interfaccia delle operazioni DMA, a partire dalla versione 1 in Windows 2000. Una chiamata a MapTransfer può eseguire il mapping di un blocco contiguo di memoria fisica da un MDL. Tuttavia, il buffer di dati per un trasferimento DMA complesso potrebbe essere descritto da una catena MDL e ogni MDL nella catena potrebbe descrivere diversi blocchi di memoria fisicamente contigua. Per usare MapTransfer per trasferire tale buffer, un driver deve effettuare molte chiamate a MapTransfer. In genere, queste chiamate vengono eseguite all'interno di una coppia di cicli annidati. Il ciclo interno esegue l'iterazione da un blocco di memoria fisica contigua al successivo in ogni MDL e l'iterazione del ciclo esterno da un MDL all'altro nella catena MDL.
Al contrario, una chiamata a MapTransferEx può trasferire l'intero buffer di dati per un trasferimento DMA complesso. I tre parametri MapTransferEx seguenti descrivono la memoria del buffer da usare per il trasferimento.
Parametro | Descrizione |
---|---|
Mdl | Puntatore al primo MDL in una catena di uno o più MDL. Per altre informazioni sulle catene MDL, vedere Uso di MDLs. |
Offset | Offset di byte del buffer dall'inizio della memoria descritta dalla catena MDL. |
Lunghezza | Puntatore a una posizione contenente la lunghezza, in byte, del buffer dati. |
All'inizio di una chiamata MapTransferEx , la routine MapTransferEx passa attraverso la catena MDL per trovare l'inizio del buffer. L'inizio del buffer viene specificato dal parametro Offset . Successivamente, lavorando dall'inizio del buffer alla fine, MapTransferEx costruisce un elenco a dispersione/raccolta in cui ogni frammento di buffer nell'elenco è un blocco fisicamente contiguo di memoria dalla catena MDL. Per costruire questo elenco, MapTransferEx passaggi da un blocco di memoria fisicamente contiguo al successivo all'interno di ogni MDL e da un MDL al successivo nella catena MDL. La costruzione dell'elenco termina quando la quantità totale di memoria del buffer descritta dall'elenco di dispersione/raccolta equivale al numero di byte specificati dal parametro di input *Length . L'ordinamento dei frammenti di buffer nell'elenco a dispersione/raccolta risultante corrisponde all'ordinamento dei blocchi fisicamente contigui nella catena MDL.
Più chiamate a MapTransferEx
MapTransferEx potrebbe non essere sempre in grado di trasferire un intero buffer di dati DMA in una chiamata. L'elenco seguente descrive alcune delle condizioni che potrebbero richiedere che MapTransferEx venga chiamato più di una volta per completare il trasferimento:
- L'adattatore DMA richiede registri mappa e il numero di registri mappa assegnati alla scheda non è sufficiente per descrivere l'intero buffer.
- L'archiviazione allocata dal driver per contenere l'elenco di dispersione/raccolta non è sufficiente per contenere l'elenco di dispersione/raccolta per l'intero buffer.
- Il trasferimento usa un controller DMA di sistema che limita il numero di frammenti di buffer che possono essere specificati in un elenco di dispersione/raccolta hardware.
In tutti questi casi, MapTransferEx esegue il mapping della maggior parte del buffer di dati come può in una chiamata e indica al driver la quantità di buffer mappata dalla chiamata. L'elenco precedente non include altre condizioni, ad esempio il comportamento della cache specifico della piattaforma, che potrebbe richiedere più chiamate a MapTransferEx per completare un trasferimento. Le piattaforme hardware future potrebbero imporre vincoli aggiuntivi sulla lunghezza del trasferimento DMA. Per questi motivi, gli sviluppatori di driver devono progettare i driver per gestire correttamente il caso in cui MapTransferEx non può eseguire il mapping di un intero buffer di dati DMA in una chiamata.
Prima di chiamare MapTransferEx, il chiamante imposta il parametro *Length sul numero di byte nel buffer di dati DMA che deve comunque essere mappato. Prima di restituire, MapTransferEx imposta *Length sul numero di byte nel buffer effettivamente mappato dalla chiamata. Quando una chiamata MapTransferEx non può eseguire il mapping dell'intera lunghezza del buffer, come specificato dal valore di input *Length , il valore di output di *Length è minore del valore di input. Se un trasferimento DMA richiede due o più chiamate MapTransferEx , il driver chiamante deve ottenere il valore di output *Length da una chiamata prima di poter specificare il valore di input *Length per la chiamata successiva.
Ad esempio, se una chiamata MapTransferEx può trasferire solo byte X a o da un buffer per il quale Offset = B e *Length = N (in input), quindi, sulla restituzione, *Length = X. Per la chiamata successiva a MapTransferEx, il driver deve impostare Offset = B + X e *Length = N - X. In entrambe le chiamate viene usata la stessa catena MDL senza modifiche.
Se il chiamante specifica un DmaCompletionRoutine, MapTransferEx scrive il valore di output *Length prima di pianificare l'esecuzione di DmaCompletionRoutine . Questo comportamento garantisce che il valore *Length aggiornato sia sempre disponibile prima dell'esecuzione di DmaCompletionRoutine . Ad esempio, se un trasferimento DMA richiede due chiamate MapTransferEx , DmaCompletionRoutine che la prima pianificazione delle chiamate può ottenere il valore di output *Length dalla prima chiamata. La routine può quindi usare questo valore per calcolare il valore di input *Length per la seconda chiamata. In genere, il parametro Length punta a una posizione nel valore *CompletionContext fornito a DmaCompletionRoutine come parametro.