<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > WindowsNT4.0下設備驅動(dòng)程序的開(kāi)發(fā)與應用

WindowsNT4.0下設備驅動(dòng)程序的開(kāi)發(fā)與應用

作者: 時(shí)間:2006-05-07 來(lái)源:網(wǎng)絡(luò ) 收藏

摘要: 介紹了Windows NT4.0內核模式設備驅動(dòng)程序開(kāi)發(fā)中的一般性過(guò)程。通過(guò)提供一個(gè)最小化驅動(dòng)程序的核心代碼,解釋各組成部分的結構功能和使用方法。在實(shí)踐中,結合自身的開(kāi)發(fā)需要,可編寫(xiě)出具有實(shí)用價(jià)值的驅動(dòng)程序。

本文引用地址:http://dyxdggzs.com/article/241584.htm

關(guān)鍵詞:Win32子系統 設備驅動(dòng) 系統注冊表 I/O請求包

Windows NT 以其安全、穩定及界面友好等特性逐漸成為工業(yè)控制領(lǐng)域的前臺操作系統。面對工業(yè)控制中大量采用的串/并行通信及總線(xiàn)控制等技術(shù),要求用戶(hù)不斷開(kāi)發(fā)出滿(mǎn)足自身需要的硬件設備,同時(shí)又要求用戶(hù)應用程序與這些硬件設備進(jìn)行通信,發(fā)送控制命令,讀取狀態(tài)信息等等。Windows NT出于安全性、穩定性等考慮,不允許用戶(hù)應用程序對物理硬件進(jìn)行直接訪(fǎng)問(wèn),這就需要使用設備驅動(dòng)程序跨越操作系統邊界對物理硬件進(jìn)行操作,并向上提供客戶(hù)應用程序控制接口以供調用。

1 分層結構與設備驅動(dòng)程序

Windows NT分層結構(如圖1所示)包括運行于用戶(hù)模式及內核模式的各種部件,設備驅動(dòng)程序在圖1的左下角,處于內核模式下I/O管理器之中。

2 驅動(dòng)程序工作方式

內核模式驅動(dòng)程序與應用程序之間的最大差別之一是驅動(dòng)程序的控制結構。內核模式驅動(dòng)程序沒(méi)有main或WinMain,而是由I/O管理器根據需要調用一個(gè)驅動(dòng)程序例程:

· 驅動(dòng)程序被裝入時(shí);

· 驅動(dòng)程序被卸出或系統關(guān)閉時(shí);

· 用戶(hù)程序發(fā)出I/O系統服務(wù)調用時(shí);

· 共享硬件資源對驅動(dòng)程序可用時(shí);

· 設備操作過(guò)程中的任何時(shí)候。

3 初始化過(guò)程

3.1 系統注冊表中有關(guān)設備驅動(dòng)程序的項目是系統加載設備驅動(dòng)程序的入口點(diǎn)

系統注冊表中用于系統加載設備驅動(dòng)程序的項目如下:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DriverName]

″Type″ = dword00000001

″Start″ = dword00000002

″Group″ = ″Extended Base″

″ErrorControl″ = dword∶00000001

其中Start含義如下:

SERVICE_BOOT_START (0×0) 操作系統裝入時(shí)

SERVICE_SYSTEM_START (0×01) 操作系統初始化時(shí)

SERVICE_AUTO_START (0×02) 服務(wù)控制管理器啟動(dòng)時(shí)

SERVICE_DEMAND_START (0×03) 服務(wù)控制管理器手工啟動(dòng)

SERVICE_DISABLED (0×04) 不啟動(dòng)

Type含義如下:

SERVICE_KERNEL_DRIVER (0×1)

SERVICE_FILE_SYSTEM_DRIVER (0×2)

SERVICE_ADAPTER (0×4)

系統注冊表中用于設備驅動(dòng)程序加載后讀取的項目如下:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DriverName\Parameters]

″Parameter1″ = dword∶00000001

″Parameter2″ = dword∶00000004

3.2 加載驅動(dòng)程序的裝入例程

I/O管理器調用驅動(dòng)程序的DriverEntry例程,執行初始化。該例程完成:

· 初始化其它例程的入口;

· 創(chuàng )建命名設備對象;

