一个简单的串口过滤驱动及一点体会

来源:互联网 发布:如何将程序导入单片机 编辑:程序博客网 时间:2024/05/02 04:15

最近写一个简单的串口过滤驱动,代码如下:

driver.h

 

#ifdef __cplusplus
extern "C"
{
#endif

#include <ntddk.h>

#ifdef __cplusplus
}
#endif

#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")
#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")

#define arraysize(x) (sizeof(x) / sizeof(x[0]))

typedef struct
{
 PDEVICE_OBJECT LowerLevelDeviceObject;
 UNICODE_STRING SymbolicLink;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

NTSTATUS DispatchPassthrough(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS Read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS CreateDevice(IN PDRIVER_OBJECT DriverObject);
NTSTATUS OnRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);

driver.cpp

#include "Driver.h"

#pragma INITCODE
#ifdef __cplusplus
extern "C"
{
#endif

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
 KdPrint(("Enter DriverEntry!/n"));
 for(int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
  DriverObject->MajorFunction[i] = DispatchPassthrough;
  
 DriverObject->MajorFunction[IRP_MJ_READ] = Read;

 DriverObject->DriverUnload = DriverUnload;
 
 KdPrint(("Leave DriverEntry!/n"));
 return CreateDevice(DriverObject);
}

#ifdef __cplusplus
}
#endif

 

#pragma PAGEDCODE
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
 KdPrint(("Enter DriverUnload!/n"));
 PDEVICE_OBJECT Dev = DriverObject->DeviceObject;
 
 while(NULL != Dev)
 {
  PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)Dev->DeviceExtension;
  //删除符号链接
  IoDeleteSymbolicLink(&DevExt->SymbolicLink);
  
  IoDetachDevice(DevExt->LowerLevelDeviceObject);
  
  //删除设备对象

  IoDeleteDevice(Dev);
  Dev = Dev->NextDevice;
 }
 KdPrint(("Leave DriverUnload!/n"));
}

 

#pragma PAGEDCODE
NTSTATUS DispatchPassthrough(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
 KdPrint(("Enter DispatchPassthrough!/n"));
 NTSTATUS status = STATUS_SUCCESS;
 static char* irpname[] =
 {
  "IRP_MJ_CREATE",
  "IRP_MJ_CREATE_NAMED_PIPE",
  "IRP_MJ_CLOSE",
  "IRP_MJ_READ",
  "IRP_MJ_WRITE",
  "IRP_MJ_QUERY_INFORMATION",
  "IRP_MJ_SET_INFORMATION",
  "IRP_MJ_QUERY_EA",
  "IRP_MJ_SET_EA",
  "IRP_MJ_FLUSH_BUFFERS",
  "IRP_MJ_QUERY_VOLUME_INFORMATION",
  "IRP_MJ_SET_VOLUME_INFORMATION",
  "IRP_MJ_DIRECTORY_CONTROL",
  "IRP_MJ_FILE_SYSTEM_CONTROL",
  "IRP_MJ_DEVICE_CONTROL",
  "IRP_MJ_INTERNAL_DEVICE_CONTROL",
  "IRP_MJ_SHUTDOWN",
  "IRP_MJ_LOCK_CONTROL",
  "IRP_MJ_CLEANUP",
  "IRP_MJ_CREATE_MAILSLOT",
  "IRP_MJ_QUERY_SECURITY",
  "IRP_MJ_SET_SECURITY",
  "IRP_MJ_POWER",
  "IRP_MJ_SYSTEM_CONTROL",
  "IRP_MJ_DEVICE_CHANGE",
  "IRP_MJ_QUERY_QUOTA",
  "IRP_MJ_SET_QUOTA",
  "IRP_MJ_PNP",
 };
 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
 UCHAR type = stack->MajorFunction;
 if(type >= arraysize(irpname))
  KdPrint(("Unkown IRP, major type %X/n", type));
 else
  KdPrint(("/t%s/n", irpname[type]));
  
 IoSkipCurrentIrpStackLocation(Irp);
 status = IoCallDriver(DevExt->LowerLevelDeviceObject, Irp);
 KdPrint(("Leave DispatchPassthrough!/n"));
 return status;
}

 

