Condividi tramite


Elaborazione di IRP in un driver Lowest-Level

I driver fisici di livello più basso hanno alcune routine standard che non richiedono 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 che ogni conducente controlla

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

  • La progettazione del singolo driver

Per illustrare i ruoli delle routine dei driver standard, nella figura seguente viene illustrato il percorso che può assumere un esempio di IRP mentre viene elaborato da un driver di dispositivo di archiviazione di massa di livello più basso. Il driver nella figura presenta le caratteristiche seguenti:

  • Il dispositivo genera interrupt 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 gli IRP e gestire il proprio accodamento.

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

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

Come illustrato in questa 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 I/O del driver . Tali routine includono routine dispatch che gestiscono più di un codice di funzione di 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 indeterminato di posizioni dello stack di I/O dei driver di livello superiore visualizzate in ombra. Per semplicità, le chiamate a IoGetCurrentIrpStackLocation dalle routine DispatchReadWrite, StartIo, AdapterControle DpcForIsr non vengono visualizzate nella figura precedente.

Chiamare IoMarkIrpPending e IoStartPacket

Il driver di esempio non completa l'IRP nella routine dispatch, ma elabora invece l'IRP nella routine StartIo. Prima di poter eseguire questa operazione, 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 da parte della 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 sta elaborando un altro IRP nel dispositivo, IoStartPacket inserisce l'IRP nella coda di dispositivi associata all'oggetto dispositivo. Il driver può facoltativamente fornire un valore Key come parametro a IoStartPacket per imporre un ordine stabilito dal driver sugli IRP 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 dei dispositivi di archiviazione di massa elaborano rapidamente i pacchetti di richiesta I/O.

In genere, il driver di livello più alto in una catena di driver stratificati gestisce l'annullamento degli IRP.

Chiamata delle funzioni AllocateAdapterChannel e MapTransfer

Supponendo che la routine StartIo , illustrata nella figura che illustra un percorso IRP tramite routine di driver di livello più basso, determini che la richiesta di trasferimento possa essere eseguita da una singola operazione DMA, la routine StartIo chiama AllocateAdapterChannel con il punto di ingresso della routine AdapterControl del driver e l'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. Quindi il driver programma il dispositivo per l'operazione DMA e restituisce. Per altre informazioni sull'uso di oggetti DMA e adattatori, vedere Tecniche di Input/Output.

Chiamata a IoRequestDpc dall'ISR del driver

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

Questa chiamata accoda la routine del driver DpcForIsr per completare il più possibile l'operazione di trasferimento con una priorità hardware inferiore (IRQL).

Chiamata di IoStartNextPacket e IoCompleteRequest

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

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

chiamare iostartnextpacket e iocompleterequest.

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

Se ci sono IRP accodati per il dispositivo, IoStartNextPacket chiama KeRemoveDeviceQueue per rimuovere il prossimo IRP dalla coda. Il gestore di I/O chiama quindi la routine StartIo del driver passando l'IRP rimosso dalla coda. Se non sono attualmente presenti IRP nella coda del dispositivo, IoStartNextPacket ritorna 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 I/O 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, in ultima analisi, 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 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 ritenta 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 a 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 di driver di livello più basso, imposta STATUS_SUCCESS in Status e il numero di byte trasferiti in Information per il blocco di stato I/O di IRP.

Molte delle routine del driver standard restituiscono anche valori di tipo NTSTATUS. Per altre informazioni sulle costanti NTSTATUS come STATUS_SUCCESS, consultare la registrazione degli errori.