一个简单的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
#include
//使用CTL_CODE必须加入winioctl.h
#include
#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;