您的位置:首页 > 理论基础 > 数据结构算法

菜鸟之驱动开发2

2011-08-15 21:40 204 查看
 
上一篇文章里我们写了第一个驱动程序-HelloWorld, 今天我们来完善它,主要完成两个功能:添加一个驱动设备与给驱动添加默认派遣(IRP)。

首先我们来完成第一个功能:添加一个驱动设备。

代码如下:

 

NTSTATUS CreateTheDevice(IN PDRIVER_OBJECT pDeviceObject)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;

UNICODE_STRING devName;
UNICODE_STRING symLinkName;

RtlInitUnicodeString(&devName, L"\\Device\\first_Device");

//create device
status = IoCreateDevice(pDeviceObject,\
0,\
&devName,\
FILE_DEVICE_UNKNOWN,\
0,\
TRUE,\
&pDevObj\
);
if (!NT_SUCCESS(status))
{
if (STATUS_INSUFFICIENT_RESOURCES == status)
{
KdPrint(("资源不足"));
}

if (STATUS_OBJECT_NAME_EXISTS == status)
{
KdPrint(("指定对象名存在"));
}

if (STATUS_OBJECT_NAME_COLLISION == status)
{
KdPrint(("//对象名有冲突"));
}

KdPrint(("设备创建失败"));
return status;
}

KdPrint(("创建设备成功"));

pDevObj->Flags |= DO_BUFFERED_IO;

//创建符号链接
RtlInitUnicodeString(&symLinkName,L"\\??\\firstSymDevice");
status = IoCreateSymbolicLink( &symLinkName,&devName );
if (!NT_SUCCESS(status)) /*status等于0*/
{
IoDeleteDevice( pDevObj );
return status;
}
return STATUS_SUCCESS;
}


这样就可以给我们的驱动加入一个设备,驱动开发是unicode的方式,所以不能直接用用户态的API去处理字符串,必须用Rtl开头的内核函数,如上面RtlInitUnicodeString就是给第一个参数初始化。

第二个功能是关于IRP的,什么叫IRP(I/O Request  Package).用户模式下所有对驱动的I/O请求,全部由操作系统转化为一个叫着IRP的数据结构,不同的IRP请求会被“派遣”到不同的派遣函数中。

有五种常用IRP类型,分别是:

#define IRP_MJ_CREATE                     0x00 //CreateFile()
#define IRP_MJ_CLOSE                      0x02 //CloseHandle()
#define IRP_MJ_READ                       0x03//ReadFile
#define IRP_MJ_WRITE                      0x04//WriteFile
#define IRP_MJ_DEVICE_CONTROL           0x0e//DeviceIoControl


步骤是:

1.创建IRP处理函数

2.在驱动入口外注册IRP处理发函数

3.实现IRP处理函数

有两种方式注册IRP派遣函数,第一种是只有一个派遣函数,在该派遣函数内分别对根据IRP类型做不同的处理,这种方式代码如下:

//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_CREATE]=ddk_DispatchRoutine;
//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine;
//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_READ]=ddk_DispatchRoutine;
//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_WRITE]=ddk_DispatchRoutine;
//注册派遗函数
pDriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL]=ddk_DispatchRoutine;

NTSTATUS ddk_DispatchRoutine(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp	)
{
PIO_STACK_LOCATION irpsp=IoGetCurrentIrpStackLocation(pIrp);
switch (irpsp->MajorFunction)
{
case IRP_MJ_CREATE:
break;
case IRP_MJ_CLOSE:
break;
case IRP_MJ_READ:
break;
case IRP_MJ_WRITE:
break;
case  IRP_MJ_DEVICE_CONTROL:
break;
default:
KdPrint(("其它处理"));
//指示完成此IRP

}
//成功返回
return STATUS_SUCCESS;
}


 

第二种是对每一种类型的IRP注册一个派遣函数,代码如下:

 

//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_CREATE]=ddk_DispatchRoutine_CREATE;
//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_CLOSE]=ddk_DispatchRoutine_CLOSE;
//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_READ]=ddk_DispatchRoutine_READ;
//注册派遗函数
pDriverObject->MajorFunction[IRP_MJ_WRITE]=ddk_DispatchRoutine_WRITE;
//注册派遗函数
pDriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL]=ddk_DispatchRoutine_CONTROL;

NTSTATUS ddk_DispatchRoutine_CONTROL(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp	)
{
//对相应的IPR进行处理
pIrp->IoStatus.Information=0;//设置操作的字节数为0,这里无实际意义
pIrp->IoStatus.Status=STATUS_SUCCESS;//返回成功
IoCompleteRequest(pIrp,IO_NO_INCREMENT);//指示完成此IRP
KdPrint(("离开派遣函数\n"));//调试信息
return STATUS_SUCCESS; //返回成功
}


到此代码介绍完毕, 记得在卸载驱动的时候,要卸载设备,不然下次加载驱动的时候,因为设备没有卸载而不能成功创建设备。请参看完整的源码 。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息