一个简单的Windows驱动例程

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

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
  对于在“蓝网之家”影响下蠢蠢而动搞 Windows 95 远程启动的朋友可能不少,那么大家一定对 NDIS 这几个字母不会感到陌生。其实不只是在远程启动这一层,只要是网卡的驱动盘,大家都会在里面发现有类似 NDIS、NDIS2、NDIS3、NDIS4一样的目录,只是大家在 Windows 9x 或 NT 中安装、设置网卡时没有注意到它罢了。但即使大搞特搞 RPL 的朋友对其大概也是只知其然而不其所以然。    NDIS 是什么?有什么作用?       NDIS 的全称是 Network Device Interface Specification,中文意思就是网络设备接口规范。    根据 OSI 七层模型,物理层定义了对网卡、线缆以及其它物理硬件设备进行配置的标准。节点间建立通信时是由物理层在传输介质上传送二进制信息实现的,因此,在发送端和接收端都还必须有一个程序来格式化这种信息流并将其传送给上一层。NDIS 的作用就是避免在访问网卡每次进行传输时都编写相应的代码。由此说来,NDIS 本质上是一种软件接口,有了 NDIS ,所有的传输就可以采用一种通用的方式来访问由不同厂商制造的网卡了,即它是用来连接协议堆栈和网卡的。   与此相关的软件还有重定向器(Redirector)和服务器(Server)。前者的目的是截获来自 OSI 会话层的网络调用,并通过将其传送到相应的协议驱动程序接口而格式化成 NDIS 能够识别和使用的命令。后者则负责接收从重向器传过来的来自于远程计算机的请求,再将这一请求传送给相应的本地文件系统驱动程序,最后再由该“服务器”将数据沿协议堆栈向下传递给客户机。    TCP协议也是通过调用 NDIS 接口服务来完成传输操作的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大牛攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值