· 讀取系統注冊表中相關(guān)項目并聲明必要的資源;

· 設置內核驅動(dòng)程序名與Win32子系統名的聯(lián)接;

· 創(chuàng )建或初始化任意驅動(dòng)程序使用的對象、類(lèi)型和資源;

· 返回狀態(tài)值。

I/O管理器建立與設備關(guān)聯(lián)的Driver對象,并將其傳遞給DriverEntry例程。實(shí)際上Driver對象基本上是一個(gè)目錄,含有指向各個(gè)驅動(dòng)程序服務(wù)例程函數的指針,其結構如表1所示。

表1 Driver對象

說(shuō)明
PDRIVER_STARTIO DriverStartIo 驅動(dòng)程序的Start I/O例程的地址
PDRIVER_UNLOAD DriverUnload 驅動(dòng)程序的Unload例程地址
PDRIVER_DISPATCH Majorfunction[ ] 驅動(dòng)程序的Dispatch例程的表,由I/O操作代碼索引
PDEVICE_OBJECT DeviceObject 驅動(dòng)程序創(chuàng )建的Device對象鏈表

I/O管理器能夠找到DriverEntry例程,是因為它有一個(gè)公認的名字,而其他的例程則通過(guò)下列兩種方法查找:

·在Driver對象中有明確槽的函數如DirverObject->DriverUnload;

·在Driver對象的MajorFunction數組中——Driver對象的MajorFunction支持兩種類(lèi)型的功能代碼。一種為標準的功能代碼,如IRP_MJ_CREATE。另一種是用戶(hù)自定義的功能代碼,如IRP_MJ_DEVICE_CONTROL。

所有驅動(dòng)程序必須支持IRP_MJ_CREATE功能代碼,這是因為Win32子系統下的用戶(hù)程序調用CreateFile函數創(chuàng )建設備時(shí),產(chǎn)生該功能代碼。如果不處理這個(gè)功能代碼,Win32程序就不能得到設備句柄。

用戶(hù)自定義的功能代碼IRP_MJ_DEVICE_CONTROL只有在用戶(hù)模式下的客戶(hù)程序執行自定義的功能時(shí)可用。

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)



//聲明設備對象

PDEVICE_OBJECT DeviceObject,

//生成函數接口指針

DriverObject->MajorFunction[IRP_MJ_CREATE]=XxSelfDispatch;

DriverObject->MajorFunction[IRP_MJ_CLOSE]=
XxSelfDispatch;

DriverObject->MajorFunction[IRP_MJ_READ]=
XxReadDispatch;

DriverObject->MajorFunction[IRP_MJ_WRITE]=
XxWriteDispatch

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=XxSelfDispatch

DriverObject->DriverUnload=XxUnload

//生成Windows NT Executive知道的設備名

RtlInitUnicodeString(&NtDeviceName, SelfDeviceName);

//生成自己的設備

Status=IoCreateDevice(

DriverObject, // Driver對象

sizeof(SELF_DEVICE_INFO), // Device對象

Extension結構大小

&NtDeviceName,

DeviceType,

0,

FALSE, // 不執行

&DeviceObject //Device對象指針

);
 //生成Win32子系統下的用戶(hù)程序可識別的設備名

RtlInitUnicodeString(&Win32DeviceName, SelfWin32Name);

//聯(lián)接內部設備名與Win32子系統下的設備名

Status = IoCreateSymbolicLink( &Win32DeviceName, &NtDeviceName);

//利用RtlQueryRegistryValues函數讀出注冊表中Parameters下的參數值,初始化自己的硬件

...



4 驅動(dòng)程序服務(wù)例程

驅動(dòng)程序初始化之后,始終等待發(fā)自用戶(hù)的命令或由其它事件源引起的事件。一旦命令或事件發(fā)生,I/O管理器就調用相應的服務(wù)例程提供服務(wù)。而幾乎所有的I/O都是通過(guò)I/O請求包IRP驅動(dòng)的。所謂IRP驅動(dòng),就是I/O管理器負責在非分頁(yè)的系統內存中分配一定空間,當接受用戶(hù)發(fā)出的命令或由事件引發(fā)后,將工作指令按一定的數據結構置于其中,傳遞到驅動(dòng)程序服務(wù)例程。換言之,IRP包含了驅動(dòng)程序服務(wù)例程所需要的信息指令。表2、表3為IRP的一些數據結構。

