今天下雨,在下的时候,赶紧回来!还好呵呵,还是有点忙!又是加班的一天。
今天介绍下Windows驱动中资源,资源就是硬件需要用的,我们知道,所有的这些资源,我们都是在ACPI的DSDT中分配的,包含IO地址,内存地址,中断号等等。硬件抽象层会根据我们所配置的资源,根据不同的芯片,来给我们外围的芯片分配这些资源。那么我们一般在驱动哪里接受这些资源呢?
我们知道,在WDM中,接收IRP_MN_START_DEVICE的IRP的函数中,会得到系统分配的资源。例如如下的函数:
NTSTATUS StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)
这里面最重要的就是这个PCM_PARTIAL_RESOURCE_LIST,MSDN中给出了其定义:
typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR {
UCHAR Type;
UCHAR ShareDisposition;
USHORT Flags;
union {
struct {
PHYSICAL_ADDRESS Start;
ULONG Length;
} Generic;
struct {
PHYSICAL_ADDRESS Start;
ULONG Length;
} Port;
struct {
#if defined(NT_PROCESSOR_GROUPS)
USHORT Level;
USHORT Group;
#else
ULONG Level;
#endif
ULONG Vector;
KAFFINITY Affinity;
} Interrupt;
// This member exists only on Windows Vista and later
struct {
union {
struct {
#if defined(NT_PROCESSOR_GROUPS)
USHORT Group;
#else
USHORT Reserved;
#endif
USHORT MessageCount;
ULONG Vector;
KAFFINITY Affinity;
} Raw;
struct {
#if defined(NT_PROCESSOR_GROUPS)
USHORT Level;
USHORT Group;
#else
ULONG Level;
#endif
ULONG Vector;
KAFFINITY Affinity;
} Translated;
};
} MessageInterrupt;
struct {
PHYSICAL_ADDRESS Start;
ULONG Length;
} Memory;
struct {
ULONG Channel;
ULONG Port;
ULONG Reserved1;
} Dma;
struct {
ULONG Channel;
ULONG RequestLine;
UCHAR TransferWidth;
UCHAR Reserved1;
UCHAR Reserved2;
UCHAR Reserved3;
} DmaV3;
struct {
ULONG Data[3];
} DevicePrivate;
struct {
ULONG Start;
ULONG Length;
ULONG Reserved;
} BusNumber;
struct {
ULONG DataSize;
ULONG Reserved1;
ULONG Reserved2;
} DeviceSpecificData;
// The following structures provide support for memory-mapped
// IO resources greater than MAXULONG
struct {
PHYSICAL_ADDRESS Start;
ULONG Length40;
} Memory40;
struct {
PHYSICAL_ADDRESS Start;
ULONG Length48;
} Memory48;
struct {
PHYSICAL_ADDRESS Start;
ULONG Length64;
} Memory64;
struct {
UCHAR Class;
UCHAR Type;
UCHAR Reserved1;
UCHAR Reserved2;
ULONG IdLowPart;
ULONG IdHighPart;
} Connection;
} u;
} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR;
暂且不去理会这个结构体的成员,MSDN中有详细的说明。我们看WDF中如何接收资源的。在WDF中,一般我们会在创建设备对象的函数,来初始化这个函数指针。这个指针在哪里了?在WDF_PNPPOWER_EVENT_CALLBACKS的结构中,MSDN中就给出这个结构体的说明:
typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS {
ULONG Size;
PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry;
PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled;
PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit;
PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED
EvtDeviceD0ExitPreInterruptsDisabled;
PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware;
PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware;
PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup;
PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush;
PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit;
PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend;
PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart;
PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval;
PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove;
PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop;
PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification;
PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery;
} WDF_PNPPOWER_EVENT_CALLBACKS, *PWDF_PNPPOWER_EVENT_CALLBACKS;
EvtDevicePrepareHardware就是这个函数指针。在WDF中,例如: NTSTATUS MarsEvtDevicePrepareHardware(WDFDEVICE Device,WDFCMRESLIST Resources,WDFCMRESLIST ResourcesTranslated) 接收到资源后,下一步就是取出来,一般来说,就是两个函数:WdfCmResourceListGetCount和WdfCmResourceListGetDescriptor。如果我们的设备是挂在某个总线上的,我们在ACPI中配置了总线的地址,我们在这里就可以得到通向总线的一个链接名,我们通过这个链接名就可以跟总线进行通讯,读或写等,这个详细的说明,我们放在WDFIOTARGET中详细说明。如果分配了内存,我们首先就需要调用MmMapIoSpace进行映射,才可以操作这段内存。中断都不用进行特殊的处理,因为我们会在之前就创建中断对象,这里我们只需要将中断的引用加1就可以。