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 plug-hot, notifica al driver del bus padre del dispositivo che il dispositivo è scomparso. Il driver dell'autobus chiama IoInvalidateDeviceRelations. In risposta, il gestore PnP esegue una query sul driver del bus per i relativi elementi figlio (IRP_MN_QUERY_DEVICE_RELATIONS per BusRelations). Il gestore PnP determina che il dispositivo non è incluso nel nuovo elenco di elementi figlio e avvia le operazioni di rimozione a sorpresa per il dispositivo.
Il bus viene enumerato per un altro motivo e il dispositivo rimosso a sorpresa non è incluso nell'elenco di elementi figlio. Il gestore 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 si verifica più volte il timeout). L'autobus potrebbe essere enumerabile, ma non dispone di una notifica con plug-hot.The bus might be enumerable but it does not have hot-plug notification. 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 che indica che il dispositivo non è riuscito.
Lo stack di driver completa correttamente una richiesta di IRP_MN_STOP_DEVICE , ma quindi non riesce 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 la chiamata alla routine AddDevice del 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 plug-in hot e i relativi driver devono essere progettati per gestire la rimozione a sorpresa. Gli utenti si aspettano di essere in grado di rimuovere i dispositivi che supportano la connessione ad accesso frequente in qualsiasi momento.
Il gestore PnP invia un IRP_MN_SURPRISE_REMOVAL in IRQL = PASSIVE_LEVEL nel contesto di un thread di sistema.
Il gestore PnP invia questo protocollo IRP ai driver prima di notificare le applicazioni in modalità utente e 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 inviare una notifica al risparmio energia. Per altre informazioni, vedere Risparmio energia.
Impedire nuove operazioni di I/O nel dispositivo.
Un driver deve elaborare le richieste di IRP_MJ_CLEANUP, IRP_MJ_CLOSE, IRP_MJ_POWER e IRP_MJ_PNP successive, ma il driver deve impedire nuove operazioni di I/O. Un driver deve avere esito negativo per tutti i runtime di integrazione successivi che il driver avrebbe gestito se il dispositivo fosse presente, oltre a chiudere, pulire e PnP IRP.
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 runtime di integrazione che il driver non gestisce per il dispositivo.
Disabilitare le interfacce del dispositivo con IoSetDeviceInterfaceState.
Pulire eventuali allocazioni, memoria, eventi o altre risorse di sistema specifiche del dispositivo.
Un driver potrebbe posticipare tale pulizia fino a quando non riceve la richiesta di IRP_MN_REMOVE_DEVICE successiva, ma se un componente legacy ha un handle aperto che non può essere chiuso, l'IRP di rimozione non verrà mai inviato.
Lasciare l'oggetto dispositivo collegato allo stack di dispositivi.
Non scollegare ed eliminare l'oggetto dispositivo fino alla richiesta di IRP_MN_REMOVE_DEVICE successiva.
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 conducente dell'autobus (che gestisce questo IRP per un PDO figlio):
Impostare Irp-IoStatus.Status> su STATUS_SUCCESS.
Completare 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 alla rimozione di IRP, i driver scollegano gli oggetti dispositivo dallo stack ed eliminarli. Se un componente legacy ha un handle aperto al dispositivo e lascia aperto l'handle 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. Non c'è rischio che i driver tentino di accedere al dispositivo dopo che è stato rimosso perché la funzione e i driver di filtro accedono al dispositivo solo tramite il driver del bus padre. Poiché il bus supporta la notifica di rimozione, il driver del bus padre riceve una notifica quando il dispositivo scompare e il driver dell'autobus non riesce a tutti i tentativi successivi di accedere al dispositivo.
In Windows 98/Me, il gestore PnP non invia questo IRP. Se un utente rimuove un dispositivo senza prima usare 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 cheIRP_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.
Uso di GUID_REENUMERATE_SELF_INTERFACE_STANDARD
L'interfaccia GUID_REENUMERATE_SELF_INTERFACE_STANDARD consente a un driver di richiedere che il dispositivo venga rinumerato.
Per usare questa interfaccia, inviare un IRP_MN_QUERY_INTERFACE IRP al driver dell'autobus con InterfaceType = GUID_REENUMERATE_SELF_INTERFACE_STANDARD. Il conducente del bus fornisce un puntatore a una struttura REENUMERATE_SELF_INTERFACE_STANDARD che contiene puntatori alle singole routine dell'interfaccia. Una routine ReenumerateSelf richiede che un driver del bus rienumeri 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 del flag in un valore PNP_DEVICE_STATE sono definiti come segue.
Flag bit | Descrizione |
---|---|
PNP_DEVICE_DISABLED | Il dispositivo è fisicamente presente ma è disabilitato nell'hardware. |
PNP_DEVICE_DONT_DISPLAY_IN_UI | 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 viene scollegato. Vedere anche il flag NoDisplayInUI nella struttura DEVICE_CAPABILITIES . |
PNP_DEVICE_FAILED | Il dispositivo è presente ma non funziona correttamente. Quando questo flag e PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED sono impostati, il dispositivo deve essere arrestato prima che il gestore PnP assegni nuove risorse hardware (il ribilanciamento senza interruzioni non è supportato per il dispositivo). |
PNP_DEVICE_NOT_DISABLEABLE | 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 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 del dispositivo, al dispositivo padre e così via. Se questo bit è impostato per un dispositivo con enumerazione radice, il dispositivo non può essere disabilitato o disinstallato. |
PNP_DEVICE_REMOVED | 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. |
PNP_DEVICE_DISCONNECTED | 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 dispositivi wireless. Ad esempio, il flag viene impostato quando il dispositivo esce dall'intervallo e viene cancellato dopo che il dispositivo si sposta di nuovo nell'intervallo e si riconnette. Un driver del bus in genere non imposta questo flag. 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 di funzione gestisce la connessione. L'unico scopo di questo flag è informare i client se il dispositivo è connesso. L'impostazione del flag non influisce sul fatto che 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 valore DisableableDepends 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.