同時(shí),I/O管理器和驅動(dòng)程序都需要在所有時(shí)候知道一個(gè)I/O設備所進(jìn)行的情況。系統提供Device對象以滿(mǎn)足此要求。該對象在DriverEntry例程中生成設備時(shí)由系統創(chuàng )建后,分配給驅動(dòng)程序,并在整個(gè)驅動(dòng)程序生存期內有效。當I/O管理器調用驅動(dòng)程序服務(wù)例程時(shí),傳遞該對象。表4為Device對象的外部可見(jiàn)域。

表2 IRP標頭中外部可見(jiàn)的域

  內 容 含 義
標頭 I/O_STATUS_BLOCK IoStatus Stutus I/O請求的狀態(tài)
Information
AssociatedIrp.Systembuffer   執行緩沖I/O時(shí),系統空間緩沖區指針
PMDL MdlAddress   執行直接I/O時(shí),用戶(hù)空間緩沖區的內存描述符列表的指針
PVOID User Buffer   I/O緩沖區的用戶(hù)空間地址
BOOLEAN Cancel   指示IRP已被取消

表3 IRP堆棧單元的一些內容

  IO_STACK_LOCATION,*PIO_STACK_LOCATION
I/O堆棧單元 UCHAR MajorFunction   指定操作的 IRP_MJ_XXX 函數
UCHAR MinorFunction   有文件系統和 SCSI 驅動(dòng)程序
union Parameters   Majorfunction 代碼的聯(lián)合類(lèi)型
struct Read ULONG Length IRP_MJ_READ 的參數
ULONG Key
LARGE_INTEGER ByteOffset
struct Write ULONG Length IRP_MJ_WRITE 的參數據
ULONG Key
LARGE_INTEGER ByteOffset
struct DeviceIoControl ULONG OutputBufferLength IRP_MJ_DEVICE_CONTROL, IRP_MJ_INTERNAL_DEVICE _CONTROL 的參數
OutputBuffer Length
ULONG Iocontrolcode

表4 Device 對象的外部可見(jiàn)域

含 義
PVOID DeviceExtension 指向 Device Extension 結構的指針
PDRIVER_OBJECT DriverObject 指向這個(gè)設備 Driver 對象
ULONG Flags 指定這個(gè)設備的緩沖策略 DO_BUFFER_IO DO_DIRECT_IO
PDEVICE_OBJECT NextDevice 指向屬于這個(gè)驅動(dòng)程序的下一個(gè)設備
CCHAR StackSize 發(fā)送到這個(gè)設備的IRP需要的I/O堆棧單元的最小數目
ULONG AlignmentRequirement 緩沖區要求的內存對齊

其中,DeviceExtension域是一個(gè)重要的數據結構。它是由I/O管理器創(chuàng )建并自動(dòng)掛接到Device對象的非分頁(yè)池,是保存驅動(dòng)程序任意全局變量的最好辦法。因為DeviceExtension是驅動(dòng)程序特定的,要自定義它的數據結構。

下面是一個(gè)驅動(dòng)程序服務(wù)例程利用Device對象和IRP的片段:

NTSTATUS XxSelfDispatch(IN PDEVICE_OBJECT pDO IN PIRP pIrp);



PLOCAL_DEVICE_INFO pLDI;

PIO_STACK_LOCATION pIrpStack;

PULONG pIOBuffer;

//得到全局信息

pLDI = (PSELF_DEVICE_INFO)pDO->DeviceExtension;

pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

//得到由用戶(hù)應用程序發(fā)來(lái)的用戶(hù)數據,并在需要時(shí),將結果通過(guò)此變量返回給用戶(hù)

pIOBuffer=PULONGpIrp->AssociatedIrp.System

Buffer;

// 由IRP攜帶的信息決定驅動(dòng)程序的執行

switch (pIrpStack->MajorFunction)



case IRP_MJ_CREATE:

case IRP_MJ_CLOSE:

Status = STATUS_SUCCESS;

break;

case IRP_MJ_DEVICE_CONTROL:

