📄 drvpnp.c
字号:
* Return Value : NTSTATUS value from the IoCallDriver() call.
* Description : 产生一个内部的IRP来获得设备性能信息,主要是获取
* 设备电源状态信息
*************************************************************************************************/
NTSTATUS hwQueryCapabilities
(
IN PDEVICE_OBJECT LowerDeviceObject,
IN PDEVICE_CAPABILITIES DeviceCapabilities
)
{
PIO_STACK_LOCATION nextStack;
PIRP irp;
NTSTATUS ntStatus;
KEVENT event;
hwDbgPrint ( " -->>>>>> hwQueryCapabilities()\n" );
hwDbgPrint ( "LowerDeviceObject = 0x%x \n",LowerDeviceObject );
hwDbgPrint ( "DeviceCapabilities = 0x%x \n",DeviceCapabilities );
// 这是DDK定义的调试版本的宏,IRQL高于APC_LEVEL时我们的可分页代码
// 将不会被运行
PAGED_CODE();
// 构造一个IRP用来产生内部对PDO的查询请求
irp = IoAllocateIrp(LowerDeviceObject->StackSize, FALSE);
if (!irp)
{
// 资源不够
return STATUS_INSUFFICIENT_RESOURCES;
}
// Preinit the device capability structures appropriately.
RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
DeviceCapabilities->Version = 1;
DeviceCapabilities->Address = -1;
DeviceCapabilities->UINumber = -1;
// IoGetNextIrpStackLocation()获取一个高层驱动在一个IRP里访问下层驱动
// 的I/O栈位置
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->MajorFunction= IRP_MJ_PNP; // 主功能代码
nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES; // 次功能代码
// 初始化一个完成例程将要使用的事件,这个事件将告诉我们
// 下层驱动处理我们的irp已经完成了。
KeInitializeEvent(&event, NotificationEvent, FALSE);
// 设置一个完成例程
IoSetCompletionRoutine(irp,
hwIRPCompletionRoutine,
&event, // pass the event as Context to completion routine
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
// 在下层驱动I/O栈位置的参数中填好我们的DEVICE_CAPABILITIES结构体
// 指针
nextStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
// 事先调整irp为不支持的状态
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
// 将irp提交给下层驱动
ntStatus = IoCallDriver(LowerDeviceObject,irp);
hwDbgPrint(" ntStatus returned by IoCallDriver 0x%x\n", ntStatus);
if (ntStatus == STATUS_PENDING)
{
// 等待irp处理完成
KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
ntStatus = irp->IoStatus.Status;
}
// failed? this is probably a bug
hwDbgPrint("hwQueryCapabilities() %s -->>>>>>\n",NT_SUCCESS(ntStatus)?"success":"falied");
// 释放前面申请的irp
IoFreeIrp(irp);
return ntStatus;
}
/************************************************************************************************
* Function Type : global
* Parameter : DriverObject - pointer to the driver object for device
* pdo - pointer to a device object created by the bus
* 指向设备堆栈底部的物理设备对象。
* Return Value : STATUS_SUCCESS - if successful,
* STATUS_UNSUCCESSFUL - otherwise
* Description : This routine is called to create and initialize our Functional Device Object (FDO).
* For monolithic drivers, this is done in DriverEntry(), but Plug and Play devices
* wait for a PnP event
*Note : 1、创建功能设备对象(FDO)、符号连接
* 2、设置IO读写方式为直接IO
* 3、将FDO与PDO挂钩
* 4、查询设备性能,设置好最低的电源状态
* 5、将设备挂起
*************************************************************************************************/
NTSTATUS zjHMCFUsb_AddDevice
(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT pdo
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT fdo = NULL;
PDEVICE_EXTENSION dx;
USBD_VERSION_INFORMATION versionInformation;
ULONG i;
NTSTATUS actStat;
UNICODE_STRING deviceLinkUnicodeString;
hwDbgPrint(" -->>>>>> zjHMCFUsb_AddDevice(DriverObject=0x%x,pdo=0x%s)\n",
DriverObject,pdo);
PrintCurIrql();
// 创建功能设备对象(FDO)
ntStatus = hwCreateDeviceObject ( DriverObject, pdo, &fdo );
if (!NT_SUCCESS(ntStatus))
{
hwDbgPrint ( "Create device object failed!\n");
goto done;
}
dx = fdo->DeviceExtension;
// 注册一个符号连接供应用程序使用打开该设备时使用
ntStatus = hwRegisterSymbolicLink( pdo, fdo, &deviceLinkUnicodeString );
if ( NT_SUCCESS(ntStatus) )
{
hwDbgPrint("Create GUID_CLASS_zjHMCFUsb_BULK-based Device name success\n" );
}
else
{
hwDbgPrint("Create GUID_CLASS_zjHMCFUsb_BULK-based Device name failed\n" );
goto done;
}
// 设置IO读写方式为直接IO或缓冲IO
#ifdef _BUFFERED_IO
fdo->Flags |= DO_BUFFERED_IO;
#else
fdo->Flags |= DO_DIRECT_IO;
#endif
// 设置这个标志以使驱动在设备挂起的时候不会收到
// IRP_MN_STOP_DEVICE,在设备恢复使用的时候不会收到
// IRP_MN_START_DEVICE,这个标志必须设置,因为在启动设备时
// 调用GetDescriptors()从USB栈中获取描述信息将会失败。
fdo->Flags |= DO_POWER_PAGABLE;
// 保存物理设备对象到设备扩展结构体中
dx->pdo = pdo;
// 保存功能设备对象到设备扩展结构体中
dx->fdo = fdo;
//将FDO与PDO挂钩,并获取设备对象堆栈顶端DO保存起来,
//它将是我们的FDO的直接下属
dx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo);
hwDbgPrint ( "LowerDeviceObject = 0x%x,fdo=0x%x,pdo=0x%x\n",
dx->LowerDeviceObject,fdo,pdo );
// 将物理设备的性能拷贝一份到我们的设备扩展的DEVICE_CAPABILITIES
// 结构体中,我们感兴趣的是哪一种系统电源状态被映射到哪一种
// 设备电源状态来处理IRP_MJ_SET_POWER IRPs
hwQueryCapabilities(dx->LowerDeviceObject,&dx->DeviceCapabilities);
// 我们要确定一下自动关闭电源的标准。最低的睡眠标准小于D3
// 如果所有的被设置到D3,驱动关闭/开启电源的功能将被禁用
dx->PowerDownLevel = PowerDeviceUnspecified; // 初始化为禁用
for (i=PowerSystemSleeping1; i<= PowerSystemSleeping3; i++)
{
if ( dx->DeviceCapabilities.DeviceState[i] < PowerDeviceD3 )
dx->PowerDownLevel = dx->DeviceCapabilities.DeviceState[i];
}
// 我们首先让正在处理的IO计数(dx->PendingIoCount)加1,这个1表示
// 我们增加了一个设备。以后每新收到1个irp就加1,irp处理完
// 后就减1
// 如果IO计数是1则表示没有正在处理的IO并且dx->NoPendingIoEvent
// 被置信号,在处理IRP_MN_QUERY_REMOVE_DEVICE的时候这是必须的。
// 当处理IRP_MN_REMOVE_DEVICE时这个IO计数将减到0,并且dx->RemoveEvent
// 被置为有信号,表明设备可以被移除
hwIncrementIoCount(fdo);
// 获取控制客户USB设备的HCD(host controller driver)的版本信息
USBD_GetUSBDIVersion(&versionInformation);
hwDbgPrint( "USB Version : 0x%x - 0x%x\n",
versionInformation.USBDI_Version, versionInformation.Supported_USB_Version);
// 先将电源关闭直到有实际的IO请求
actStat = hwSelfSuspendOrActivate( fdo, TRUE );
// 当这个标志设置时,I/O管理器将拒绝任何打开该设备句柄
// 的请求或向该设备对象上附着其它设备对象的请求
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
done:
//free buffer from unicode string we used to init interface
RtlFreeUnicodeString( &deviceLinkUnicodeString );
hwDbgPrint("zjHMCFUsb_AddDevice() (%x) -->>>>>\n", ntStatus);
if ( !NT_SUCCESS( ntStatus ) )
ntStatus = STATUS_DEVICE_REMOVED;
return ntStatus;
}
/************************************************************************************************
* Function Type : global
* Parameter : fdo - pointer to our FDO (Functional Device Object )
* IRP - pointer to an I/O Request Packet
* Return Value : Status returned from lower driver
* Description : Dispatch table routine for IRP_MJ_PNP.
* Process the Plug and Play IRPs sent to this device.
*************************************************************************************************/
NTSTATUS zjHMCFUsb_PNP(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION dx;
NTSTATUS ntStatus = STATUS_SUCCESS;
// 获取当前IRP位置,以从中取得功能代码和参数
irpStack = IoGetCurrentIrpStackLocation (Irp);
// Get a pointer to the device extension
dx = fdo->DeviceExtension;
hwDbgPrint(" -->>>>>> zjHMCFUsb_PNP() IRP_MJ_PNP\n" );
PrintCurIrql();
// 增加正在处理的IO数量
hwIncrementIoCount(fdo);
hwASSERT( IRP_MJ_PNP == irpStack->MajorFunction );
switch (irpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
hwDbgPrint ( "IRP_MN_START_DEVICE\n");
hwStartDevice( fdo , Irp ,&ntStatus);
return ntStatus;
case IRP_MN_QUERY_STOP_DEVICE:
hwDbgPrint ( "IRP_MN_QUERY_STOP_DEVICE\n");
if ( hwQueryStopDevice ( fdo , Irp ,&ntStatus) )
return ntStatus;
break;
case IRP_MN_CANCEL_STOP_DEVICE:
hwDbgPrint ( "IRP_MN_CANCEL_STOP_DEVICE\n");
if ( hwCancelStopDevice ( fdo , Irp ,&ntStatus) )
return ntStatus;
break;
case IRP_MN_STOP_DEVICE:
hwDbgPrint ( "IRP_MN_STOP_DEVICE\n");
ntStatus = hwStopDevice(fdo);
Irp->IoStatus.Status = ntStatus;
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
hwDbgPrint ( "IRP_MN_QUERY_REMOVE_DEVICE\n");
if ( hwQueryRemoveDevice ( fdo , Irp ,&ntStatus) )
return ntStatus;
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
hwDbgPrint ( "IRP_MN_QUERY_REMOVE_DEVICE\n");
if ( hwCancelRemoveDevice ( fdo , Irp ,&ntStatus) )
return ntStatus;
break;
case IRP_MN_SURPRISE_REMOVAL:
hwDbgPrint("IRP_MN_SURPRISE_REMOVAL\n");
hwSurpriseRemovalDevice ( fdo , Irp ,&ntStatus);
return ntStatus;
case IRP_MN_REMOVE_DEVICE:
hwDbgPrint("IRP_MN_REMOVE_DEVICE\n");
hwRemoveDevice( fdo , Irp ,&ntStatus);
return ntStatus;
default:
hwDbgPrint("IRP_MJ_PNP Minor PnP IOCTL not handled!!!\n");
} /* case MinorFunction */
if (!NT_SUCCESS(ntStatus))
{
// 如果产生错误就不用将IRP下传了,直接返回失败
ntStatus = CompleteIrp( Irp, ntStatus,0,IO_NO_INCREMENT);
hwDecrementIoCount(fdo);
hwDbgPrint("zjHMCFUsb_PNP() Exit zjHMCFUsb_PNP FAILURE %x\n", ntStatus);
return ntStatus;
}
IoCopyCurrentIrpStackLocationToNext(Irp);
hwDbgPrint("zjHMCFUsb_PNP() Passing PnP Irp down, status = %x\n", ntStatus);
ntStatus = IoCallDriver(dx->LowerDeviceObject, Irp);
hwDecrementIoCount(fdo);
hwDbgPrint("zjHMCFUsb_PNP(ntStatus = 0x%x) -->>>>>>\n", ntStatus);
return ntStatus;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -