Condividi tramite


Elaborazione di irP in un driver Lowest-Level

I driver fisici di livello più basso hanno determinate routine standard che non sono necessarie driver di livello superiore. Il set di routine standard per i driver di livello più basso varia anche in base ai criteri seguenti:

  • La natura del dispositivo ogni controllo driver

  • Indica se il driver configura gli oggetti dispositivo per operazioni di I/O dirette o memorizzate nel buffer

  • Progettazione del singolo driver

Per illustrare i ruoli delle routine del driver standard, nella figura seguente viene illustrato il percorso che un provider di risorse IRP di esempio potrebbe accettare durante l'elaborazione da parte di un driver di dispositivo di archiviazione di massa di livello più basso. Il conducente nella figura presenta le caratteristiche seguenti:

  • Il dispositivo genera interruzioni alla fine di ogni operazione di I/O, quindi questo driver ha routine ISR e DpcForIsr .

  • Il driver ha una routine StartIo , anziché configurare code interne per i provider di integrazione e gestire la propria accodamento.

  • Il driver usa DMA di sistema, quindi imposta i flag degli oggetti dispositivo per l'I/O diretto e ha una routine AdapterControl .

diagramma che illustra un percorso irp attraverso routine di driver di livello più basso.

Come illustrato nella figura, il gestore di I/O crea un IRP e lo invia alla routine dispatch del driver per il codice di funzione principale specificato. Supponendo che il codice della funzione sia IRP_MJ_READ o IRP_MJ_WRITE, la routine dispatch è DDDispatchReadWrite.

Chiamata a IoGetCurrentIrpStackLocation

Qualsiasi routine del driver che richiede parametri IRP deve chiamare IoGetCurrentIrpStackLocation per ottenere il percorso dello stack di I/O del driver. Tali routine includono routine dispatch che gestiscono più di un codice di funzione I/O principale (IRP_MJ_*XXX), gestire una funzione che supporta funzioni secondarie (IRP_MN_XXX) o gestire le richieste di controllo di I/O del dispositivo (*IRP_MJ_DEVICE_CONTROL e/o IRP_MJ_INTERNAL_DEVICE_CONTROL), insieme a tutte le altre routine driver che elaborano un IRP.

La posizione dello stack di I/O di questo driver è quella più bassa, con un numero indefinito di percorsi dello stack di I/O dei driver di livello superiore visualizzati ombreggiati. Per semplicità, le chiamate a IoGetCurrentIrpStackLocation dalle routine DispatchReadWrite, StartIo, AdapterControl e DpcForIsr non vengono visualizzate nella figura precedente.

Chiamata di IoMarkIrpPending e IoStartPacket

Il driver di esempio non completa l'IRP nella routine dispatch, ma elabora invece l'IRP nella routine StartIo . Prima di farlo, la routine dispatch chiama IoMarkIrpPending per indicare che l'IRP non è ancora stato completato. Chiama quindi IoStartPacket per accodare l'IRP per un'ulteriore elaborazione dalla routine StartIo del driver. La routine dispatch restituisce anche il valore NTSTATUS STATUS_PENDING.

La figura seguente illustra la chiamata a IoStartPacket.

diagramma che illustra una chiamata a iostartpacket.

Se il driver è occupato nell'elaborazione di un altro IRP nel dispositivo, IoStartPacket inserisce l'IRP nella coda di dispositivi associata all'oggetto dispositivo. Il driver può facoltativamente specificare un valore Key come parametro per IoStartPacket per imporre un ordine determinato dal driver nei provider di integrazione nella coda del dispositivo.

Se il driver non è occupato e la coda del dispositivo è vuota, il gestore di I/O chiama immediatamente la routine StartIo , passando l'IRP di input.

Per i dispositivi di archiviazione di massa, il driver di livello più basso non deve fornire una routine Cancel quando chiama IoStartPacket per due motivi:

  1. Un file system a più livelli su tale driver gestisce in genere l'annullamento delle richieste di I/O dei file.

  2. I driver di dispositivo di archiviazione di massa elaborano rapidamente i runtime di integrazione.

In genere, il driver di livello più alto in una catena di driver a più livelli gestisce l'annullamento dei runtime di integrazione.

Chiamata di AllocateAdapterChannel e MapTransfer

