Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Pour la plupart des pilotes intermédiaires et de niveau le plus bas, l’extension de périphérique est la structure de données la plus importante associée à un objet d’appareil. Sa structure interne est définie par le pilote et elle est généralement utilisée pour :
Conservez les informations d’état de l’appareil.
Fournissez un stockage pour tous les objets définis par le noyau ou d’autres ressources système, telles que les verrous de rotation, utilisés par le pilote.
Conservez les données nécessaires que le pilote doit avoir résidentes dans l'espace système pour effectuer ses opérations d'entrées/sorties.
Étant donné que la plupart des pilotes de bus, de fonction et de filtre (pilotes de niveau le plus bas et intermédiaire) s’exécutent dans un contexte de thread arbitraire (celui du thread actuel), une extension de périphérique est l’emplacement principal de chaque pilote pour maintenir l’état de l’appareil et toutes les autres données spécifiques à l’appareil dont le pilote a besoin. Par exemple, tout pilote qui implémente une routine CustomTimerDpc ou CustomDpc fournit généralement un stockage pour le minuteur défini par le noyau requis et/ou les objets DPC dans une extension d’appareil.
Chaque pilote disposant d’un ISR doit fournir un stockage pour un pointeur vers un ensemble d’objets d’interruption définis par le noyau, et la plupart des pilotes de périphérique stockent ce pointeur dans une extension de périphérique. Chaque pilote détermine la taille de l’extension de périphérique lorsqu’il crée un objet d’appareil, et chaque pilote définit le contenu et la structure de ses propres extensions d’appareil.
Les routines IoCreateDevice et IoCreateDeviceSecure du gestionnaire d’E/S allouent de la mémoire pour l’objet et l’extension de l’appareil à partir du pool de mémoires nonpage.
Chaque routine de pilote standard qui reçoit un IRP reçoit également un pointeur vers un objet d’appareil représentant l’appareil cible pour l’opération d’E/S demandée. Ces routines de pilote peuvent accéder à l’extension de périphérique correspondante via ce pointeur. En règle générale, un pointeur DeviceObject est également un paramètre d’entrée vers l’ISR d’un pilote de niveau le plus bas.
La figure suivante montre un ensemble représentatif de données définies par le pilote pour l’extension de périphérique d’un objet de périphérique de niveau le plus bas. Un pilote de niveau supérieur ne fournirait pas de stockage pour un pointeur d’objet d’interruption retourné par IoConnectInterrupt et passé à KeSynchronizeExecution et IoDisconnectInterrupt. Toutefois, un pilote de niveau supérieur fournit un stockage pour les objets minuteur et DPC indiqués dans la figure suivante si le pilote a une routine CustomTimerDpc . Un pilote de niveau supérieur peut également fournir un stockage pour un verrou de rotation exécutif et une file d’attente de travail verrouillée.
En plus de fournir un stockage pour un pointeur d’objet d’interruption, un pilote de périphérique de niveau inférieur doit fournir un stockage pour un verrou de rotation d’interruption si son ISR gère les interruptions pour deux appareils ou plus sur différents vecteurs ou s’il a plusieurs ISR. Pour plus d’informations sur l’inscription d’un ISR, consultez Inscription d’un ISR.
En règle générale, les pilotes stockent des pointeurs vers leurs objets d’appareil dans leurs extensions d’appareil, comme illustré dans la figure. Un pilote peut également conserver une copie de la liste des ressources pour l’appareil dans l’extension.
Un pilote de niveau supérieur stocke généralement un pointeur vers l’objet de périphérique du pilote immédiatement inférieur dans son extension d’appareil. Un pilote de niveau supérieur doit passer un pointeur vers l'objet de périphérique du pilote inférieur suivant à IoCallDriver, après avoir configuré l'emplacement de pile d'E/S du pilote inférieur suivant dans un IRP, comme expliqué dans La gestion des IRPs.
Notez également que tout pilote de niveau supérieur qui alloue des IRPs pour des pilotes de niveau inférieur doit spécifier combien d'emplacements de pile que doivent avoir les nouveaux IRPs. En particulier, si un pilote de niveau supérieur appelle IoMakeAssociatedIrp, IoAllocateIrp ou IoInitializeIrp, il doit accéder à l'objet de périphérique cible du pilote de niveau inférieur suivant pour obtenir la valeur de StackSize, afin de fournir la valeur correcte de StackSize comme argument à ces routines de support.
Bien qu’un pilote de niveau supérieur puisse lire des données à partir de l’objet d’appareil du pilote de niveau inférieur suivant via le pointeur retourné par IoAttachDeviceToDeviceStack, ce pilote doit suivre ces instructions d’implémentation :
N’essayez jamais d’écrire des données dans l’objet périphérique du pilote inférieur.
Les seules exceptions à cette directive sont les systèmes de fichiers, qui définissent et effacent DO_VERIFY_VOLUME dans les Flags des pilotes de périphériques média amovible de niveau inférieur.
N’essayez jamais d’accéder à l’extension de périphérique du conducteur inférieur pour les raisons suivantes :
Il n’existe aucun moyen sûr de synchroniser l’accès à une seule extension de périphérique entre deux pilotes.
Une paire de pilotes qui implémentent un tel schéma de communication de porte dérobée ne peut pas être mise à niveau individuellement, ne peut pas avoir de pilote intermédiaire inséré entre eux sans modifier le code source du pilote existant, et ne peut pas être recompilée et transférée facilement d’une plateforme Windows à une autre.
Pour préserver leur interopérabilité avec des pilotes de niveau inférieur d'une plateforme ou d'une version Windows à la suivante, les pilotes de niveau supérieur doivent réutiliser les IRPs donnés ou créer de nouveaux IRPs, et ils doivent utiliser IoCallDriver pour communiquer les demandes aux pilotes de niveau inférieur.