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.
Un minidriver ou un miniporteur agit comme la moitié d’une paire de pilotes. Les paires de pilotes telles que (miniport, port) peuvent faciliter le développement de pilotes. Dans une paire de pilotes, un pilote gère les tâches générales communes à un ensemble complet d’appareils, tandis que l’autre pilote gère les tâches spécifiques à un appareil individuel. Les pilotes qui gèrent des tâches spécifiques aux appareils passent par divers noms, notamment le pilote miniport, le pilote miniclass et le minidriver.
Microsoft fournit le pilote général, et généralement un fournisseur de matériel indépendant fournit le pilote spécifique. Avant de lire cette rubrique, vous devez comprendre les idées présentées dans les nœuds de périphériques et les piles de périphériques et les paquets de requêtes d’E/S.
Chaque pilote en mode noyau doit implémenter une fonction nommée DriverEntry, qui est appelée peu après le chargement du pilote. La fonction DriverEntry remplit certains membres d’une structure DRIVER_OBJECT avec des pointeurs vers plusieurs autres fonctions que le pilote implémente. Par exemple, la fonction DriverEntry remplit le membre Deload de la structure DRIVER_OBJECT avec un pointeur vers la fonction Deload du pilote, comme illustré dans le diagramme suivant.
Le membre MajorFunction de la structure DRIVER_OBJECT est un tableau de pointeurs vers des fonctions qui gèrent les paquets de requête d’E/S (S IRP), comme illustré dans le diagramme suivant. En règle générale, le pilote remplit plusieurs membres du tableau MajorFunction avec des pointeurs vers des fonctions (implémentées par le pilote) qui gèrent différents types d’IRPs.
Un IRP peut être classé en fonction de son code de fonction principal, identifié par une constante, telle que IRP_MJ_READ, IRP_MJ_WRITE ou IRP_MJ_PNP. Les constantes qui identifient le code de fonction principal servent d’index dans le tableau MajorFunction . Par exemple, supposons que le pilote implémente une fonction de dispatch pour gérer les IRPs qui ont le code de fonction principal IRP_MJ_WRITE. Dans ce cas, le pilote doit renseigner l’élément MajorFunction[IRP_MJ_WRITE] du tableau avec un pointeur vers la fonction de répartition.
En règle générale, le pilote remplit certains éléments du tableau MajorFunction et laisse les éléments restants définis sur les valeurs par défaut fournies par le gestionnaire d’E/S. L’exemple suivant montre comment utiliser l’extension du débogueur !drvobj pour inspecter les pointeurs de fonction pour le pilote parport.
0: kd> !drvobj parport 2
Driver object (fffffa80048d9e70) is for:
\Driver\Parport
DriverEntry: fffff880065ea070 parport!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: fffff880065e131c parport!PptUnload
AddDevice: fffff880065d2008 parport!P5AddDevice
Dispatch routines:
[00] IRP_MJ_CREATE fffff880065d49d0 parport!PptDispatchCreateOpen
[01] IRP_MJ_CREATE_NAMED_PIPE fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE fffff880065d4a78 parport!PptDispatchClose
[03] IRP_MJ_READ fffff880065d4bac parport!PptDispatchRead
[04] IRP_MJ_WRITE fffff880065d4bac parport!PptDispatchRead
[05] IRP_MJ_QUERY_INFORMATION fffff880065d4c40 parport!PptDispatchQueryInformation
[06] IRP_MJ_SET_INFORMATION fffff880065d4ce4 parport!PptDispatchSetInformation
[07] IRP_MJ_QUERY_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[09] IRP_MJ_FLUSH_BUFFERS fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL fffff880065d4be8 parport!PptDispatchDeviceControl
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880065d4c24 parport!PptDispatchInternalDeviceControl
[10] IRP_MJ_SHUTDOWN fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP fffff880065d4af4 parport!PptDispatchCleanup
[13] IRP_MJ_CREATE_MAILSLOT fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[16] IRP_MJ_POWER fffff880065d491c parport!PptDispatchPower
[17] IRP_MJ_SYSTEM_CONTROL fffff880065d4d4c parport!PptDispatchSystemControl
[18] IRP_MJ_DEVICE_CHANGE fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA fffff80001b6ecd4 nt!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP fffff880065d4840 parport!PptDispatchPnp
Dans la sortie du débogueur, vous pouvez voir que parport.sys implémente GsDriverEntry, le point d’entrée du pilote. GsDriverEntry, qui a été généré automatiquement lors de la génération du pilote, effectue une initialisation, puis appelle DriverEntry, qui a été implémenté par le développeur du pilote.
Vous pouvez également voir que le pilote parport (dans sa fonction DriverEntry) fournit des pointeurs vers des fonctions de distribution pour ces codes de fonction principaux :
- IRP_MJ_CREATE
- IRP_MJ_CLOSE
- IRP_MJ_READ
- IRP_MJ_WRITE
- IRP_MJ_QUERY_INFORMATION
- IRP_MJ_SET_INFORMATION (Opération de mise à jour des informations)
- IRP_MJ_DEVICE_CONTROL
- IRP_MJ_INTERNAL_DEVICE_CONTROL
- IRP_MJ_CLEANUP
- IRP_MJ_POWER
- IRP_MJ_SYSTEM_CONTROL
- IRP_MJ_PNP
Les éléments restants du tableau MajorFunction contiennent des pointeurs vers la fonction de répartition par défaut nt ! IopInvalidDeviceRequest.
Dans la sortie du débogueur, vous pouvez voir que le pilote de port a fourni des pointeurs de fonction pour Unload et AddDevice, mais n’a pas fourni de pointeur de fonction pour StartIo. La fonction AddDevice est inhabituelle, car son pointeur de fonction n’est pas stocké dans la structure DRIVER_OBJECT . Au lieu de cela, il est stocké dans le membre AddDevice d’une extension à la structure DRIVER_OBJECT . Le diagramme suivant illustre les pointeurs de fonction que le pilote parport a fournis dans sa fonction DriverEntry. Les pointeurs de fonction fournis par le parport sont ombrés.
Faciliter l’utilisation des paires de pilotes
Au fil du temps, alors que les développeurs de pilotes, tant à l'intérieur qu'à l'extérieur de Microsoft, ont acquis de l'expérience avec le modèle de pilote Windows (WDM), ils ont réalisé certaines choses à propos des fonctions de distribution :
- Les fonctions dispatch sont en grande partie du code standard. Par exemple, une grande partie du code dans la fonction dispatch pour IRP_MJ_PNP est la même pour tous les pilotes. Il ne s’agit que d’une petite partie du code Plug-and-Play (PnP) spécifique à un pilote individuel qui contrôle un élément matériel individuel.
- Les fonctions de répartition sont complexes et difficiles à maîtriser. L’implémentation de fonctionnalités telles que la synchronisation de threads, la mise en file d’attente IRP et l’annulation IRP est difficile et nécessite une compréhension approfondie du fonctionnement du système d’exploitation.
Pour faciliter les choses pour les développeurs de pilotes, Microsoft a créé plusieurs modèles de pilotes spécifiques à la technologie. À première vue, les modèles spécifiques à la technologie semblent assez différents les uns des autres, mais un regard plus proche révèle que beaucoup d’entre eux sont basés sur ce paradigme :
- Le pilote est divisé en deux éléments : un qui gère le traitement général et un qui gère le traitement spécifique à un appareil particulier.
- La pièce générale est écrite par Microsoft.
- La pièce spécifique peut être écrite par Microsoft ou par un fournisseur de matériel indépendant.
Supposons que les entreprises Proseware et Contoso fabriquent toutes les deux un robot jouet qui nécessite un pilote WDM. Supposons également que Microsoft fournit un pilote robot général appelé GeneralRobot.sys. Proseware et Contoso peuvent chacun écrire de petits pilotes qui gèrent les exigences de leurs robots respectifs. Par exemple, Proseware peut écrire ProsewareRobot.sys, et la paire de pilotes (ProsewareRobot.sys, GeneralRobot.sys) peut être combinée pour former un seul pilote WDM. De même, la paire de pilotes (ContosoRobot.sys, GeneralRobot.sys) peut se combiner pour former un seul pilote WDM. Dans sa forme la plus générale, l’idée est que vous pouvez créer des pilotes à l’aide de paires (specific.sys, general.sys).
Pointeurs de fonction dans les paires de pilotes
Dans une paire (specific.sys, general.sys), Windows charge specific.sys et appelle sa fonction DriverEntry . La fonction DriverEntry de specific.sys reçoit un pointeur vers une structure DRIVER_OBJECT . Normalement, vous vous attendez à ce que DriverEntry remplisse plusieurs éléments du tableau MajorFunction avec des pointeurs pour distribuer des fonctions. Vous pouvez également vous attendre à ce que DriverEntry remplisse le membre Unload (et éventuellement le membre StartIo ) de la structure DRIVER_OBJECT et du membre AddDevice de l’extension d’objet du pilote. Toutefois, dans un modèle de paire de pilotes, DriverEntry ne le fait pas nécessairement. Au lieu de cela, la fonction DriverEntry de specific.sys passe la structure DRIVER_OBJECT le long d’une fonction d’initialisation implémentée par general.sys. L’exemple de code suivant montre comment la fonction d’initialisation peut être appelée dans la paire (ProsewareRobot.sys, GeneralRobot.sys).
PVOID g_ProsewareRobottCallbacks[3] = {DeviceControlCallback, PnpCallback, PowerCallback};
// DriverEntry function in ProsewareRobot.sys
NTSTATUS DriverEntry (DRIVER_OBJECT *DriverObject, PUNICODE_STRING RegistryPath)
{
// Call the initialization function implemented by GeneralRobot.sys.
return GeneralRobotInit(DriverObject, RegistryPath, g_ProsewareRobottCallbacks);
}
La fonction d’initialisation dans GeneralRobot.sys écrit les pointeurs de fonction dans les membres appropriés de la structure DRIVER_OBJECT (et de son extension) et les éléments appropriés du tableau MajorFunction. L’idée est que lorsque le gestionnaire d’E/S envoie un IRP à la paire de pilotes, l’IRP passe d’abord à une fonction de répartition implémentée par GeneralRobot.sys. Si GeneralRobot.sys pouvez gérer l’IRP par lui-même, alors le pilote spécifique, ProsewareRobot.sys, n’a pas besoin d’être impliqué. Si GeneralRobot.sys peut gérer une partie, mais pas tout le traitement des IRP, il obtient de l'aide de l'une des fonctions de rappel implémentées par ProsewareRobot.sys. GeneralRobot.sys reçoit des pointeurs vers les rappels de ProsewareRobot dans l’appel GeneralRobotInit.
À un moment donné après que DriverEntry a retourné, une pile de périphériques est construite pour le nœud de périphérique Proseware Robot. La pile d’appareils peut ressembler à ceci.
Comme illustré dans le diagramme précédent, la pile d’appareils pour Proseware Robot a trois objets d’appareil. L'objet d'appareil en haut est un objet d'appareil de filtre (Filter DO) lié au pilote de filtre AfterThought.sys. L’objet de périphérique intermédiaire est un objet d’appareil fonctionnel (FDO) associé à la paire de pilotes (ProsewareRobot.sys, GeneralRobot.sys). La paire de pilotes sert de pilote de fonction pour la pile de périphériques. L'objet de périphérique inférieur est un objet de périphérique physique (PDO) associé à Pci.sys.
Notez que la paire de pilotes occupe un seul niveau dans la pile d’appareils et est associée à un seul objet d’appareil : le FDO. Lorsque GeneralRobot.sys traite un IRP, il peut appeler ProsewareRobot.sys pour obtenir de l’aide, mais cela ne revient pas à faire descendre la demande dans la pile de périphérique. La paire de pilotes forme un seul pilote WDM qui se trouve à un niveau dans la pile d’appareils. La paire de pilotes termine l’IRP ou la transmet à la pile d’appareils vers le PDO, qui est associé à Pci.sys.
Exemple de paire de pilotes
Supposons que vous disposez d’une carte réseau sans fil sur votre ordinateur portable, et en recherchant Device Manager, vous déterminez que netwlv64.sys est le pilote de la carte réseau. Vous pouvez utiliser l’extension du débogueur !drvobj pour vérifier les pointeurs de fonction pour netwlv64.sys.
1: kd> !drvobj netwlv64 2
Driver object (fffffa8002e5f420) is for:
\Driver\netwlv64
DriverEntry: fffff8800482f064 netwlv64!GsDriverEntry
DriverStartIo: 00000000
DriverUnload: fffff8800195c5f4 ndis!ndisMUnloadEx
AddDevice: fffff88001940d30 ndis!ndisPnPAddDevice
Dispatch routines:
[00] IRP_MJ_CREATE fffff880018b5530 ndis!ndisCreateIrpHandler
[01] IRP_MJ_CREATE_NAMED_PIPE fffff88001936f00 ndis!ndisDummyIrpHandler
[02] IRP_MJ_CLOSE fffff880018b5870 ndis!ndisCloseIrpHandler
[03] IRP_MJ_READ fffff88001936f00 ndis!ndisDummyIrpHandler
[04] IRP_MJ_WRITE fffff88001936f00 ndis!ndisDummyIrpHandler
[05] IRP_MJ_QUERY_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[06] IRP_MJ_SET_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[07] IRP_MJ_QUERY_EA fffff88001936f00 ndis!ndisDummyIrpHandler
[08] IRP_MJ_SET_EA fffff88001936f00 ndis!ndisDummyIrpHandler
[09] IRP_MJ_FLUSH_BUFFERS fffff88001936f00 ndis!ndisDummyIrpHandler
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[0b] IRP_MJ_SET_VOLUME_INFORMATION fffff88001936f00 ndis!ndisDummyIrpHandler
[0c] IRP_MJ_DIRECTORY_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[0d] IRP_MJ_FILE_SYSTEM_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[0e] IRP_MJ_DEVICE_CONTROL fffff8800193696c ndis!ndisDeviceControlIrpHandler
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL fffff880018f9114 ndis!ndisDeviceInternalIrpDispatch
[10] IRP_MJ_SHUTDOWN fffff88001936f00 ndis!ndisDummyIrpHandler
[11] IRP_MJ_LOCK_CONTROL fffff88001936f00 ndis!ndisDummyIrpHandler
[12] IRP_MJ_CLEANUP fffff88001936f00 ndis!ndisDummyIrpHandler
[13] IRP_MJ_CREATE_MAILSLOT fffff88001936f00 ndis!ndisDummyIrpHandler
[14] IRP_MJ_QUERY_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler
[15] IRP_MJ_SET_SECURITY fffff88001936f00 ndis!ndisDummyIrpHandler
[16] IRP_MJ_POWER fffff880018c35e8 ndis!ndisPowerDispatch
[17] IRP_MJ_SYSTEM_CONTROL fffff880019392c8 ndis!ndisWMIDispatch
[18] IRP_MJ_DEVICE_CHANGE fffff88001936f00 ndis!ndisDummyIrpHandler
[19] IRP_MJ_QUERY_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler
[1a] IRP_MJ_SET_QUOTA fffff88001936f00 ndis!ndisDummyIrpHandler
[1b] IRP_MJ_PNP fffff8800193e518 ndis!ndisPnPDispatch
Dans la sortie du débogueur, vous pouvez voir que netwlv64.sys implémente GsDriverEntry, le point d’entrée du pilote. GsDriverEntry, qui a été généré automatiquement lors de la génération du pilote, effectue une initialisation, puis appelle DriverEntry, qui a été écrit par le développeur du pilote.
Dans cet exemple, netwlv64.sys implémente DriverEntry, mais ndis.sys implémente AddDevice, Unload et plusieurs fonctions de répartition. Netwlv64.sys est appelée pilote miniport NDIS et ndis.sys est appelée bibliothèque NDIS. Ensemble, les deux modules forment une paire (miniport NDIS, bibliothèque NDIS).
Ce diagramme montre la pile des appareils pour la carte réseau sans fil. Notez que la paire de pilotes (netwlv64.sys, ndis.sys) occupe un seul niveau dans la pile d’appareils et est associée à un seul objet d’appareil : le FDO.
Paires de pilotes disponibles
Les différents modèles de pilotes spécifiques à la technologie utilisent divers noms pour les éléments spécifiques et généraux d’une paire de pilotes. Dans de nombreux cas, la partie spécifique de la paire a le préfixe « mini ». Voici quelques paires (spécifiques, générales) disponibles :
- (pilote de miniport d'affichage, pilote de port d'affichage)
- (pilote audio miniport, pilote de port audio)
- (pilote de miniport de stockage, pilote de port de stockage)
- (pilote de la miniclasse batterie, pilote de la classe batterie)
- (minipilote HID, pilote de classe HID)
- (changer le pilote miniclasse, pilote de port de changement)
- (Pilote miniport NDIS, bibliothèque NDIS)
Note Comme vous pouvez le voir dans la liste, plusieurs modèles utilisent le terme 'pilote de classe' pour désigner la partie générale d’une paire de pilotes. Ce type de pilote de classe est différent d’un pilote de classe autonome et différent d’un pilote de filtre de classe.
rubriques connexes
Concepts pour tous les développeurs de pilotes