第3章代码
// #include
#include
#define NTSTRSAFE_LIB
#include
#define CPP_MAX_COM_ID 32
#define DELAY_ONE_MICROSECOND (-10)
#define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000)
#define DELAY_ONE_SECOND (DELAY_ONE_MILLISECOND*1000)
static PDEVICE_OBJECT s_fltobj[CPP_MAX_COM_ID] = {0};
static PDEVICE_OBJECT s_nextobj[CPP_MAX_COM_ID] = {0};
NTSTATUS ccpAttachDevice(
PDRIVER_OBJECT driver
, PDEVICE_OBJECT oldobj
, PDEVICE_OBJECT *fltobj
, PDEVICE_OBJECT *next)
{
NTSTATUS status;
PDEVICE_OBJECT topdev = NULL;
// IoCreateDevice 创建设备对象
// driver 驱动程序对象 , oldobj->DeviceType设备的类型
// fltobj指向接收DEVICE_OBJECT结构体的指针
status = IoCreateDevice (driver, 0, NULL, oldobj->DeviceType, 0, FALSE, fltobj);
if (status != STATUS_SUCCESS)
{
return status;
}
if (oldobj -> Flags & DO_BUFFERED_IO)
{
(*fltobj)->Flags |= DO_BUFFERED_IO;
}
if (oldobj->Flags & DO_DIRECT_IO)
{
(*fltobj)->Flags |= DO_DIRECT_IO;
}
if (oldobj->Flags & FILE_DEVICE_SECURE_OPEN)
{
(*fltobj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
}
(*fltobj)->Flags |= DO_POWER_PAGABLE;
// 将调用方的设备对象附加到设备对象链中的最高层,并返回之前在设备对象链中最高的设备对象。
// fltobj需要附着的源设备对象, oldobj附着到的目标设备对象
// 把fltobj放到oldobj所在的链的顶端
topdev = IoAttachDeviceToDeviceStack (*fltobj, oldobj);
if (NULL == topdev)
{
// 从系统中删除一个设备对象fltobj
// VOID IoDeleteDevice(
// _In_ PDEVICE_OBJECT DeviceObject
// );
// DeviceObject 要删除的设备对象指针
IoDeleteDevice (*fltobj);
*fltobj = NULL;
status = STATUS_UNSUCCESSFUL;
return status;
}
*next = topdev;
(*fltobj)->Flags = (*fltobj)->Flags & ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
PDEVICE_OBJECT cppOpenCom(ULONG id, NTSTATUS *status)
{
UNICODE_STRING name_str;
static WCHAR name[32] = {0};
PFILE_OBJECT fileobj = NULL;
PDEVICE_OBJECT devobj = NULL;
memset (name, 0, sizeof(WCHAR)*32);
RtlStringCchPrintfW(name, 32, L"\\Device\\Serial%d", id);
RtlInitUnicodeString (&name_str, name);
// 获取命名对象
// IoGetDeviceObjectPointer返回一个指向命名对象设备堆栈顶部的对象指针和
// 相应的文件对象指针
// The IoGetDeviceObjectPointer routine returns a pointer to the top object
// in the named device object's stack and a pointer to the corresponding file object,
// if the requested access to the objects can be granted.
*status = IoGetDeviceObjectPointer(&name_str, FILE_ALL_ACCESS, &fileobj, &devobj);
if (*status == STATUS_SUCCESS)
{
// 解除引用。
// ObDereferenceObject检查给定对象的引用计
// The ObDereferenceObject routine decrements the given object's reference count
// and performs retention checks.
ObDereferenceObject(fileobj);
}
return devobj;
}
void cppAttachAllCom(PDRIVER_OBJECT driver)
{
ULONG i;
PDEVICE_OBJECT com_ob;
NTSTATUS status;
for (i = 0; i < CPP_MAX_COM_ID; ++i)
{
com_ob = cppOpenCom (i, &status);
if (NULL == com_ob)
{
continue;
}
ccpAttachDevice(driver, com_ob, &s_fltobj[i], &s_nextobj[i]);
}
}
NTSTATUS ccpDispatch(PDEVICE_OBJECT device, PIRP irp)
{
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation (irp);
NTSTATUS status;
ULONG i, j;
for (i = 0; i < CPP_MAX_COM_ID; ++i)
{
if (device == s_fltobj[i])
{
if (irpsp->MajorFunction == IRP_MJ_POWER)
{
// The PoStartNextPowerIrp routine signals the power manager that
// the driver is ready to handle the next power IRP.
// (Windows Server 2003, Windows XP, and Windows 2000 only.)
PoStartNextPowerIrp (irp);
// The IoSkipCurrentIrpStackLocation macro modifies the system's
// IO_STACK_LOCATION array pointer, so that when the current
// driver calls the next-lower driver, that driver receives
// the same IO_STACK_LOCATION structure that
// the current driver received.
IoSkipCurrentIrpStackLocation (irp);
// The PoCallDriver routine passes a power IRP to the next-lower
// driver in the device stack.
// (Windows Server 2003, Windows XP, and Windows 2000 only.)
return PoCallDriver (s_nextobj[i], irp);
}
if (irpsp->MajorFunction == IRP_MJ_WRITE)
{
ULONG len = (irpsp->Parameters.Write.Length);
PUCHAR buf = NULL;
if (irp->MdlAddress != NULL)
{
// The MmGetSystemAddressForMdlSafe macro returns a
// nonpaged system-space virtual address for the buffer that
// the specified MDL describes.
buf = (PUCHAR)MmGetSystemAddressForMdlSafe(
irp->MdlAddress, NormalPagePriority);
}
else
{
buf = (PUCHAR)irp->UserBuffer;
}
if (NULL == buf)
{
buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;
}
for (j = 0; j < len; ++j)
{
DbgPrint("comcap: Send Data: %2x\r\n", buf[j]);
}
}
IoSkipCurrentIrpStackLocation (irp);
// The IoCallDriver routine sends an IRP to the driver associated with
// a specified device object.
// 发送irp给s_nextobj[i]
return IoCallDriver (s_nextobj[i], irp);
}
}
irp->IoStatus.Information = 0;
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
// The IoCompleteRequest routine indicates that the caller has completed all processing
// for a given I/O request and is returning the given IRP to the I/O manager.
// 调用者已完成所有处理对于一个给定的I / O请求和返回给定的irp到I / O管理器。
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
void ccpUnload(PDRIVER_OBJECT drv)
{
ULONG i;
LARGE_INTEGER interval;
for (i = 0; i < CPP_MAX_COM_ID; ++i)
{
if (NULL != s_nextobj[i])
{
// The IoDetachDevice routine releases an attachment between the caller's
// device object and a lower driver's device object.
// 从设备链上删除 s_nextobj[i]
// s_nextobj[i] 下层堆栈上的设备对象
IoDetachDevice (s_nextobj[i]);
}
}
interval.QuadPart = 5*1000*DELAY_ONE_MILLISECOND;
// The KeDelayExecutionThread routine puts the current thread into an alertable or
// nonalertable wait state for a specified interval.
// 延时
KeDelayExecutionThread (KernelMode, FALSE, &interval);
for (i = 0; i < CPP_MAX_COM_ID; ++i)
{
if (NULL != s_fltobj[i])
{
IoDeleteDevice (s_fltobj[i]);
}
}
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
size_t i;
#if DBG
_asm int 3;
#endif
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i)
{
driver->MajorFunction[i] = ccpDispatch;
}
driver->DriverUnload = ccpUnload ;
cppAttachAllCom (driver);
return STATUS_SUCCESS;
}