Condividi tramite


Utilizzo del sistema DMA Common-Buffer

Un driver che usa la modalità di inizializzazione automatica di un controller DMA di sistema deve allocare memoria per un buffer in cui o da cui è possibile eseguire trasferimenti DMA. Il driver chiama AllocateCommonBuffer per ottenere questo buffer, in genere dalla routine DispatchPnP che gestisce una richiesta di IRP_MN_START_DEVICE . La figura seguente mostra come un driver alloca il buffer ed esegue il mapping dell'intervallo di indirizzi virtuali alla memoria fisica di sistema.

diagramma che illustra come un driver alloca un buffer comune per dma di sistema.

Come illustrato nella figura precedente, un driver esegue i passaggi seguenti per allocare un buffer per DMA di sistema:

  1. Il driver chiama AllocateCommonBuffer, passando un puntatore all'oggetto adapter restituito da IoGetDmaAdapter, insieme alla lunghezza in byte richiesta per il relativo buffer. Per usare economicamente la memoria, il valore length di input per il buffer deve essere minore o uguale a PAGE_SIZE o deve essere un multiplo integrale di PAGE_SIZE.

  2. Se AllocateCommonBuffer restituisce un puntatore NULL , il driver deve liberare tutte le risorse di sistema già richieste e restituire STATUS_INSUFFICIENT_RESOURCES in risposta alla richiesta di IRP_MN_START_DEVICE .

    In caso contrario, AllocateCommonBuffer alloca la quantità di memoria richiesta nello spazio indirizzi virtuale del sistema e restituisce due tipi diversi di puntatori a tale buffer:

    • L'LogicalAddress del buffer (BufferLogicalAddress nella figura precedente), per il quale il driver deve fornire archiviazione, ma che deve poi ignorare.

    • Indirizzo virtuale del buffer (BufferVirtualAddress nella figura precedente), che il driver deve archiviare in modo da poter compilare un file MDL che descrive il relativo buffer per le operazioni DMA

    Il driver deve archiviare questi puntatori nell'estensione del dispositivo o in un'altra memoria residente allocata dal driver.

  3. Il driver chiama IoAllocateMdl per allocare un MDL per il buffer. Il driver passa VirtualAddress del buffer restituito da AllocateCommonBuffer e la Length del relativo buffer per allocare un MDL.

  4. Il driver chiama MmBuildMdlForNonPagedPool con il puntatore restituito da IoAllocateMdl per mappare l'intervallo di indirizzi virtuali del proprio buffer residente nella memoria fisica del sistema.

Dopo aver allocato un buffer comune e aver eseguito il mapping dell'intervallo di indirizzi virtuali, il driver di un dispositivo subordinato può iniziare a elaborare un IRP che richiede un trasferimento DMA. A tale scopo, il driver chiama la sequenza generale seguente di routine di supporto:

  1. A discrezione dell'autore del driver, RtlMoveMemory per copiare i dati da un buffer utente bloccato nel buffer comune allocato dal driver per un trasferimento al dispositivo.

  2. AllocateAdapterChannel quando il driver è pronto per programmare il dispositivo per DMA e necessita del controller DMA di sistema

  3. MapTransfer, con MDL che descrive il buffer comune allocato dal driver, per configurare il controller DMA di sistema per l'operazione di trasferimento

    Si noti che il driver chiama MapTransfer una sola volta per configurare il controller DMA di sistema per usare il buffer comune. Durante un trasferimento, il driver può chiamare ReadDmaCounter per determinare il numero di byte rimanenti da trasferire e, se necessario, chiamare RtlMoveMemory per copiare altri dati da o verso un buffer utente.

  4. FlushAdapterBuffers quando il driver ha completato il trasferimento DMA da/verso il dispositivo subordinato

  5. FreeAdapterChannel non appena tutti i dati richiesti sono stati trasferiti o se il driver deve fallire l'IRP per un errore di I/O del dispositivo

Il puntatore all'oggetto adapter restituito da IoGetDmaAdapter è un parametro obbligatorio per ognuna di queste routine di supporto, ad eccezione di RtlMoveMemory.

I singoli driver chiamano questa sequenza di routine di supporto in punti diversi, a seconda del modo in cui ogni driver viene implementato per il servizio del dispositivo. Ad esempio, la routine StartIo di un driver potrebbe effettuare la chiamata a AllocateAdapterChannel, un altro driver potrebbe eseguire questa chiamata da una routine che rimuove gli IRP da una coda interbloccata creata dal driver stesso e un altro driver potrebbe effettuare questa chiamata quando il dispositivo DMA subordinato indica di essere pronto per trasferire i dati.