#pragma PAGEDCODE
NTSTATUS CreateDevice(IN PDRIVER_OBJECT DriverObject)
{
 NTSTATUS status = STATUS_SUCCESS;
 KdPrint(("Enter CreateDevice!/n"));
 UNICODE_STRING DevName;
 RtlInitUnicodeString(&DevName, L"//Device//MyDevice");
 PDEVICE_OBJECT fdo = NULL;
 status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
 if(!NT_SUCCESS(status))
  return status;
 
 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)fdo->DeviceExtension;
 RtlZeroMemory(DevExt, sizeof(DEVICE_EXTENSION));
 
 UNICODE_STRING SymbolicLinkName;
 RtlInitUnicodeString(&SymbolicLinkName, L"//??//COMMFILT");
 status = IoCreateSymbolicLink(&SymbolicLinkName, &DevName);
 if(!NT_SUCCESS(status))
 {
  IoDeleteDevice(fdo);
  return status;
 }
 DevExt->SymbolicLink = SymbolicLinkName;
 
 UNICODE_STRING TargetDeviceName;
 RtlInitUnicodeString(&TargetDeviceName, L"//Device//Winachsf0");
 status = IoAttachDevice(fdo, &TargetDeviceName, &DevExt->LowerLevelDeviceObject);
 if(!NT_SUCCESS(status))
 {
  IoDeleteSymbolicLink(&SymbolicLinkName);
  IoDeleteDevice(fdo);
  return status;
 }
 
 fdo->DeviceType = DevExt->LowerLevelDeviceObject->DeviceType;
 fdo->Characteristics = DevExt->LowerLevelDeviceObject->Characteristics;
 fdo->Flags |= (DevExt->LowerLevelDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO));
 fdo->Flags &= ~DO_DEVICE_INITIALIZING;

 KdPrint(("Leave CreateDevice!/n"));
 return status;
}

 

#pragma PAGEDCODE
NTSTATUS Read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
 KdPrint(("Enter Read!/n"));
 PDEVICE_EXTENSION DevExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
 IoCopyCurrentIrpStackLocationToNext(Irp);
 
 IoSetCompletionRoutine(Irp, OnRead, NULL, TRUE, TRUE, TRUE);
 KdPrint(("Leave Read!/n"));
 
 return IoCallDriver(DevExt->LowerLevelDeviceObject, Irp);
}

 

#pragma LOCKEDCODE
NTSTATUS OnRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
 KdPrint(("Enter OnRead!/n"));
 if(Irp->PendingReturned)
  IoMarkIrpPending(Irp);
 else if(NT_SUCCESS(Irp->IoStatus.Status))
 {
  if(Irp->IoStatus.Information > 0 && NULL != Irp->AssociatedIrp.SystemBuffer)
  {
   for(unsigned int i = 0; i < Irp->IoStatus.Information; i++)
    KdPrint(("0x%2x", ((char*)Irp->AssociatedIrp.SystemBuffer)[i]));
   KdPrint(("/n"));
  }
 }
  
 KdPrint(("Leave OnRead!/n"));
 return Irp->IoStatus.Status;
}

在这个过程中我有以下四点体会:

1、在将新建的设备挂接到串口之后,需要将串口的DeviceType和Characteristic赋值给新建的设备的相应成员中
2、对于过滤驱动,由于不知道下层设备的IO方式到底是哪种,所以需要将Flags |= lowerDev->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)
3、只有在完成例程返回STATUS_MORE_PROCESSING_REQUIRED时才需要由上层驱动结束IRP(IoCompleteRequest)
4、过滤驱动派遣函数的默认处理中应该将IRP转发至下层驱动,否则下层驱动会有很多IRP接收不到,这样会出问题