一個簡單的Windows驅動例程
本文所需代碼在這裡下載下傳:http://download.csdn.net/detail/li171049/6777587
一、Windows驅動程式對于我們來說經常使用,卻又了解很少,給我們的感覺好像是很神秘。這裡我們通過一個簡單的例程來說明,Windows驅動程式的工作原理。在例程沒有貼出來前,我們需要了解Windows與之相關的基本概念。
一、如下圖,我們需要了解Windows的應用程式和驅動程式在Windows系統中的位置。
二、Windows記憶體管理
1. 實體記憶體位址(Physical Memory Address)。32位的CPU的尋址能力為4GB個位元組。使用者最多可以使用4GB的真是的實體記憶體。
2. 虛拟記憶體位址(Virtual Memory Address)。硬體上MMU和軟體上作業系統,為使用者提供了虛拟記憶體的概念。對虛拟記憶體的操作,最終會變成一系列對真實實體記憶體的操作。
3.Windows的核心代碼和Windows的驅動程式加載的位置都是在高2GB的核心位址裡。
三、具體例程實作個人電腦上喇叭響
這個例程最終是實作對電腦上的I/O端口操作,每個PC系統至少包含一個8253可程式設計時鐘或等價的晶片。這個晶片控制系統喇叭。這裡的總做就像單片機操作自身I/O前,要去配置寄存器一樣的過程。隻不過這裡隔着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;