天天看点

一个简单的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;

继续阅读