Windows 驱动开发笔记(六)
一个驱动程序是要能操作硬件的。那么,操作硬件就要能够操作设备的端口和特定的内存映射等。在windows nt设计时为了避免为兼容各种平台而使用大量条件编译代码,Windows NT的设计者发明了硬件抽象层(HAL),HAL提供了用于访问端口和内存资源的函数。而不是使用_inp(),_outp()等函数直接来操作端口。下面我们来使用写一个用PC喇叭法声的例子。
WRITE_PORT_UCHAR((PUCHAR)0x43,(UCHAR)0xb6);//设置定时器
WRITE_PORT_UCHAR((PUCHAR)0x42,(UCHAR)0x12);//设置发声频率
WRITE_PORT_UCHAR((PUCHAR)0x42,(UCHAR)0x10);//设置发声频率
WRITE_PORT_UCHAR((PUCHAR)0x61,(UCHAR)(READ_PORT_UCHAR((PUCHAR)0x61)|(UCHAR)0x3));//开启设备
WRITE_PORT_UCHAR((PUCHAR)0x61,(UCHAR)(READ_PORT_UCHAR((PUCHAR)0x61)&(UCHAR)0xfc));//关闭设备
我们把这些代码加入驱动中.
hello.c 文件
#ifndef __HELLOWORLD_C__
#define __HELLOWORLD_C__
#define DEBUGMSG
#include "Hello.h"
//驱动入口
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
NTSTATUS ntStatus=STATUS_SUCCESS;
PDEVICE_OBJECT lpDeviceObject=NULL; //指向设备对象的指针
UNICODE_STRING DeviceNameString; //设备名称
UNICODE_STRING DeviceLinkString; //符号连接
//调试信息
#ifdef DEBUGMSG
DbgPrint("Starting DriverEntry()/n");
#endif
RtlInitUnicodeString(&DeviceNameString,NT_DEVICE_NAME); //初始化Unicode字符串
//创建设备
ntStatus=IoCreateDevice(DriverObject,0,&DeviceNameString,FILE_DEVICE_UNKNOWN,
0,FALSE,&lpDeviceObject);
lpDeviceObject->Flags |= DO_BUFFERED_IO; //定义使用缓冲方式
//使用NT_SUCCESS宏检测函数调用是否成功
if (!NT_SUCCESS(ntStatus))
{
#ifdef DEBUGMSG
DbgPrint("Error IoCreateDevice()/n");
#endif
goto Error;
}
RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
//创建符号连接
ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&DeviceNameString);
if (!NT_SUCCESS(ntStatus))
{
#ifdef DEBUGMSG
DbgPrint("Error IoCreateSymbolicLink()/n");
#endif
goto Error;
}
//设置IRP派遣例程和卸载例程
DriverObject->MajorFunction[IRP_MJ_CREATE]=HelloCreateDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE]=HelloCloseDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=HelloControlDispatch;
DriverObject->DriverUnload=HelloWorldUnLoad;
return ntStatus;
Error:
#ifdef DEBUGMSG
DbgPrint("Error DriverEntry()/n");
#endif
return ntStatus;
}
//打开设备例程
NTSTATUS HelloCreateDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
NTSTATUS ntStatus=STATUS_SUCCESS;
ULONG IoControlCodes=0; //I/O控制代码
PIO_STACK_LOCATION IrpStack=NULL; //IRP堆栈
//设置IRP状态
pIrp->IoStatus.Status=STATUS_SUCCESS;
pIrp->IoStatus.Information=0;
#ifdef DEBUGMSG
DbgPrint("Starting HelloCreateDispatch()/n");
#endif
IrpStack=IoGetCurrentIrpStackLocation(pIrp); //得到当前调用者的IRP
#ifdef DEBUGMSG
DbgPrint("IRP_MJ_CREATE/n");
#endif
ntStatus=pIrp->IoStatus.Status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return ntStatus;
}
//关闭例程
NTSTATUS HelloCloseDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
NTSTATUS ntStatus=STATUS_SUCCESS;
ULONG IoControlCodes=0; //I/O控制代码
PIO_STACK_LOCATION IrpStack=NULL; //IRP堆栈
//设置IRP状态
pIrp->IoStatus.Status=STATUS_SUCCESS;
pIrp->IoStatus.Information=0;
#ifdef DEBUGMSG
DbgPrint("Starting HelloCloseDispatch()/n");
#endif
IrpStack=IoGetCurrentIrpStackLocation(pIrp); //得到当前调用者的IRP
#ifdef DEBUGMSG
DbgPrint("IRP_MJ_CLOSE/n");
#endif
ntStatus=pIrp->IoStatus.Status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return ntStatus;
}
//控制例程
NTSTATUS HelloControlDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
NTSTATUS ntStatus=STATUS_SUCCESS;
ULONG IoControlCodes=0; //I/O控制代码
PIO_STACK_LOCATION IrpStack=NULL; //IRP堆栈
PVOID pInputBuffer,pOutputBuffer; //缓冲区指针
ULONG inputLength,outputLength; //缓冲区长度
PCHAR pReturnData = "IOCTL - Buffered I/O From Kernel!";
ULONG dwDataSize = sizeof("Example_ReadDirectIO - Hello from the Kernel!");
//设置IRP状态
pIrp->IoStatus.Status=STATUS_SUCCESS;
pIrp->IoStatus.Information=0;
#ifdef DEBUGMSG
DbgPrint("Starting HelloControlDispatch()/n");
#endif
IrpStack=IoGetCurrentIrpStackLocation(pIrp); //得到当前调用者的IRP堆栈
//取得I/O控制代码
IoControlCodes=IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (IoControlCodes)
{
//启动
case START_HELLPWORLD:
DbgPrint("Starting /"Hello World/"/n");
WRITE_PORT_UCHAR((PUCHAR)0x43,(UCHAR)0xb6);
WRITE_PORT_UCHAR((PUCHAR)0x42,(UCHAR)0x12);
WRITE_PORT_UCHAR((PUCHAR)0x42,(UCHAR)0x10);
WRITE_PORT_UCHAR((PUCHAR)0x61,(UCHAR)(READ_PORT_UCHAR((PUCHAR)0x61)|(UCHAR)0x3));
break;
//停止
case STOP_HELLPWORLD:
DbgPrint("Stoping /"Hello World/"/n");
WRITE_PORT_UCHAR((PUCHAR)0x61,(UCHAR)(READ_PORT_UCHAR((PUCHAR)0x61)&(UCHAR)0xfc));
break;
case WRITE_HELLPWORLD:
inputLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; //IRP堆栈中得到长度
pInputBuffer = pIrp->AssociatedIrp.SystemBuffer;//IRP中得到地址
DbgPrint("Reading a Buffer Data!/n");
if(pInputBuffer)
{
DbgPrint("COMM_BufferedIo UserModeMessage = '%s'/n", pInputBuffer);
}
break;
case READ_HELLPWORLD:
outputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; //IRP堆栈中得到长度
pOutputBuffer = pIrp->AssociatedIrp.SystemBuffer;//IRP中得到地址
DbgPrint("Writing a Buffer Data!/n");
if(pOutputBuffer)
{
RtlCopyMemory(pOutputBuffer, pReturnData, dwDataSize);
pIrp->IoStatus.Information=dwDataSize;
}
break;
default:
DbgPrint("Invalid Parameter /"Hello World/"/n");
pIrp->IoStatus.Status=STATUS_INVALID_PARAMETER;
break;
}
ntStatus=pIrp->IoStatus.Status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return ntStatus;
}
VOID HelloWorldUnLoad (IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING DeviceLinkString;
PDEVICE_OBJECT DeviceObjectTemp1=NULL;
PDEVICE_OBJECT DeviceObjectTemp2=NULL;
#ifdef DEBUGMSG
DbgPrint("Starting HelloWorldUnLoad()/n");
#endif
RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&DeviceLinkString); //删除符号连接
if (DriverObject)
{
DeviceObjectTemp1=DriverObject->DeviceObject;
//删除设备
while (DeviceObjectTemp1)
{
DeviceObjectTemp2=DeviceObjectTemp1;
DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;
IoDeleteDevice(DeviceObjectTemp2);
}
}
}
#endif
hello.h 文件
#ifndef __HELLOWORLD_H__
#define __HELLOWORLD_H__
#include <ntddk.h>
#define DEVICE_HELLO_INDEX 0x860
#define START_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define STOP_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+1,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define WRITE_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+2,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define READ_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+3,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define NT_DEVICE_NAME L"//Device//hello" //设备名称
#define DOS_DEVICE_NAME L"//DosDevices//hello" //符号连接
NTSTATUS HelloCreateDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);
NTSTATUS HelloCloseDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);
NTSTATUS HelloControlDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);
VOID HelloWorldUnLoad (IN PDRIVER_OBJECT DriverObject);
#endif
helloctl.c 文件
#define DEBUGMSG
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#define DEVICE_HELLO_INDEX 0x860
#define START_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define STOP_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+1,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define WRITE_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+2,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define READ_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+3,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define erron GetLastError()
#define MY_DEVICE_NAME ".//hello"
#define MY_DEVICE_START "-start"
#define MY_DEVICE_STOP "-stop"
#define MY_DEVICE_WRITE "-input"
#define MY_DEVICE_READ "-output"
#define MY_INPUT_BUF_SIZE 255
#define MY_OUTPUT_BUF_SIZE 255
BOOL DriverControl (TCHAR *Maik);
void Usage (TCHAR *Paramerter);
int main (int argc,TCHAR *argv[])
{
if (argc!=2)
{
Usage(argv[0]);
return 0;
}
if (strcmpi(argv[1],MY_DEVICE_START)==0 || strcmpi(argv[1],MY_DEVICE_STOP)==0
|| strcmpi(argv[1],MY_DEVICE_WRITE)==0 || strcmpi(argv[1],MY_DEVICE_READ)==0)
DriverControl(argv[1]);
else
{
Usage(argv[0]);
return 0;
}
return 0;
}
BOOL DriverControl (TCHAR *Maik)
{
HANDLE hDevice=NULL; //设备句柄
DWORD RetBytes=0;
char inputBuffer[MY_INPUT_BUF_SIZE]; //输出用户缓冲区
char outputBuffer[MY_OUTPUT_BUF_SIZE];//输入用户缓冲区
//获得设备句柄
hDevice=CreateFile(MY_DEVICE_NAME,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hDevice==INVALID_HANDLE_VALUE)
{
#ifdef DEBUGMSG
printf("CreateFile() GetLastError reports %d/n",erron);
#endif
return FALSE;
}
//启动
if (strcmpi(Maik,MY_DEVICE_START)==0)
{
//传递启动的I/O控制代码
if (!(DeviceIoControl(hDevice,START_HELLPWORLD,NULL,0,NULL,0,&RetBytes,NULL)))
{
#ifdef DEBUGMSG
printf("DeviceIoControl() GetLastError reports %d/n",erron);
#endif
CloseHandle(hDevice);
return FALSE;
}
}
//停止
if (strcmpi(Maik,MY_DEVICE_STOP)==0)
{
//传递停止的I/O控制代码
if (!(DeviceIoControl(hDevice,STOP_HELLPWORLD,NULL,0,NULL,0,&RetBytes,NULL)))
{
#ifdef DEBUGMSG
printf("DeviceIoControl() GetLastError reports %d/n",erron);
#endif
CloseHandle(hDevice);
return FALSE;
}
}
//输入数据
if (strcmpi(Maik,MY_DEVICE_WRITE)==0)
{
//输入数据缓冲区
strcpy(inputBuffer,"Hello,Input Data!");
if (!(DeviceIoControl(hDevice,WRITE_HELLPWORLD,&inputBuffer,MY_INPUT_BUF_SIZE,NULL,0,&RetBytes,NULL)))
{
#ifdef DEBUGMSG
printf("DeviceIoControl() GetLastError reports %d/n",erron);
#endif
CloseHandle(hDevice);
return FALSE;
}
}
//输出数据
if (strcmpi(Maik,MY_DEVICE_READ)==0)
{
if (!(DeviceIoControl(hDevice,READ_HELLPWORLD,NULL,0,&outputBuffer,MY_OUTPUT_BUF_SIZE,&RetBytes,NULL)))
{
#ifdef DEBUGMSG
printf("DeviceIoControl() GetLastError reports %d/n",erron);
#endif
CloseHandle(hDevice);
return FALSE;
}else{
printf("DeviceIoControl() output Data! s=%s/n return Bytes=%d%/n",outputBuffer,RetBytes);
}
}
if (hDevice)
CloseHandle(hDevice); //关闭句柄
return TRUE;
}
void Usage (TCHAR *Paramerter)
{
fprintf(stderr,"============================================================================/n"
" Hello驱动控制例程/n"
"%s -start/t启动/n"
"%s -stop /t停止/n"
"%s -input/t输入/n"
"%s -output/t输入/n"
"本程序只是用做代码交流,如有错误,还请多多包含!/n"
"============================================================================/n"
,Paramerter,Paramerter,Paramerter);
}
安装驱动.
使用
>helloctl -start 开启
>helloctl -stop 关闭