Minidrivers, Miniport-stuurprogramma's en stuurprogrammaparen
Een minidriver of een minipoortstuurprogramma fungeert als deel van een stuurprogrammapaar. Stuurprogrammaparen zoals (miniport, poort) kunnen de ontwikkeling van stuurprogramma's vereenvoudigen. In een stuurprogrammapaar verwerkt één stuurprogramma algemene taken die gebruikelijk zijn voor een hele verzameling apparaten, terwijl het andere stuurprogramma taken verwerkt die specifiek zijn voor een afzonderlijk apparaat. De stuurprogramma's die apparaatspecifieke taken verwerken, hebben verschillende namen, waaronder minipoortstuurprogramma, miniclassestuurprogramma en minidriver.
Microsoft biedt het algemene stuurprogramma en doorgaans een onafhankelijke hardwareleverancier biedt het specifieke stuurprogramma. Voordat u dit onderwerp leest, moet u de ideeën begrijpen die worden gepresenteerd in Apparaatknooppunten en apparaatstacks en I/O-aanvraagpakketten.
Elk kernelmodusstuurprogramma moet een functie implementeren met de naam DriverEntry, die kort nadat het stuurprogramma is geladen, wordt aangeroepen. De functie DriverEntry vult bepaalde leden van een DRIVER_OBJECT structuur in met aanwijzers naar verschillende andere functies die het stuurprogramma implementeert. De DriverEntry functie vult bijvoorbeeld het Unload lid van de DRIVER_OBJECT-structuur met een aanwijzer naar de Unload functie van de stuurprogramma, zoals weergegeven in het volgende diagram.
De MajorFunction lid van de DRIVER_OBJECT-structuur is een matrix met aanwijzers voor functies die I/O-aanvraagpakketten verwerken (IRPs), zoals wordt weergegeven in het volgende diagram. Meestal vult het stuurprogramma verschillende leden van de MajorFunction matrix met aanwijzers naar functies (geïmplementeerd door het stuurprogramma) die verschillende soorten IRP's verwerken.
Een IRP kan worden gecategoriseerd op basis van de primaire functiecode, die wordt geïdentificeerd door een constante, zoals IRP_MJ_READ, IRP_MJ_WRITEof IRP_MJ_PNP. De constanten waarmee de primaire functiecode wordt geïdentificeerd, fungeren als indexen in de matrix MajorFunction. Stel dat het stuurprogramma een dispatch-functie implementeert om IRP's met de hoofdfunctiecode IRP_MJ_WRITEte verwerken. In dit geval moet het stuurprogramma het element MajorFunction [IRP_MJ_WRITE] van de matrix invullen met een aanwijzer naar de verzendfunctie.
Meestal vult het stuurprogramma enkele elementen van de MajorFunction matrix in en laat de overige elementen ingesteld op standaardwaarden die door de I/O-manager worden geleverd. In het volgende voorbeeld ziet u hoe u de !drvobj foutopsporingsprogramma-extensie gebruikt om de functie-aanwijzers voor het parallelpoortstuurprogramma te inspecteren.
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
In de uitvoer van het foutopsporingsprogramma ziet u dat parport.sys GsDriverEntry-implementeert, het toegangspunt voor het stuurprogramma. GsDriverEntry-, die automatisch is gegenereerd toen het stuurprogramma werd gebouwd, voert een initialisatie uit en roept vervolgens DriverEntryaan, die is geïmplementeerd door de stuurprogrammaontwikkelaar.
U kunt ook zien dat het parportstuurprogramma (in de functie DriverEntry ) aanwijzers biedt naar dispatchfuncties voor deze belangrijke functiecodes:
- IRP_MJ_CREATE
- IRP_MJ_CLOSE
- IRP_MJ_READ
- IRP_MJ_WRITE
- IRP_MJ_QUERY_INFORMATION
- IRP_MJ_SET_INFORMATION
- IRP_MJ_DEVICE_CONTROL
- IRP_MJ_INTERNAL_DEVICE_CONTROL
- IRP_MJ_CLEANUP
- IRP_MJ_POWER
- IRP_MJ_SYSTEM_CONTROL
- IRP_MJ_PNP
De resterende elementen van de MajorFunction array bevatten pointers naar de standaardafhandelaarfunctie nt!IopInvalidDeviceRequest.
In de uitvoer van de debugger ziet u dat het parportstuurprogramma functieaanroepers heeft geleverd voor Unload en AddDevice, maar geen functieaanroeper heeft opgegeven voor StartIo. De functie AddDevice is ongebruikelijk omdat de functieaanwijzer niet is opgeslagen in de DRIVER_OBJECT structuur. In plaats daarvan wordt het opgeslagen in het AddDevice- lid van een extensie van de DRIVER_OBJECT-structuur. In het volgende diagram ziet u de functie-aanwijzers die geleverd worden door het parportstuurprogramma in de DriverEntry-functie. De functiepointers die door parport worden geleverd, zijn aangegeven.
Het gemakkelijker maken door het gebruik van stuurprogrammaparen
In de loop van de tijd, toen stuurprogrammaontwikkelaars binnen en buiten Microsoft ervaring opdeden met het Windows Driver Model (WDM), realiseerden ze bepaalde inzichten over dispatchfuncties.
- Dispatchfuncties zijn grotendeels sjabloonmatig. Een groot deel van de code in de verzendfunctie voor IRP_MJ_PNP is bijvoorbeeld hetzelfde voor alle stuurprogramma's. Het is slechts een klein deel van de PnP-code (Plug and Play) die specifiek is voor een afzonderlijk stuurprogramma dat een afzonderlijk stuk hardware beheert.
- Dispatch-functies zijn ingewikkeld en moeilijk correct te krijgen. Het implementeren van functies zoals threadsynchronisatie, IRP-wachtrijen en IRP-annulering is lastig en vereist een grondig begrip van de werking van het besturingssysteem.
Om het voor ontwikkelaars van stuurprogramma's gemakkelijker te maken, heeft Microsoft verschillende technologiespecifieke stuurprogrammamodellen gemaakt. Op het eerste gezicht lijken de technologiespecifieke modellen heel anders dan elkaar, maar een nadere blik laat zien dat veel van deze modellen zijn gebaseerd op dit paradigma:
- Het stuurprogramma is gesplitst in twee delen: een die de algemene verwerking afhandelt en een die de verwerking afhandelt die specifiek is voor een bepaald apparaat.
- Het algemene stuk is geschreven door Microsoft.
- Het specifieke stuk kan worden geschreven door Microsoft of een onafhankelijke hardwareleverancier.
Stel dat de bedrijven Proseware en Contoso beide een speelgoedrobot maken waarvoor een WDM-stuurprogramma is vereist. Stel ook dat Microsoft een General Robot Driver met de naam GeneralRobot.sysbiedt. Proseware en Contoso kunnen elk kleine stuurprogramma's schrijven die voldoen aan de vereisten van hun specifieke robots. Proseware kan bijvoorbeeld ProsewareRobot.sysschrijven en het paar stuurprogramma's (ProsewareRobot.sys, GeneralRobot.sys) kunnen worden gecombineerd om één WDM-stuurprogramma te vormen. Op dezelfde manier kan het paar stuurprogramma's (ContosoRobot.sys, GeneralRobot.sys) worden gecombineerd om één WDM-stuurprogramma te vormen. In de meest algemene vorm is het idee dat u stuurprogramma's kunt maken met behulp van (specific.sys, general.sys) paren.
Functie-aanwijzers in stuurprogrammaparen
In een paar (specific.sys, general.sys) laadt Windows specific.sys en roept de bijbehorende DriverEntry-functie aan. De DriverEntry--functie van specific.sys ontvangt een aanwijzer naar een DRIVER_OBJECT structuur. Normaal gesproken zou je verwachten dat DriverEntry verschillende elementen van de MajorFunction-tabel vult met pointers naar dispatchfuncties. U zou ook verwachten dat DriverEntry het Unload lid (en mogelijk het StartIo lid) van de DRIVER_OBJECT-structuur en het AddDevice lid van de extensie van de driver-object invult. Echter, in een model voor stuurprogrammaparen doet DriverEntry dit niet noodzakelijkerwijs. In plaats daarvan geeft de DriverEntry--functie van specific.sys de DRIVER_OBJECT-structuur door aan een initialisatiefunctie die door general.sysis geïmplementeerd. In het volgende codevoorbeeld ziet u hoe de initialisatiefunctie kan worden aangeroepen in het paar (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);
}
De initialisatiefunctie in GeneralRobot.sys schrijft functie-aanwijzers naar de juiste leden van de DRIVER_OBJECT-structuur (en de extensie) en de juiste elementen van de MajorFunction matrix. Het idee is dat wanneer de I/O-manager een IRP naar het stuurprogrammapaar verzendt, de IRP eerst naar een verzendfunctie gaat die door GeneralRobot.sysis geïmplementeerd. Als GeneralRobot.sys zelf de IRP kan verwerken, hoeft het specifieke stuurprogramma, ProsewareRobot.sys, niet betrokken te zijn. Als GeneralRobot.sys een aantal, maar niet alle, van de IRP-verwerking kan verwerken, krijgt deze hulp van een van de callback-functies die door ProsewareRobot.syszijn geïmplementeerd. GeneralRobot.sys krijgt aanwijzers naar de ProsewareRobot-callbacks in de GeneralRobotInit-aanroep.
Op een bepaald moment nadat DriverEntry retourneert, wordt er een apparaatstack gemaakt voor het Proseware Robot-apparaatknooppunt. De apparaatstack kan er als volgt uitzien.
Zoals in het voorgaande diagram wordt weergegeven, heeft de apparaatstack voor Proseware Robot drie apparaatobjecten. Het bovenste apparaatobject is een filterapparaatobject (Filter DO) dat is gekoppeld aan het filterstuurprogramma AfterThought.sys. Het middelste apparaatobject is een functioneel apparaatobject (FDO) dat is gekoppeld aan het stuurprogrammapaar (ProsewareRobot.sys, GeneralRobot.sys). Het stuurprogrammapaar fungeert als het functiestuurprogramma voor de apparaatstack. Het onderste apparaatobject is een fysiek apparaatobject (PDO) dat is gekoppeld aan Pci.sys.
U ziet dat het stuurprogrammapaar slechts één niveau in de apparaatstack in beslag neemt en is gekoppeld aan slechts één apparaatobject: de FDO. Wanneer GeneralRobot.sys een IRP verwerkt, kan dit ProsewareRobot.sys aanroepen voor hulp, maar dat is niet hetzelfde als het doorgeven van de aanvraag op de apparaatstack. Het stuurprogrammapaar vormt één WDM-stuurprogramma dat zich op één niveau in de apparaatstack bevindt. Het stuurprogrammapaar voltooit de IRP of geeft deze door naar de apparaatsstapel aan de PDO, die is gekoppeld aan Pci.sys.
voorbeeld van een stuurprogrammapaar
Stel dat u een draadloze netwerkkaart op uw laptopcomputer hebt en door in Apparaatbeheer te kijken, bepaalt u dat netwlv64.sys het stuurprogramma voor de netwerkkaart is. U kunt de extensie !drvobj foutopsporingsprogramma gebruiken om de functieaanwijzers voor netwlv64.syste inspecteren.
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
In de uitvoer van het foutopsporingsprogramma kunt u zien dat netwlv64.sys, GsDriverEntryimplementeert, het toegangspunt voor het stuurprogramma. GsDriverEntry, die automatisch is gegenereerd toen het stuurprogramma werd gebouwd, voert een initialisatie uit en roept vervolgens DriverEntryaan, die is geschreven door de ontwikkelaar van het stuurprogramma.
In dit voorbeeld implementeert netwlv64.sys DriverEntry, maar ndis.sys implementeert AddDevice, Unloaden verschillende dispatcheerfuncties. Netwlv64.sys wordt een NDIS-minipoortstuurprogramma genoemd en ndis.sys wordt de NDIS-bibliotheek genoemd. Samen vormen de twee modules een paar (NDIS miniport, NDIS Library).
In dit diagram ziet u de apparaatstack voor de draadloze netwerkkaart. U ziet dat het stuurprogrammapaar (netwlv64.sys, ndis.sys) slechts één niveau in de apparaatstack in beslag neemt en is gekoppeld aan slechts één apparaatobject: de FDO.
Beschikbare stuurprogrammaparen
De verschillende technologiespecifieke stuurprogrammamodellen gebruiken verschillende namen voor de specifieke en algemene onderdelen van een stuurprogrammapaar. In veel gevallen heeft het specifieke gedeelte van het paar het voorvoegsel 'mini'. Hier volgen enkele (specifieke, algemene) paren die beschikbaar zijn:
- (miniportstuurprogramma voor beeldscherm, poortstuurprogramma voor beeldscherm)
- (audio-miniportstuurprogramma, audiopoortstuurprogramma)
- (stuurprogramma voor opslagminiport, stuurprogramma voor opslagpoort)
- (miniklassestuurprogramma voor batterij, batterijklassestuurprogramma)
- (HID minidriver, HID-klassestuurprogramma)
- (changer miniclass driver, changer port driver)
- (NDIS miniport-stuurprogramma, NDIS-bibliotheek)
Opmerking Zoals u in de lijst kunt zien, gebruiken verschillende modellen de term classdriver voor het algemene gedeelte van een driverpaar. Dit type klassestuurprogramma verschilt van een zelfstandig klassestuurprogramma en verschilt van een klassefilterstuurprogramma.
verwante onderwerpen
Concepten voor alle ontwikkelaars van stuurprogramma's