电源事件相关的IRP包括 IRP_MJ_POWER和IRP_MN_QUERY_CAPABILITIES 此处关于IRP_MN_QUERY_CAPABILITIES的使用FDO通过向底层PDO请求此IRP,会得到
DEVICE_CAPABILITIES结构体数据,此结构体会指明驱动程序支持的电源特新。
驱动代码:
///////////////////////////////////////////////////////////////////////////////
///
/// Copyright (c) 2014 -
///
/// Original filename: HelloWdm.cpp
/// Project : HelloWdm
/// Date of creation : 2014-07-02
/// Author(s) :
///
/// Purpose :
///
/// Revisions:
/// 0000 [2014-07-02] Initial revision.
///
///////////////////////////////////////////////////////////////////////////////
// $Id$
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#ifdef __cplusplus
}; // extern "C"
#endif
#include "HelloWdm.h"
static const GUID WdmHello1 = { 0xf8f8064c, 0xee05, 0x41ea, { 0x99, 0xd5, 0x55, 0x36, 0x5a, 0xb8, 0x17, 0x18 } };
// {F8F8064C-EE05-41ea-99D5-55365AB81718}
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT pFdo;
PDEVICE_OBJECT pNextStackDev;
UNICODE_STRING interfaceName;
}DEVICE_EXTENSION,*PDEVICE_EXTENSION;
#pragma code_seg("PAGE")
NTSTATUS
OnCompleteRoutine(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp,
__in PVOID Context
)
{
KdPrint(("OnCompleteRoutine Enter...."));
PKEVENT pKevent = (PKEVENT)Context;
KeSetEvent(pKevent,IO_NO_INCREMENT,FALSE);
KdPrint(("OnCompleteRoutine Leave...."));
return STATUS_MORE_PROCESSING_REQUIRED;
}
#pragma code_seg("PAGE")
NTSTATUS
ForwardAndWait(PDEVICE_EXTENSION pdx, PIRP Irp)
{
KdPrint(("ForwardAndWait Enter...."));
NTSTATUS status = STATUS_UNSUCCESSFUL;
//初始化一个事件
KEVENT kEvent;
KeInitializeEvent(&kEvent,NotificationEvent,FALSE);
//赋值irp到下层堆栈
IoCopyCurrentIrpStackLocationToNext(Irp);
//设置完成例程
IoSetCompletionRoutine(Irp,OnCompleteRoutine,&kEvent,TRUE,TRUE,TRUE);
//调用底层驱动
status = IoCallDriver(pdx->pNextStackDev,Irp);
//等待完成例程返回
KeWaitForSingleObject(&kEvent,Executive,KernelMode,FALSE,NULL);
KdPrint(("ForwardAndWait Leave...."));
return Irp->IoStatus.Status;
}
NTSTATUS HELLOWDM_DispatchCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS HELLOWDM_DispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
switch(irpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_HELLOWDM_OPERATION:
// status = SomeHandlerFunction(irpSp);
break;
default:
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
break;
}
status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
VOID HELLOWDM_DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
KdPrint(("HELLOWDM_DriverUnload...."));
}
NTSTATUS HelloWdmAddDevice(PDRIVER_OBJECT pDriverObj,PDEVICE_OBJECT pPhysicalDeviceObj)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PDEVICE_OBJECT pFdo;
status = IoCreateDevice(pDriverObj,sizeof(DEVICE_EXTENSION),NULL,FILE_DEVICE_UNKNOWN,0,FALSE,&pFdo);
if (!NT_SUCCESS(status))
{
KdPrint(("IoCreateDevice Error:0x%x",status));
return status;
}
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pFdo->DeviceExtension;
pDevExt->pFdo = pFdo;
pDevExt->pNextStackDev = IoAttachDeviceToDeviceStack(pFdo,pPhysicalDeviceObj);
if (pDevExt->pNextStackDev == NULL)
{
KdPrint(("IoAttachDeviceToDeviceStack Error:0x%x",status));
IoDeleteDevice(pFdo);
return status;
}
status = IoRegisterDeviceInterface(pPhysicalDeviceObj,&WdmHello1,NULL,&pDevExt->interfaceName);
if (!NT_SUCCESS(status))
{
KdPrint(("IoRegisterDeviceInterface Error:0x%x",status));
IoDeleteDevice(pFdo);
return status;
}
KdPrint(("%wZ
",&pDevExt->interfaceName));
status = IoSetDeviceInterfaceState(&pDevExt->interfaceName,TRUE);
if (!NT_SUCCESS(status))
{
KdPrint(("IoSetDeviceInterfaceState Error:0x%x",status));
IoDeleteDevice(pFdo);
return status;
}
//设置缓冲区方式
pFdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
pFdo->Flags &= ~DO_DEVICE_INITIALIZING;
return /*status*/STATUS_SUCCESS;
}
#pragma code_seg("PAGE")
NTSTATUS DefaultPnpHandler(PDEVICE_EXTENSION pdx,PIRP irp)
{
IoSkipCurrentIrpStackLocation(irp);
return IoCallDriver(pdx->pNextStackDev,irp);
}
#define SetMostPoweredState( SystemState, OurDeviceState)
dps = pDevCap->DeviceState[SystemState];
if( dps==PowerDeviceUnspecified || dps>OurDeviceState)
pDevCap->DeviceState[SystemState] = OurDeviceState
#pragma code_seg("PAGE")
NTSTATUS PnpQueryCapabilitiesHandler(PDEVICE_EXTENSION pdx,PIRP irp)
{
/*
电源事件相关的IRP包括 IRP_MJ_POWER和IRP_MN_QUERY_CAPABILITIES
此处关于IRP_MN_QUERY_CAPABILITIES的使用FDO通过向底层PDO请求此IRP,会得到
DEVICE_CAPABILITIES结构体数据,此结构体会指明驱动程序支持的电源特新。
*/
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = ForwardAndWait(pdx,irp);
if (NT_SUCCESS(status))
{
PIO_STACK_LOCATION pCurrStack = IoGetCurrentIrpStackLocation(irp);
PDEVICE_CAPABILITIES pDevCap = pCurrStack->Parameters.DeviceCapabilities.Capabilities;
for (int i=PowerSystemWorking;iDeviceState[i]));
}
DEVICE_POWER_STATE dps;
SetMostPoweredState(PowerSystemWorking,PowerDeviceD0);
SetMostPoweredState(PowerSystemSleeping1,PowerDeviceD3);
SetMostPoweredState(PowerSystemSleeping2,PowerDeviceD3);
SetMostPoweredState(PowerSystemSleeping3,PowerDeviceD3);
SetMostPoweredState(PowerSystemShutdown,PowerDeviceD3);
//重点
pDevCap->Removable = TRUE;//支持热插拔
//下面2项不用设置
//pDevCap->SurpriseRemovalOK = TRUE;//支持热插拔,意外拔出
//pDevCap->EjectSupported = TRUE;//支持热插拔,是否可弹出
for (int i=PowerSystemWorking;iDeviceState[i]));
}
}
irp->IoStatus.Status = status;
irp->IoStatus.Status = 0;
IoCompleteRequest(irp,IO_NO_INCREMENT);
return status;
}
#pragma code_seg("PAGE")
VOID ShowResources(PCM_PARTIAL_RESOURCE_LIST list)
{
if (list == NULL)
{
return;
}
//枚举资源
PCM_PARTIAL_RESOURCE_DESCRIPTOR pListDesc = list->PartialDescriptors;
ULONG uRes = list->Count;
ULONG i = 0;
for(int i =0;iType;
KdPrint(("ShowResources uTyep:%d
",uTyep));
switch (uTyep)
{
//物理资源
case CmResourceTypePort:
case CmResourceTypeMemory:
{
KdPrint(("start:%8X%8.8lX Length: %X
",pListDesc->u.Port.Start.HighPart,
pListDesc->u.Port.Start.HighPart,pListDesc->u.Port.Length));
}
break;
//中断
case CmResourceTypeInterrupt:
{
KdPrint(("Level:%X Vector:%X Affinity:%X
",pListDesc->u.Interrupt.Level,
pListDesc->u.Interrupt.Vector,pListDesc->u.Interrupt.Affinity));
}
break;
//DMA
case CmResourceTypeDma:
{
KdPrint(("Channel:%X,PORT:%X
",pListDesc->u.Dma.Channel,pListDesc->u.Dma.Port));
}
break;
}
}
}
#pragma code_seg("PAGE")
NTSTATUS HandleStartDevice(PDEVICE_EXTENSION pdx,PIRP irp)
{
KdPrint(("HandleStartDevice Enter...."));
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = ForwardAndWait(pdx,irp);
if (!NT_SUCCESS(status))//非成功的情况下,直接完成IRP
{
irp->IoStatus.Status = status;
IoCompleteRequest(irp,IO_NO_INCREMENT);
return status;
}
PIO_STACK_LOCATION pCurrStack = IoGetCurrentIrpStackLocation(irp);
//从当前栈获取源信息
PCM_PARTIAL_RESOURCE_LIST raw;
if (pCurrStack->Parameters.StartDevice.AllocatedResources)
{
raw = &pCurrStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
}else
{
raw = NULL;
}
//显示PCI资源
ShowResources(raw);
//从当前栈获取翻译信息
PCM_PARTIAL_RESOURCE_LIST tranlated;
if (pCurrStack->Parameters.StartDevice.AllocatedResourcesTranslated)
{
tranlated = &pCurrStack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
}else
{
tranlated = NULL;
}
//显示PCI资源
ShowResources(tranlated);
irp->IoStatus.Status = status;
IoCompleteRequest(irp,IO_NO_INCREMENT);
//因为完成例程返回STATUS_MORE_PROCEING_REQUIRED,需要再次完成IRP
KdPrint(("HandleStartDevice Leave...."));
return status;
}
#pragma code_seg("PAGE")
NTSTATUS HandleRemoveDevice(PDEVICE_EXTENSION pdx,PIRP irp)
{
KdPrint(("HandleRemoveDevice enter"));
NTSTATUS status = STATUS_UNSUCCESSFUL;
irp->IoStatus.Status = STATUS_SUCCESS;
status = DefaultPnpHandler(pdx,irp);
IoSetDeviceInterfaceState(&pdx->interfaceName,FALSE);
RtlFreeUnicodeString(&pdx->interfaceName);
//把FDO从设备栈脱开
if (pdx->pNextStackDev)
{
IoDetachDevice(pdx->pNextStackDev);
}
//删除FDO
IoDeleteDevice(pdx->pFdo);
KdPrint(("HandleRemoveDevice leave"));
return status;
}
#define arraySize(p) (sizeof(p)/sizeof(p[0]))
NTSTATUS HelloWdmPnp(PDEVICE_OBJECT pDeviceObj,PIRP pIrp)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PAGED_CODE();//Checked模式下有效,确保运行在irql足够低,允许分页的级别
KdPrint(("HelloWdmPnp Enter..."));
//获得设备扩展
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;
//获得当前IO栈
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
static NTSTATUS (*FunTab[])(PDEVICE_EXTENSION ,PIRP ) = {
HandleStartDevice, // IRP_MN_START_DEVICE
DefaultPnpHandler, // IRP_MN_QUERY_REMOVE_DEVICE
HandleRemoveDevice, // IRP_MN_REMOVE_DEVICE
DefaultPnpHandler, // IRP_MN_CANCEL_REMOVE_DEVICE
DefaultPnpHandler, // IRP_MN_STOP_DEVICE
DefaultPnpHandler, // IRP_MN_QUERY_STOP_DEVICE
DefaultPnpHandler, // IRP_MN_CANCEL_STOP_DEVICE
DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_RELATIONS
DefaultPnpHandler, // IRP_MN_QUERY_INTERFACE
PnpQueryCapabilitiesHandler, // IRP_MN_QUERY_CAPABILITIES
DefaultPnpHandler, // IRP_MN_QUERY_RESOURCES
DefaultPnpHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_TEXT
DefaultPnpHandler, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
DefaultPnpHandler, //
DefaultPnpHandler, // IRP_MN_READ_CONFIG
DefaultPnpHandler, // IRP_MN_WRITE_CONFIG
DefaultPnpHandler, // IRP_MN_EJECT
DefaultPnpHandler, // IRP_MN_SET_LOCK
DefaultPnpHandler, // IRP_MN_QUERY_ID
DefaultPnpHandler, // IRP_MN_QUERY_PNP_DEVICE_STATE
DefaultPnpHandler, // IRP_MN_QUERY_BUS_INFORMATION
DefaultPnpHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION
DefaultPnpHandler, // IRP_MN_SURPRISE_REMOVAL
};
ULONG uFunc = pStack->MinorFunction;
if (uFunc >= arraySize(FunTab))
{
status = DefaultPnpHandler(pDevExt,pIrp);
return status;
}
static char* fcnname[] =
{
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
};
KdPrint(("PNP Request uFunc:%d (%s)
",uFunc, fcnname[uFunc]));
status = (*FunTab[uFunc])(pDevExt,pIrp);
KdPrint(("HelloWdmPnp leave..."));
return status;
}
#ifdef __cplusplus
extern "C" {
#endif
NTSTATUS DriverEntry(
IN OUT PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
KdPrint(("DriverEntry enter...."));
DriverObject->DriverExtension->AddDevice = HelloWdmAddDevice;
DriverObject->MajorFunction[IRP_MJ_PNP] = HelloWdmPnp;
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = HELLOWDM_DispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HELLOWDM_DispatchDeviceControl;
DriverObject->DriverUnload = HELLOWDM_DriverUnload;
KdPrint(("DriverEntry leave...."));
return STATUS_SUCCESS;
}
#ifdef __cplusplus
}; // extern "C"
#endif
INF文件:
;--------- Version Section ---------------------------------------------------
[Version]
Signature="$CHICAGO$";
Provider=WorldWang_Device
DriverVer=11/1/2007,3.0.0.3
; If device fits one of the standard classes, use the name and GUID here,
; otherwise create your own device class and GUID as this example shows.
Class=WorldWangDevice
ClassGUID={F8F8064C-EE05-41ea-99D5-55365AB81718}
;--------- SourceDiskNames and SourceDiskFiles Section -----------------------
; These sections identify source disks and files for installation. They are
; shown here as an example, but commented out.
[SourceDisksNames]
1 = "HelloWdm",Disk1,,
[SourceDisksFiles]
HelloWdm.sys = 1, ,
;--------- ClassInstall/ClassInstall32 Section -------------------------------
; Not necessary if using a standard class
; 9X Style
[ClassInstall]
Addreg=Class_AddReg
; NT Style
[ClassInstall32]
Addreg=Class_AddReg
[Class_AddReg]
HKR,,,,%DeviceClassName%
HKR,,Icon,,"-5"
;--------- DestinationDirs Section -------------------------------------------
[DestinationDirs]
YouMark_Files_Driver = 10,System32Drivers
;--------- Manufacturer and Models Sections ----------------------------------
[Manufacturer]
%MfgName%=Mfg0
[Mfg0]
; PCI hardware Ids use the form
; PCIVEN_aaaa&DEV_bbbb&SUBSYS_cccccccc&REV_dd
;PCIVEN_9999&DEV_9999
;PCIVEN_8086&DEV_7111
;修改要挂载的设备的vendorId和productID
%DeviceDesc%=YouMark_DDI, PCIVEN_9999&DEV_9999
;---------- DDInstall Sections -----------------------------------------------
; --------- Windows 9X -----------------
; Experimentation has shown that DDInstall root names greater than 19 characters
; cause problems in Windows 98
[YouMark_DDI]
CopyFiles=YouMark_Files_Driver
AddReg=YouMark_9X_AddReg
[YouMark_9X_AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,HelloWdm.sys
HKR, "Parameters", "BreakOnEntry", 0x00010001, 0
; --------- Windows NT -----------------
[YouMark_DDI.NT]
CopyFiles=YouMark_Files_Driver
AddReg=YouMark_NT_AddReg
[YouMark_DDI.NT.Services]
Addservice = HelloWdm, 0x00000002, YouMark_AddService
[YouMark_AddService]
DisplayName = %SvcDesc%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %10%System32DriversHelloWdm.sys
[YouMark_NT_AddReg]
HKLM, "SystemCurrentControlSetServicesHelloWdmParameters",
"BreakOnEntry", 0x00010001, 0
; --------- Files (common) -------------
[YouMark_Files_Driver]
HelloWdm.sys
;--------- Strings Section ---------------------------------------------------
[Strings]
ProviderName="WorldWang."
MfgName="WorldWang Soft"
DeviceDesc="Hello World WDM!"
DeviceClassName="WorldWang_Device"
SvcDesc="WorldWang"