Condividi tramite


Uso di Common-Buffer System DMA

Un driver che utilizza 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 . Nella figura seguente viene illustrato come un driver alloca il buffer e ne esegue il mapping all'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 la memoria economicamente, il valore lunghezza 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à richiesta di memoria nello spazio indirizzi virtuale di sistema e restituisce due tipi diversi di puntatori a tale buffer:

    • Oggetto LogicalAddress del buffer (BufferLogicalAddress nella figura precedente), per il quale il driver deve fornire spazio di archiviazione, ma che deve ignorare successivamente

    • Indirizzo virtuale del buffer (BufferVirtualAddress nella figura precedente), che il driver deve archiviare in modo da poter compilare un MDL che descrive il 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 lunghezza del relativo buffer per allocare un MDL.

  4. Il driver chiama MmBuildMdlForNonPagedPool con il puntatore restituito da IoAllocateMdl per eseguire il mapping dell'intervallo di indirizzi virtuali per il buffer residente alla 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 del writer 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 da trasferire e, se necessario, chiamare RtlMoveMemory per copiare più dati da o verso un buffer utente.

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

  5. FreeAdapterChannel non appena tutti i dati richiesti sono stati trasferiti o se il driver deve non riuscire a causa di 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 gestire il dispositivo. Ad esempio, la routine StartIo di un driver potrebbe effettuare la chiamata a AllocateAdapterChannel, un altro driver potrebbe effettuare questa chiamata da una routine che rimuove i runtime di integrazione da una coda interlock creata dal driver e un altro driver potrebbe effettuare questa chiamata quando il dispositivo DMA subordinato indica che è pronto per il trasferimento dei dati.