Minidrivery, ovladače miniportu a páry ovladačů
Minidriver nebo ovladač miniport funguje jako polovina páru ovladačů. Páry ovladačů jako (miniport, port) můžou usnadnit vývoj ovladačů. V páru ovladačů jeden ovladač zpracovává obecné úlohy, které jsou společné pro celou kolekci zařízení, zatímco druhý ovladač zpracovává úlohy specifické pro jednotlivá zařízení. Ovladače, které zpracovávají úlohy specifické pro zařízení, mají různé názvy, včetně ovladače miniportu, ovladače minitřídy a minidriveru.
Společnost Microsoft poskytuje obecný ovladač a obvykle nezávislý dodavatel hardwaru poskytuje konkrétní ovladač. Než si přečtete toto téma, měli byste porozumět konceptům představeným v "uzlech zařízení a zásobnících zařízení" a a v "paketech požadavků na vstupně-výstupní operace" .
Každý ovladač v režimu jádra musí implementovat funkci s názvem DriverEntry, která se volá krátce po načtení ovladače. Funkce DriverEntry vyplní určité členy struktury DRIVER_OBJECT ukazateli na několik dalších funkcí, které implementuje ovladač. Například funkce DriverEntry naplní člena Unload struktury DRIVER_OBJECT ukazatelem na funkci Unload ovladače, jak je znázorněno v následujícím diagramu.
MajorFunction člen struktury DRIVER_OBJECT je pole ukazatelů na funkce, které zpracovávají vstupně-výstupní pakety požadavků (IRPs), jak je znázorněno v následujícím diagramu. Ovladač obvykle vyplní několik členů MajorFunction pole s ukazateli na funkce (implementované ovladačem), které zpracovávají různé druhy IRPs.
IRP lze kategorizovat podle jeho hlavního kódu funkce, který je identifikován konstantou, například IRP_MJ_READ, IRP_MJ_WRITEnebo IRP_MJ_PNP. Konstanty, které identifikují kód hlavní funkce, slouží jako indexy v poli MajorFunction. Předpokládejme například, že ovladač implementuje funkci dispatch pro zpracování irPs, které mají hlavní kód funkce IRP_MJ_WRITE. V tomto případě musí ovladač vyplnit prvek MajorFunction[IRP_MJ_WRITE] pole ukazatelem na funkci dispatch.
Ovladač obvykle vyplní některé prvky pole MajorFunction a zbývající prvky ponechá nastavené na výchozí hodnoty poskytované správcem vstupně-výstupních operací. Následující příklad ukazuje, jak použít rozšíření ladicího programu !drvobj ke kontrole ukazatelů funkcí pro ovladač paralelního portu.
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
Ve výstupu ladicího programu vidíte, že parport.sys implementuje GsDriverEntry, vstupní bod pro ovladač. GsDriverEntry, který se automaticky vygeneroval při sestavení ovladače, provede určitou inicializaci a potom zavolá DriverEntry, který implementoval vývojář ovladače.
Můžete také vidět, že ovladač parportu (ve své funkci DriverEntry) poskytuje ukazatele na odesílání funkcí pro tyto hlavní kódy funkcí:
- 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
Zbývající prvky pole MajorFunction obsahují ukazatele na výchozí dispečinkovou funkci nt!IopInvalidDeviceRequest.
Ve výstupu ladicího programu můžete vidět, že ovladač parportu poskytl ukazatele funkcí pro Unload a AddDevice, ale neposkytl ukazatel pro funkci StartIo. Funkce AddDevice je neobvyklá, protože její ukazatel funkce není uložen ve struktuře DRIVER_OBJECT. Místo toho je uložen v AddDevice člen rozšíření DRIVER_OBJECT struktury. Následující diagram znázorňuje ukazatele na funkce, které poskytuje ovladač parport ve své funkci DriverEntry. Ukazatele funkce poskytované parportem jsou stínovány.
Snadnější používání dvojic ovladačů
Během časového období, kdy vývojáři ovladačů uvnitř a mimo společnost Microsoft získali zkušenosti s modelem ovladačů systému Windows (WDM), si uvědomili několik věcí o funkcích odesílání:
- Dispečerské funkce jsou do značné míry standardizované. Například většina kódu ve funkci dispatch pro IRP_MJ_PNP je stejná pro všechny ovladače. Jedná se pouze o malou část kódu Plug and Play (PnP), která je specifická pro jednotlivé ovladače, který řídí jednotlivé kusy hardwaru.
- Funkce dispatch jsou složité a obtížně se správně nastavují. Implementace funkcí, jako je synchronizace vláken, řazení IRP a zrušení IRP, je náročné a vyžaduje hluboké porozumění tomu, jak funguje operační systém.
Aby vývojářům ovladačů ulehčil práci, vytvořil Microsoft několik modelů ovladačů specifických pro technologie. Na první pohled se modely specifické pro technologie zdají být zcela odlišné od sebe, ale bližší pohled ukazuje, že mnohé z nich jsou založené na tomto paradigmatu:
- Ovladač je rozdělený na dvě části: jeden, který zpracovává obecné zpracování, a druhý, který zpracovává zpracování specifické pro konkrétní zařízení.
- Obecná část je napsána Microsoftem.
- Konkrétní kus může napsat Microsoft nebo nezávislý dodavatel hardwaru.
Předpokládejme, že společnosti Proseware a Contoso dělají robota, který vyžaduje ovladač WDM. Předpokládejme také, že Společnost Microsoft poskytuje obecný ovladač robota s názvem GeneralRobot.sys. Proseware a Contoso můžou každý psát malé ovladače, které zpracovávají požadavky konkrétních robotů. Proseware může například napsat ProsewareRobot.sysa dvojici ovladačů (ProsewareRobot.sys, GeneralRobot.sys) lze zkombinovat tak, aby vytvořil jeden ovladač WDM. Stejně tak by dvojice ovladačů (ContosoRobot.sys, GeneralRobot.sys) mohla zkombinovat a vytvořit jeden ovladač WDM. Ve své nejobecnější podobě je myšlenka, že můžete vytvářet ovladače pomocí (specific.sys, general.sys) dvojic.
ukazatele funkce v ovladačových dvojicích
Ve dvojici (specific.sys, general.sys) načte systém Windows specific.sys a zavolá funkci DriverEntry. Funkce DriverEntry specific.sys obdrží ukazatel na strukturu DRIVER_OBJECT. Normálně byste očekávali, že DriverEntry vyplní několik prvků pole MajorFunction ukazateli na dispečerské funkce. Také byste očekávali, že DriverEntry naplní člen Unload (a případně člen StartIo) struktury DRIVER_OBJECT a člen AddDevice rozšíření objektu ovladače. V modelu páru ovladačů ale DriverEntry to nutně nedělá. Místo toho funkce DriverEntry specific.sys předává DRIVER_OBJECT strukturu spolu s inicializační funkcí implementovanou general.sys. Následující příklad kódu ukazuje, jak může být inicializační funkce volána ve dvojici (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);
}
Inicializační funkce v GeneralRobot.sys zapisuje ukazatele funkcí do příslušných členů struktury DRIVER_OBJECT (a její rozšíření) a do příslušných prvků pole MajorFunction. Myšlenka spočívá v tom, že když manažer I/O odešle IRP do dvojice ovladačů, IRP přejde jako první do dispečerské funkce implementované GeneralRobot.sys. Pokud GeneralRobot.sys dokáže zpracovat IRP samostatně, pak konkrétní ovladač, ProsewareRobot.sys, nemusí být zapojen. Pokud GeneralRobot.sys dokáže zpracovat některé, ale ne všechny zpracování protokolu IRP, získá pomoc z jedné z funkcí zpětného volání implementovaných ProsewareRobot.sys. GeneralRobot.sys obdrží ukazatele na zpětná volání ProsewareRobot během volání funkce GeneralRobotInit.
V určitém bodě po vrácení DriverEntry se vytvoří zásobník zařízení pro uzel zařízení Proseware Robot. Zásobník zařízení může vypadat takto.
Jak je znázorněno v předchozím diagramu, zásobník zařízení pro robota Proseware má tři objekty zařízení. Nejvyšší objekt zařízení je objekt filtru (Filter DO) asociovaný s ovladačem filtru AfterThought.sys. Prostřední objekt zařízení je funkční objekt zařízení (FDO) přidružený ke dvojici ovladačů (ProsewareRobot.sys, GeneralRobot.sys). Párový ovladač slouží jako funkční ovladač pro zařízení. Dolní objekt zařízení je objekt fyzického zařízení přidružený k Pci.sys.
Všimněte si, že dvojice ovladačů zabírá v zásobníku zařízení pouze jednu úroveň a je přidružena pouze k jednomu objektu zařízení: FDO. Když GeneralRobot.sys zpracovává IRP, může požádat ProsewareRobot.sys o pomoc, ale to není to samé jako předání požadavku do zásobníku zařízení. Dvojice ovladačů tvoří jeden ovladač WDM, který je na jedné úrovni ve vrstvě zařízení. Dvojice ovladačů buď dokončí IRP, nebo ho předá zásobníku zařízení k PDO, který je spojen s Pci.sys.
Příklad páru ovladačů
Předpokládejme, že máte v přenosném počítači bezdrátovou síťovou kartu a když se podíváte do Správce zařízení, zjistíte, že netwlv64.sys je ovladač síťové karty. Pomocí rozšíření ladicího programu !drvobj můžete prohlížet ukazatele funkcí pro 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
Ve výstupu ladicího programu vidíte, že netwlv64.sys implementuje GsDriverEntry, vstupní bod pro ovladač. GsDriverEntry, který se automaticky vygeneroval při sestavení ovladače, provede inicializaci a potom zavolá DriverEntry, který napsal vývojář ovladače.
V tomto příkladu netwlv64.sys implementuje DriverEntry, ale ndis.sys implementuje AddDevice, Unloada několik funkcí odesílání. Netwlv64.sys se nazývá ovladač miniportu NDIS a ndis.sys se nazývá knihovna NDIS. Oba moduly společně tvoří pár (miniport NDIS, knihovna NDIS).
Tento diagram znázorňuje zásobník zařízení pro bezdrátovou síťovou kartu. Všimněte si, že dvojice ovladačů (netwlv64.sys, ndis.sys) zabírá pouze jednu úroveň v zásobníku zařízení a je přidružena pouze k jednomu objektu zařízení: FDO.
Dostupné páry ovladačů
Různé modely ovladačů specifické pro technologie používají různé názvy pro konkrétní a obecné části páru ovladačů. V mnoha případech má konkrétní část dvojice předponu mini. Tady jsou některé (specifické, obecné) páry, které jsou k dispozici:
- (ovladač miniportu, ovladač portu zobrazení)
- (ovladač audio miniportu, ovladač zvukového portu)
- (ovladač miniportu úložiště, ovladač portu úložiště)
- (ovladač minitřídy baterie, ovladač třídy baterie)
- (Minidriver HID, ovladač třídy HID)
- (ovladač minitřídy měniče, ovladač portu měniče)
- (Ovladač miniportu NDIS, knihovna NDIS)
Poznámka Jak je vidět v seznamu, několik modelů používá termín ovladače třídy pro obecnou část páru ovladačů. Tento druh ovladače třídy se liší od samostatného ovladače třídy a liší se od ovladače filtru tříd.
související témata
koncepty pro všechny vývojáře ovladačů