Coordenando solicitações de E/S com o estado de energia do componente
[Aplica-se somente ao KMDF]
Um driver KMDF para um dispositivo de vários componentes só deve enviar solicitações para componentes que estão em um estado ativo. Normalmente, o driver atribui filas de E/S a componentes ou conjuntos de componentes.
Considere primeiro uma fila atribuída a um único componente. O driver inicia a fila quando o componente fica ativo e interrompe a fila quando o componente fica ocioso. Dessa forma, quando o KMDF chama um manipulador de solicitação para a fila, o dispositivo está totalmente no estado (D0) e o componente necessário está ativo. O manipulador de solicitação pode acessar com segurança o hardware do componente.
O mesmo conceito se aplica a uma fila atribuída a um conjunto de componentes. Nesse caso, o driver inicia a fila quando todos os componentes no conjunto estão ativos. O driver interrompe a fila quando qualquer um dos componentes fica ocioso.
Este tópico descreve como um driver KMDF para um dispositivo de vários componentes pode implementar esse suporte em uma situação que envolve vários tipos de solicitação que exigem combinações diferentes de componentes.
Exemplo
Para cada tipo de solicitação compatível com o driver, identifique os componentes necessários. Por exemplo, considere um dispositivo que tenha três componentes: 0, 1 e 2, para os quais o driver recebe três tipos de solicitações: A, B e C. Os requisitos de componente das solicitações são os seguintes:
Tipo de solicitação | Componentes necessários |
---|---|
A | 0,2 |
B | 1 |
C | 0,1,2 |
Neste exemplo, há três conjuntos distintos de componentes, um para cada tipo de solicitação. O driver fornece uma fila de E/S gerenciada por energia padrão para o dispositivo, bem como uma fila gerenciada por energia adicional correspondente a cada conjunto de componentes. No exemplo acima, o driver cria uma fila primária e três filas secundárias, uma correspondente a cada conjunto de componentes. Essa configuração de fila é mostrada no diagrama a seguir:
O driver mantém uma máscara de bits para cada conjunto de componentes. Cada bit na máscara de bits representa o estado ativo/ocioso de um dos componentes. Se o bit estiver definido, o componente estará ativo. Se o bit estiver limpo, o componente estará ocioso.
Quando uma solicitação chega, um manipulador de solicitação para a fila de nível superior determina quais componentes a solicitação precisa e chama PoFxActivateComponent para cada um deles. Em seguida, o manipulador de solicitação encaminha a solicitação para a fila de E/S secundária correspondente ao conjunto desse componente.
Quando um componente se torna ativo, a PoFx (estrutura de gerenciamento de energia) chama a rotina ComponentActiveConditionCallback do driver. Nesse retorno de chamada, o driver define o bit correspondente ao componente especificado, em cada máscara de bits em que esse componente é representado. Se todos os bits em uma determinada máscara de bits estiverem definidos, todos os componentes no conjunto correspondente estarão ativos. Para cada conjunto de componentes totalmente ativo, o driver chama WdfIoQueueStart para iniciar a fila de E/S secundária correspondente.
Por exemplo, considere o dispositivo hipotético acima. Suponha que o componente 0 esteja ativo, enquanto os componentes 1 e 2 estão ociosos. Quando o componente 2 se torna ativo, o PoFx chama a rotina ComponentActiveConditionCallback desse componente. Os tipos de solicitação A e C usam o componente 2, portanto, o driver manipula as máscaras de bits para esses dois tipos de solicitação. Como todos os bits na máscara de bits para o tipo de solicitação A agora estão definidos, o driver inicia a fila para o tipo de solicitação A. No entanto, nem todos os bits são definidos para o tipo de solicitação C (o componente 1 ainda está ocioso). O driver não inicia a fila para o tipo de solicitação C.
Quando uma fila de E/S secundária é iniciada, a estrutura começa a fornecer as solicitações armazenadas na fila. No manipulador de solicitação para a fila de E/S secundária, o driver pode processar as solicitações com segurança porque o componente está ativo e uma referência de energia foi feita no componente para cada uma das solicitações.
Quando o driver termina de processar uma solicitação, ele chama PoFxIdleComponent para cada componente que a solicitação estava usando e, em seguida, conclui a solicitação. Quando não há mais solicitações usando um componente, a estrutura de energia chama a rotina ComponentIdleConditionCallback do driver.
Nesse retorno de chamada, o driver limpa o bit correspondente ao componente especificado, em cada máscara de bits em que esse componente é representado. Se uma máscara de bits especificada indicar que o componente é o primeiro no conjunto correspondente a fazer a transição para a condição ociosa, o driver chamará WdfIoQueueStop para interromper a fila de E/S secundária correspondente. Ao fazer isso, o driver garante que a fila não envie solicitações, a menos que todos os componentes no conjunto correspondente estejam ativos.
Considere novamente o exemplo acima. Suponha que todos os componentes estejam ativos e, portanto, todas as filas sejam iniciadas. Quando o componente 1 fica ocioso, PoFx chama a rotina ComponentIdleConditionCallback para o componente 1. Nesse retorno de chamada, o driver manipula as máscaras de bits para os tipos de solicitação B e C porque eles usam o componente 1. Como o componente 1 é o primeiro componente a ficar ocioso para esses dois tipos de solicitação, o driver interrompe as filas para os tipos de solicitação B e C.
Suponha que, neste ponto, o componente 0 fique ocioso. No ComponentIdleConditionCallback para o componente 0, o driver manipula as máscaras de bits para os tipos de solicitação A e C. Como o componente 0 é o primeiro componente a ficar ocioso para o tipo de solicitação A (o componente 2 ainda está ativo), o driver interrompe a fila para o tipo de solicitação A. No entanto, para o tipo de solicitação C, o componente 0 não é o primeiro componente a ficar ocioso. O driver não interrompe a fila para o tipo de solicitação C (ele fez isso anteriormente).
Para usar a técnica descrita neste exemplo, o driver também deve registrar uma função de retorno de chamada EvtIoCanceledOnQueue para cada uma de suas filas secundárias. Se uma solicitação fosse cancelada durante a fila secundária, o driver poderia usar esse retorno de chamada para chamar PoFxIdleComponent para cada componente correspondente. Isso libera a referência de energia que o manipulador de solicitação usou quando chamou PoFxActivateComponent antes de encaminhar a solicitação para a fila secundária.