知识点
-
串口设备命名规则:Windows中串口设备具有固定的名字,第一个串口叫"\Device\Serial0",第二个叫"\Device\Serial1"。
-
快速构造UNICODE_STRING:可以直接使用
RTL_CONSTANT_STRING
宏来快速构造UNICODE_STRING,例如UNICODE_STRING com_name = RTL_CONSTANT_STRING(L"\\Device\\Serial0");
。 -
过滤设备名称:过滤设备一般不需要名称,
IoCreateDevice
传入NULL即可。 -
设备对象生成:一个驱动中生成从属于其他驱动的设备对象,理论上是可以的。
-
IRP请求:串口设备接受到的请求都是IRP(I/O Request Packet)。
-
设备卸载API:
IoDetachDevice
和IoDeleteDevice
用于设备卸载,KeDelayExecutionThread
用于等待IRP处理结束。 -
设备绑定API:
IoAttachDevice
用于绑定有名设备,IoAttachDeviceToDeviceStack
和IoAttachDeviceToDeviceStackSafe
用于绑定无名设备。 -
获取IRP数据:从IRP中获取缓冲区和长度,用于读取或写入数据。
操作Demo
以下是一个简单的串口过滤驱动的示例代码:
- 驱动入口函数:
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObj, IN PUNICODE_STRING RegistryPath) {
size_t i;
for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
DriverObj->MajorFunction[i] = ccpDispatch;
}
DriverObj->DriverUnload = ccpUnload;
ccpAttachAlloComs(DriverObj);
return STATUS_SUCCESS;
}
- 派遣函数:
NTSTATUS ccpDispatch(PDEVICE_OBJECT device, PIRP irp) {
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status;
ULONG i, j;
for(i = 0; i < CCP_MAX_COM_ID; i++) {
if(s_fltobj[i] == device) {
if(irpsp->MajorFunction == IRP_MJ_POWER) {
PoStartNextPowerIrp(irp);
IoSkipCurrentIrpStackLocation(irp);
return IoCallDriver(s_nextobj[i], irp);
}
if(irpsp->MajorFunction == IRP_MJ_WRITE) {
ULONG len = irpsp->Parameters.Write.Length;
PUCHAR buf = NULL;
if(irp->MdlAddress != NULL) {
buf = (PUCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
} else {
buf = (PUCHAR)irp->UserBuffer;
}
if(buf == NULL) {
buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;
}
for(j = 0; j < len; j++) {
KdPrint(("comcap:Send Data: %2x\r\n", buf[j]));
}
}
IoSkipCurrentIrpStackLocation(irp);
return IoCallDriver(s_nextobj[i], irp);
}
}
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
- 驱动卸载函数:
void ccpUnload(PDRIVER_OBJECT drv) {
ULONG i;
LARGE_INTEGER interval;
for(i = 0; i < CCP_MAX_COM_ID; i++) {
if(s_nextobj[i] != NULL) {
IoDeleteDevice(s_nextobj[i]);
}
}
interval.QuadPart = (5*1000*DELAY_ONE_MILLISECOND);
KeDelayExecutionThread(KernelMode, FALSE, &interval);
for(i = 0; i < CCP_MAX_COM_ID; i++) {
if(s_nextobj[i] != NULL) {
IoDeleteDevice(s_fltobj[i]);
}
}
}
- 创建过滤设备并绑定:
NTSTATUS ccpAttachDevice(PDRIVER_OBJECT driverObj, PDEVICE_OBJECT oldDev, PDEVICE_OBJECT *fltObj, PDEVICE_OBJECT *next) {
NTSTATUS status;
PDEVICE_OBJECT topDev = NULL;
status = IoCreateDevice(driverObj, 0, NULL, oldDev->DeviceType, 0, FALSE, fltObj);
if(status != STATUS_SUCCESS) {
return status;
}
if(oldDev->Flags & DO_BUFFERED_IO) {
(*fltObj)->Flags |= DO_BUFFERED_IO;
} else if(oldDev->Flags & DO_DIRECT_IO) {
(*fltObj)->Flags |= DO_DIRECT_IO;
} else if(oldDev->Characteristics & FILE_DEVICE_SECURE_OPEN) {
(*fltObj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
}
(*fltObj)->Flags |= DO_POWER_PAGABLE;
topDev = IoAttachDeviceToDeviceStack(*fltObj, oldDev);
if(topDev == NULL) {
IoDeleteDevice(*fltObj);
*fltObj = NULL;
status = STATUS_SUCCESS;
return status;
}
*next = topDev;
return STATUS_SUCCESS;
}