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:

  1. 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.

  2. 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.

  3. 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:

  1. 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.

  2. Libere os recursos de hardware do dispositivo (interrupções, portas de E/S, registros de memória e canais de DMA).

  3. 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.

  4. 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.

  5. Falha nas solicitações de E/S pendentes no dispositivo.

  6. Continue a passar todos os IRPs que o driver não manipula para o dispositivo.

  7. Desabilite interfaces de dispositivo com IoSetDeviceInterfaceState.

  8. 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.

  9. 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.

  10. 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.