天天看點

一個簡單的Windows驅動例程

一個簡單的Windows驅動例程

本文所需代碼在這裡下載下傳:http://download.csdn.net/detail/li171049/6777587

一、Windows驅動程式對于我們來說經常使用,卻又了解很少,給我們的感覺好像是很神秘。這裡我們通過一個簡單的例程來說明,Windows驅動程式的工作原理。在例程沒有貼出來前,我們需要了解Windows與之相關的基本概念。

一、如下圖,我們需要了解Windows的應用程式和驅動程式在Windows系統中的位置。

一個簡單的Windows驅動例程

二、Windows記憶體管理

1. 實體記憶體位址(Physical Memory Address)。32位的CPU的尋址能力為4GB個位元組。使用者最多可以使用4GB的真是的實體記憶體。

2. 虛拟記憶體位址(Virtual Memory Address)。硬體上MMU和軟體上作業系統,為使用者提供了虛拟記憶體的概念。對虛拟記憶體的操作,最終會變成一系列對真實實體記憶體的操作。

一個簡單的Windows驅動例程

3.Windows的核心代碼和Windows的驅動程式加載的位置都是在高2GB的核心位址裡。                           

三、具體例程實作個人電腦上喇叭響

這個例程最終是實作對電腦上的I/O端口操作,每個PC系統至少包含一個8253可程式設計時鐘或等價的晶片。這個晶片控制系統喇叭。這裡的總做就像單片機操作自身I/O前,要去配置寄存器一樣的過程。隻不過這裡隔着Windows作業系統。是以,第一步我們應該知道,需要配置哪些寄存器,都配置成什麼值。這裡我們不細說具體要配置寄存器,有興趣的讀者可以參考《Windows驅動開發技術詳解》第十五章。

這裡我們把整個曆程的流程圖畫出:

一個簡單的Windows驅動例程

應用程式的函數最終能夠讀寫硬體層寄存器的資料,還要靠IOCTL派遣函數調用DDK提供的函數。如READ_PORT_UCHAR READ_PORT_USHORT READ_PORT_ULONG WRITE_PORT_UCHARWRITE_PORT_USHORT WRITE_PORT_ULONG

代碼如下:

應用程式(vs2008)

//winows應用程式

#include <windows.h>

#include <stdio.h>

//使用CTL_CODE必須加入winioctl.h

#include <winioctl.h>

#include "..\NT_Driver\Ioctls.h"

UCHAR In_8(HANDLE hDevice,USHORT port)

{

     DWORD dwOutput ;

     DWORD inputBuffer[2] =

     {

         port,//對port進行操作

         1//1代表位操作,代表位操作,代表位操作

     };

     DWORD dResult;

     DeviceIoControl(hDevice,READ_PORT, inputBuffer, sizeof(inputBuffer),&dResult, sizeof(DWORD), &dwOutput,NULL);

     return(UCHAR) dResult;

}

void Out_8(HANDLE hDevice,USHORT port,UCHAR value)

{

     DWORD dwOutput ;

     DWORD inputBuffer[3] =

     {

         port,//對port進行操作

         1,//1代表位操作,代表位操作,代表位操作

         value//輸出位元組

     };

     DeviceIoControl(hDevice,WRITE_PORT, inputBuffer, sizeof(inputBuffer),NULL, 0, &dwOutput, NULL);

}

//發音程式,參數f代表頻率

void Sound(HANDLE hDevice,int f)

     //計數為/F

     USHORT   B=1193180/f;

     //從端口x61取數

     UCHAR temp = In_8(hDevice,0x61);

     //兩低位置

     temp = temp | 3;

     //輸出到x61端口

     Out_8(hDevice,0x61,temp);

     //輸出到x61端口

     Out_8(hDevice,0x43,0xB6);

     //輸出到x42端口,寫低位

     Out_8(hDevice,0x42,B&0xF);

     //輸出到x42端口,寫高位

     Out_8(hDevice,0x42,(B>>8)&0xF);

}

// 關閉聲音

void SoundOff(HANDLE hDevice)                              

{

     //取端口x61的位元組

     UCHAR value =In_8(hDevice,0x61);

     //強制置最後兩位為

     value = value & 0xFC;

     //返送端口x61 

     Out_8(hDevice,0x61,value);

}

