Gestione di una richiesta di IRP_MN_SURPRISE_REMOVAL
Il gestore PnP di Windows 2000 e versioni successive invia questo IRP per notificare ai driver che un dispositivo non è più disponibile per le operazioni di I/O e probabilmente è stato rimosso in modo imprevisto dal computer ("rimozione a sorpresa").
Il gestore PnP invia una richiesta di IRP_MN_SURPRISE_REMOVAL per i motivi seguenti:
Se il bus ha una notifica di hot-plug, notifica al driver del bus genitore del dispositivo che il dispositivo è sparito. Il conducente del bus chiama IoInvalidateDeviceRelations. In risposta, il gestore PnP esegue una query sull'autista del bus per i relativi figli (IRP_MN_QUERY_DEVICE_RELATIONS per BusRelations). Il gestore PnP determina che il dispositivo non è incluso nel nuovo elenco di figli e avvia le operazioni di rimozione imprevista per il dispositivo.
Il bus viene enumerato per un altro motivo e il dispositivo rimosso a sorpresa non è incluso nell'elenco dei bambini. Il responsabile PnP avvia le operazioni di rimozione a sorpresa.
Il driver di funzione per il dispositivo determina che il dispositivo non è più presente (perché, ad esempio, le richieste vanno in timeout ripetutamente). Il bus potrebbe essere enumerabile, ma non ha una notifica di collegamento a caldo. In questo caso, il driver di funzione chiama IoInvalidateDeviceState. In risposta, il gestore PnP invia una richiesta di IRP_MN_QUERY_PNP_DEVICE_STATE allo stack di dispositivi. Il driver della funzione imposta il flag PNP_DEVICE_FAILED nella maschera di bit PNP_DEVICE_STATE, indicando che il dispositivo ha avuto un guasto.
Lo stack di driver completa correttamente una richiesta di IRP_MN_STOP_DEVICE, ma non riesce quindi a una richiesta di IRP_MN_START_DEVICE successiva. In questi casi, il dispositivo è probabilmente ancora connesso.
Tutti i driver PnP devono gestire questo IRP e devono impostare Irp->IoStatus.Status su STATUS_SUCCESS. Un driver per un dispositivo PnP deve essere preparato per gestire IRP_MN_SURPRISE_REMOVAL in qualsiasi momento dopo che viene chiamata la routine AddDevicedel driverdel driver. Una corretta gestione di IRP consente ai driver e al gestore PnP di:
Disabilitare il dispositivo, nel caso in cui sia ancora connesso.
Se lo stack di driver ha completato correttamente una richiesta di IRP_MN_STOP_DEVICE ma, per qualche motivo, non è riuscita una richiesta di IRP_MN_START_DEVICE successiva, il dispositivo deve essere disabilitato.
Rilasciare le risorse hardware assegnate al dispositivo e renderle disponibili per un altro dispositivo.
Non appena un dispositivo non è più disponibile, le risorse hardware devono essere liberate. Il gestore PnP può quindi riassegnare le risorse a un altro dispositivo, incluso lo stesso dispositivo, che un utente potrebbe ricollegare al computer.
Ridurre al minimo il rischio di perdita di dati e interruzioni del sistema.
I dispositivi che supportano il collegamento a caldo e i relativi driver devono essere progettati per gestire la rimozione delle sorprese. Gli utenti si aspettano di poter rimuovere i dispositivi che supportano il collegamento a caldo in qualsiasi momento.
Il gestore PnP invia un IRP_MN_SURPRISE_REMOVAL a IRQL = PASSIVE_LEVEL nel contesto di un thread di sistema.
Il gestore PnP invia questo protocollo IRP ai driver prima di inviare notifiche alle applicazioni in modalità utente e ad altri componenti in modalità kernel. Al termine dell'IRP, il gestore PnP invia una notifica EventCategoryTargetDeviceChange con GUID_TARGET_DEVICE_REMOVE_COMPLETE ai componenti in modalità kernel registrati per tale notifica nel dispositivo.
Il IRP_MN_SURPRISE_REMOVAL IRP viene gestito prima dal driver principale nello stack di dispositivi e quindi da ogni driver inferiore successivo.
In risposta a IRP_MN_SURPRISE_REMOVAL, un driver deve eseguire le operazioni seguenti, nell'ordine elencato:
Determinare se il dispositivo è stato rimosso.
Il driver deve sempre tentare di determinare se il dispositivo è ancora connesso. In caso affermativo, il driver deve tentare di arrestare il dispositivo e disabilitarlo.
Rilasciare le risorse hardware del dispositivo (interrupt, porte di I/O, registri di memoria e canali DMA).
In un conducente dell'autobus padre, spegnere lo slot dell'autobus se il conducente è in grado di farlo. Chiamare PoSetPowerState per notificare il gestore dell'energia. Per altre informazioni, vedere Risparmio energia.
Impedire le nuove operazioni di I/O nel dispositivo.
Un driver deve elaborare le richieste di IRP_MJ_CLEANUPsuccessive, IRP_MJ_CLOSE, IRP_MJ_POWERe IRP_MJ_PNP; tuttavia, è fondamentale che il driver impedisca qualsiasi nuova operazione di I/O. Un driver deve rigettare tutti gli IRP successivi che il driver avrebbe gestito se il dispositivo fosse presente, eccetto gli IRP di chiusura, pulizia e PnP.
Un driver può impostare un bit nell'estensione del dispositivo per indicare che il dispositivo è stato rimosso a sorpresa. Le routine di invio del driver devono controllare questo bit.
Non è possibile eseguire richieste di I/O in sospeso nel dispositivo.
Continuare a passare tutti i pacchetti di richiesta I/O che il driver non gestisce per il dispositivo.
Disabilitare le interfacce del dispositivo con IoSetDeviceInterfaceState.
Pulire eventuali allocazioni specifiche del dispositivo, memoria, eventi o altre risorse di sistema.
Un driver potrebbe posticipare tale pulizia fino a ricevere la richiesta successiva di IRP_MN_REMOVE_DEVICE, ma se un componente legacy ha un handle aperto che non può essere chiuso, l'IRP di rimozione non verrà mai inviato.
Lasciare collegato l'oggetto dispositivo allo stack di dispositivi.
Non scollegare né eliminare l'oggetto dispositivo fino alla richiesta successiva di IRP_MN_REMOVE_DEVICE.
Completare l'IRP.
In una funzione o in un driver di filtro:
Impostare Irp->IoStatus.Status su STATUS_SUCCESS.
Configurare la posizione successiva dello stack con IoSkipCurrentIrpStackLocation e passare l'IRP al driver inferiore successivo con IoCallDriver.
Propagare lo stato da IoCallDriver come stato restituito dalla routine DispatchPnP.
Non completare l'IRP.
In un autista di autobus (che gestisce questo IRP per un PDO figlio):
Impostare Irp->IoStatus.Status su STATUS_SUCCESS.
Completare l'IRP (IoCompleteRequest) con IO_NO_INCREMENT.
Tornare dalla routine DispatchPnP.
Dopo che l'IRP ha esito positivo e tutti gli handle aperti per il dispositivo vengono chiusi, il gestore PnP invia una richiesta di IRP_MN_REMOVE_DEVICE allo stack di dispositivi. In risposta agli IRP di rimozione, i driver scollegano gli oggetti dispositivo dallo stack e li eliminano. Se un componente legacy mantiene un handle aperto al dispositivo e lascia l'handle aperto nonostante gli errori di I/O, il gestore PnP non invia mai l'IRP di rimozione.
Tutti i driver devono gestire questo IRP e devono notare che il dispositivo è stato fisicamente rimosso dal computer. Alcuni driver, tuttavia, non causeranno risultati negativi se non gestiscono l'IRP. Ad esempio, un dispositivo che non utilizza risorse hardware di sistema e risiede in un bus basato su protocollo, ad esempio USB o 1394, non può collegare le risorse hardware perché non utilizza alcuna risorsa hardware. Non c'è alcun rischio che i driver tentino di accedere al dispositivo dopo che è stato rimosso, perché i driver di funzione e filtro accedono al dispositivo solo tramite il driver del bus principale. Poiché il bus supporta la notifica di rimozione, il driver del bus principale riceve una notifica quando il dispositivo scompare e il driver del bus non riesce in tutti i tentativi successivi di accesso al dispositivo.
In Windows 98/Me, il gestore PnP non invia questo IRP. Se un utente rimuove un dispositivo senza usare prima l'interfaccia utente appropriata, il gestore PnP invia solo una richiesta di IRP_MN_REMOVE_DEVICE ai driver per il dispositivo. Tutti i driver WDM devono gestire sia IRP_MN_SURPRISE_REMOVAL che IRP_MN_REMOVE_DEVICE. Il codice per IRP_MN_REMOVE_DEVICE deve verificare se il driver ha ricevuto un IRP di rimozione sorpresa precedente e deve gestire entrambi i casi.
Utilizzo di GUID_REENUMERATE_SELF_INTERFACE_STANDARD
L'interfaccia GUID_REENUMERATE_SELF_INTERFACE_STANDARD consente a un driver di richiedere la rinumerazione del proprio dispositivo.
Per utilizzare questa interfaccia, inviare un IRP_MN_QUERY_INTERFACE IRP al driver del bus con InterfaceType = GUID_REENUMERATE_SELF_INTERFACE_STANDARD. Il conducente del bus fornisce un puntatore verso una struttura di tipo REENUMERATE_SELF_INTERFACE_STANDARD che contiene puntatori alle singole routine dell'interfaccia. Una routine ReenumerateSelf richiede che un autista del bus rienumera un dispositivo figlio.
Informazioni su PNP_DEVICE_STATE
Il tipo PNP_DEVICE_STATE è una maschera di bit che descrive lo stato PnP di un dispositivo. Un driver restituisce un valore di questo tipo in risposta a una richiesta di IRP_MN_QUERY_PNP_DEVICE_STATE.
typedef ULONG PNP_DEVICE_STATE, *PPNP_DEVICE_STATE;
I bit di flag in un valore PNP_DEVICE_STATE sono definiti come segue.
Bit di segnalazione | Descrizione |
---|---|
Dispositivo PNP disabilitato | Il dispositivo è fisicamente presente, ma è disabilitato nell'hardware. |
Dispositivo PNP_Non Mostrare nell'Interfaccia Utente | Non visualizzare il dispositivo nell'interfaccia utente. Impostare per un dispositivo fisicamente presente ma non utilizzabile nella configurazione corrente, ad esempio una porta di gioco su un portatile che non è utilizzabile quando il portatile è scollegato. Vedere anche il flag di NoDisplayInUI nella struttura DEVICE_CAPABILITIES. |
DISPOSITIVO_PNP_NON_RIUSCITO | Il dispositivo è presente ma non funziona correttamente. Quando vengono impostati sia questo flag che PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED, il dispositivo deve essere arrestato prima che il gestore PnP assegni nuove risorse hardware (il ribilanciamento non è supportato per il dispositivo). |
DISPOSITIVO_PNP_NON_DISATTIVABILE | Il dispositivo è necessario all'avvio del computer. Un dispositivo di questo tipo non deve essere disabilitato. Un driver imposta questo bit per un dispositivo necessario per il corretto funzionamento del sistema. Ad esempio, se un driver riceve una notifica che indica che un dispositivo si trova nel percorso di paging (IRP_MN_DEVICE_USAGE_NOTIFICATION per DeviceUsageTypePaging), il driver chiama IoInvalidateDeviceState e imposta questo flag nella richiesta di IRP_MN_QUERY_PNP_DEVICE_STATE risultante. Se questo bit è impostato per un dispositivo, il gestore PnP propaga questa impostazione al dispositivo padre, al dispositivo nonno e così via. Se questo bit è impostato per un dispositivo enumerato come principale, il dispositivo non può essere disabilitato o disinstallato. |
DISPOSITIVO_PNP_RIMOSSO | Il dispositivo è stato rimosso fisicamente. |
PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED | I requisiti delle risorse per il dispositivo sono stati modificati. In genere, un driver del bus imposta questo flag quando ha determinato che deve espandere i requisiti delle risorse per enumerare un nuovo dispositivo figlio. |
DISPOSITIVO_PNP_DISCONNESSO | Il driver di dispositivo viene caricato, ma questo driver ha rilevato che il dispositivo non è più connesso al computer. In genere, questo flag viene usato per i driver di funzione che comunicano con i dispositivi wireless. Ad esempio, il flag viene impostato quando il dispositivo esce dall'intervallo e viene cancellato dopo che il dispositivo torna nell'intervallo e si connette di nuovo. Un autista di autobus non imposta in genere questo segnale. Il driver del bus deve invece interrompere l'enumerazione del dispositivo figlio se il dispositivo non è più connesso. Questo flag viene usato solo se il driver della funzione gestisce la connessione. L'unico scopo di questo flag è informare i client se il dispositivo è connesso. L'impostazione del flag non influisce sul se il driver venga caricato. |
Il gestore PnP esegue una query sul PNP_DEVICE_STATE di un dispositivo subito dopo l'avvio del dispositivo inviando una richiesta di IRP_MN_QUERY_PNP_DEVICE_STATE allo stack di dispositivi. In risposta a questo IRP, i driver per il dispositivo impostano i flag appropriati in PNP_DEVICE_STATE.
Se una delle caratteristiche dello stato cambia dopo la query iniziale, un driver invia una notifica al gestore PnP chiamando IoInvalidateDeviceState. In risposta a una chiamata a IoInvalidateDeviceState, il gestore PnP esegue di nuovo una query sul PNP_DEVICE_STATE del dispositivo.
Se un dispositivo è contrassegnato PNP_DEVICE_NOT_DISABLEABLE, il debugger visualizza un flag utente DNUF_NOT_DISABLEABLE per devnode. Il debugger visualizza anche un DisableableDepends valore che conta il numero di motivi per cui il dispositivo non può essere disabilitato. Questo valore è la somma di X+Y, dove X è uno se il dispositivo non può essere disabilitato e Y è il conteggio dei dispositivi figlio del dispositivo che non possono essere disabilitati.