<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

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

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

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

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

          本文引用地址:http://www.ex-cimer.com/article/241584.htm

          關(guān)鍵詞:Win32子系統(tǒng) 設(shè)備驅(qū)動(dòng) 系統(tǒng)注冊(cè)表 I/O請(qǐng)求包

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

          1 分層結(jié)構(gòu)與設(shè)備驅(qū)動(dòng)程序

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

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

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

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

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

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

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

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

          3 初始化過(guò)程

          3.1 系統(tǒng)注冊(cè)表中有關(guān)設(shè)備驅(qū)動(dòng)程序的項(xiàng)目是系統(tǒng)加載設(shè)備驅(qū)動(dòng)程序的入口點(diǎn)

          系統(tǒng)注冊(cè)表中用于系統(tǒng)加載設(shè)備驅(qū)動(dòng)程序的項(xià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) 操作系統(tǒng)裝入時(shí)

          SERVICE_SYSTEM_START (0×01) 操作系統(tǒng)初始化時(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)

          系統(tǒng)注冊(cè)表中用于設(shè)備驅(qū)動(dòng)程序加載后讀取的項(xiàng)目如下:

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

          ″Parameter1″ = dword∶00000001

          ″Parameter2″ = dword∶00000004

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

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

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

          · 創(chuàng)建命名設(shè)備對(duì)象;

          · 讀取系統(tǒng)注冊(cè)表中相關(guān)項(xiàng)目并聲明必要的資源;

          · 設(shè)置內(nèi)核驅(qū)動(dòng)程序名與Win32子系統(tǒng)名的聯(lián)接;

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

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

          I/O管理器建立與設(shè)備關(guān)聯(lián)的Driver?qū)ο?,并將其傳遞給DriverEntry例程。實(shí)際上Driver?qū)ο蠡旧鲜且粋€(gè)目錄,含有指向各個(gè)驅(qū)動(dòng)程序服務(wù)例程函數(shù)的指針,其結(jié)構(gòu)如表1所示。

          表1 Driver對(duì)象

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

          I/O管理器能夠找到DriverEntry例程,是因?yàn)樗幸粋€(gè)公認(rèn)的名字,而其他的例程則通過(guò)下列兩種方法查找:

          ·在Driver?qū)ο笾杏忻鞔_槽的函數(shù)如DirverObject->DriverUnload;

          ·在Driver?qū)ο蟮模停幔辏铮颍疲酰睿悖簦椋铮顢?shù)組中——Driver?qū)ο蟮模停幔辏铮颍疲酰睿悖簦椋铮钪С謨煞N類(lèi)型的功能代碼。一種為標(biāo)準(zhǔn)的功能代碼,如IRP_MJ_CREATE。另一種是用戶(hù)自定義的功能代碼,如IRP_MJ_DEVICE_CONTROL。

          所有驅(qū)動(dòng)程序必須支持IRP_MJ_CREATE功能代碼,這是因?yàn)椋祝椋睿常沧酉到y(tǒng)下的用戶(hù)程序調(diào)用CreateFile函數(shù)創(chuàng)建設(shè)備時(shí),產(chǎn)生該功能代碼。如果不處理這個(gè)功能代碼,Win32程序就不能得到設(shè)備句柄。

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

          NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)



          //聲明設(shè)備對(duì)象

          PDEVICE_OBJECT DeviceObject,

          //生成函數(shù)接口指針

          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知道的設(shè)備名

          RtlInitUnicodeString(&NtDeviceName, SelfDeviceName);

          //生成自己的設(shè)備

          Status=IoCreateDevice(

          DriverObject, // Driver?qū)ο?br>
          sizeof(SELF_DEVICE_INFO), // Device對(duì)象

          Extension結(jié)構(gòu)大小

          &NtDeviceName,

          DeviceType,

          0,

          FALSE, // 不執(zhí)行

          &DeviceObject //Device對(duì)象指針

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

          RtlInitUnicodeString(&Win32DeviceName, SelfWin32Name);

          //聯(lián)接內(nèi)部設(shè)備名與Win32子系統(tǒng)下的設(shè)備名

          Status = IoCreateSymbolicLink( &Win32DeviceName, &NtDeviceName);

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

          ...



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

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

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

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

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

          表3 IRP堆棧單元的一些內(nèi)容

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

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

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

          其中,DeviceExtension域是一個(gè)重要的數(shù)據(jù)結(jié)構(gòu)。它是由I/O管理器創(chuàng)建并自動(dòng)掛接到Device對(duì)象的非分頁(yè)池,是保存驅(qū)動(dòng)程序任意全局變量的最好辦法。因?yàn)椋模澹觯椋悖澹牛簦澹睿螅椋铮钍球?qū)動(dòng)程序特定的,要自定義它的數(shù)據(jù)結(jié)構(gòu)。

          下面是一個(gè)驅(qū)動(dòng)程序服務(wù)例程利用Device對(duì)象和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ù)應(yīng)用程序發(fā)來(lái)的用戶(hù)數(shù)據(jù),并在需要時(shí),將結(jié)果通過(guò)此變量返回給用戶(hù)

          pIOBuffer=PULONGpIrp->AssociatedIrp.System

          Buffer;

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

          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:

          //執(zhí)行功能代碼

          Field1 = pLDI->SelfField1;

          ...

          break;

          case IOCTL_Function2:

          //執(zhí)行功能代碼

          ...

          break;

          }

          break



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

          pIrp->IoStatus.Status = Status;

          IoCompleteRequest(pIrp IO_NO_INCREMENT); 

          return Status;



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

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

          VOID XxUnload(PDRIVER_OBJECT DriverObject)



          PLOCAL_DEVICE_INFO pLDI;

          UNICODE_STRING Win32DeviceName;

          // 得到全局?jǐn)?shù)據(jù),根據(jù)全局?jǐn)?shù)據(jù)進(jìn)行清理工作

          pLDI=PLOCAL_DEVICE_INFODriverObject->Device

          Object->DeviceExtension

          if (pLDI->Field2 == TRUE)


          ...

          // 刪除分配的設(shè)備名及設(shè)備

          RtlInitUnicodeString(&Win32DeviceName, SelfWin32 Name);

          IoDeleteSymbolicLink(&Win32DeviceName);

          IoDeleteDevice(pLDI->DeviceObject);



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

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

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

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

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

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

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

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

          void main()



          HANDLE hndFile; // 由CreateFile得到

          union {

          ULONG LongData;

          USHORT ShortData;

          UCHAR CharData;

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

          LONG IoctlCode; //功能代碼

          ULONG DataLength;

          LONG Parameter1;

          //調(diào)用IRP中的IRP _MJ_CREATE功能

          hndFile = CreateFile(

          ″\\\\.\\SelfWin32Name″, // 打開(kāi)設(shè)備文件″ 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 //設(shè)備文件句柄

          IoctlCode//功能代碼,對(duì)應(yīng)IRP中的Parameter.

          //DeviceIoControl.IoControlCode域

          &Parameter1,//傳遞到驅(qū)動(dòng)程序的參數(shù)緩沖區(qū),對(duì)應(yīng)

          //IRP中的AssociatedIrp.SystemBuffer

          sizeof(Parameter1) //參數(shù)緩沖區(qū)長(zhǎng)度

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

          DataLength, //緩沖區(qū)長(zhǎng)度

          &ReturnedLength, //返回的實(shí)際緩沖區(qū)長(zhǎng)度

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

          );

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



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


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

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


          評(píng)論


          相關(guān)推薦

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

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();