int main()

{

     HANDLE hDevice =

         CreateFile("\\\\.\\HelloDDK",

                       GENERIC_READ |GENERIC_WRITE,

                       0,       // share modenone

                       NULL,    // no security

                       OPEN_EXISTING,

                       FILE_ATTRIBUTE_NORMAL,//

                       NULL );       // no template

     if(hDevice == INVALID_HANDLE_VALUE)

     {

         printf("Failed to obtain file handle to device: "

              "%s with Win32 error code: %d\n",

              "MyWDMDevice", GetLastError() );

         return1;

     }

     //産生KHz頻率的聲音

     Sound(hDevice,2000);

     //持續毫秒

     Sleep(200);

     //産生KHz頻率的聲音

     Sound(hDevice,2000);

     //持續毫秒

     Sleep(200);

     //産生KHz頻率的聲音

     Sound(hDevice,2000);

     //持續毫秒

     Sleep(200);

     //産生KHz頻率的聲音

     Sound(hDevice,2000);

     //持續毫秒

     Sleep(200);

     SoundOff(hDevice);

     CloseHandle(hDevice);

     return0;

}

驅動程式(vs2008+DDK):僅僅貼出關鍵代碼

定義IOCTLCODE

#define READ_PORT CTL_CODE(\

              FILE_DEVICE_UNKNOWN, \

              0x800, \

              METHOD_BUFFERED, \

              FILE_ANY_ACCESS)

#define WRITE_PORT CTL_CODE(\

              FILE_DEVICE_UNKNOWN, \

              0x801, \

              METHOD_BUFFERED, \

              FILE_ANY_ACCESS)

設定派遣函數

pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]= HelloDDKDeviceIOControl;

派遣函數(HelloDDKDeviceIOControl)判斷動作是讀寫

     switch(code)

     {                           // processrequest

         caseREAD_PORT:

         {

              KdPrint(("READ_PORT\n"));

              //緩沖區方式IOCTL

              //顯示輸入緩沖區資料

              PULONGInputBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;

              ULONG port =(ULONG)(*InputBuffer);

              InputBuffer++;

              UCHAR method =(UCHAR)(*InputBuffer);

              KdPrint(("port:%x\n",port));

              KdPrint(("method:%x\n",method));

              //操作輸出緩沖區

              PULONG OutputBuffer =(PULONG)pIrp->AssociatedIrp.SystemBuffer;

              if (method==1)//8位操作

              {

                   *OutputBuffer =READ_PORT_UCHAR((PUCHAR)port);

              }else if(method==2)//16位操作

              {

                   *OutputBuffer =READ_PORT_USHORT((PUSHORT)port);

              }else if(method==4)//32位操作

              {

                   *OutputBuffer =READ_PORT_ULONG((PULONG)port);

              }

              //設定實際操作輸出緩沖區長度

              info= 4;

              break;

         }

         caseWRITE_PORT:

         {

              KdPrint(("WRITE_PORT\n"));

              //緩沖區方式IOCTL

              //顯示輸入緩沖區資料

              PULONGInputBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;

              ULONG port =(ULONG)(*InputBuffer);

              InputBuffer++;

              UCHAR method =(UCHAR)(*InputBuffer);

              InputBuffer++;

              ULONG value =(ULONG)(*InputBuffer);

              KdPrint(("port:%x\n",port));

              KdPrint(("method:%x\n",method));

              KdPrint(("value:%x\n",value));

              //操作輸出緩沖區

              PULONG OutputBuffer =(PULONG)pIrp->AssociatedIrp.SystemBuffer;

              if (method==1)//8位操作

              {

                   WRITE_PORT_UCHAR((PUCHAR)port,(UCHAR)value);

              }else if(method==2)//16位操作

              {

                   WRITE_PORT_USHORT((PUSHORT)port,(USHORT)value);

              }else if(method==4)//32位操作

              {

                   WRITE_PORT_ULONG((PULONG)port,(ULONG)value);

              }

              //設定實際操作輸出緩沖區長度

              info= 0;

              break;

         }

         default:

              status = STATUS_INVALID_VARIANT;

繼續閱讀