Coordination des demandes d’E/S avec l’état d’alimentation du composant
[S’applique uniquement à KMDF]
Un pilote KMDF pour un appareil à plusieurs composants doit uniquement envoyer des requêtes aux composants qui sont dans un état actif. En règle générale, le pilote affecte des files d’attente d’E/S à des composants ou à des ensembles de composants.
Considérez d’abord une file d’attente affectée à un seul composant. Le pilote démarre la file d’attente lorsque le composant devient actif et arrête la file d’attente lorsque le composant devient inactif. Par conséquent, lorsque KMDF appelle un gestionnaire de requêtes pour la file d’attente, l’appareil est dans son état entièrement activé (D0) et le composant requis est actif. Le gestionnaire de requêtes peut accéder en toute sécurité au matériel du composant.
Le même concept s’applique à une file d’attente affectée à un ensemble de composants. Dans ce cas, le pilote démarre la file d’attente lorsque tous les composants du jeu sont actifs. Le pilote arrête la file d’attente lorsque l’un des composants devient inactif.
Cette rubrique décrit comment un pilote KMDF pour un appareil à composants multiples peut implémenter une telle prise en charge dans une situation impliquant plusieurs types de requêtes qui nécessitent différentes combinaisons de composants.
Exemple
Pour chaque type de requête pris en charge par le pilote, identifiez les composants requis. Par exemple, considérez un appareil qui a trois composants : 0, 1 et 2, pour lequel le pilote reçoit trois types de requêtes : A, B et C. Les exigences de composant des requêtes sont les suivantes :
Type de demande | Composants nécessaires |
---|---|
A | 0,2 |
B | 1 |
C | 0,1,2 |
Dans cet exemple, il existe trois ensembles distincts de composants, un pour chaque type de requête. Le pilote fournit une file d’E/S par défaut gérée par l’alimentation pour l’appareil, ainsi qu’une file d’attente supplémentaire sous gestion de l’alimentation correspondant à chaque ensemble de composants. Dans l’exemple ci-dessus, le pilote crée une file d’attente principale et trois files d’attente secondaires, une correspondant à chaque ensemble de composants. Cette configuration de file d’attente est illustrée dans le diagramme suivant :
Le pilote gère un masque de bits pour chaque ensemble de composants. Chaque bit dans le masque de bits représente l’état actif/inactif de l’un des composants. Si le bit est défini, le composant est actif. Si le bit est effacé, le composant est inactif.
Lorsqu’une requête arrive, un gestionnaire de requêtes pour la file d’attente de niveau supérieur détermine les composants dont la requête a besoin et appelle PoFxActivateComponent pour chacun d’eux. Le gestionnaire de requêtes transfère ensuite la demande à la file d’attente d’E/S secondaire correspondant à l’ensemble de ce composant.
Lorsqu’un composant devient actif, l’infrastructure de gestion de l’alimentation (PoFx) appelle la routine ComponentActiveConditionCallback du pilote. Dans ce rappel, le pilote définit le bit correspondant au composant spécifié, dans chaque masque de bits où ce composant est représenté. Si tous les bits d’un masque de bits donné sont définis, tous les composants du jeu correspondant sont actifs. Pour chaque jeu de composants entièrement actif, le pilote appelle WdfIoQueueStart pour démarrer la file d’attente d’E/S secondaire correspondante.
Par exemple, considérez l’appareil hypothétique ci-dessus. Supposons que le composant 0 soit actif, tandis que les composants 1 et 2 sont inactifs. Lorsque le composant 2 devient actif, PoFx appelle la routine ComponentActiveConditionCallback de ce composant. Les types de requête A et C utilisent le composant 2, de sorte que le pilote manipule les masques de bits pour ces deux types de requête. Étant donné que tous les bits du masque de bits pour la requête de type A sont désormais définis, le pilote démarre la file d’attente pour le type de requête A. Toutefois, tous les bits ne sont pas définis pour le type de requête C (le composant 1 est toujours inactif). Le pilote ne démarre pas la file d’attente pour le type de requête C.
Lorsqu’une file d’E/S secondaire est démarrée, l’infrastructure commence à remettre les requêtes stockées dans la file d’attente. Dans le gestionnaire de demandes pour la file d’attente d’E/S secondaire, le pilote peut traiter les demandes en toute sécurité, car le composant est actif et une référence d’alimentation a été effectuée sur le composant pour chacune des demandes.
Lorsque le pilote termine le traitement d’une requête, il appelle PoFxIdleComponent pour chaque composant utilisé par la demande, puis termine la demande. Lorsqu’il n’y a plus de demandes à l’aide d’un composant, l’infrastructure d’alimentation appelle la routine ComponentIdleConditionCallback du pilote.
Dans ce rappel, le pilote efface le bit correspondant au composant spécifié, dans chaque masque de bits où ce composant est représenté. Si un masque de bits donné indique que le composant est le premier du jeu correspondant à passer à la condition d’inactivité, le pilote appelle WdfIoQueueStop pour arrêter la file d’E/S secondaire correspondante. Ce faisant, le pilote s’assure que la file d’attente ne distribue pas les requêtes, sauf si tous les composants de l’ensemble correspondant sont actifs.
Examinez à nouveau l’exemple ci-dessus. Supposons que tous les composants sont actifs et que, par conséquent, toutes les files d’attente sont démarrées. Lorsque le composant 1 devient inactif, PoFx appelle la routine ComponentIdleConditionCallback pour le composant 1. Dans ce rappel, le pilote manipule les masques de bits pour les types de requête B et C, car ils utilisent le composant 1. Étant donné que le composant 1 est le premier composant à devenir inactif pour ces deux types de requêtes, le pilote arrête les files d’attente pour les types de requête B et C.
Supposons qu’à ce stade, le composant 0 devient inactif. Dans le ComponentIdleConditionCallback pour le composant 0, le pilote manipule les masques de bits pour les types de requête A et C. Étant donné que le composant 0 est le premier composant à devenir inactif pour le type de requête A (le composant 2 est toujours actif), le pilote arrête la file d’attente pour le type de requête A. Toutefois, pour le type de requête C, le composant 0 n’est pas le premier composant à devenir inactif. Le pilote n’arrête pas la file d’attente pour le type de requête C (il l’a fait précédemment).
Pour utiliser la technique décrite dans cet exemple, le pilote doit également inscrire une fonction de rappel EvtIoCanceledOnQueue pour chacune de ses files d’attente secondaires. Si une demande devait être annulée dans la file d’attente secondaire, le pilote peut utiliser ce rappel pour appeler PoFxIdleComponent pour chaque composant correspondant. Cela libère la référence d’alimentation que le gestionnaire de requêtes a prise lorsqu’il a appelé PoFxActivateComponent avant de transférer la demande à la file d’attente secondaire.