Manipulando uma solicitação de IRP_MN_SURPRISE_REMOVAL
O gerenciador PnP do Windows 2000 e posterior envia esse IRP para notificar os drivers de que um dispositivo não está mais disponível para operações de E/S e provavelmente foi removido inesperadamente do computador ("remoção surpresa").
O gerenciador PnP envia uma solicitação de IRP_MN_SURPRISE_REMOVAL pelos seguintes motivos:
Se o barramento tiver uma notificação de hot-plug, ele notificará o motorista do barramento pai do dispositivo de que o dispositivo desapareceu. O motorista do ônibus chama IoInvalidateDeviceRelations. Em resposta, o gerente PnP consulta o motorista do ônibus para seus filhos (IRP_MN_QUERY_DEVICE_RELATIONS para BusRelations). O gerenciador PnP determina que o dispositivo não está na nova lista de filhos e inicia suas operações de remoção surpresa para o dispositivo.
O barramento é enumerado por outro motivo e o dispositivo removido de surpresa não está incluído na lista de filhos. O gerenciador PnP inicia suas operações de remoção surpresa.
O driver de função para o dispositivo determina que o dispositivo não está mais presente (porque, por exemplo, suas solicitações tempo limite repetidamente). O barramento pode ser enumerável, mas não tem notificação de hot-plug. Nesse caso, o driver de função chama IoInvalidateDeviceState. Em resposta, o gerenciador PnP envia uma solicitação de IRP_MN_QUERY_PNP_DEVICE_STATE para a pilha de dispositivos. O driver de função define o sinalizador PNP_DEVICE_FAILED na máscara de bits PNP_DEVICE_STATE indicando que o dispositivo falhou.
A pilha de driver conclui com êxito uma solicitação de IRP_MN_STOP_DEVICE , mas falha em uma solicitação de IRP_MN_START_DEVICE subsequente. Nesses casos, o dispositivo provavelmente ainda está conectado.
Todos os drivers PnP devem lidar com esse IRP e devem definir Irp-IoStatus.Status> como STATUS_SUCCESS. Um driver para um dispositivo PnP deve estar preparado para lidar com IRP_MN_SURPRISE_REMOVAL a qualquer momento depois que a rotina AddDevice do driver for chamada. A manipulação adequada do IRP permite que os drivers e o gerenciador PnP:
Desabilite o dispositivo, caso ele ainda esteja conectado.
Se a pilha de driver tiver concluído com êxito uma solicitação de IRP_MN_STOP_DEVICE , mas, por algum motivo, falhou em uma solicitação de IRP_MN_START_DEVICE subsequente, o dispositivo deverá ser desabilitado.
Libere os recursos de hardware atribuídos ao dispositivo e disponibilize-os para outro dispositivo.
Assim que um dispositivo não estiver mais disponível, seus recursos de hardware deverão ser liberados. O gerenciador PnP pode reatribuir os recursos para outro dispositivo, incluindo o mesmo dispositivo, que um usuário pode conectar-se novamente ao computador.
Minimize o risco de perda de dados e interrupção do sistema.
Os dispositivos que dão suporte à hot-pluging e seus drivers devem ser projetados para lidar com a remoção surpresa. Os usuários esperam poder remover dispositivos que dão suporte ao hot-pluging a qualquer momento.
O gerenciador PnP envia um IRP_MN_SURPRISE_REMOVAL em IRQL = PASSIVE_LEVEL no contexto de um thread do sistema.
O gerenciador PnP envia esse IRP para drivers antes de notificar aplicativos de modo de usuário e outros componentes do modo kernel. Após a conclusão do IRP, o gerenciador de PnP envia uma notificação EventCategoryTargetDeviceChange com GUID_TARGET_DEVICE_REMOVE_COMPLETE para componentes do modo kernel registrados para essa notificação no dispositivo.
O IRP_MN_SURPRISE_REMOVAL IRP é manipulado primeiro pelo driver superior na pilha do dispositivo e, em seguida, por cada driver inferior seguinte.
Em resposta a IRP_MN_SURPRISE_REMOVAL, um driver deve fazer o seguinte, na ordem listada:
Determine se o dispositivo foi removido.
O driver sempre deve tentar determinar se o dispositivo ainda está conectado. Se estiver, o driver deve tentar parar o dispositivo e desabilitá-lo.
Libere os recursos de hardware do dispositivo (interrupções, portas de E/S, registros de memória e canais de DMA).
Em um motorista de ônibus pai, desligue o slot do ônibus se o motorista for capaz de fazê-lo. Chame PoSetPowerState para notificar o power manager. Para obter informações adicionais, consulte Gerenciamento de Energia.
Impedir novas operações de E/S no dispositivo.
Um driver deve processar solicitações subsequentes de IRP_MJ_CLEANUP, IRP_MJ_CLOSE, IRP_MJ_POWER e IRP_MJ_PNP , mas o driver deve impedir novas operações de E/S. Um driver deve falhar em todos os IRPs subsequentes que o driver teria manipulado se o dispositivo estivesse presente, além de fechar, limpo-up e PnP IRPs.
Um driver pode definir um pouco na extensão do dispositivo para indicar que o dispositivo foi removido de surpresa. As rotinas de expedição do driver devem marcar esse bit.
Falha nas solicitações de E/S pendentes no dispositivo.
Continue a passar todos os IRPs que o driver não manipula para o dispositivo.
Desabilite interfaces de dispositivo com IoSetDeviceInterfaceState.
Limpe todas as alocações, memória, eventos ou outros recursos do sistema específicos do dispositivo.
Um driver pode adiar esse limpo até receber a solicitação de IRP_MN_REMOVE_DEVICE subsequente, mas se um componente herdado tiver um identificador aberto que não possa ser fechado, o IRP de remoção nunca será enviado.
Deixe o objeto do dispositivo anexado à pilha do dispositivo.
Não desanexe e exclua o objeto de dispositivo até que o IRP_MN_REMOVE_DEVICE solicitação subsequente.
Conclua o IRP.
Em uma função ou driver de filtro:
Defina Irp-IoStatus.Status> como STATUS_SUCCESS.
Configure o próximo local de pilha com IoSkipCurrentIrpStackLocation e passe o IRP para o próximo driver inferior com IoCallDriver.
Propagar o status do IoCallDriver como o status de retorno da rotina DispatchPnP.
Não conclua o IRP.
Em um motorista de ônibus (que está tratando esse IRP para um PDO filho):
Defina Irp-IoStatus.Status> como STATUS_SUCCESS.
Conclua o IRP (IoCompleteRequest) com IO_NO_INCREMENT.
Retorne da rotina DispatchPnP .
Depois que esse IRP for bem-sucedido e todos os identificadores abertos para o dispositivo forem fechados, o gerenciador de PnP enviará uma solicitação de IRP_MN_REMOVE_DEVICE para a pilha de dispositivos. Em resposta à remoção do IRP, os drivers desanexam seus objetos de dispositivo da pilha e os excluem. Se um componente herdado tiver um identificador aberto no dispositivo e deixar o identificador aberto apesar de falhas de E/S, o gerenciador de PnP nunca enviará o IRP de remoção.
Todos os drivers devem lidar com esse IRP e devem observar que o dispositivo foi fisicamente removido do computador. Alguns drivers, no entanto, não causarão resultados adversos se não lidarem com o IRP. Por exemplo, um dispositivo que não consome recursos de hardware do sistema e reside em um barramento baseado em protocolo, como USB ou 1394, não pode vincular recursos de hardware porque não consome nenhum. Não há risco de drivers tentarem acessar o dispositivo depois que ele tiver sido removido porque a função e os drivers de filtro acessam o dispositivo somente por meio do driver de ônibus pai. Como o barramento dá suporte à notificação de remoção, o motorista do ônibus pai é notificado quando o dispositivo desaparece e o motorista do ônibus falha em todas as tentativas subsequentes de acessar o dispositivo.
No Windows 98/Me, o gerenciador PnP não envia esse IRP. Se um usuário remover um dispositivo sem primeiro usar a interface do usuário apropriada, o gerenciador de PnP enviará apenas uma solicitação de IRP_MN_REMOVE_DEVICE para os drivers do dispositivo. Todos os drivers WDM devem lidar com IRP_MN_SURPRISE_REMOVAL e IRP_MN_REMOVE_DEVICE. O código para IRP_MN_REMOVE_DEVICE deve marcar se o driver recebeu um IRP de remoção surpresa anterior e deve lidar com ambos os casos.
Usando GUID_REENUMERATE_SELF_INTERFACE_STANDARD
A interface GUID_REENUMERATE_SELF_INTERFACE_STANDARD permite que um driver solicite que seu dispositivo seja reenumerado.
Para usar essa interface, envie um IRP_MN_QUERY_INTERFACE IRP para o driver de barramento com InterfaceType = GUID_REENUMERATE_SELF_INTERFACE_STANDARD. O driver de barramento fornece um ponteiro para uma estrutura REENUMERATE_SELF_INTERFACE_STANDARD que contém ponteiros para as rotinas individuais da interface. Uma rotina ReenumerateSelf solicita que um motorista de ônibus reenumere um dispositivo filho.
Sobre PNP_DEVICE_STATE
O tipo PNP_DEVICE_STATE é uma máscara de bits que descreve o estado PnP de um dispositivo. Um driver retorna um valor desse tipo em resposta a uma solicitação de IRP_MN_QUERY_PNP_DEVICE_STATE .
typedef ULONG PNP_DEVICE_STATE, *PPNP_DEVICE_STATE;
Os bits de sinalizador em um valor PNP_DEVICE_STATE são definidos da seguinte maneira.
Bit de sinalizador | Descrição |
---|---|
PNP_DEVICE_DISABLED | O dispositivo está fisicamente presente, mas está desabilitado no hardware. |
PNP_DEVICE_DONT_DISPLAY_IN_UI | Não exiba o dispositivo na interface do usuário. Defina para um dispositivo fisicamente presente, mas não utilizável na configuração atual, como uma porta de jogo em um laptop que não é utilizável quando o laptop é desencaixado. (Consulte também o sinalizador NoDisplayInUI na estrutura DEVICE_CAPABILITIES .) |
PNP_DEVICE_FAILED | O dispositivo está presente, mas não está funcionando corretamente. Quando esse sinalizador e PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED são definidos, o dispositivo deve ser interrompido antes que o gerenciador PnP atribua novos recursos de hardware (não há suporte para o rebalanceamento sem interrupção para o dispositivo). |
PNP_DEVICE_NOT_DISABLEABLE | O dispositivo é necessário quando o computador é iniciado. Esse dispositivo não deve ser desabilitado. Um driver define esse bit para um dispositivo necessário para a operação adequada do sistema. Por exemplo, se um driver receber uma notificação de que um dispositivo está no caminho de paginação (IRP_MN_DEVICE_USAGE_NOTIFICATION para DeviceUsageTypePaging), o driver chamará IoInvalidateDeviceState e definirá esse sinalizador na solicitação de IRP_MN_QUERY_PNP_DEVICE_STATE resultante. Se esse bit estiver definido para um dispositivo, o gerenciador PnP propagará essa configuração para o dispositivo pai do dispositivo, o dispositivo pai e assim por diante. Se esse bit estiver definido para um dispositivo enumerado raiz, o dispositivo não poderá ser desabilitado ou desinstalado. |
PNP_DEVICE_REMOVED | O dispositivo foi fisicamente removido. |
PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED | Os requisitos de recurso para o dispositivo foram alterados. Normalmente, um motorista de barramento define esse sinalizador quando determina que ele deve expandir seus requisitos de recursos para enumerar um novo dispositivo filho. |
PNP_DEVICE_DISCONNECTED | O driver do dispositivo é carregado, mas esse driver detectou que o dispositivo não está mais conectado ao computador. Normalmente, esse sinalizador é usado para drivers de função que se comunicam com dispositivos sem fio. Por exemplo, o sinalizador é definido quando o dispositivo sai do intervalo e é limpo depois que o dispositivo volta para o intervalo e se conecta novamente. Normalmente, um motorista de ônibus não define esse sinalizador. Em vez disso, o motorista do barramento deve parar de enumerar o dispositivo filho se o dispositivo não estiver mais conectado. Esse sinalizador será usado somente se o driver de função gerenciar a conexão. A única finalidade desse sinalizador é informar os clientes se o dispositivo está conectado. Definir o sinalizador não afeta se o driver está carregado. |
O gerenciador PnP consulta a PNP_DEVICE_STATE de um dispositivo logo após iniciar o dispositivo enviando uma solicitação IRP_MN_QUERY_PNP_DEVICE_STATE para a pilha de dispositivos. Em resposta a esse IRP, os drivers do dispositivo definem os sinalizadores apropriados em PNP_DEVICE_STATE.
Se qualquer uma das características de estado for alterada após a consulta inicial, um driver notificará o gerenciador PnP chamando IoInvalidateDeviceState. Em resposta a uma chamada para IoInvalidateDeviceState, o gerenciador PnP consulta o PNP_DEVICE_STATE do dispositivo novamente.
Se um dispositivo estiver marcado como PNP_DEVICE_NOT_DISABLEABLE, o depurador exibirá um sinalizador de usuário DNUF_NOT_DISABLEABLE para o devnode. O depurador também exibe um valor DisableDepends que conta o número de motivos pelos quais o dispositivo não pode ser desabilitado. Esse valor é a soma de X+Y, em que X é um se o dispositivo não pode ser desabilitado e Y é a contagem dos dispositivos filho do dispositivo que não podem ser desabilitados.