Supponendo che la routine StartIo , illustrata nella figura che illustra un percorso IRP tramite routine driver di livello più basso, determina che la richiesta di trasferimento può essere eseguita da una singola operazione DMA, la routine StartIo chiama AllocateAdapterChannel con il punto di ingresso della routine AdapterControl del driver e IRP.

Quando il controller DMA di sistema è disponibile, il gestore di I/O chiama la routine AdapterControl del driver per configurare l'operazione di trasferimento. La routine AdapterControl chiama MapTransfer per configurare il controller DMA di sistema. Il driver programma quindi il dispositivo per l'operazione DMA e restituisce . Per altre informazioni sull'uso di oggetti DMA e adapter, vedere Tecniche di input/output.

Chiamata di IoRequestDpc dall'ISR del driver

Quando il dispositivo interrompe per indicare che l'operazione di trasferimento è stata completata, l'ISR del driver impedisce al dispositivo di generare interrupt e chiama IoRequestDpc, come illustrato nella figura che illustra un percorso IRP tramite routine driver di livello più basso.

Questa chiamata accoda la routine DpcForIsr del driver per completare la maggior parte dell'operazione di trasferimento possibile con una priorità hardware inferiore (IRQL).

Chiamata a IoStartNextPacket e IoCompleteRequest

Quando la routine DpcForIsr ha completato l'elaborazione del trasferimento, chiama tempestivamente IoStartNextPacket in modo che la routine StartIo del driver venga chiamata con il successivo IRP nella coda del dispositivo, se presente. La routine DpcForIsr imposta anche il blocco di stato I/O di I/O appena completato e quindi chiama IoCompleteRequest per IRP.

La figura seguente illustra le chiamate di questo driver a IoStartNextPacket e IoCompleteRequest.

chiamando iostartnextpacket e iocompleterequest.

I driver devono chiamare IoStartNextPacket o IoStartNextPacketByKey per avviare la successiva operazione di I/O richiesta appena possibile, preferibilmente prima di chiamare IoCompleteRequest.

Se vengono accodati provider di integrazione per il dispositivo, IoStartNextPacket chiama KeRemoveDeviceQueue per rimuovere l'IRP successivo dalla coda. Il gestore di I/O chiama quindi la routine StartIo del driver, passando l'IRP dequeued. Se nella coda del dispositivo non sono presenti IRP, IoStartNextPacket torna semplicemente al chiamante.

Impostazione del blocco di stato di I/O in un IRP

Ogni driver di livello più basso deve impostare il blocco di stato di I/O di IRP prima di chiamare IoCompleteRequest. Nella figura precedente la seconda area ombreggiata indica il blocco di stato. Il blocco di stato di I/O fornisce informazioni ai driver di livello superiore e, infine, al richiedente originale dell'operazione di I/O. Qualsiasi driver di livello superiore al driver nella figura precedente potrebbe aver configurato una routine IoCompletion che legge il blocco di stato di I/O impostato da questo driver. I driver di livello superiore in genere non modificano il blocco di stato di I/O in un IRP completato da un driver di dispositivo, a meno che il driver di livello superiore non stia ritentando l'IRP, nel qual caso reinizializza il blocco di stato di I/O.

Ogni driver di livello superiore che completa un IRP senza inviarlo al driver inferiore successivo deve anche impostare il blocco di stato di I/O in tale IRP prima di chiamare IoCompleteRequest. Per una buona velocità effettiva di I/O complessiva, un driver di livello superiore deve controllare i parametri nella propria posizione dello stack di I/O di ogni IRP e, se i parametri non sono validi, deve impostare il blocco di stato di I/O e completare la richiesta stessa. Quando possibile, un driver deve evitare di passare una richiesta non valida ai driver inferiori nella catena.

Supponendo che l'operazione di trasferimento nella figura precedente abbia esito positivo, la routine DpcForIsr , illustrata nella figura che illustra un percorso IRP tramite routine driver di livello più basso, imposta STATUS_SUCCESS in Stato e il numero di byte trasferiti in Informazioni per il blocco di stato di I/O di IRP.

Molte routine del driver standard restituiscono anche valori di tipo NTSTATUS. Per altre informazioni sulle costanti NTSTATUS come STATUS_SUCCESS, vedere Registrazione degli errori.