//由Parameters進(jìn)一步解釋控制代碼含義

switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)



case IOCTL_Function1:

//執行功能代碼

Field1 = pLDI->SelfField1;

...

break;

case IOCTL_Function2:

//執行功能代碼

...

break;

}

break



// 返回I/O操作的狀態(tài)

pIrp->IoStatus.Status = Status;

IoCompleteRequest(pIrp IO_NO_INCREMENT); 

return Status;



5 驅動(dòng)程序終止例程

Unload例程負責取消由DriverEntry例程所做的任何事情,包括解除屬于該驅動(dòng)程序的任何硬件資源的分配,以及刪除屬于驅動(dòng)程序的任何內核對象。通常這僅在系統關(guān)閉時(shí)需要。

VOID XxUnload(PDRIVER_OBJECT DriverObject)



PLOCAL_DEVICE_INFO pLDI;

UNICODE_STRING Win32DeviceName;

// 得到全局數據,根據全局數據進(jìn)行清理工作

pLDI=PLOCAL_DEVICE_INFODriverObject->Device

Object->DeviceExtension

if (pLDI->Field2 == TRUE)


...

// 刪除分配的設備名及設備

RtlInitUnicodeString(&Win32DeviceName, SelfWin32 Name);

IoDeleteSymbolicLink(&Win32DeviceName);

IoDeleteDevice(pLDI->DeviceObject);



6 用戶(hù)層應用程序與驅動(dòng)程序間的接口

驅動(dòng)程序完成后,將在系統重新引導時(shí)裝入并初始化(由DriverEntry例程完成)。此時(shí),驅動(dòng)程序處于可用狀態(tài),等待用戶(hù)層應用程序使用。用戶(hù)層應用程序可以:

·打開(kāi)該設備文件(由IRP_MJ_CREATE功能代碼完成)

·讀出數據(由IRP_MJ_READ功能代碼完成)

·寫(xiě)入數據(由IRP_MJ_WRITE功能代碼完成)

·執行用戶(hù)自定義的功能代碼(由IRP_MJ_DEVICE_CONTROL功能代碼完成)

·關(guān)閉該設備文件(由IRP_MJ_CLOSE功能代碼完成)

以下是部分實(shí)現代碼:

void main()



HANDLE hndFile; // 由CreateFile得到

union {

ULONG LongData;

USHORT ShortData;

UCHAR CharData;

 }DataBuffer; //從設備驅動(dòng)程序中得到的數據

LONG IoctlCode; //功能代碼

ULONG DataLength;

LONG Parameter1;

//調用IRP中的IRP _MJ_CREATE功能

hndFile = CreateFile(

″\\\\.\\SelfWin32Name″, // 打開(kāi)設備文件″ SelfWin32Name″

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ | FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

0,

NULL

if (hndFile == INVALID_HANDLE_VALUE)



printf(″Unable to open the device.\n″);

exit(1);

}

IoctlCode = IOCTL_Function1; //自定義功能代碼

Parameter1 = 1;

DataLength = sizeof(DataBuffer.CharData);

IoctlResult = DeviceIoControl(

hndFile //設備文件句柄

IoctlCode//功能代碼,對應IRP中的Parameter.

//DeviceIoControl.IoControlCode域

&Parameter1,//傳遞到驅動(dòng)程序的參數緩沖區,對應

//IRP中的AssociatedIrp.SystemBuffer

sizeof(Parameter1) //參數緩沖區長(cháng)度

&DataBuffer, //從驅動(dòng)程序傳出的數據緩沖區

DataLength, //緩沖區長(cháng)度

&ReturnedLength, //返回的實(shí)際緩沖區長(cháng)度

NULL //等待,直到操作完成

);

if(?。茫欤铮螅澹龋幔睿洌欤澹煟瑁睿洌疲椋欤澹?//關(guān)閉設備



printf(″Failed to close device.\n″);
}


以上介紹了Windows NT4.0設備驅動(dòng)程序開(kāi)發(fā)中的一般性過(guò)程。用戶(hù)可利用NT SDK 及DDK開(kāi)發(fā)工具包,并根據自身需要,對以上核心代碼進(jìn)行擴充完成所需任務(wù)。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>