Traitement des IRP dans un pilote Lowest-Level
Les conducteurs physiques de niveau inférieur ont certaines routines standard dont les conducteurs de niveau supérieur n’ont pas besoin. L’ensemble des routines standard pour les conducteurs de niveau inférieur varie également en fonction des critères suivants :
La nature du périphérique que chaque pilote contrôle
Indique si le pilote configure ses objets de périphérique pour les E/S directes ou mises en mémoire tampon
La conception du pilote individuel
Pour illustrer les rôles des routines de pilotes standard, la figure suivante montre le chemin d’accès qu’un exemple d’IRP peut prendre pendant qu’il est traité par un pilote de périphérique de stockage de masse de niveau le plus bas. Le pilote de la figure présente les caractéristiques suivantes :
L’appareil génère des interruptions à la fin de chaque opération d’E/S, de sorte que ce pilote a des routines ISR et DpcForIsr .
Le pilote a une routine StartIo , au lieu de configurer des files d’attente internes pour les IRP et de gérer sa propre mise en file d’attente.
Le pilote utilise le système DMA, de sorte qu’il définit les indicateurs de ses objets de périphérique pour les E/S directes et a une routine AdapterControl .
Comme le montre cette figure, le gestionnaire d’E/S crée un IRP et l’envoie à la routine de distribution du pilote pour le code de fonction principale donné. En supposant que le code de la fonction est IRP_MJ_READ ou IRP_MJ_WRITE, la routine de distribution est DDDispatchReadWrite.
Appel de IoGetCurrentIrpStackLocation
Toute routine de pilote qui nécessite des paramètres IRP doit appeler IoGetCurrentIrpStackLocation pour obtenir l’emplacement de la pile d’E/S du pilote. Ces routines incluent des routines de répartition qui gèrent plusieurs codes de fonction d’E/S principaux (IRP_MJ_*XXX), gèrent une fonction qui prend en charge des fonctions mineures (IRP_MN_XXX) ou gèrent les demandes de contrôle d’E/S d’appareil (*IRP_MJ_DEVICE_CONTROL et/ou IRP_MJ_INTERNAL_DEVICE_CONTROL), ainsi que toutes les autres routines de pilote qui traitent un IRP.
L’emplacement de la pile d’E/S de ce pilote est le plus bas, avec un nombre indéfini d’emplacements de pile d’E/S de niveau supérieur affichés ombrés. Par souci de simplicité, les appels à IoGetCurrentIrpStackLocation à partir des routines DispatchReadWrite, StartIo, AdapterControl et DpcForIsr ne sont pas indiqués dans la figure précédente.
Appel d’IoMarkIrpPending et IoStartPacket
L’exemple de pilote ne termine pas l’IRP dans sa routine de répartition, mais traite plutôt l’IRP dans sa routine StartIo . Avant de pouvoir le faire, la routine de répartition appelle IoMarkIrpPending pour indiquer que l’IRP n’est pas encore terminé. Ensuite, il appelle IoStartPacket pour mettre en file d’attente l’IRP en vue d’un traitement ultérieur par la routine StartIo du pilote. La routine de répartition retourne également la valeur NTSTATUS STATUS_PENDING.
La figure suivante illustre l’appel à IoStartPacket.
Si le pilote est occupé à traiter une autre IRP sur l’appareil, IoStartPacket insère l’IRP dans la file d’attente d’appareils associée à l’objet de périphérique. Le pilote peut éventuellement fournir une valeur de clé en tant que paramètre à IoStartPacket pour imposer un ordre déterminé par le pilote sur les IRP dans la file d’attente des appareils.
Si le pilote n’est pas occupé et que la file d’attente de périphériques est vide, le gestionnaire d’E/S appelle immédiatement sa routine StartIo , en passant l’IRP d’entrée.
Pour les appareils de stockage de masse, le pilote de niveau le plus bas n’a pas besoin de fournir une routine Cancel lorsqu’il appelle IoStartPacket pour deux raisons :
Un système de fichiers superposé sur un tel pilote gère généralement l’annulation des demandes d’E/S de fichiers.
Les pilotes de périphériques de stockage de masse traitent rapidement les irps.
En règle générale, le pilote de niveau supérieur d’une chaîne de pilotes en couches gère l’annulation des IRP.
Appel de AllocateAdapterChannel et MapTransfer
En supposant que la routine StartIo , illustrée dans la figure illustrant un chemin d’accès IRP à travers les routines de pilotes de niveau le plus bas, détermine que la demande de transfert peut être effectuée par une seule opération DMA, la routine StartIo appelle AllocateAdapterChannel avec le point d’entrée de la routine AdapterControl du pilote et de l’IRP.
Lorsque le contrôleur DMA système est disponible, le gestionnaire d’E/S appelle la routine AdapterControl du pilote pour configurer l’opération de transfert. La routine AdapterControl appelle MapTransfer pour configurer le contrôleur DMA système. Ensuite, le pilote programme son périphérique pour l’opération DMA et retourne. (Pour plus d’informations sur l’utilisation des objets DMA et adaptateurs, consultez Techniques d’entrée/sortie.)
Appel d’IoRequestDpc à partir de l’ISR du pilote
Lorsque l’appareil s’interrompt pour indiquer que son opération de transfert est terminée, l’ISR du pilote empêche l’appareil de générer des interruptions et appelle IoRequestDpc, comme illustré dans la figure illustrant un chemin d’accès IRP via les routines de pilotes de niveau inférieur.
Cet appel met en file d’attente la routine DpcForIsr du pilote pour effectuer autant que possible l’opération de transfert à une priorité matérielle inférieure (IRQL).
Appel d’IoStartNextPacket et IoCompleteRequest
Lorsque la routine DpcForIsr a terminé de traiter le transfert, elle appelle rapidement IoStartNextPacket afin que la routine StartIo du pilote soit appelée avec la prochaine IRP dans la file d’attente de l’appareil, le cas échéant. La routine DpcForIsr définit également le bloc de status d’E/S de l’IRP juste terminé, puis appelle IoCompleteRequest pour l’IRP.
La figure suivante illustre les appels de ce pilote à IoStartNextPacket et IoCompleteRequest.
Les pilotes doivent appeler IoStartNextPacket ou IoStartNextPacketByKey pour commencer la prochaine opération d’E/S demandée dès que possible, de préférence avant d’appeler IoCompleteRequest.
Si des irps sont mis en file d’attente pour l’appareil, IoStartNextPacket appelle KeRemoveDeviceQueue pour supprimer le IRP suivant de la file d’attente. Le gestionnaire d’E/S appelle ensuite la routine StartIo du pilote, en passant l’IRP en file d’attente. Si aucun IRP ne se trouve actuellement dans la file d’attente des appareils, IoStartNextPacket retourne simplement à l’appelant.
Définition du bloc d’état d’E/S dans un IRP
Chaque pilote de niveau le plus bas doit définir le bloc d’E/S de l’IRP status avant d’appeler IoCompleteRequest. (Dans la figure précédente, la deuxième zone ombrée indique le bloc status.) Le bloc d’E/S status fournit des informations aux pilotes de niveau supérieur et, finalement, au demandeur d’origine de l’opération d’E/S. Tout pilote de niveau supérieur superposé au pilote de la figure précédente peut avoir configuré une routine IoCompletion qui lit le bloc d’E/S status défini par ce pilote. Les pilotes de niveau supérieur ne modifient généralement pas le bloc d’E/S status dans un IRP qui a été effectué par un pilote de périphérique, sauf si le pilote de niveau supérieur tente à nouveau l’IRP, auquel cas il réinitialise le bloc de status d’E/S.
Chaque pilote de niveau supérieur qui termine une IRP sans l’envoyer au pilote inférieur suivant doit également définir le bloc d’E/S status dans cette IRP avant d’appeler IoCompleteRequest. Pour un débit d’E/S global correct, un pilote de niveau supérieur doit case activée les paramètres dans son propre emplacement de pile d’E/S de chaque IRP et, si les paramètres ne sont pas valides, doit définir le bloc d’E/S status et terminer la requête elle-même. Dans la mesure du possible, un pilote doit éviter de transmettre une requête non valide à des pilotes inférieurs dans la chaîne.
En supposant que l’opération de transfert dans la figure précédente est réussie, la routine DpcForIsr, illustrée dans la figure illustrant un chemin DRP via les routines de pilote de niveau le plus bas, définit STATUS_SUCCESS dans État et le nombre d’octets transférés dans Informations pour le bloc d’E/S status de l’IRP.
La plupart des routines de pilotes standard retournent également des valeurs de type NTSTATUS. Pour plus d’informations sur les constantes NTSTATUS comme STATUS_SUCCESS, consultez Erreurs de journalisation.