5871 lines
179 KiB
C
5871 lines
179 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
assign.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
IoAssignResources
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Ken Reneris
|
|||
|
|
|||
|
Environment:
|
|||
|
EDIT IN 110 COLUMN MODE
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Add PnP support - shielint
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "iop.h"
|
|||
|
|
|||
|
#define IDBG DBG
|
|||
|
#define PAGED 1
|
|||
|
#define INLINE __inline
|
|||
|
#define STATIC static
|
|||
|
|
|||
|
//#define IDBG 1
|
|||
|
//#define DBG 1
|
|||
|
//#define PAGED
|
|||
|
//#define INLINE
|
|||
|
//#define STATIC
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* IDBG - Internal debugging. Turn on for runtime DbgPrints of calls to IoAssignResources
|
|||
|
* PAGED - Declare functions as pageable or not. (usefull for debugging)
|
|||
|
* INLINE - Inline functions
|
|||
|
* STATIC - internal functions to this module which are static
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
extern WCHAR IopWstrOtherDrivers[];
|
|||
|
extern WCHAR IopWstrAssignedResources[];
|
|||
|
extern WCHAR IopWstrRequestedResources[];
|
|||
|
extern WCHAR IopWstrSystemResources[];
|
|||
|
extern WCHAR IopWstrReservedResources[];
|
|||
|
extern WCHAR IopWstrAssignmentOrdering[];
|
|||
|
extern WCHAR IopWstrBusValues[];
|
|||
|
extern WCHAR IopWstrTranslated[];
|
|||
|
extern WCHAR IopWstrBusTranslated[];
|
|||
|
|
|||
|
#define HRESOURCE_MAP 0
|
|||
|
#define HDEVICE_STORAGE 1
|
|||
|
#define HCURRENT_CONTROL_SET 2
|
|||
|
#define HSYSTEMRESOURCES 3
|
|||
|
#define HORDERING 4
|
|||
|
#define HRESERVEDRESOURCES 5
|
|||
|
#define HBUSVALUES 6
|
|||
|
#define HOWNER_MAP 7
|
|||
|
#define MAX_REG_HANDLES 8
|
|||
|
|
|||
|
#define INVALID_HANDLE (HANDLE) -1
|
|||
|
|
|||
|
#define BUFFERSIZE (2048 + sizeof( KEY_FULL_INFORMATION ))
|
|||
|
#define MAX_ENTRIES 50
|
|||
|
#define SCONFLICT 5
|
|||
|
|
|||
|
//
|
|||
|
// Wrapper structures around IO_RESOURCE lists
|
|||
|
//
|
|||
|
|
|||
|
// owner of TENTRY
|
|||
|
typedef struct {
|
|||
|
LIST_ENTRY InConflict;
|
|||
|
UNICODE_STRING KeyName;
|
|||
|
UNICODE_STRING DeviceName;
|
|||
|
WCHAR UnicodeBuffer[1]; // Must be last!
|
|||
|
} *POWNER;
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
struct _RECONFIGURED_DRIVER;
|
|||
|
|
|||
|
//
|
|||
|
// Flags for TENTRY
|
|||
|
//
|
|||
|
|
|||
|
#define TENTRY_FLAGS_IN_USE 0
|
|||
|
#define TENTRY_FLAGS_BEING_RELOCATED 1
|
|||
|
#define TENTRY_FLAGS_REMOVED 2
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
// translated entry
|
|||
|
typedef struct {
|
|||
|
LONGLONG BAddr; // Beginning address
|
|||
|
LONGLONG EAddr; // Ending address
|
|||
|
KAFFINITY Affinity; // Processor affinity of resource
|
|||
|
POWNER Owner; // Owner of this resource
|
|||
|
#if _PNP_POWER_
|
|||
|
UCHAR Flags; // Flags of this entry
|
|||
|
#else
|
|||
|
#if IDBG
|
|||
|
ULONG na[2];
|
|||
|
#endif
|
|||
|
#endif // _PNP_POWER_
|
|||
|
} TENTRY, *PTENTRY; // Translated resource
|
|||
|
|
|||
|
#define DoesTEntryCollide(a,b) \
|
|||
|
( (a).EAddr >= (b).BAddr && (a).BAddr <= (b).EAddr && ((a).Affinity & (b).Affinity) )
|
|||
|
|
|||
|
|
|||
|
// list of translated entries
|
|||
|
typedef struct _LTENTRY {
|
|||
|
struct _LTENTRY *Next; // Allocated table size
|
|||
|
ULONG CurEntries; // No entries in table
|
|||
|
ULONG na[2];
|
|||
|
TENTRY Table[MAX_ENTRIES];
|
|||
|
} LTENTRY, *PLTENTRY; // List of translated resources
|
|||
|
|
|||
|
// list of translated entries by CmResourceType
|
|||
|
typedef struct {
|
|||
|
PLTENTRY ByType[CmResourceTypeMaximum];
|
|||
|
} TENTRIESBYTYPE, *PTENTRIESBYTYPE;
|
|||
|
|
|||
|
// information about conflict
|
|||
|
typedef struct {
|
|||
|
ULONG NoConflicts; // # of BAddrs
|
|||
|
struct {
|
|||
|
UCHAR Type;
|
|||
|
LONGLONG BAddr;
|
|||
|
POWNER Owner;
|
|||
|
} EasyConflict[SCONFLICT];
|
|||
|
|
|||
|
LIST_ENTRY OtherConflicts;
|
|||
|
} IO_TRACK_CONFLICT, *PIO_TRACK_CONFLICT;
|
|||
|
|
|||
|
// a required resource with it's alternatives
|
|||
|
typedef struct {
|
|||
|
// work in progress...
|
|||
|
ULONG CurLoc; // Which IoResourceDescriptor
|
|||
|
ULONG RunLen; // length of alternative run
|
|||
|
ULONG PassNo;
|
|||
|
|
|||
|
// current bus specific ordering location
|
|||
|
ULONG CurBusLoc; // Current Bus descriptor location
|
|||
|
LONGLONG CurBusMin; // Current bus desc min
|
|||
|
LONGLONG CurBusMax; // Current bus desc max
|
|||
|
|
|||
|
// raw selection being considered...
|
|||
|
UCHAR Type; // type of descriptor
|
|||
|
ULONG CurBLoc;
|
|||
|
LONGLONG CurBAddr; // bus native BAddr
|
|||
|
|
|||
|
// the raw selection's translation
|
|||
|
UCHAR TType; // Translated type
|
|||
|
TENTRY Trans; // Translated info
|
|||
|
|
|||
|
LONG BestPref; // only has meaning on first pass
|
|||
|
LONG CurPref; // Prefernce of current selection
|
|||
|
|
|||
|
// Phase 3
|
|||
|
ULONG PrefCnt; // # of times this level skipped
|
|||
|
ULONG Pass2HoldCurLoc; // CurBLoc of best selection so far
|
|||
|
LONGLONG Pass2HoldBAddr; // CurBAddr of best selection so far
|
|||
|
|
|||
|
// resource options
|
|||
|
ULONG NoAlternatives; // entries in IoResourceDescriptor
|
|||
|
PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor[1]; // MUST BE LAST ENTRY
|
|||
|
} DIR_REQUIRED_RESOURCE, *PDIR_REQUIRED_RESOURCE;
|
|||
|
|
|||
|
// a list of required resources for the alternative list
|
|||
|
typedef struct _DIR_RESOURCE_LIST {
|
|||
|
struct _DIR_RESOURCE_LIST *Next; // next alternative list
|
|||
|
PDIR_REQUIRED_RESOURCE ResourceByType[CmResourceTypeMaximum]; // catagorized list
|
|||
|
LONG CurPref;
|
|||
|
ULONG LastLevel; // last level tried
|
|||
|
ULONG FailedLevel; // which level had conflict
|
|||
|
IO_TRACK_CONFLICT Conflict; // pass3
|
|||
|
PIO_RESOURCE_LIST IoResourceList; // this IO_RESOURCE_LIST
|
|||
|
ULONG NoRequiredResources; // entries in RequiredResource
|
|||
|
PDIR_REQUIRED_RESOURCE RequiredResource[1]; // MUST BE LAST ENTRY
|
|||
|
} DIR_RESOURCE_LIST, *PDIR_RESOURCE_LIST;
|
|||
|
|
|||
|
// top level structure
|
|||
|
typedef struct _DIR_RESREQ_LIST {
|
|||
|
HANDLE RegHandle[MAX_REG_HANDLES]; // handles to different registry locations
|
|||
|
struct _DIR_RESREQ_LIST *UserDir;
|
|||
|
struct _DIR_RESREQ_LIST *BusDir;
|
|||
|
struct _DIR_RESREQ_LIST *FreeResReqList; // other DIR_RESREQ_LIST which need freed
|
|||
|
SINGLE_LIST_ENTRY AllocatedHeap; // heap which needs freed
|
|||
|
TENTRIESBYTYPE InUseResources;
|
|||
|
TENTRIESBYTYPE InUseSharableResources;
|
|||
|
TENTRIESBYTYPE ReservedSharableResources;
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST IoResourceReq; // this IO_RESOURCES_REQUIREMENTS_LIST
|
|||
|
PDIR_RESOURCE_LIST Alternative; // list of alternatives
|
|||
|
PWCHAR Buffer; // Scratch memory
|
|||
|
#if _PNP_POWER_
|
|||
|
PDIR_RESOURCE_LIST ListPicked; // Resources assigned list
|
|||
|
struct _RECONFIGURED_DRIVER *ReconfiguredDriver;
|
|||
|
#endif
|
|||
|
} DIR_RESREQ_LIST, *PDIR_RESREQ_LIST;
|
|||
|
|
|||
|
// a list of heap which was allocated
|
|||
|
typedef struct {
|
|||
|
SINGLE_LIST_ENTRY FreeLink; // List of heap to free
|
|||
|
PVOID FreeHeap; // pointer to heap to free
|
|||
|
} USED_HEAP, *PUSED_HEAP;
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
//
|
|||
|
// IopRelocatedDirList - List of all the DIRs which were created to resolve conflicts.
|
|||
|
//
|
|||
|
|
|||
|
PDIR_RESREQ_LIST IopRelocatedDirList = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Information about conflict used by conflict relocator
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _RELOCATED_TENTRIES{
|
|||
|
struct _RELOCATED_TENTRIES *Next;
|
|||
|
UCHAR Type; // Type of the TENTRY
|
|||
|
PTENTRY TranslatedEntry; // Pointer to the TENTRY
|
|||
|
UNICODE_STRING OriginalDriver; // The names of the original
|
|||
|
UNICODE_STRING OriginalDevice; // owner. So we can restore then
|
|||
|
// if necessary.
|
|||
|
} RELOCATED_TENTRIES, *PRELOCATED_TENTRIES;
|
|||
|
|
|||
|
//
|
|||
|
// IopInProcessedConflicts - list of all the conflict translated
|
|||
|
// entries under processed.
|
|||
|
//
|
|||
|
|
|||
|
PRELOCATED_TENTRIES IopInProcessedConflicts = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// IopNewResources - list of all the new translated entries
|
|||
|
// allocated by the reconfigured drivers.
|
|||
|
//
|
|||
|
|
|||
|
PRELOCATED_TENTRIES IopNewResources = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Information about driver/device to be reconfigured.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _RECONFIGURED_DRIVER {
|
|||
|
struct _RECONFIGURED_DRIVER *Next;
|
|||
|
POWNER Owner; // Owner of this structure
|
|||
|
struct _DIR_RESREQ_LIST *ReconfiguredDir; // pointer to DIR_RESREQ_LIST
|
|||
|
PCM_RESOURCE_LIST CmResourceList; // Cm res list of the driver/device
|
|||
|
ULONG ResourceLength; // The length of the CM resource list
|
|||
|
UNICODE_STRING DriverClassName; // Required by ReportResourceUsage
|
|||
|
PDRIVER_OBJECT DriverObject; // pointer to the dev obj of the driver
|
|||
|
PDEVICE_OBJECT DeviceObject; // Not NULL if resource is device specific
|
|||
|
PFILE_OBJECT DeviceFileObject; // redundant??
|
|||
|
} RECONFIGURED_DRIVER, *PRECONFIGURED_DRIVER;
|
|||
|
|
|||
|
PRECONFIGURED_DRIVER IopReconfiguredDrivers;
|
|||
|
|
|||
|
//
|
|||
|
// Information to help reconstruct DIR_REQUIRED_LIST
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _REG_REQUIRED_RESOURCE {
|
|||
|
|
|||
|
//
|
|||
|
// raw selection
|
|||
|
//
|
|||
|
UCHAR Type; // type of descriptor
|
|||
|
ULONG CurBLoc;
|
|||
|
LONGLONG CurBAddr; // bus native BAddr
|
|||
|
|
|||
|
//
|
|||
|
// the raw selection's translation
|
|||
|
//
|
|||
|
UCHAR TType; // Translated type
|
|||
|
TENTRY Trans; // Translated info
|
|||
|
} REG_REQUIRED_RESOURCE, *PREG_REQUIRED_RESOURCE;
|
|||
|
|
|||
|
typedef struct _REG_REQUIRED_RESOURCE_LIST {
|
|||
|
ULONG NoRequiredResources;
|
|||
|
REG_REQUIRED_RESOURCE RegResource[1]; // Must be last entry
|
|||
|
} REG_REQUIRED_RESOURCE_LIST, *PREG_REQUIRED_RESOURCE_LIST;
|
|||
|
#endif // _PNP_POWER
|
|||
|
|
|||
|
//
|
|||
|
// Internal prototypes
|
|||
|
//
|
|||
|
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST
|
|||
|
IopGetResourceReqRegistryValue (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PWSTR ValueName
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopAssignResourcesPhase1 (
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST *CopiedList
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopAssignResourcesPhase2 (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PUNICODE_STRING DriverClassName,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
);
|
|||
|
|
|||
|
PDIR_RESOURCE_LIST
|
|||
|
IopAssignResourcesPhase3 (
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
);
|
|||
|
|
|||
|
PCM_RESOURCE_LIST
|
|||
|
IopAssignResourcesPhase4 (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
OUT PULONG Length
|
|||
|
);
|
|||
|
|
|||
|
STATIC VOID
|
|||
|
IopLogConflict (
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN NTSTATUS FinalStatus
|
|||
|
);
|
|||
|
|
|||
|
STATIC PVOID
|
|||
|
IopAllocateDirPool (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN ULONG Length
|
|||
|
);
|
|||
|
|
|||
|
INLINE PTENTRY
|
|||
|
IopNewTransEntry (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PTENTRIESBYTYPE pTypes,
|
|||
|
IN ULONG Type
|
|||
|
);
|
|||
|
|
|||
|
STATIC NTSTATUS
|
|||
|
IopAddCmDescriptorToInUseList (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PTENTRIESBYTYPE pTypes,
|
|||
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc,
|
|||
|
IN POWNER Owner
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
IopFindCollisionInTList (
|
|||
|
IN PTENTRY SEntry,
|
|||
|
#if _PNP_POWER_
|
|||
|
IN PLTENTRY List,
|
|||
|
OUT PTENTRY *ConflictEntry
|
|||
|
#else
|
|||
|
IN PLTENTRY List
|
|||
|
#endif // _PNP_POWER_
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
IopPickupCollisionInTList (
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN UCHAR Type,
|
|||
|
IN LONGLONG BAddr,
|
|||
|
IN PTENTRY SEntry,
|
|||
|
IN PLTENTRY List
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopBuildResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST ParentDir,
|
|||
|
IN PDIR_RESREQ_LIST *DirResourceList,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
IopFreeResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST DirResourceList
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
IopSortDescriptors (
|
|||
|
IN OUT PDIR_RESREQ_LIST Dir
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopCatagorizeDescriptors (
|
|||
|
IN OUT PDIR_RESREQ_LIST Dir
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
IopDescriptorSortingWeight (
|
|||
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopGenNextValidResourceList (
|
|||
|
IN ULONG level,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopGenNextValidDescriptor (
|
|||
|
IN ULONG level,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PULONG collisionlevel
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopSlotResourceOwner (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|||
|
IN BOOLEAN AddOwner
|
|||
|
);
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
PDIR_RESOURCE_LIST
|
|||
|
IopAssignMachineDefaultResources (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResource
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopRelocateResource (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN UCHAR TranslatedType,
|
|||
|
IN PTENTRY ConflictEntry,
|
|||
|
IN PTENTRY TranslatedEntry
|
|||
|
);
|
|||
|
|
|||
|
PDIR_RESOURCE_LIST
|
|||
|
IopResolveConflicts (
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
IopAddRelocatedEntry (
|
|||
|
IN PRELOCATED_TENTRIES *List,
|
|||
|
IN PTENTRY Entry,
|
|||
|
IN UCHAR Type,
|
|||
|
IN POWNER NewOwner
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
IopFindCollisionInRelocatedList (
|
|||
|
IN PTENTRY SEntry,
|
|||
|
IN PRELOCATED_TENTRIES List,
|
|||
|
OUT PTENTRY *ConflictEntry
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
IopFreeRelocatedTEntryLists (
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopQueryReconfigureResource(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PCM_RESOURCE_LIST CmResources
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopReconfigureResource(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PCM_RESOURCE_LIST CmResources
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopCancelReconfigureResource(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopRecordAssignInformation(
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PUNICODE_STRING DriverClassName,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PDIR_RESOURCE_LIST CurList
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
IopFreeRelocatedResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST DirResourceList
|
|||
|
);
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
#if IDBG
|
|||
|
VOID
|
|||
|
IopDumpIoResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
IopDumpIoResourceDescriptor (
|
|||
|
IN PUCHAR Indent,
|
|||
|
IN PIO_RESOURCE_DESCRIPTOR Desc
|
|||
|
);
|
|||
|
#endif
|
|||
|
|
|||
|
#if DBG
|
|||
|
#define CHECK_STATUS(a,b) { if(!NT_SUCCESS(a)) { DebugString = b; goto Exit; } }
|
|||
|
#else
|
|||
|
#define CHECK_STATUS(a,b) { if(!NT_SUCCESS(a)) goto Exit; }
|
|||
|
#endif
|
|||
|
|
|||
|
#if DBG
|
|||
|
#define DBGMSG(a) DbgPrint(a)
|
|||
|
#else
|
|||
|
#define DBGMSG(a)
|
|||
|
#endif
|
|||
|
|
|||
|
#if IDBG
|
|||
|
#define IDBGMSG(a) DbgPrint(a)
|
|||
|
#else
|
|||
|
#define IDBGMSG(a)
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef PAGED
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
|
|||
|
#pragma alloc_text(PAGE,IoAssignResources)
|
|||
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase1)
|
|||
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase2)
|
|||
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase3)
|
|||
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase4)
|
|||
|
#pragma alloc_text(PAGE,IopLogConflict)
|
|||
|
#pragma alloc_text(PAGE,IopGenNextValidResourceList)
|
|||
|
#pragma alloc_text(PAGE,IopGenNextValidDescriptor)
|
|||
|
#pragma alloc_text(PAGE,IopFindCollisionInTList)
|
|||
|
#pragma alloc_text(PAGE,IopPickupCollisionInTList)
|
|||
|
#pragma alloc_text(PAGE,IopAllocateDirPool)
|
|||
|
#pragma alloc_text(PAGE,IopGetResourceReqRegistryValue)
|
|||
|
#pragma alloc_text(PAGE,IopBuildResourceDir)
|
|||
|
#pragma alloc_text(PAGE,IopFreeResourceDir)
|
|||
|
#pragma alloc_text(PAGE,IopCatagorizeDescriptors)
|
|||
|
#pragma alloc_text(PAGE,IopSortDescriptors)
|
|||
|
#pragma alloc_text(PAGE,IopAddCmDescriptorToInUseList)
|
|||
|
#pragma alloc_text(PAGE,IopSlotResourceOwner)
|
|||
|
#if _PNP_POWER_
|
|||
|
#pragma alloc_text(PAGE,IoAssignDeviceResources)
|
|||
|
#pragma alloc_text(PAGE,IopResolveConflicts)
|
|||
|
#pragma alloc_text(PAGE,IopAddRelocatedEntry)
|
|||
|
#pragma alloc_text(PAGE,IopFindCollisionInRelocatedList)
|
|||
|
#pragma alloc_text(PAGE,IopFreeRelocatedTEntryLists)
|
|||
|
#pragma alloc_text(PAGE,IopRelocateResource)
|
|||
|
#pragma alloc_text(PAGE,IopQueryReconfigureResource)
|
|||
|
#pragma alloc_text(PAGE,IopReconfigureResource)
|
|||
|
#pragma alloc_text(PAGE,IopCancelReconfigureResource)
|
|||
|
#pragma alloc_text(PAGE,IopRecordAssignInformation)
|
|||
|
#pragma alloc_text(PAGE,IopFreeRelocatedResourceDir)
|
|||
|
#endif // _PNP_POWER_
|
|||
|
|
|||
|
#if IDBG
|
|||
|
#pragma alloc_text(PAGE,IopDumpIoResourceDir)
|
|||
|
#pragma alloc_text(PAGE,IopDumpIoResourceDescriptor)
|
|||
|
#endif
|
|||
|
|
|||
|
#ifndef INLINE
|
|||
|
#pragma alloc_text(PAGE,IO_DESC_MIN)
|
|||
|
#pragma alloc_text(PAGE,IO_DESC_MAX)
|
|||
|
#pragma alloc_text(PAGE,IopDescriptorSortingWeight)
|
|||
|
#pragma alloc_text(PAGE,IopNewTransEntry)
|
|||
|
#endif // INLINE
|
|||
|
|
|||
|
#endif // ALLOC_PRAGMA
|
|||
|
#endif // PAGED
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
NTSTATUS
|
|||
|
IoAssignDeviceResources (
|
|||
|
IN PDEVICE_HANDLER_OBJECT DeviceHandler,
|
|||
|
IN PUNICODE_STRING RegistryPath OPTIONAL,
|
|||
|
IN PUNICODE_STRING DriverClassName OPTIONAL,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResources OPTIONAL,
|
|||
|
IN OUT PCM_RESOURCE_LIST *AllocatedResources
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine takes an input request of RequestedResources, and returned
|
|||
|
allocated resources in pAllocatedResources. The allocated resources are
|
|||
|
automatically recorded in the registry under the ResourceMap for the
|
|||
|
DriverClassName/DriverObject/DeviceObject requestor.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceHandler
|
|||
|
Supplies a pointer to the device's device handler object.
|
|||
|
|
|||
|
RegistryPath
|
|||
|
For a simple driver, this would be the value passed to the drivers
|
|||
|
initialization function. For drivers call IoAssignResources with
|
|||
|
multiple DeviceObjects are responsible for passing in a unique
|
|||
|
RegistryPath for each object. Drivers do not need to specify this
|
|||
|
argument if it is the same as ServiceKeyName.
|
|||
|
|
|||
|
The registry path is checked for:
|
|||
|
RegitryPath:
|
|||
|
AssignedSystemResources.
|
|||
|
|
|||
|
AssignSystemResources is of type REG_RESOURCE_REQUIREMENTS_LIST
|
|||
|
|
|||
|
If present, IoAssignResources will attempt to use these settings to
|
|||
|
satisify the requested resources. If the listed settings do
|
|||
|
not conform to the resource requirements, then IoAssignResources
|
|||
|
will fail.
|
|||
|
|
|||
|
Note: IoAssignResources may store other internal binary information
|
|||
|
in the supplied RegisteryPath.
|
|||
|
|
|||
|
DriverObject:
|
|||
|
The driver object of the caller.
|
|||
|
|
|||
|
DeviceObject:
|
|||
|
Supplies a pointer to a device object that the requested resoruce
|
|||
|
list refers to.
|
|||
|
|
|||
|
DriverClassName
|
|||
|
Used to partition allocated resources into different device classes.
|
|||
|
|
|||
|
RequestedResources
|
|||
|
A list of resources to allocate. If NULL, it will be retrieved from
|
|||
|
the location specified by ServiceKeyName\InstanceNumber.
|
|||
|
|
|||
|
Allocated resources may be freed by re-invoking
|
|||
|
IoAssignResources with the same RegistryPath, DriverObject and
|
|||
|
DeviceObject.
|
|||
|
|
|||
|
AllocatedResources
|
|||
|
Returns the allocated resources for the requested resource list.
|
|||
|
|
|||
|
Note that the driver is responsible for passing in a pointer to
|
|||
|
an uninitialized pointer. IoAssignDeviceResources will initialize the
|
|||
|
pointer to point to the allocated CM_RESOURCE_LIST. The driver
|
|||
|
is responisble for returning the memory back to pool when it is
|
|||
|
done with them structure.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The status returned is the final completion status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST ioResources = NULL, adjustedIoResources = NULL;
|
|||
|
PCM_RESOURCE_LIST cmResList = NULL;
|
|||
|
ULONG instanceFlags, bufferSize, requiredSize;
|
|||
|
HAL_BUS_INFORMATION busInfo;
|
|||
|
UNICODE_STRING unicodeName, fullServiceName;
|
|||
|
HANDLE handle;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// If caller does not specify RegistryPath, use ServiceKeyName instead.
|
|||
|
//
|
|||
|
|
|||
|
fullServiceName.Buffer = NULL;
|
|||
|
if (!ARGUMENT_PRESENT(RegistryPath)) {
|
|||
|
bufferSize = CmRegistryMachineSystemCurrentControlSetServices.Length +
|
|||
|
2 * sizeof(UNICODE_NULL) + DeviceHandler->ServiceKeyName.Length;
|
|||
|
fullServiceName.Buffer = (PWSTR)ExAllocatePool(PagedPool, bufferSize);
|
|||
|
if (!fullServiceName.Buffer) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
fullServiceName.Length = (USHORT)bufferSize - sizeof(UNICODE_NULL);
|
|||
|
fullServiceName.MaximumLength = (USHORT)bufferSize;
|
|||
|
bufferSize = CmRegistryMachineSystemCurrentControlSetServices.Length;
|
|||
|
RtlMoveMemory (fullServiceName.Buffer,
|
|||
|
CmRegistryMachineSystemCurrentControlSetServices.Buffer,
|
|||
|
bufferSize
|
|||
|
);
|
|||
|
fullServiceName.Buffer[bufferSize / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
|
|||
|
bufferSize += sizeof(WCHAR);
|
|||
|
RtlMoveMemory((PUCHAR)fullServiceName.Buffer + bufferSize,
|
|||
|
DeviceHandler->ServiceKeyName.Buffer,
|
|||
|
DeviceHandler->ServiceKeyName.Length
|
|||
|
);
|
|||
|
bufferSize += DeviceHandler->ServiceKeyName.Length;
|
|||
|
fullServiceName.Buffer[bufferSize / sizeof(WCHAR)] = UNICODE_NULL;
|
|||
|
RegistryPath = &fullServiceName;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if caller does not supplies RequestedResources try to get it from
|
|||
|
// registry specified by ServiceKeyName and InstanceNumber.
|
|||
|
//
|
|||
|
|
|||
|
if (!ARGUMENT_PRESENT(RequestedResources)) {
|
|||
|
bufferSize = 1024;
|
|||
|
allocAgain:
|
|||
|
ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool(PagedPool, bufferSize);
|
|||
|
if (ioResources == NULL) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exit0;
|
|||
|
}
|
|||
|
status = IoQueryDeviceConfigurationVector(
|
|||
|
DeviceHandler,
|
|||
|
&instanceFlags,
|
|||
|
ioResources,
|
|||
|
bufferSize,
|
|||
|
&requiredSize
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(ioResources);
|
|||
|
ioResources = NULL;
|
|||
|
if (status == STATUS_BUFFER_TOO_SMALL) {
|
|||
|
bufferSize = requiredSize;
|
|||
|
goto allocAgain;
|
|||
|
}
|
|||
|
} else if (ioResources->ListSize == 0 || requiredSize == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// if it is an empty list, free the space
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(ioResources);
|
|||
|
ioResources = NULL;
|
|||
|
} else {
|
|||
|
RequestedResources = ioResources;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get machine default resources frome ServiceKeyName\InstanceNumber.
|
|||
|
//
|
|||
|
|
|||
|
bufferSize = 512;
|
|||
|
tryAgain:
|
|||
|
cmResList = (PCM_RESOURCE_LIST)ExAllocatePool(PagedPool, bufferSize);
|
|||
|
if (cmResList == NULL) {
|
|||
|
if (ioResources) {
|
|||
|
ExFreePool(ioResources);
|
|||
|
}
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exit0;
|
|||
|
}
|
|||
|
status = IoQueryDeviceConfiguration(
|
|||
|
DeviceHandler,
|
|||
|
&busInfo,
|
|||
|
&instanceFlags,
|
|||
|
cmResList,
|
|||
|
bufferSize,
|
|||
|
&requiredSize
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(cmResList);
|
|||
|
cmResList = NULL;
|
|||
|
if (status == STATUS_BUFFER_TOO_SMALL) {
|
|||
|
bufferSize = requiredSize;
|
|||
|
goto tryAgain;
|
|||
|
}
|
|||
|
} else if (requiredSize == 0 || cmResList->Count == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// if it is an empty list, free the space
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(cmResList);
|
|||
|
cmResList = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no possible resource lists and default resource list,
|
|||
|
// exit.
|
|||
|
//
|
|||
|
|
|||
|
if (!RequestedResources && !cmResList) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto exit0;
|
|||
|
}
|
|||
|
|
|||
|
if (cmResList) {
|
|||
|
|
|||
|
//
|
|||
|
// Insert default resources to the RequestedResources such that
|
|||
|
// the default resource list will be picked with highest priority.
|
|||
|
//
|
|||
|
|
|||
|
adjustedIoResources = IopAddDefaultResourceList (RequestedResources, cmResList);
|
|||
|
ExFreePool(cmResList);
|
|||
|
if (adjustedIoResources) {
|
|||
|
if (ioResources) {
|
|||
|
ExFreePool(ioResources);
|
|||
|
ioResources = NULL;
|
|||
|
}
|
|||
|
RequestedResources = adjustedIoResources;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// call IoAssignResources to allocate resources for the device
|
|||
|
//
|
|||
|
|
|||
|
status = IoAssignResources (
|
|||
|
RegistryPath,
|
|||
|
DriverClassName,
|
|||
|
DriverObject,
|
|||
|
DeviceObject,
|
|||
|
RequestedResources,
|
|||
|
AllocatedResources
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto exit;
|
|||
|
}
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Call Hal to set the allocated resources to the device's corresponding
|
|||
|
// configuration space.
|
|||
|
//
|
|||
|
|
|||
|
requiredSize = IopDetermineResourceListSize(*AllocatedResources);
|
|||
|
status = HalSlotControl(RequestedResources->InterfaceType,
|
|||
|
RequestedResources->BusNumber,
|
|||
|
RequestedResources->SlotNumber,
|
|||
|
DeviceObject,
|
|||
|
BCTL_SET_DEVICE_RESOURCES,
|
|||
|
*AllocatedResources,
|
|||
|
&requiredSize,
|
|||
|
NULL,
|
|||
|
(PSLOT_CONTROL_COMPLETION)NULL
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// If configuration space was updated successfully, change our registry data.
|
|||
|
//
|
|||
|
|
|||
|
KeEnterCriticalRegion();
|
|||
|
ExAcquireResourceExclusive(&PpRegistryDeviceResource, TRUE);
|
|||
|
|
|||
|
status = IopServiceInstanceToDeviceInstance (
|
|||
|
NULL,
|
|||
|
&DeviceHandler->ServiceKeyName,
|
|||
|
DeviceHandler->InstanceNumber,
|
|||
|
NULL,
|
|||
|
&handle,
|
|||
|
KEY_ALL_ACCESS
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Set Configuration = data entry to caller supplied resources.
|
|||
|
//
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VALUE_CONFIGURATION);
|
|||
|
ZwSetValueKey(handle,
|
|||
|
&unicodeName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_RESOURCE_LIST,
|
|||
|
*AllocatedResources,
|
|||
|
requiredSize
|
|||
|
);
|
|||
|
ZwClose(handle);
|
|||
|
}
|
|||
|
ExReleaseResource(&PpRegistryDeviceResource);
|
|||
|
KeLeaveCriticalRegion();
|
|||
|
}
|
|||
|
#endif // 0
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
exit:
|
|||
|
if (ioResources) {
|
|||
|
ExFreePool(ioResources);
|
|||
|
}
|
|||
|
if (adjustedIoResources) {
|
|||
|
ExFreePool(adjustedIoResources);
|
|||
|
}
|
|||
|
exit0:
|
|||
|
RtlFreeUnicodeString(&fullServiceName);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
#endif // _PNP_POWER_
|
|||
|
NTSTATUS
|
|||
|
IoAssignResources (
|
|||
|
IN PUNICODE_STRING RegistryPath,
|
|||
|
IN PUNICODE_STRING DriverClassName OPTIONAL,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResources,
|
|||
|
IN OUT PCM_RESOURCE_LIST *pAllocatedResources
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine takes an input request of RequestedResources, and returned
|
|||
|
allocated resources in pAllocatedResources. The allocated resources are
|
|||
|
automatically recorded in the registry under the ResourceMap for the
|
|||
|
DriverClassName/DriverObject/DeviceObject requestor.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RegistryPath
|
|||
|
For a simple driver, this would be the value passed to the drivers
|
|||
|
initialization function. For drivers call IoAssignResources with
|
|||
|
multiple DeviceObjects are responsible for passing in a unique
|
|||
|
RegistryPath for each object.
|
|||
|
|
|||
|
The registry path is checked for:
|
|||
|
RegitryPath:
|
|||
|
AssignedSystemResources.
|
|||
|
|
|||
|
AssignSystemResources is of type REG_RESOURCE_REQUIREMENTS_LIST
|
|||
|
|
|||
|
If present, IoAssignResources will attempt to use these settings to
|
|||
|
satisify the requested resources. If the listed settings do
|
|||
|
not conform to the resource requirements, then IoAssignResources
|
|||
|
will fail.
|
|||
|
|
|||
|
Note: IoAssignResources may store other internal binary information
|
|||
|
in the supplied RegisteryPath.
|
|||
|
|
|||
|
DriverObject:
|
|||
|
The driver object of the caller.
|
|||
|
|
|||
|
DeviceObject:
|
|||
|
If non-null, then requested resoruce list refers to this device.
|
|||
|
If null, the requested resource list refers to the driver.
|
|||
|
|
|||
|
DriverClassName
|
|||
|
Used to partition allocated resources into different device classes.
|
|||
|
|
|||
|
RequestedResources
|
|||
|
A list of resources to allocate.
|
|||
|
|
|||
|
Allocated resources may be appended or freed by re-invoking
|
|||
|
IoAssignResources with the same RegistryPath, DriverObject and
|
|||
|
DeviceObject. (editing requirements on a resource list by using
|
|||
|
sucessive calls is not preferred driver behaviour).
|
|||
|
|
|||
|
AllocatedResources
|
|||
|
Returns the allocated resources for the requested resource list.
|
|||
|
|
|||
|
Note that the driver is responsible for passing in a pointer to
|
|||
|
an uninitialized pointer. IoAssignResources will initialize the
|
|||
|
pointer to point to the allocated CM_RESOURCE_LIST. The driver
|
|||
|
is responisble for returning the memory back to pool when it is
|
|||
|
done with them structure.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The status returned is the final completion status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDIR_RESREQ_LIST Dir;
|
|||
|
USED_HEAP DirHeap;
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST IoResources;
|
|||
|
PKEY_VALUE_PARTIAL_INFORMATION PartInf;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
ULONG i, busflags, len;
|
|||
|
PDIR_RESOURCE_LIST CurList;
|
|||
|
NTSTATUS status;
|
|||
|
BOOLEAN flag;
|
|||
|
BOOLEAN SemaphoreOwned;
|
|||
|
|
|||
|
#if DBG
|
|||
|
PSZ DebugString = NULL;
|
|||
|
#endif
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
SemaphoreOwned = FALSE;
|
|||
|
IoResources = NULL;
|
|||
|
Dir = NULL;
|
|||
|
|
|||
|
if (pAllocatedResources) {
|
|||
|
*pAllocatedResources = NULL;
|
|||
|
}
|
|||
|
|
|||
|
KeEnterCriticalRegion( );
|
|||
|
|
|||
|
//
|
|||
|
// Copy input structure & let hal have a crack at it
|
|||
|
//
|
|||
|
|
|||
|
if (RequestedResources) {
|
|||
|
status = IopAssignResourcesPhase1 (RequestedResources, &IoResources);
|
|||
|
CHECK_STATUS (status, "IopAssignResourcesPhase1 failed");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build a resource directory from the requested list
|
|||
|
//
|
|||
|
|
|||
|
status = IopBuildResourceDir (NULL, &Dir, IoResources);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
if (IoResources) {
|
|||
|
ExFreePool (IoResources);
|
|||
|
}
|
|||
|
CHECK_STATUS (status, "RequestedResources could no be parsed");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// put IoResources onto allocated heap list
|
|||
|
//
|
|||
|
|
|||
|
if (IoResources) {
|
|||
|
DirHeap.FreeHeap = (PVOID) IoResources;
|
|||
|
PushEntryList (&Dir->AllocatedHeap, &DirHeap.FreeLink);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// allocate a scratch buffer
|
|||
|
//
|
|||
|
|
|||
|
Dir->Buffer = (PWSTR) IopAllocateDirPool (Dir, BUFFERSIZE);
|
|||
|
if (!Dir->Buffer) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
CHECK_STATUS (status, "No memory");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get handles to registry keys:
|
|||
|
// HRESOURCE_MAP
|
|||
|
// HDEVICE_STORAGE
|
|||
|
// HCURRENT_CONTROL_SET
|
|||
|
// HSYSTEMRESOURCES
|
|||
|
// HBUSVALUES
|
|||
|
// HORDERING
|
|||
|
// HRESERVEDRESOURCES
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Open resource map
|
|||
|
//
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HRESOURCE_MAP],
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineHardwareResourceMapName,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "No ResourceMap");
|
|||
|
|
|||
|
//
|
|||
|
// Open owner map
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HOWNER_MAP],
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineHardwareOwnerMapName,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "No OwnerMap");
|
|||
|
|
|||
|
//
|
|||
|
// Open up storage location for this Device/Driver in the registry
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HDEVICE_STORAGE],
|
|||
|
NULL,
|
|||
|
RegistryPath,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "RegistryPath parameter incorrect");
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Open up current control set
|
|||
|
//
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HCURRENT_CONTROL_SET],
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineSystemCurrentControlSet,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "No CurrentControlSet?");
|
|||
|
|
|||
|
//
|
|||
|
// Open up ...Control\SystemResources
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString (&unicodeString, IopWstrSystemResources);
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HSYSTEMRESOURCES],
|
|||
|
Dir->RegHandle[HCURRENT_CONTROL_SET],
|
|||
|
&unicodeString,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "SystemResources not found");
|
|||
|
|
|||
|
//
|
|||
|
// Open up ...SystemResources\BusValues
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString (&unicodeString, IopWstrBusValues);
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HBUSVALUES],
|
|||
|
Dir->RegHandle[HSYSTEMRESOURCES],
|
|||
|
&unicodeString,
|
|||
|
KEY_READ,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "BusValues not found");
|
|||
|
|
|||
|
//
|
|||
|
// Open up ...SystemResources\AssignmentOrdering
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString (&unicodeString, IopWstrAssignmentOrdering);
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HORDERING],
|
|||
|
Dir->RegHandle[HSYSTEMRESOURCES],
|
|||
|
&unicodeString,
|
|||
|
KEY_READ,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "AssignmentOrdering not found");
|
|||
|
|
|||
|
//
|
|||
|
// Open up ...SystemResources\ReservedResources
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString (&unicodeString, IopWstrReservedResources);
|
|||
|
status = IopOpenRegistryKey (
|
|||
|
&Dir->RegHandle[HRESERVEDRESOURCES],
|
|||
|
Dir->RegHandle[HSYSTEMRESOURCES],
|
|||
|
&unicodeString,
|
|||
|
KEY_READ,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "ReservedResources not found");
|
|||
|
|
|||
|
//
|
|||
|
// If no resource list, then caller wishes to free allocated resources
|
|||
|
// Else caller wishes to allocate resources
|
|||
|
//
|
|||
|
|
|||
|
if (RequestedResources == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Lookup callers requested resources which are being freed
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &unicodeString, IopWstrRequestedResources );
|
|||
|
status = ZwQueryValueKey( Dir->RegHandle[HDEVICE_STORAGE],
|
|||
|
&unicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&len
|
|||
|
);
|
|||
|
|
|||
|
if (status == STATUS_BUFFER_TOO_SMALL) {
|
|||
|
PartInf = (PKEY_VALUE_PARTIAL_INFORMATION) IopAllocateDirPool (Dir, len);
|
|||
|
if (!PartInf) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
CHECK_STATUS (status, "No memory");
|
|||
|
}
|
|||
|
status = ZwQueryValueKey( Dir->RegHandle[HDEVICE_STORAGE],
|
|||
|
&unicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
PartInf,
|
|||
|
len,
|
|||
|
&len
|
|||
|
);
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
DBGMSG ("IoAllocateResources - could not find copy of requested resource to free\n");
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IoResources = (PIO_RESOURCE_REQUIREMENTS_LIST) PartInf->Data;
|
|||
|
flag = IopSlotResourceOwner (
|
|||
|
Dir,
|
|||
|
DriverObject,
|
|||
|
DeviceObject,
|
|||
|
IoResources,
|
|||
|
FALSE // Adding owner
|
|||
|
);
|
|||
|
|
|||
|
if (!flag) {
|
|||
|
status = STATUS_INVALID_OWNER;
|
|||
|
CHECK_STATUS (status, "(free resources) not owner of slot");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Release the the acquired resources
|
|||
|
//
|
|||
|
|
|||
|
i = 0;
|
|||
|
if (!DeviceObject) {
|
|||
|
status = IopReportResourceUsage (
|
|||
|
DriverClassName,
|
|||
|
DriverObject, // DriverObject
|
|||
|
(PCM_RESOURCE_LIST) &i, // DriverList
|
|||
|
sizeof (i), // DriverListSize
|
|||
|
DeviceObject,
|
|||
|
NULL, // DeviceList
|
|||
|
0, // DeviceListSize
|
|||
|
FALSE, // override conflict
|
|||
|
&flag // conflicted detected
|
|||
|
);
|
|||
|
} else {
|
|||
|
status = IopReportResourceUsage (
|
|||
|
DriverClassName,
|
|||
|
DriverObject, // DriverObject
|
|||
|
NULL, // DriverList
|
|||
|
0, // DriverListSize
|
|||
|
DeviceObject,
|
|||
|
(PCM_RESOURCE_LIST) &i, // DeviceList
|
|||
|
sizeof (i), // DeviceListSize
|
|||
|
FALSE, // override conflict
|
|||
|
&flag // conflicted detected
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
CHECK_STATUS (status, "free resources failed");
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
flag = IopSlotResourceOwner (
|
|||
|
Dir,
|
|||
|
DriverObject,
|
|||
|
DeviceObject,
|
|||
|
IoResources,
|
|||
|
TRUE // Adding owner
|
|||
|
);
|
|||
|
|
|||
|
if (!flag) {
|
|||
|
status = STATUS_INVALID_OWNER;
|
|||
|
CHECK_STATUS (status, "not owner of slot");
|
|||
|
}
|
|||
|
#ifndef _PNP_POWER_
|
|||
|
|
|||
|
//
|
|||
|
// The copy of the requested resources is stored under
|
|||
|
// new location : ServiceKeyName\ResourceInformation
|
|||
|
// Driver\DeviceName.RequestedResources
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Put a copy of the driver's request into the registry
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &unicodeString, IopWstrRequestedResources );
|
|||
|
status = ZwSetValueKey( Dir->RegHandle[HDEVICE_STORAGE],
|
|||
|
&unicodeString,
|
|||
|
0L,
|
|||
|
REG_RESOURCE_REQUIREMENTS_LIST,
|
|||
|
Dir->IoResourceReq,
|
|||
|
Dir->IoResourceReq->ListSize
|
|||
|
);
|
|||
|
CHECK_STATUS (status, "SetValueKey error");
|
|||
|
#endif
|
|||
|
//
|
|||
|
// Sort the request descriptors such that all alternative descriptor
|
|||
|
// options are grouped by CmResourceType.
|
|||
|
//
|
|||
|
|
|||
|
IopSortDescriptors (Dir);
|
|||
|
|
|||
|
#if IDBG
|
|||
|
DbgPrint ("IoAssignResources: Dump of requested resource list\n");
|
|||
|
IopDumpIoResourceDir (Dir);
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Check for user assigned resources in RegistryPath
|
|||
|
//
|
|||
|
|
|||
|
IoResources = IopGetResourceReqRegistryValue (
|
|||
|
Dir,
|
|||
|
Dir->RegHandle[HDEVICE_STORAGE],
|
|||
|
IopWstrAssignedResources
|
|||
|
);
|
|||
|
|
|||
|
if (IoResources) {
|
|||
|
//
|
|||
|
// Build directory out of user's assignments
|
|||
|
//
|
|||
|
|
|||
|
status = IopBuildResourceDir (Dir, &Dir->UserDir, IoResources);
|
|||
|
CHECK_STATUS (status, "Device AssignedResources could not be parsed");
|
|||
|
|
|||
|
status = IopCatagorizeDescriptors (Dir->UserDir);
|
|||
|
CHECK_STATUS (status, "Device AssignedResources could not be catagorized");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find bus specific ordering
|
|||
|
//
|
|||
|
|
|||
|
IoResources = NULL;
|
|||
|
status = IopLookupBusStringFromID (
|
|||
|
Dir->RegHandle[HBUSVALUES],
|
|||
|
Dir->IoResourceReq->InterfaceType,
|
|||
|
Dir->Buffer,
|
|||
|
BUFFERSIZE - 10,
|
|||
|
&busflags
|
|||
|
);
|
|||
|
|
|||
|
CHECK_STATUS (status, "Bus identifier unknown");
|
|||
|
|
|||
|
//
|
|||
|
// First try BusName_#
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; Dir->Buffer[i]; i++) ;
|
|||
|
swprintf (Dir->Buffer+i, L"_%d", Dir->IoResourceReq->BusNumber);
|
|||
|
IoResources = IopGetResourceReqRegistryValue (
|
|||
|
Dir,
|
|||
|
Dir->RegHandle[HORDERING],
|
|||
|
Dir->Buffer
|
|||
|
);
|
|||
|
|
|||
|
if (!IoResources) {
|
|||
|
//
|
|||
|
// Use just BusName
|
|||
|
//
|
|||
|
|
|||
|
Dir->Buffer[i] = 0;
|
|||
|
IoResources = IopGetResourceReqRegistryValue (
|
|||
|
Dir,
|
|||
|
Dir->RegHandle[HORDERING],
|
|||
|
Dir->Buffer
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (!IoResources) {
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
CHECK_STATUS (status, "Bus ordering information not found");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build a directory & catagorize the resource ordering information for
|
|||
|
// the bus.
|
|||
|
//
|
|||
|
|
|||
|
status = IopBuildResourceDir (Dir, &Dir->BusDir, IoResources);
|
|||
|
CHECK_STATUS (status, "Bus ordering information could not be parsed");
|
|||
|
|
|||
|
status = IopCatagorizeDescriptors (Dir->BusDir);
|
|||
|
CHECK_STATUS (status, "Bus ordering information could not be catagorized");
|
|||
|
|
|||
|
//
|
|||
|
// Serialize with other resource reporting & assignments
|
|||
|
//
|
|||
|
|
|||
|
status = KeWaitForSingleObject( &IopRegistrySemaphore,
|
|||
|
DelayExecution,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL );
|
|||
|
|
|||
|
CHECK_STATUS (status, "Wait for RegistrySemaphore");
|
|||
|
SemaphoreOwned = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Read all currently allocated resources into memory
|
|||
|
//
|
|||
|
|
|||
|
status = IopAssignResourcesPhase2 (Dir, DriverClassName, DriverObject, DeviceObject);
|
|||
|
CHECK_STATUS (status, "Phase2 failed");
|
|||
|
|
|||
|
//
|
|||
|
// Make resource assignments
|
|||
|
//
|
|||
|
|
|||
|
CurList = IopAssignResourcesPhase3 (Dir);
|
|||
|
if (!CurList) {
|
|||
|
status = STATUS_CONFLICTING_ADDRESSES;
|
|||
|
IopLogConflict (DriverObject, Dir, status);
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
//
|
|||
|
// After logging the conflicts, try to resolve the them.
|
|||
|
//
|
|||
|
|
|||
|
CurList = IopResolveConflicts(Dir);
|
|||
|
if (!CurList) {
|
|||
|
status = STATUS_CONFLICTING_ADDRESSES;
|
|||
|
} else {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
#endif
|
|||
|
CHECK_STATUS (status, "Resource assignments failed");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Build CmResourceList from assignments
|
|||
|
//
|
|||
|
|
|||
|
*pAllocatedResources = IopAssignResourcesPhase4 (Dir, CurList, &len);
|
|||
|
if (!*pAllocatedResources) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
CHECK_STATUS (status, "Phase4 failed");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Report consumed resources..
|
|||
|
//
|
|||
|
|
|||
|
if (!DeviceObject) {
|
|||
|
status = IopReportResourceUsage (
|
|||
|
DriverClassName,
|
|||
|
DriverObject, // DriverObject
|
|||
|
*pAllocatedResources, // DriverList
|
|||
|
len, // DriverListSize
|
|||
|
DeviceObject, // DeviceObject
|
|||
|
NULL, // DeviceList
|
|||
|
0, // DeviceListSize
|
|||
|
FALSE, // override conflict
|
|||
|
&flag // conflicted detected
|
|||
|
);
|
|||
|
} else {
|
|||
|
status = IopReportResourceUsage (
|
|||
|
DriverClassName,
|
|||
|
DriverObject, // DriverObject
|
|||
|
NULL, // DriverList
|
|||
|
0, // DriverListSize
|
|||
|
DeviceObject,
|
|||
|
*pAllocatedResources, // DeviceList
|
|||
|
len, // DeviceListSize
|
|||
|
FALSE, // override conflict
|
|||
|
&flag // conflicted detected
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status) && flag) {
|
|||
|
|
|||
|
//
|
|||
|
// IopReportResourceUsage saw a conflict?
|
|||
|
//
|
|||
|
|
|||
|
status = STATUS_CONFLICTING_ADDRESSES;
|
|||
|
#if _PNP_POWER_
|
|||
|
} else if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Save all the resource information to registry. We may need it
|
|||
|
// again to solve conflicts.
|
|||
|
//
|
|||
|
|
|||
|
IopRecordAssignInformation(Dir,
|
|||
|
DriverClassName,
|
|||
|
DriverObject,
|
|||
|
DeviceObject,
|
|||
|
CurList);
|
|||
|
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CHECK_STATUS (status, "IoReportResourceUsage failed");
|
|||
|
|
|||
|
Exit:
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
#if DBG
|
|||
|
DbgPrint ("IoAssignResources failed %08x - %s\n", status, DebugString);
|
|||
|
#endif
|
|||
|
if (pAllocatedResources && *pAllocatedResources) {
|
|||
|
ExFreePool (*pAllocatedResources);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free memory, handles, and other any other obtain resources
|
|||
|
//
|
|||
|
|
|||
|
IopFreeResourceDir (Dir);
|
|||
|
|
|||
|
if (SemaphoreOwned) {
|
|||
|
KeReleaseSemaphore( &IopRegistrySemaphore, 0, 1, FALSE );
|
|||
|
}
|
|||
|
KeLeaveCriticalRegion( );
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopSlotResourceOwner (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|||
|
IN BOOLEAN AddOwner
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG busflags, len, i;
|
|||
|
PWCHAR KeyName;
|
|||
|
UNICODE_STRING KeyString, ValueString;
|
|||
|
POBJECT_NAME_INFORMATION ObjectName;
|
|||
|
PKEY_VALUE_PARTIAL_INFORMATION PartInf;
|
|||
|
BOOLEAN Match;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
KeyName = ExAllocatePool (PagedPool, BUFFERSIZE * 2);
|
|||
|
if (!KeyName) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
ObjectName = (POBJECT_NAME_INFORMATION) ((PCHAR)KeyName + BUFFERSIZE);
|
|||
|
Match = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Find bus specific ordering
|
|||
|
//
|
|||
|
|
|||
|
status = IopLookupBusStringFromID (
|
|||
|
Dir->RegHandle[HBUSVALUES],
|
|||
|
IoResources->InterfaceType,
|
|||
|
KeyName,
|
|||
|
BUFFERSIZE-40,
|
|||
|
&busflags
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Does this bus have unique SlotNumber ownership?
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(status) && (busflags & 0x1)) {
|
|||
|
|
|||
|
//
|
|||
|
// Build keyname
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; KeyName[i]; i++) ;
|
|||
|
swprintf (KeyName+i, L"_%d_%x", IoResources->BusNumber, IoResources->SlotNumber);
|
|||
|
RtlInitUnicodeString( &KeyString, KeyName );
|
|||
|
|
|||
|
//
|
|||
|
// Build valuename
|
|||
|
//
|
|||
|
|
|||
|
status = ObQueryNameString(
|
|||
|
DeviceObject ? (PVOID) DeviceObject : (PVOID) DriverObject,
|
|||
|
ObjectName,
|
|||
|
BUFFERSIZE,
|
|||
|
&len
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Look it up
|
|||
|
//
|
|||
|
|
|||
|
PartInf = (PKEY_VALUE_PARTIAL_INFORMATION) Dir->Buffer;
|
|||
|
status = ZwQueryValueKey (
|
|||
|
Dir->RegHandle[HOWNER_MAP],
|
|||
|
&KeyString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
Dir->Buffer,
|
|||
|
BUFFERSIZE,
|
|||
|
&len
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// No owner listed, see if we should add ourselves
|
|||
|
//
|
|||
|
|
|||
|
if (AddOwner) {
|
|||
|
//
|
|||
|
// Add the key
|
|||
|
//
|
|||
|
|
|||
|
ZwSetValueKey (
|
|||
|
Dir->RegHandle[HOWNER_MAP],
|
|||
|
&KeyString,
|
|||
|
0L,
|
|||
|
REG_SZ,
|
|||
|
ObjectName->Name.Buffer,
|
|||
|
ObjectName->Name.Length
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Owner is listed, see if it's us
|
|||
|
//
|
|||
|
|
|||
|
ValueString.Buffer = (PWCHAR) PartInf->Data;
|
|||
|
ValueString.Length = (USHORT) len - (USHORT) FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
|||
|
ValueString.MaximumLength = ValueString.Length;
|
|||
|
|
|||
|
Match = RtlEqualUnicodeString (&ObjectName->Name, &ValueString, TRUE);
|
|||
|
if (Match && !AddOwner) {
|
|||
|
|
|||
|
//
|
|||
|
// Free ownership
|
|||
|
//
|
|||
|
|
|||
|
ZwDeleteValueKey( Dir->RegHandle[HOWNER_MAP], &KeyString);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool (KeyName);
|
|||
|
return Match;
|
|||
|
}
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
IO_DESC_MIN - Returns the descriptor's MIN,MAX or ALIGMENT requirements
|
|||
|
IO_DESC_MAX
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
INLINE LONGLONG
|
|||
|
IO_DESC_MIN (
|
|||
|
IN PIO_RESOURCE_DESCRIPTOR Desc
|
|||
|
)
|
|||
|
{
|
|||
|
LONGLONG li;
|
|||
|
|
|||
|
switch (Desc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
li = Desc->u.Port.MinimumAddress.QuadPart;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
li = Desc->u.Memory.MinimumAddress.QuadPart;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
li = Desc->u.Interrupt.MinimumVector;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
li = Desc->u.Dma.MinimumChannel;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return li;
|
|||
|
}
|
|||
|
|
|||
|
INLINE LONGLONG
|
|||
|
IO_DESC_MAX (
|
|||
|
IN PIO_RESOURCE_DESCRIPTOR Desc
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Returns the IO_RESORUCE_DESCRIPTOR's maximum value
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LONGLONG li;
|
|||
|
|
|||
|
switch (Desc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
li = Desc->u.Port.MaximumAddress.QuadPart;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
li = Desc->u.Memory.MaximumAddress.QuadPart;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
li = Desc->u.Interrupt.MaximumVector;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
li = Desc->u.Dma.MaximumChannel;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return li;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopGenNextValidResourceList (
|
|||
|
IN ULONG level,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Attempts to find a setting for every required resource in the CurList
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
level - Index to which required resource list to start finding resources from
|
|||
|
CurList - List of required resources being processed
|
|||
|
Dir - The top directory of resources
|
|||
|
|
|||
|
PassNo - The pass #
|
|||
|
1 - Preferred settings only
|
|||
|
2 - Available settings
|
|||
|
3 - Available settings, find conflict to report
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
TRUE if all required resources found available settings
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG collisionlevel;
|
|||
|
BOOLEAN flag;
|
|||
|
#if _PNP_POWER_
|
|||
|
ULONG i;
|
|||
|
#endif
|
|||
|
|
|||
|
do {
|
|||
|
if (level > CurList->LastLevel) {
|
|||
|
CurList->LastLevel = level;
|
|||
|
}
|
|||
|
|
|||
|
flag = IopGenNextValidDescriptor (
|
|||
|
level,
|
|||
|
CurList,
|
|||
|
Dir,
|
|||
|
&collisionlevel
|
|||
|
);
|
|||
|
|
|||
|
if (flag == FALSE) {
|
|||
|
//
|
|||
|
// Could not generate a valid descriptor setting
|
|||
|
//
|
|||
|
|
|||
|
if (level == 0 || collisionlevel == -1) {
|
|||
|
//
|
|||
|
// No more settings
|
|||
|
//
|
|||
|
|
|||
|
CurList->FailedLevel = level;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Backup to the collision level and try anew
|
|||
|
//
|
|||
|
|
|||
|
while (level > collisionlevel) {
|
|||
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[level]->RunLen = 0;
|
|||
|
level--;
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
if (CurList->RequiredResource[level]->PassNo == 6) {
|
|||
|
|
|||
|
//
|
|||
|
// if we returned back to here from pass 6, we just resolved a
|
|||
|
// resource conflict for current level. It is possible that the
|
|||
|
// reconfigured driver took the resouce which was selected by earlier
|
|||
|
// level. We must reset level back to 0 and reset PassNo of
|
|||
|
// current level to 2 to restart the resource assignment.
|
|||
|
//
|
|||
|
|
|||
|
CurList->RequiredResource[level]->PassNo = 2;
|
|||
|
i=0;
|
|||
|
while (i <= level) {
|
|||
|
CurList->RequiredResource[i]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[i]->RunLen = 0;
|
|||
|
i++;
|
|||
|
}
|
|||
|
level = 0;
|
|||
|
continue;
|
|||
|
}
|
|||
|
#endif
|
|||
|
if (CurList->RequiredResource[level]->PassNo == 1 &&
|
|||
|
CurList->RequiredResource[level]->CurPref <
|
|||
|
CurList->RequiredResource[level]->BestPref) {
|
|||
|
|
|||
|
//
|
|||
|
// First time through don't mess with unpreferred settings, continue
|
|||
|
// looking at this level
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Go to next level
|
|||
|
//
|
|||
|
|
|||
|
level++;
|
|||
|
} while (level < CurList->NoRequiredResources);
|
|||
|
|
|||
|
//
|
|||
|
// Determine list's preference
|
|||
|
// (only used on PassNo > 1 since PassNo == 1 only suceedes when
|
|||
|
// preferred settings are used)
|
|||
|
//
|
|||
|
|
|||
|
CurList->CurPref = 0;
|
|||
|
for (level = 0; level < CurList->NoRequiredResources; level++) {
|
|||
|
CurList->CurPref += CurList->RequiredResource[level]->CurPref;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Got a setting for each requested resource, return TRUE
|
|||
|
//
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopGenNextValidDescriptor (
|
|||
|
IN ULONG level,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
OUT PULONG collisionlevel
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
TRUE if descriptor setting was found
|
|||
|
FALSE if no setting found
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDIR_REQUIRED_RESOURCE Res, CRes;
|
|||
|
PIO_RESOURCE_DESCRIPTOR *Desc, DescTmp;
|
|||
|
LONGLONG BAddr, EAddr;
|
|||
|
LONGLONG NBAddr;
|
|||
|
LONGLONG DescMax, MinAddr, LiILen, LiELen, LiTmp;
|
|||
|
LONGLONG NAddr, BusMax, BusMin, PBAddr;
|
|||
|
ULONG indx, j, k, NBLoc;
|
|||
|
ULONG DescLen, Align, len;
|
|||
|
BOOLEAN NBSet, flag, flag2;
|
|||
|
LONG Preference, NPref;
|
|||
|
UCHAR TType, NTType;
|
|||
|
TENTRY Trans, NTrans;
|
|||
|
#if _PNP_POWER_
|
|||
|
PRELOCATED_TENTRIES pResourceRecord;
|
|||
|
PTENTRY pConflictTrans, pNewTrans;
|
|||
|
UCHAR newTransType;
|
|||
|
#endif
|
|||
|
|
|||
|
Res = CurList->RequiredResource[level];
|
|||
|
|
|||
|
*collisionlevel = (ULONG) -1; // assume no collision
|
|||
|
NBSet = FALSE;
|
|||
|
|
|||
|
do {
|
|||
|
Desc = &Res->IoResourceDescriptor[Res->CurLoc];
|
|||
|
|
|||
|
if (!Res->RunLen) {
|
|||
|
|
|||
|
if (Res->CurLoc >= Res->NoAlternatives) {
|
|||
|
//
|
|||
|
// No more runs
|
|||
|
//
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get number of alternatives which are of the same type
|
|||
|
// (alternatives have been sorted into types).
|
|||
|
//
|
|||
|
|
|||
|
Res->Type = Desc[0]->Type;
|
|||
|
for (j=Res->CurLoc; j < Res->NoAlternatives; j++) {
|
|||
|
if (Res->Type != Res->IoResourceDescriptor[j]->Type) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Res->RunLen = j - Res->CurLoc;
|
|||
|
if (!Res->RunLen) {
|
|||
|
//
|
|||
|
// Out of alternatives for this resource
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Start at beginning of bus options
|
|||
|
//
|
|||
|
|
|||
|
Res->CurBusLoc = 0;
|
|||
|
|
|||
|
DescTmp = Dir->BusDir->Alternative->ResourceByType[Res->Type]->IoResourceDescriptor[0];
|
|||
|
|
|||
|
if (!DescTmp) {
|
|||
|
//
|
|||
|
// There are no bus settings for this type of resource
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Res->CurBusMin = IO_DESC_MIN (DescTmp);
|
|||
|
Res->CurBusMax = IO_DESC_MAX (DescTmp);
|
|||
|
NAddr = Res->CurBusMax;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Decrease current value by one - this will cause this
|
|||
|
// function to find the next acceptable value.
|
|||
|
//
|
|||
|
|
|||
|
NAddr = Res->CurBAddr - 1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return the next available address from NAddr
|
|||
|
//
|
|||
|
|
|||
|
DescLen = Res->RunLen;
|
|||
|
BusMax = Res->CurBusMax;
|
|||
|
BusMin = Res->CurBusMin;
|
|||
|
|
|||
|
NBAddr = 0;
|
|||
|
|
|||
|
for (; ;) {
|
|||
|
|
|||
|
//
|
|||
|
// Loop for each descriptor in this run and pick the numerical highest
|
|||
|
// value available for this resource
|
|||
|
//
|
|||
|
|
|||
|
for (indx=0; indx < DescLen ; indx++) {
|
|||
|
|
|||
|
//
|
|||
|
// Set len, Align, MinAddr, DescMax
|
|||
|
//
|
|||
|
|
|||
|
DescTmp = Desc[indx];
|
|||
|
switch (DescTmp->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
len = DescTmp->u.Port.Length;
|
|||
|
Align = DescTmp->u.Port.Alignment;
|
|||
|
MinAddr = DescTmp->u.Port.MinimumAddress.QuadPart;
|
|||
|
DescMax = DescTmp->u.Port.MaximumAddress.QuadPart;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
len = DescTmp->u.Memory.Length;
|
|||
|
Align = DescTmp->u.Memory.Alignment;
|
|||
|
MinAddr = DescTmp->u.Memory.MinimumAddress.QuadPart;
|
|||
|
DescMax = DescTmp->u.Memory.MaximumAddress.QuadPart;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
len = 1;
|
|||
|
Align = 1;
|
|||
|
MinAddr = DescTmp->u.Interrupt.MinimumVector;
|
|||
|
DescMax = DescTmp->u.Interrupt.MaximumVector;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
len = 1;
|
|||
|
Align = 1;
|
|||
|
MinAddr = DescTmp->u.Dma.MinimumChannel;
|
|||
|
DescMax = DescTmp->u.Dma.MaximumChannel;
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// MinAddr is the largest of Descriptor-MinAddr, Bus-MinAddr, or
|
|||
|
// NextBest-MinAddr. Don't go below the last MinAddr (NBAddr).
|
|||
|
// So the search is from NAddr -to-> NBAddr
|
|||
|
//
|
|||
|
|
|||
|
if (BusMin > MinAddr) {
|
|||
|
MinAddr = BusMin;
|
|||
|
}
|
|||
|
|
|||
|
if (NBAddr > MinAddr) {
|
|||
|
MinAddr = NBAddr;
|
|||
|
}
|
|||
|
|
|||
|
BAddr = NAddr;
|
|||
|
LiELen = len; // Exclusive length
|
|||
|
LiILen = len - 1; // Inclusive length
|
|||
|
|
|||
|
//
|
|||
|
// Set initial preference
|
|||
|
//
|
|||
|
|
|||
|
Preference = 0;
|
|||
|
if (Res->PassNo == 1) {
|
|||
|
if (DescTmp->Option & IO_RESOURCE_PREFERRED) {
|
|||
|
// Account for device's preference durning first pass
|
|||
|
Preference = 1;
|
|||
|
|
|||
|
} else if (Res->BestPref) {
|
|||
|
// Some resource in this list has a prefernce, but it's not
|
|||
|
// this one. Since this is the PassNo == 1 skip non-preferred.
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Loop while BAddr being tested is above MinAddr
|
|||
|
//
|
|||
|
|
|||
|
while (BAddr >= MinAddr) {
|
|||
|
|
|||
|
EAddr = BAddr + LiILen;
|
|||
|
if (EAddr > DescMax) {
|
|||
|
//
|
|||
|
// The ending address is above the requested limit
|
|||
|
// compute the best possible beginning address
|
|||
|
//
|
|||
|
|
|||
|
BAddr = DescMax - LiILen;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (EAddr > BusMax) {
|
|||
|
//
|
|||
|
// The ending address is above the bus'es limit
|
|||
|
// compute best possible beginning address
|
|||
|
//
|
|||
|
|
|||
|
BAddr = BusMax - LiILen;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify selection is within any user supplied requirements
|
|||
|
// (this is from RegistryPath\AssignResources)
|
|||
|
//
|
|||
|
|
|||
|
if (Dir->UserDir) {
|
|||
|
CRes = Dir->UserDir->Alternative->ResourceByType[Res->Type];
|
|||
|
flag = FALSE;
|
|||
|
PBAddr = -1;
|
|||
|
|
|||
|
for (j=0; j < CRes->NoAlternatives; j++) {
|
|||
|
LiTmp = IO_DESC_MIN (CRes->IoResourceDescriptor[j]);
|
|||
|
|
|||
|
if (BAddr < LiTmp) {
|
|||
|
//
|
|||
|
// Beginning address is before user's range, check
|
|||
|
// next descriptor
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
LiTmp = IO_DESC_MAX (CRes->IoResourceDescriptor[j]);
|
|||
|
if (EAddr > LiTmp) {
|
|||
|
|
|||
|
//
|
|||
|
// Ending address is above user's range.
|
|||
|
// Check for new BAddr to continue from
|
|||
|
//
|
|||
|
|
|||
|
LiTmp = LiTmp - LiILen;
|
|||
|
if (LiTmp > PBAddr && LiTmp < BAddr) {
|
|||
|
|
|||
|
//
|
|||
|
// Update next possible setting
|
|||
|
//
|
|||
|
|
|||
|
PBAddr = LiTmp;
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Within user's requested range
|
|||
|
//
|
|||
|
|
|||
|
flag = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (!flag) {
|
|||
|
BAddr = PBAddr;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// So far resource looks good - translate it to system global
|
|||
|
// settings and verify resource is available
|
|||
|
//
|
|||
|
|
|||
|
LiTmp = 0;
|
|||
|
switch (Res->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
case CmResourceTypeMemory:
|
|||
|
j = k = Res->Type == CmResourceTypePort ? 1 : 0;
|
|||
|
flag = HalTranslateBusAddress (
|
|||
|
Dir->IoResourceReq->InterfaceType,
|
|||
|
Dir->IoResourceReq->BusNumber,
|
|||
|
*((PPHYSICAL_ADDRESS) &BAddr),
|
|||
|
&j,
|
|||
|
(PPHYSICAL_ADDRESS) &Trans.BAddr
|
|||
|
);
|
|||
|
|
|||
|
// precheck alignment on first half
|
|||
|
if (Align > 1 && (Trans.BAddr & 0xffffffff00000000) == 0) {
|
|||
|
RtlEnlargedUnsignedDivide (
|
|||
|
*((PULARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp);
|
|||
|
|
|||
|
if (LiTmp & 0xffffffff) {
|
|||
|
break; // alignment is off - don't bother with second translation
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
flag2 = HalTranslateBusAddress (
|
|||
|
Dir->IoResourceReq->InterfaceType,
|
|||
|
Dir->IoResourceReq->BusNumber,
|
|||
|
*((PPHYSICAL_ADDRESS) &EAddr),
|
|||
|
&k,
|
|||
|
(PPHYSICAL_ADDRESS) &Trans.EAddr
|
|||
|
);
|
|||
|
|
|||
|
TType = j == 1 ? CmResourceTypePort : CmResourceTypeMemory;
|
|||
|
Trans.Affinity = (KAFFINITY) -1;
|
|||
|
|
|||
|
if (flag == FALSE || flag2 == FALSE || j != k) {
|
|||
|
// HalAdjustResourceList should ensure that the returned range
|
|||
|
// for the bus is within the bus limits and no translation
|
|||
|
// within those limits should ever fail
|
|||
|
|
|||
|
DBGMSG ("IopGenNextValidDescriptor: Error return for HalTranslateBusAddress\n");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
TType = CmResourceTypeInterrupt;
|
|||
|
|
|||
|
Trans.Affinity = 0;
|
|||
|
Trans.BAddr = HalGetInterruptVector (
|
|||
|
Dir->IoResourceReq->InterfaceType,
|
|||
|
Dir->IoResourceReq->BusNumber,
|
|||
|
(ULONG) BAddr, // bus level
|
|||
|
(ULONG) BAddr, // bus vector
|
|||
|
(PKIRQL) &j, // translated level
|
|||
|
&Trans.Affinity
|
|||
|
);
|
|||
|
|
|||
|
Trans.EAddr = Trans.BAddr;
|
|||
|
|
|||
|
if (Trans.Affinity == 0) {
|
|||
|
// skip vectors which can not be translated
|
|||
|
LiTmp = 1;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
TType = CmResourceTypeDma;
|
|||
|
Trans.BAddr = BAddr;
|
|||
|
Trans.EAddr = EAddr;
|
|||
|
Trans.Affinity = (KAFFINITY) -1;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
DBGMSG ("IopGenNextValidDescriptor: Invalid resource type\n");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check bias from translation
|
|||
|
//
|
|||
|
|
|||
|
if (LiTmp != 0) {
|
|||
|
|
|||
|
// move to next address
|
|||
|
BAddr = BAddr - LiTmp;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check alignment restrictions
|
|||
|
//
|
|||
|
|
|||
|
if (Align > 1) {
|
|||
|
if ((Trans.BAddr & 0xffffffff00000000) == 0) {
|
|||
|
RtlEnlargedUnsignedDivide (
|
|||
|
*((PULARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp);
|
|||
|
} else {
|
|||
|
RtlExtendedLargeIntegerDivide (
|
|||
|
*((PLARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (LiTmp != 0) {
|
|||
|
//
|
|||
|
// Starting address not on proper alignment, move to next
|
|||
|
// aligned address
|
|||
|
//
|
|||
|
|
|||
|
BAddr = BAddr - LiTmp;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check for collision with other settings being considered
|
|||
|
//
|
|||
|
|
|||
|
for (j=0; j < level; j++) {
|
|||
|
if (CurList->RequiredResource[j]->TType == TType) {
|
|||
|
CRes = CurList->RequiredResource[j];
|
|||
|
if (DoesTEntryCollide (Trans, CRes->Trans)) {
|
|||
|
// collision
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (j < level) {
|
|||
|
//
|
|||
|
// Current BAddr - EAddr collides with CRes selection
|
|||
|
//
|
|||
|
|
|||
|
if (j < *collisionlevel) {
|
|||
|
|
|||
|
//
|
|||
|
// If we fail, back up to this level
|
|||
|
//
|
|||
|
|
|||
|
*collisionlevel = j;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try BAddr just best address before collision range
|
|||
|
//
|
|||
|
|
|||
|
BAddr = CRes->CurBAddr - LiELen;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
|
|||
|
//
|
|||
|
// Avoid picking up the resources in In-Processed list for pass
|
|||
|
// no >= 4.
|
|||
|
//
|
|||
|
|
|||
|
if (Res->PassNo >= 4) {
|
|||
|
j = IopFindCollisionInRelocatedList (&Trans,
|
|||
|
IopInProcessedConflicts,
|
|||
|
&pConflictTrans);
|
|||
|
if (j) {
|
|||
|
BAddr = BAddr - j;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
//
|
|||
|
// Check InUse system resources to verify this range is available.
|
|||
|
//
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
j = IopFindCollisionInTList (&Trans,
|
|||
|
Dir->InUseResources.ByType[TType],
|
|||
|
&pConflictTrans);
|
|||
|
#else
|
|||
|
j = IopFindCollisionInTList (&Trans, Dir->InUseResources.ByType[TType]);
|
|||
|
#endif
|
|||
|
if (j) {
|
|||
|
if (Res->PassNo == 3) {
|
|||
|
//
|
|||
|
// Track this collision
|
|||
|
//
|
|||
|
|
|||
|
IopPickupCollisionInTList (
|
|||
|
CurList,
|
|||
|
Res->Type,
|
|||
|
BAddr,
|
|||
|
&Trans,
|
|||
|
Dir->InUseResources.ByType[TType]
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
else if (Res->PassNo > 4) {
|
|||
|
|
|||
|
//
|
|||
|
// Try to resolve the conflict by relocating the resources
|
|||
|
// consumed by other drivers.
|
|||
|
//
|
|||
|
|
|||
|
if (IopRelocateResource (
|
|||
|
Dir,
|
|||
|
CurList,
|
|||
|
TType,
|
|||
|
&Trans,
|
|||
|
pConflictTrans)) {
|
|||
|
|
|||
|
if (Res->PassNo == 6) {
|
|||
|
|
|||
|
//
|
|||
|
// Mark conflict entry in in-used list to be "Deleted"
|
|||
|
// if at pass 6.
|
|||
|
//
|
|||
|
|
|||
|
pConflictTrans->Flags = TENTRY_FLAGS_REMOVED;
|
|||
|
}
|
|||
|
Res->CurBAddr = BAddr;
|
|||
|
Res->TType = TType;
|
|||
|
Res->Trans = Trans;
|
|||
|
Res->CurBLoc = Res->CurLoc + indx;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // _PNP_POWER_
|
|||
|
//
|
|||
|
// This range collides with a resource which is already in use.
|
|||
|
// Moving begining address to next possible setting
|
|||
|
//
|
|||
|
|
|||
|
BAddr = BAddr - j;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if this resource selection is being shared
|
|||
|
//
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
j = IopFindCollisionInTList (&Trans,
|
|||
|
Dir->InUseResources.ByType[TType],
|
|||
|
&pConflictTrans);
|
|||
|
#else
|
|||
|
j = IopFindCollisionInTList (&Trans, Dir->InUseSharableResources.ByType[TType]);
|
|||
|
#endif
|
|||
|
if (j) {
|
|||
|
//
|
|||
|
// Current range collided with a resource which is already in use,
|
|||
|
// but is sharable. If the current required resource is not sharable,
|
|||
|
// then skip this range; otherwise, reduce the preference for this setting.
|
|||
|
//
|
|||
|
|
|||
|
if (Res->PassNo == 1 || Desc[indx]->ShareDisposition != CmResourceShareShared) {
|
|||
|
if (Res->PassNo == 3) {
|
|||
|
//
|
|||
|
// Track this collision
|
|||
|
//
|
|||
|
|
|||
|
IopPickupCollisionInTList (
|
|||
|
CurList,
|
|||
|
Res->Type,
|
|||
|
BAddr,
|
|||
|
&Trans,
|
|||
|
Dir->InUseSharableResources.ByType[TType]
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
// required resource can't be shared, move to next possible setting or
|
|||
|
// this is the Pass#1 and we don't bother with non-preferred settings
|
|||
|
|
|||
|
BAddr = BAddr - j;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
Preference -= 4;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if this resource reserved, but sharable
|
|||
|
//
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
j = IopFindCollisionInTList (&Trans,
|
|||
|
Dir->InUseResources.ByType[TType],
|
|||
|
&pConflictTrans);
|
|||
|
#else
|
|||
|
j = IopFindCollisionInTList (&Trans, Dir->ReservedSharableResources.ByType[TType]);
|
|||
|
#endif
|
|||
|
if (j) {
|
|||
|
//
|
|||
|
// Current range collosided with a resource which is in the
|
|||
|
// ReservedResource list, but is marked sharable. These resources
|
|||
|
// are treated as non-preferred regions.
|
|||
|
//
|
|||
|
|
|||
|
if (Res->PassNo == 1) {
|
|||
|
// don't bother with non-preferred settings on the first pass.
|
|||
|
|
|||
|
BAddr = BAddr - j;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
Preference -= 2;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// BAddr - EAddr is a good selection
|
|||
|
// (BAddr is greater than NBAddr)
|
|||
|
//
|
|||
|
|
|||
|
NBSet = TRUE;
|
|||
|
NBAddr = BAddr;
|
|||
|
|
|||
|
NTType = TType;
|
|||
|
NTrans = Trans;
|
|||
|
NPref = Preference;
|
|||
|
NBLoc = Res->CurLoc + indx;
|
|||
|
break; // check next selector in run
|
|||
|
|
|||
|
} // next BAddr
|
|||
|
} // next descriptor in run
|
|||
|
|
|||
|
if (NBSet) {
|
|||
|
// SUCCESS We have a hit
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// No setting so far, move to next bus ordering descriptor
|
|||
|
//
|
|||
|
|
|||
|
Res->CurBusLoc++;
|
|||
|
CRes = Dir->BusDir->Alternative->ResourceByType[Res->Type];
|
|||
|
|
|||
|
if (Res->CurBusLoc >= CRes->NoAlternatives) {
|
|||
|
//
|
|||
|
// no more bus ordering descriptors, move to next ResRun
|
|||
|
//
|
|||
|
|
|||
|
Res->CurLoc += Res->RunLen;
|
|||
|
Res->RunLen = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DescTmp = CRes->IoResourceDescriptor[Res->CurBusLoc];
|
|||
|
Res->CurBusMin = IO_DESC_MIN (DescTmp);
|
|||
|
Res->CurBusMax = IO_DESC_MAX (DescTmp);
|
|||
|
BusMin = Res->CurBusMin;
|
|||
|
BusMax = Res->CurBusMax;
|
|||
|
NAddr = Res->CurBusMax;
|
|||
|
} // next bus ordering descriptor
|
|||
|
|
|||
|
} while (!NBSet);
|
|||
|
|
|||
|
//
|
|||
|
// We have a setting for this resource. Remember it and return.
|
|||
|
//
|
|||
|
|
|||
|
Res->TType = NTType; // used to detect internal conflicts of translated values
|
|||
|
Res->Trans = NTrans; // "
|
|||
|
|
|||
|
Res->CurPref = NPref; // Return prefernce of setting
|
|||
|
Res->CurBAddr = NBAddr; // Return raw BAddr of resource (used by Phase3&4)
|
|||
|
Res->CurBLoc = NBLoc; // Return location of resource (used by Phase3&4)
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
IopFindCollisionInTList (
|
|||
|
IN PTENTRY SEntry,
|
|||
|
#if _PNP_POWER_
|
|||
|
IN PLTENTRY List,
|
|||
|
OUT PTENTRY *ConflictEntry
|
|||
|
#else
|
|||
|
IN PLTENTRY List
|
|||
|
#endif
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if there's a collision between the source TENTRY and the list
|
|||
|
of TENTRIES passed by PLTENTRY.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
Returns the skew amount required to continue searching for next possible
|
|||
|
setting and a pointer to the conflicted entry.
|
|||
|
A zero skew means no collision occured.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LONGLONG LiTmp;
|
|||
|
TENTRY Source;
|
|||
|
ULONG i, j;
|
|||
|
|
|||
|
Source = *SEntry;
|
|||
|
while (List) {
|
|||
|
j = List->CurEntries;
|
|||
|
for (i=0; i < j; i++) {
|
|||
|
SEntry = List->Table+i;
|
|||
|
#if _PNP_POWER_
|
|||
|
if (SEntry->Flags != TENTRY_FLAGS_REMOVED) {
|
|||
|
#endif
|
|||
|
if (DoesTEntryCollide (Source, *SEntry)) {
|
|||
|
|
|||
|
LiTmp = Source.EAddr - SEntry->BAddr;
|
|||
|
#if _PNP_POWER_
|
|||
|
*ConflictEntry = SEntry;
|
|||
|
#endif
|
|||
|
return (ULONG) LiTmp + 1;
|
|||
|
}
|
|||
|
#if _PNP_POWER_
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
List = List->Next;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
PDIR_RESOURCE_LIST
|
|||
|
IopResolveConflicts (
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine tries to satisfy the current resource settings by relocating
|
|||
|
resources among drivers.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Dir - supplies a pointer to the DIR_RESREQ_LIST for the request.
|
|||
|
|
|||
|
Returned Value:
|
|||
|
|
|||
|
A DIR_RESOURCE_LIST is returned if the relocation succeeded. Else a value
|
|||
|
of NULL is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDIR_RESOURCE_LIST CurList;
|
|||
|
ULONG i;
|
|||
|
PRECONFIGURED_DRIVER tmp;
|
|||
|
BOOLEAN flag;
|
|||
|
BOOLEAN success = FALSE;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|||
|
|
|||
|
//
|
|||
|
// Look for settings - set LastFailed level to pass 6 and try to resolve
|
|||
|
// the conflicts by relocating resources among the drivers.
|
|||
|
//
|
|||
|
|
|||
|
while (1) {
|
|||
|
for (i = CurList->FailedLevel; i < CurList->NoRequiredResources; i++) {
|
|||
|
CurList->RequiredResource[i]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[i]->RunLen = 0;
|
|||
|
CurList->RequiredResource[i]->PassNo = 2;
|
|||
|
}
|
|||
|
CurList->RequiredResource[CurList->FailedLevel]->PassNo = 6;
|
|||
|
success = IopGenNextValidResourceList (CurList->FailedLevel, CurList, Dir);
|
|||
|
if (CurList->RequiredResource[CurList->FailedLevel]->PassNo == 6 ||
|
|||
|
success) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
while (IopReconfiguredDrivers) {
|
|||
|
tmp = IopReconfiguredDrivers;
|
|||
|
if (success) {
|
|||
|
//
|
|||
|
// We have successfully resolved the conflicts. Now for
|
|||
|
// each driver in the IopReconfigDriver List, a Reconfig command is
|
|||
|
// requested.
|
|||
|
//
|
|||
|
|
|||
|
i = 0;
|
|||
|
if (!tmp->DeviceObject) {
|
|||
|
status = IopReportResourceUsage (
|
|||
|
&tmp->DriverClassName,
|
|||
|
tmp->DriverObject, // DriverObject
|
|||
|
tmp->CmResourceList, // DriverList
|
|||
|
tmp->ResourceLength, // DriverListSize
|
|||
|
tmp->DeviceObject, // DeviceObject
|
|||
|
NULL, // DeviceList
|
|||
|
0, // DeviceListSize
|
|||
|
TRUE, // override conflict
|
|||
|
&flag // conflicted detected
|
|||
|
);
|
|||
|
} else {
|
|||
|
status = IopReportResourceUsage (
|
|||
|
&tmp->DriverClassName,
|
|||
|
tmp->DriverObject, // DriverObject
|
|||
|
NULL, // DriverList
|
|||
|
0, // DriverListSize
|
|||
|
tmp->DeviceObject,
|
|||
|
tmp->CmResourceList, // DriverList
|
|||
|
tmp->ResourceLength, // DeviceListSize
|
|||
|
TRUE, // override conflict
|
|||
|
&flag // conflicted detected
|
|||
|
);
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status) && status != STATUS_CONFLICTING_ADDRESSES) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("ResolveConflict: Report resource usage failed\n");
|
|||
|
#endif
|
|||
|
goto BugCheckExit;
|
|||
|
}
|
|||
|
status = IopReconfigureResource(tmp->DriverObject,
|
|||
|
tmp->DeviceObject,
|
|||
|
tmp->CmResourceList);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("ResolveConflict: Driver failed to reconfig resources\n");
|
|||
|
#endif
|
|||
|
goto BugCheckExit;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the resource information to registry. We may need it
|
|||
|
// again to solve conflicts.
|
|||
|
//
|
|||
|
|
|||
|
IopRecordAssignInformation(tmp->ReconfiguredDir,
|
|||
|
&tmp->DriverClassName,
|
|||
|
tmp->DriverObject,
|
|||
|
tmp->DeviceObject,
|
|||
|
tmp->ReconfiguredDir->ListPicked
|
|||
|
);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// We have failed to resolve the conflicts. Now for
|
|||
|
// each driver in the IopReconfigList, a CancelReconfig command is
|
|||
|
// sent to release the driver.
|
|||
|
//
|
|||
|
IopCancelReconfigureResource(tmp->DriverObject,
|
|||
|
tmp->DeviceObject);
|
|||
|
}
|
|||
|
IopReconfiguredDrivers = tmp->Next;
|
|||
|
ObDereferenceObject(tmp->DriverObject);
|
|||
|
if (tmp->DeviceObject) {
|
|||
|
ObDereferenceObject(tmp->DeviceObject);
|
|||
|
}
|
|||
|
RtlFreeUnicodeString(&tmp->DriverClassName);
|
|||
|
if (tmp->CmResourceList) {
|
|||
|
ExFreePool(tmp->CmResourceList);
|
|||
|
}
|
|||
|
ExFreePool(tmp);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clean up and try next list or return success.
|
|||
|
//
|
|||
|
|
|||
|
IopFreeRelocatedResourceDir(IopRelocatedDirList);
|
|||
|
IopRelocatedDirList = NULL;
|
|||
|
IopFreeRelocatedTEntryLists();
|
|||
|
|
|||
|
if (success) {
|
|||
|
return CurList;
|
|||
|
}
|
|||
|
|
|||
|
// Try next resource list
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
BugCheckExit:
|
|||
|
KeBugCheckEx(PNP_INTERNAL_ERROR, status, 0, 0, 0);
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
IopRelocateResource (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN UCHAR TranslatedType,
|
|||
|
IN PTENTRY ConflictEntry,
|
|||
|
IN PTENTRY TranslatedEntry
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine tries to satisfy the Resource settings by relocating resources
|
|||
|
among drivers. Note caller does NOT need to free the returned
|
|||
|
pNewTranslatedEntry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Dir - supplies a pointer to the DIR_RESREQ_LIST for the request.
|
|||
|
|
|||
|
CurList - supplies a pointer to the current DIR_RESOURCE_LIST.
|
|||
|
|
|||
|
Level - Indicates which level of the CurList encountered the conflict.
|
|||
|
|
|||
|
TranslatedType - the resource type.
|
|||
|
|
|||
|
ConflictEntry - supplies a point to a TENTRY which collides with
|
|||
|
TranslatedEntry.
|
|||
|
|
|||
|
TranslatedEntry - supplies a point to a TENTRY whose resources needs
|
|||
|
to be relocated.
|
|||
|
|
|||
|
Returned Value:
|
|||
|
|
|||
|
TRUE - succeed otherwise a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PRECONFIGURED_DRIVER reconfigDriver, tmp;
|
|||
|
NTSTATUS status;
|
|||
|
PDRIVER_OBJECT driverObject = NULL;
|
|||
|
PDEVICE_OBJECT deviceObject = NULL;
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|||
|
ULONG length, listPicked, collisionLevel;
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST ioResources = NULL;
|
|||
|
PREG_REQUIRED_RESOURCE_LIST reportedResources = NULL;
|
|||
|
PDIR_RESREQ_LIST driverDir = NULL, tmpDir;
|
|||
|
PDIR_RESOURCE_LIST resourceList;
|
|||
|
PDIR_REQUIRED_RESOURCE reqRes;
|
|||
|
BOOLEAN found;
|
|||
|
PCM_RESOURCE_LIST cmResources;
|
|||
|
UNICODE_STRING driverClassName = {0, 0, NULL};
|
|||
|
UNICODE_STRING unicodeValueName;
|
|||
|
UNICODE_STRING unicodeName1, unicodeName2;
|
|||
|
HANDLE driverHandle = NULL, resourcesHandle;
|
|||
|
ULONG i;
|
|||
|
LONGLONG li;
|
|||
|
PUSED_HEAP usedHeap;
|
|||
|
HANDLE deviceHandle;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
IO_STATUS_BLOCK ioStatus;
|
|||
|
PFILE_OBJECT fileObject = NULL;
|
|||
|
UCHAR tmpFlags;
|
|||
|
POWNER owner;
|
|||
|
CM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
|
|||
|
PTENTRY trans;
|
|||
|
PTENTRIESBYTYPE byType;
|
|||
|
PIO_RESOURCE_DESCRIPTOR ioDesc;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We need to reconsturct the DIR and all the supporting data structures
|
|||
|
// for the driver to be relocated.
|
|||
|
//
|
|||
|
|
|||
|
if (TranslatedEntry->Owner == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Don't know which driver has the resource. Simply return failure.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (TranslatedEntry->Flags == TENTRY_FLAGS_BEING_RELOCATED) {
|
|||
|
|
|||
|
//
|
|||
|
// To avoid infinite loop.
|
|||
|
//
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// See if the DIR for the relocating resources was built already.
|
|||
|
//
|
|||
|
|
|||
|
tmpDir = IopRelocatedDirList;
|
|||
|
while (tmpDir) {
|
|||
|
if (RtlEqualUnicodeString(&TranslatedEntry->Owner->KeyName,
|
|||
|
&tmpDir->ReconfiguredDriver->Owner->KeyName, TRUE)){
|
|||
|
if (TranslatedEntry->Owner->DeviceName.Length == 0 ||
|
|||
|
RtlEqualUnicodeString(&TranslatedEntry->Owner->DeviceName,
|
|||
|
&tmpDir->ReconfiguredDriver->Owner->KeyName, TRUE )) {
|
|||
|
driverDir = tmpDir;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
tmpDir = tmpDir->FreeResReqList;
|
|||
|
}
|
|||
|
|
|||
|
if (!driverDir) {
|
|||
|
|
|||
|
if (TranslatedEntry->Owner->DeviceName.Length > 0) {
|
|||
|
InitializeObjectAttributes( &objectAttributes,
|
|||
|
&TranslatedEntry->Owner->DeviceName,
|
|||
|
0,
|
|||
|
(HANDLE) NULL,
|
|||
|
(PSECURITY_DESCRIPTOR) NULL );
|
|||
|
status = NtOpenFile( &deviceHandle,
|
|||
|
FILE_READ_ATTRIBUTES,
|
|||
|
&objectAttributes,
|
|||
|
&ioStatus,
|
|||
|
0,
|
|||
|
FILE_NON_DIRECTORY_FILE );
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The device object was located, so convert the handle into a pointer
|
|||
|
// so that the device object itself can be examined.
|
|||
|
//
|
|||
|
|
|||
|
status = ObReferenceObjectByHandle( deviceHandle,
|
|||
|
0,
|
|||
|
IoFileObjectType,
|
|||
|
KernelMode,
|
|||
|
(PVOID *) &fileObject,
|
|||
|
NULL );
|
|||
|
deviceObject = fileObject->DeviceObject;
|
|||
|
NtClose( deviceHandle );
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read ClassName and requested resources information from
|
|||
|
// driver's ServiceKeyName\RequestedResources key.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName2, L"\\Driver\\");
|
|||
|
IopConcatenateUnicodeStrings(&unicodeName1,
|
|||
|
&unicodeName2,
|
|||
|
&TranslatedEntry->Owner->KeyName);
|
|||
|
|
|||
|
//
|
|||
|
// BUGBUG - Can NOT do this!! Will be changed soon...
|
|||
|
//
|
|||
|
|
|||
|
status = ObReferenceObjectByName(&unicodeName1,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
IoDriverObjectType,
|
|||
|
KernelMode,
|
|||
|
NULL,
|
|||
|
&driverObject
|
|||
|
);
|
|||
|
RtlFreeUnicodeString(&unicodeName1);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
status = IopOpenRegistryKey(&resourcesHandle,
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineSystemCurrentControlSetServices,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
status = IopOpenRegistryKey(&driverHandle,
|
|||
|
resourcesHandle,
|
|||
|
&driverObject->DriverExtension->ServiceKeyName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
ZwClose(resourcesHandle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName2, L"ResourceInformation");
|
|||
|
status = IopOpenRegistryKey(&resourcesHandle,
|
|||
|
driverHandle,
|
|||
|
&unicodeName2,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read driver class name (for report resources)
|
|||
|
//
|
|||
|
|
|||
|
status = IopGetRegistryValue (resourcesHandle,
|
|||
|
L"ClassName",
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
if (NT_SUCCESS( status )) {
|
|||
|
status = STATUS_FAIL_CHECK;
|
|||
|
if (keyValueInformation->DataLength != 0L) {
|
|||
|
if (PiRegSzToString((PWCHAR)KEY_VALUE_DATA(keyValueInformation),
|
|||
|
keyValueInformation->DataLength,
|
|||
|
&length,
|
|||
|
&driverClassName.Buffer)) {
|
|||
|
driverClassName.Length = (USHORT)length;
|
|||
|
driverClassName.MaximumLength =
|
|||
|
(USHORT)length + sizeof (UNICODE_NULL);
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(resourcesHandle);
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read driver/device requested and assigned resources
|
|||
|
//
|
|||
|
|
|||
|
if (TranslatedEntry->Owner->DeviceName.Length == 0) {
|
|||
|
RtlInitUnicodeString(&unicodeName1, L"Driver");
|
|||
|
} else {
|
|||
|
unicodeName1 = TranslatedEntry->Owner->DeviceName;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read information on which resource list is picked from
|
|||
|
// resource requirement list.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName2, L".ListPicked");
|
|||
|
IopConcatenateUnicodeStrings(&unicodeValueName,
|
|||
|
&unicodeName1,
|
|||
|
&unicodeName2);
|
|||
|
status = IopGetRegistryValue (resourcesHandle,
|
|||
|
unicodeValueName.Buffer,
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS( status )) {
|
|||
|
status = STATUS_FAIL_CHECK;
|
|||
|
if (keyValueInformation->DataLength != 0L) {
|
|||
|
listPicked = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
RtlFreeUnicodeString(&unicodeValueName);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(resourcesHandle);
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read requested resources
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName2, L".RequestedResources");
|
|||
|
IopConcatenateUnicodeStrings(&unicodeValueName,
|
|||
|
&unicodeName1,
|
|||
|
&unicodeName2);
|
|||
|
status = IopGetRegistryValue (resourcesHandle,
|
|||
|
unicodeValueName.Buffer,
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS( status )) {
|
|||
|
status = STATUS_FAIL_CHECK;
|
|||
|
if (keyValueInformation->DataLength != 0L) {
|
|||
|
usedHeap = (PUSED_HEAP)ExAllocatePool(
|
|||
|
PagedPool,
|
|||
|
keyValueInformation->DataLength + sizeof(USED_HEAP));
|
|||
|
ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST)(usedHeap + 1);
|
|||
|
if (usedHeap) {
|
|||
|
RtlMoveMemory(ioResources,
|
|||
|
KEY_VALUE_DATA(keyValueInformation),
|
|||
|
keyValueInformation->DataLength);
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
RtlFreeUnicodeString(&unicodeValueName);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(resourcesHandle);
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// read reported resources
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName2, L".ReportedResources");
|
|||
|
IopConcatenateUnicodeStrings(&unicodeValueName,
|
|||
|
&unicodeName1,
|
|||
|
&unicodeName2);
|
|||
|
status = IopGetRegistryValue (resourcesHandle,
|
|||
|
unicodeValueName.Buffer,
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS( status )) {
|
|||
|
status = STATUS_FAIL_CHECK;
|
|||
|
if (keyValueInformation->DataLength != 0L) {
|
|||
|
reportedResources = (PREG_REQUIRED_RESOURCE_LIST)ExAllocatePool(
|
|||
|
PagedPool,
|
|||
|
keyValueInformation->DataLength);
|
|||
|
if (reportedResources) {
|
|||
|
RtlMoveMemory(reportedResources,
|
|||
|
KEY_VALUE_DATA(keyValueInformation),
|
|||
|
keyValueInformation->DataLength);
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
RtlFreeUnicodeString(&unicodeValueName);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(usedHeap);
|
|||
|
ZwClose(resourcesHandle);
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
ZwClose(resourcesHandle);
|
|||
|
|
|||
|
//
|
|||
|
// Build a resource directory from the requested list
|
|||
|
//
|
|||
|
// Note the Io resource requirement list returned by hal is not on
|
|||
|
// allocated heap list. We will free it manually.
|
|||
|
//
|
|||
|
|
|||
|
status = IopBuildResourceDir (NULL, &driverDir, ioResources);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("RequestedResources could no be parsed. Status = %lx", status);
|
|||
|
#endif
|
|||
|
ExFreePool(usedHeap);
|
|||
|
ExFreePool(reportedResources);
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// put IoResources onto allocated heap list
|
|||
|
//
|
|||
|
|
|||
|
usedHeap->FreeHeap = (PVOID) usedHeap;
|
|||
|
PushEntryList (&driverDir->AllocatedHeap, &usedHeap->FreeLink);
|
|||
|
|
|||
|
//
|
|||
|
// allocate a scratch buffer
|
|||
|
//
|
|||
|
|
|||
|
driverDir->Buffer = (PWSTR)IopAllocateDirPool (driverDir, BUFFERSIZE);
|
|||
|
if (!driverDir->Buffer) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
#if DBG
|
|||
|
DbgPrint("No memory, status = %lx", status);
|
|||
|
#endif
|
|||
|
goto exit0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Sort the request descriptors such that all alternative descriptor
|
|||
|
// options are grouped by CmResourceType.
|
|||
|
//
|
|||
|
|
|||
|
IopSortDescriptors(driverDir);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize handles from caller's Dir.
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i < MAX_REG_HANDLES; i++) {
|
|||
|
driverDir->RegHandle[i] = Dir->RegHandle[i];
|
|||
|
}
|
|||
|
driverDir->RegHandle[HDEVICE_STORAGE] = driverHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Check for user assigned resources in RegistryPath
|
|||
|
//
|
|||
|
|
|||
|
ioResources = IopGetResourceReqRegistryValue (
|
|||
|
driverDir,
|
|||
|
driverDir->RegHandle[HDEVICE_STORAGE],
|
|||
|
IopWstrAssignedResources
|
|||
|
);
|
|||
|
|
|||
|
if (ioResources) {
|
|||
|
|
|||
|
//
|
|||
|
// Build directory out of user's assignments
|
|||
|
//
|
|||
|
|
|||
|
status = IopBuildResourceDir (driverDir, &driverDir->UserDir, ioResources);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("RelocateResource: Device AssignedResources could not be parsed status = %lx", status);
|
|||
|
#endif
|
|||
|
goto exit0;
|
|||
|
}
|
|||
|
status = IopCatagorizeDescriptors (driverDir->UserDir);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("RelocateResource: Device AssignedResources could not be catagorized, status = %lx", status);
|
|||
|
#endif
|
|||
|
goto exit0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Init bus specific ordering
|
|||
|
//
|
|||
|
|
|||
|
driverDir->BusDir = Dir->BusDir;
|
|||
|
|
|||
|
//
|
|||
|
// Init TENTRIESBYTYPE structures
|
|||
|
//
|
|||
|
|
|||
|
driverDir->InUseResources = Dir->InUseResources;
|
|||
|
driverDir->InUseSharableResources = Dir->InUseSharableResources;
|
|||
|
driverDir->ReservedSharableResources = Dir->ReservedSharableResources;
|
|||
|
|
|||
|
//
|
|||
|
// Init DIR_REQUIRED_RESOURCE structures from reported resources
|
|||
|
//
|
|||
|
|
|||
|
resourceList = driverDir->Alternative;
|
|||
|
for (i = 1; i < listPicked; i++) {
|
|||
|
resourceList = resourceList->Next;
|
|||
|
}
|
|||
|
ASSERT(resourceList->NoRequiredResources = reportedResources->NoRequiredResources);
|
|||
|
driverDir->ListPicked = resourceList;
|
|||
|
for (i = 0; i < reportedResources->NoRequiredResources; i++) {
|
|||
|
resourceList->RequiredResource[i]->Type =
|
|||
|
reportedResources->RegResource[i].Type;
|
|||
|
resourceList->RequiredResource[i]->CurBLoc =
|
|||
|
reportedResources->RegResource[i].CurBLoc;
|
|||
|
resourceList->RequiredResource[i]->CurBAddr =
|
|||
|
reportedResources->RegResource[i].CurBAddr;
|
|||
|
resourceList->RequiredResource[i]->TType =
|
|||
|
reportedResources->RegResource[i].TType;
|
|||
|
resourceList->RequiredResource[i]->Trans =
|
|||
|
reportedResources->RegResource[i].Trans;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Link the new DIR to our DIR list
|
|||
|
//
|
|||
|
|
|||
|
tmpDir = driverDir;
|
|||
|
while (tmpDir->FreeResReqList) {
|
|||
|
tmpDir = driverDir->FreeResReqList;
|
|||
|
}
|
|||
|
tmpDir->FreeResReqList = IopRelocatedDirList;
|
|||
|
IopRelocatedDirList = driverDir;
|
|||
|
|
|||
|
//
|
|||
|
// Create and initialize RECONFIGURE_DRIVER structure for this driverDir
|
|||
|
//
|
|||
|
|
|||
|
reconfigDriver = (PRECONFIGURED_DRIVER)ExAllocatePool(
|
|||
|
PagedPool,
|
|||
|
sizeof(RECONFIGURED_DRIVER));
|
|||
|
if (!reconfigDriver) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exit0;
|
|||
|
}
|
|||
|
driverDir->ReconfiguredDriver = reconfigDriver;
|
|||
|
reconfigDriver->Owner = TranslatedEntry->Owner;
|
|||
|
reconfigDriver->ReconfiguredDir = driverDir;
|
|||
|
reconfigDriver->DriverClassName = driverClassName;
|
|||
|
reconfigDriver->DriverObject = driverObject;
|
|||
|
reconfigDriver->DeviceObject = deviceObject;
|
|||
|
reconfigDriver->DeviceFileObject = fileObject;
|
|||
|
reconfigDriver->CmResourceList = NULL;
|
|||
|
} else {
|
|||
|
|
|||
|
reconfigDriver = driverDir->ReconfiguredDriver;
|
|||
|
//
|
|||
|
// Snapshot the current assignment such that we can recover it if fails.
|
|||
|
//
|
|||
|
|
|||
|
resourceList = driverDir->ListPicked;
|
|||
|
reportedResources = ExAllocatePool(PagedPool,
|
|||
|
sizeof(REG_REQUIRED_RESOURCE_LIST) +
|
|||
|
(resourceList->NoRequiredResources - 1) *
|
|||
|
sizeof(REG_REQUIRED_RESOURCE));
|
|||
|
reportedResources->NoRequiredResources = resourceList->NoRequiredResources;
|
|||
|
for (i = 0; i < reportedResources->NoRequiredResources; i++) {
|
|||
|
reportedResources->RegResource[i].Type =
|
|||
|
resourceList->RequiredResource[i]->Type;
|
|||
|
reportedResources->RegResource[i].CurBLoc =
|
|||
|
resourceList->RequiredResource[i]->CurBLoc;
|
|||
|
reportedResources->RegResource[i].CurBAddr =
|
|||
|
resourceList->RequiredResource[i]->CurBAddr;
|
|||
|
reportedResources->RegResource[i].TType =
|
|||
|
resourceList->RequiredResource[i]->TType;
|
|||
|
reportedResources->RegResource[i].Trans =
|
|||
|
resourceList->RequiredResource[i]->Trans;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// try to regenerate a resource assignment for the requiredResource which
|
|||
|
// is in conflict at pass 4.
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i < resourceList->NoRequiredResources; i++) {
|
|||
|
reqRes = resourceList->RequiredResource[i];
|
|||
|
|
|||
|
//
|
|||
|
// find the required resource which we are interested in.
|
|||
|
//
|
|||
|
|
|||
|
if (TranslatedEntry->BAddr == reqRes->Trans.BAddr &&
|
|||
|
TranslatedEntry->EAddr == reqRes->Trans.EAddr &&
|
|||
|
reqRes->TType == TranslatedType) {
|
|||
|
reqRes->CurLoc = 0;
|
|||
|
reqRes->RunLen = 0;
|
|||
|
reqRes->PassNo = 4;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
ASSERT(i < resourceList->NoRequiredResources);
|
|||
|
|
|||
|
found = IopGenNextValidDescriptor (
|
|||
|
i,
|
|||
|
resourceList,
|
|||
|
driverDir,
|
|||
|
&collisionLevel);
|
|||
|
if (!found) {
|
|||
|
tmpFlags = TranslatedEntry->Flags;
|
|||
|
TranslatedEntry->Flags = TENTRY_FLAGS_BEING_RELOCATED;
|
|||
|
|
|||
|
//
|
|||
|
// Fail go generate a valid assignment at pass 4.
|
|||
|
// Move to pass 5 see if we can relocate other driver(s)
|
|||
|
//
|
|||
|
|
|||
|
reqRes->CurLoc = 0;
|
|||
|
reqRes->RunLen = 0;
|
|||
|
reqRes->PassNo = 5;
|
|||
|
found = IopGenNextValidDescriptor (
|
|||
|
i,
|
|||
|
resourceList,
|
|||
|
driverDir,
|
|||
|
&collisionLevel);
|
|||
|
TranslatedEntry->Flags = tmpFlags;
|
|||
|
}
|
|||
|
|
|||
|
if (found) {
|
|||
|
|
|||
|
//
|
|||
|
// Build CmResourceList from assignments
|
|||
|
//
|
|||
|
|
|||
|
cmResources = IopAssignResourcesPhase4 (
|
|||
|
driverDir,
|
|||
|
resourceList,
|
|||
|
&length);
|
|||
|
if (!cmResources) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exit2;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ask driver if its resources can be reconfigured.
|
|||
|
//
|
|||
|
|
|||
|
status = IopQueryReconfigureResource(
|
|||
|
reconfigDriver->DriverObject,
|
|||
|
reconfigDriver->DeviceObject,
|
|||
|
cmResources);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Link reconfigured driver structure to to IopReconfiguredDrivers
|
|||
|
// list if it has been done.
|
|||
|
//
|
|||
|
|
|||
|
if (reconfigDriver->CmResourceList) {
|
|||
|
ExFreePool(reconfigDriver->CmResourceList);
|
|||
|
}
|
|||
|
reconfigDriver->CmResourceList = cmResources;
|
|||
|
reconfigDriver->ResourceLength = length;
|
|||
|
tmp = IopReconfiguredDrivers;
|
|||
|
while (tmp) {
|
|||
|
if (tmp == reconfigDriver) {
|
|||
|
break;
|
|||
|
}
|
|||
|
tmp = tmp->Next;
|
|||
|
}
|
|||
|
if (!tmp) {
|
|||
|
reconfigDriver->Next = IopReconfiguredDrivers;
|
|||
|
IopReconfiguredDrivers = reconfigDriver;
|
|||
|
}
|
|||
|
|
|||
|
if (reqRes->PassNo == 4) {
|
|||
|
|
|||
|
//
|
|||
|
// the NewTranslatedEntry is return only when we actually
|
|||
|
// allocated *new* resource in pass 4. If we are in PassNo 5,
|
|||
|
// we did not allocate *new* resource, we re-use the resource
|
|||
|
// which is in used.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Build Owner structure for TLIST entries
|
|||
|
//
|
|||
|
|
|||
|
owner = IopAllocateDirPool (driverDir, sizeof (*(TranslatedEntry->Owner)));
|
|||
|
if (!owner) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exit2;
|
|||
|
}
|
|||
|
|
|||
|
owner->InConflict.Flink = NULL;
|
|||
|
owner->DeviceName = TranslatedEntry->Owner->DeviceName;
|
|||
|
owner->KeyName = TranslatedEntry->Owner->KeyName;
|
|||
|
|
|||
|
//
|
|||
|
// Get a new Trans entry in the InUseResource list or the
|
|||
|
// InUseSharableResource list
|
|||
|
//
|
|||
|
|
|||
|
ioDesc = reqRes->IoResourceDescriptor[reqRes->CurBLoc];
|
|||
|
if (ioDesc->ShareDisposition == CmResourceShareShared) {
|
|||
|
byType = &driverDir->InUseSharableResources;
|
|||
|
} else {
|
|||
|
byType = &driverDir->InUseResources;
|
|||
|
}
|
|||
|
trans = IopNewTransEntry (driverDir, byType, reqRes->TType);
|
|||
|
if (!trans) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exit2;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the Trans structure
|
|||
|
//
|
|||
|
|
|||
|
*trans = reqRes->Trans;
|
|||
|
trans->Owner = owner;
|
|||
|
trans->Flags = TENTRY_FLAGS_IN_USE;
|
|||
|
|
|||
|
//
|
|||
|
// Add new translated entry to New Resource list
|
|||
|
//
|
|||
|
|
|||
|
if (!IopAddRelocatedEntry(&IopNewResources,
|
|||
|
trans,
|
|||
|
reqRes->TType,
|
|||
|
owner)) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto exit2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add the conflict entry to Conflict InProcessed list
|
|||
|
//
|
|||
|
owner = NULL;
|
|||
|
if (Dir->ReconfiguredDriver) {
|
|||
|
owner = Dir->ReconfiguredDriver->Owner;
|
|||
|
}
|
|||
|
if (!IopAddRelocatedEntry(&IopInProcessedConflicts,
|
|||
|
TranslatedEntry,
|
|||
|
TranslatedType,
|
|||
|
owner
|
|||
|
)) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
status = STATUS_CONFLICTING_ADDRESSES;
|
|||
|
}
|
|||
|
|
|||
|
exit2:
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
if (driverDir) {
|
|||
|
resourceList = driverDir->ListPicked;
|
|||
|
for (i = 0; i < reportedResources->NoRequiredResources; i++) {
|
|||
|
resourceList->RequiredResource[i]->Type =
|
|||
|
reportedResources->RegResource[i].Type;
|
|||
|
resourceList->RequiredResource[i]->CurBLoc =
|
|||
|
reportedResources->RegResource[i].CurBLoc;
|
|||
|
resourceList->RequiredResource[i]->CurBAddr =
|
|||
|
reportedResources->RegResource[i].CurBAddr;
|
|||
|
resourceList->RequiredResource[i]->TType =
|
|||
|
reportedResources->RegResource[i].TType;
|
|||
|
resourceList->RequiredResource[i]->Trans =
|
|||
|
reportedResources->RegResource[i].Trans;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (reportedResources) {
|
|||
|
ExFreePool(reportedResources);
|
|||
|
}
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return FALSE;
|
|||
|
} else {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
exit0:
|
|||
|
IopFreeResourceDir(driverDir);
|
|||
|
if (reportedResources) {
|
|||
|
ExFreePool(reportedResources);
|
|||
|
}
|
|||
|
exit1:
|
|||
|
if (driverObject) {
|
|||
|
ObDereferenceObject(driverObject);
|
|||
|
}
|
|||
|
if (driverHandle) {
|
|||
|
ZwClose(driverHandle);
|
|||
|
}
|
|||
|
if (deviceObject) {
|
|||
|
ObDereferenceObject( fileObject );
|
|||
|
ObDereferenceObject(deviceObject);
|
|||
|
}
|
|||
|
if (driverClassName.Length != 0) {
|
|||
|
ExFreePool(driverClassName.Buffer);
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopRecordAssignInformation(
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PUNICODE_STRING DriverClassName,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PDIR_RESOURCE_LIST CurList
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine saves resource assignment related information to
|
|||
|
registry. We may need it later to resolve resource conflicts.
|
|||
|
If this routine fails to save the information, it is not fatal. But
|
|||
|
we won't be able to reconfigure the resources of the driver.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Dir - Supplies a pointer to the DIR_RESREQ_LIST of the resource list
|
|||
|
|
|||
|
DriverClassName - Supplies a pointer to the Driver's class name. It is
|
|||
|
used to partition allocated resources into different device classes.
|
|||
|
|
|||
|
DriverObject - Supplies a pointer to the driver object of the caller.
|
|||
|
|
|||
|
DeviceObject - Supplies a pointer to the device object of the caller.
|
|||
|
If non-null, then requested resoruce list refers to this device.
|
|||
|
If null, the requested resource list refers to the driver.
|
|||
|
|
|||
|
CurDir - supplies a pointer to the selected DIR_RESOURCE_LIST.
|
|||
|
|
|||
|
Returned Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
HANDLE driverHandle, handle;
|
|||
|
NTSTATUS status;
|
|||
|
UNICODE_STRING unicodeName1, unicodeName2, unicodeValueName;
|
|||
|
ULONG i, length;
|
|||
|
POBJECT_NAME_INFORMATION obNameInfo;
|
|||
|
PDIR_RESOURCE_LIST resourceList;
|
|||
|
PREG_REQUIRED_RESOURCE_LIST regList;
|
|||
|
PREG_REQUIRED_RESOURCE regResource;
|
|||
|
PDIR_REQUIRED_RESOURCE reqResource;
|
|||
|
|
|||
|
//
|
|||
|
// Open CCS\ServiceKeyName\ResourceInformation key for the driver
|
|||
|
//
|
|||
|
|
|||
|
status = IopOpenRegistryKey(&handle,
|
|||
|
NULL,
|
|||
|
&CmRegistryMachineSystemCurrentControlSetServices,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
status = IopOpenRegistryKey(&driverHandle,
|
|||
|
handle,
|
|||
|
&DriverObject->DriverExtension->ServiceKeyName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
ZwClose(handle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName2, L"ResourceInformation");
|
|||
|
status = IopOpenRegistryKey(&handle,
|
|||
|
driverHandle,
|
|||
|
&unicodeName2,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Write driver class name (for report resources)
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName1, L"ClassName");
|
|||
|
if (DriverClassName == NULL) {
|
|||
|
RtlInitUnicodeString(&unicodeName2, L"OtherDrivers");
|
|||
|
DriverClassName = &unicodeName2;
|
|||
|
}
|
|||
|
|
|||
|
ZwSetValueKey(handle,
|
|||
|
&unicodeName1,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_SZ,
|
|||
|
DriverClassName->Buffer,
|
|||
|
DriverClassName->Length + sizeof(UNICODE_NULL)
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Form ValueName.
|
|||
|
//
|
|||
|
|
|||
|
obNameInfo = (POBJECT_NAME_INFORMATION) Dir->Buffer;
|
|||
|
if (DeviceObject) {
|
|||
|
status = ObQueryNameString (DeviceObject,
|
|||
|
obNameInfo,
|
|||
|
BUFFERSIZE,
|
|||
|
&i);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto exit1;
|
|||
|
}
|
|||
|
unicodeName1 = obNameInfo->Name;
|
|||
|
} else {
|
|||
|
RtlInitUnicodeString(&unicodeName1, L"Driver");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save requested resources under Driver/DeviceName.RequestedResources
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &unicodeName2, L".RequestedResources");
|
|||
|
IopConcatenateUnicodeStrings(&unicodeValueName,
|
|||
|
&unicodeName1,
|
|||
|
&unicodeName2);
|
|||
|
ZwSetValueKey( handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_BINARY,
|
|||
|
Dir->IoResourceReq,
|
|||
|
Dir->IoResourceReq->ListSize
|
|||
|
);
|
|||
|
RtlFreeUnicodeString(&unicodeValueName);
|
|||
|
|
|||
|
//
|
|||
|
// Find out which DIR_RESOURCE_LIST was picked and save its data
|
|||
|
// in Driver/DeviceName.ListPicked and .ReportedResources
|
|||
|
//
|
|||
|
|
|||
|
resourceList = Dir->Alternative;
|
|||
|
i = 1;
|
|||
|
while (resourceList) {
|
|||
|
if (CurList == resourceList) {
|
|||
|
break;
|
|||
|
}
|
|||
|
resourceList = resourceList->Next;
|
|||
|
i++;
|
|||
|
}
|
|||
|
ASSERT(resourceList != NULL);
|
|||
|
|
|||
|
//
|
|||
|
// Save Driver/DeviceName.ListPicked =
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &unicodeName2, L".ListPicked");
|
|||
|
IopConcatenateUnicodeStrings(&unicodeValueName,
|
|||
|
&unicodeName1,
|
|||
|
&unicodeName2);
|
|||
|
ZwSetValueKey( handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&i,
|
|||
|
sizeof(i)
|
|||
|
);
|
|||
|
RtlFreeUnicodeString(&unicodeValueName);
|
|||
|
|
|||
|
//
|
|||
|
// Build REG_REQUIRED_RESOURCE_LIST
|
|||
|
//
|
|||
|
|
|||
|
length = sizeof(REG_REQUIRED_RESOURCE_LIST) + sizeof(REG_REQUIRED_RESOURCE)
|
|||
|
* (CurList->NoRequiredResources - 1);
|
|||
|
regList = ExAllocatePool(PagedPool, length);
|
|||
|
regList->NoRequiredResources = CurList->NoRequiredResources;
|
|||
|
length = sizeof(regList->NoRequiredResources);
|
|||
|
for (i = 0; i < CurList->NoRequiredResources; i++) {
|
|||
|
regResource = ®List->RegResource[i];
|
|||
|
reqResource = CurList->RequiredResource[i];
|
|||
|
regResource->Type = reqResource->Type;
|
|||
|
regResource->CurBLoc = reqResource->CurBLoc;
|
|||
|
regResource->CurBAddr = reqResource->CurBAddr;
|
|||
|
regResource->TType = reqResource->TType;
|
|||
|
regResource->Trans = reqResource->Trans;
|
|||
|
length += sizeof(REG_REQUIRED_RESOURCE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the REG_REQUIRED_RESOURCE_LIST to Driver/DeviceName.ReportedResources
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &unicodeName2, L".ReportedResources");
|
|||
|
IopConcatenateUnicodeStrings(&unicodeValueName,
|
|||
|
&unicodeName1,
|
|||
|
&unicodeName2);
|
|||
|
ZwSetValueKey( handle,
|
|||
|
&unicodeValueName,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_BINARY,
|
|||
|
regList,
|
|||
|
length
|
|||
|
);
|
|||
|
RtlFreeUnicodeString(&unicodeValueName);
|
|||
|
ExFreePool(regList);
|
|||
|
exit1:
|
|||
|
ZwClose(handle);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopQueryReconfigureResource(
|
|||
|
PDRIVER_OBJECT DriverObject,
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PCM_RESOURCE_LIST CmResources
|
|||
|
)
|
|||
|
{
|
|||
|
return STATUS_SUCCESS;
|
|||
|
//return STATUS_NOT_IMPLEMENTED;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopReconfigureResource(
|
|||
|
PDRIVER_OBJECT DriverObject,
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PCM_RESOURCE_LIST CmResources
|
|||
|
)
|
|||
|
{
|
|||
|
return STATUS_SUCCESS;
|
|||
|
//return STATUS_NOT_IMPLEMENTED;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopCancelReconfigureResource(
|
|||
|
PDRIVER_OBJECT DriverObject,
|
|||
|
PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
{
|
|||
|
return STATUS_SUCCESS;
|
|||
|
//return STATUS_NOT_IMPLEMENTED;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
IopFreeRelocatedTEntryLists(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Frees pool used to resolve resource conflicts. Note, we free the
|
|||
|
RELOCATED_TENTRIES structure but leave the TENTRY in the structure.
|
|||
|
The TENTRY structure will be freed by resource dir free routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PRELOCATED_TENTRIES tmp;
|
|||
|
|
|||
|
while (IopInProcessedConflicts) {
|
|||
|
tmp = IopInProcessedConflicts;
|
|||
|
IopInProcessedConflicts = IopInProcessedConflicts->Next;
|
|||
|
ExFreePool(tmp);
|
|||
|
}
|
|||
|
while (IopNewResources) {
|
|||
|
tmp = IopNewResources;
|
|||
|
IopNewResources = IopNewResources->Next;
|
|||
|
ExFreePool(tmp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
IopFindCollisionInRelocatedList (
|
|||
|
IN PTENTRY SEntry,
|
|||
|
IN PRELOCATED_TENTRIES List,
|
|||
|
OUT PTENTRY *ConflictEntry
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks to see if there's a collision between the source TENTRY and the list
|
|||
|
of RELOCATED_TENTRIES passed by List.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
Returns the skew amount required to continue searching for next possible
|
|||
|
setting and a pointer to the conflicted entry.
|
|||
|
A zero skew means no collision occured.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
LONGLONG liTmp;
|
|||
|
TENTRY source;
|
|||
|
|
|||
|
source = *SEntry;
|
|||
|
while (List) {
|
|||
|
SEntry = List->TranslatedEntry;
|
|||
|
if (DoesTEntryCollide (source, *SEntry)) {
|
|||
|
liTmp = source.EAddr - SEntry->BAddr;
|
|||
|
*ConflictEntry = SEntry;
|
|||
|
return (ULONG) liTmp + 1;
|
|||
|
}
|
|||
|
List = List->Next;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
IopAddRelocatedEntry (
|
|||
|
IN PRELOCATED_TENTRIES *List,
|
|||
|
IN PTENTRY Entry,
|
|||
|
IN UCHAR Type,
|
|||
|
IN POWNER NewOwner
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine add Entry to the specified RELOCATED_ENTRIES list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value
|
|||
|
|
|||
|
TRUE - succeeded. FALSE - failed.
|
|||
|
--*/
|
|||
|
{
|
|||
|
PRELOCATED_TENTRIES pRelocatedEntry;
|
|||
|
|
|||
|
if (Entry == NULL) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Is the entry already in the specified list
|
|||
|
//
|
|||
|
|
|||
|
pRelocatedEntry = *List;
|
|||
|
while (pRelocatedEntry) {
|
|||
|
if (pRelocatedEntry->TranslatedEntry == Entry) {
|
|||
|
break;
|
|||
|
}
|
|||
|
pRelocatedEntry = pRelocatedEntry->Next;
|
|||
|
}
|
|||
|
if (!pRelocatedEntry) {
|
|||
|
pRelocatedEntry = (PRELOCATED_TENTRIES)ExAllocatePool(
|
|||
|
PagedPool,
|
|||
|
sizeof(RELOCATED_TENTRIES));
|
|||
|
if (!pRelocatedEntry) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("IoAssignResource P4: Failed to allocate memory for InProcess list");
|
|||
|
#endif
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remember the names of the FIRST owner (i.e. the owner before the relocation began)
|
|||
|
//
|
|||
|
|
|||
|
pRelocatedEntry->OriginalDriver = Entry->Owner->KeyName;
|
|||
|
pRelocatedEntry->OriginalDevice = Entry->Owner->DeviceName;
|
|||
|
pRelocatedEntry->Next = *List;
|
|||
|
*List = pRelocatedEntry;
|
|||
|
pRelocatedEntry->Type = Type;
|
|||
|
pRelocatedEntry->TranslatedEntry = Entry;
|
|||
|
}
|
|||
|
Entry->Owner = NewOwner;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
IopFreeRelocatedResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST DirResourceList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does a special handling to the DIR_RESREQ_LIST used
|
|||
|
to relocate driver resources before calling IopFreeResourceDir.
|
|||
|
Note, the FreeResReqList should be NULL for relocated driver
|
|||
|
resource dir.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DirResourceList - supplies a pointer to the DIR_RESREQ_LIST used
|
|||
|
to relocate driver resources.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
PDIR_RESREQ_LIST tmpDir;
|
|||
|
|
|||
|
//
|
|||
|
// Close any opened handles
|
|||
|
//
|
|||
|
|
|||
|
tmpDir = DirResourceList;
|
|||
|
while (tmpDir) {
|
|||
|
for (i=0; i< MAX_REG_HANDLES; i++) {
|
|||
|
if (i != HDEVICE_STORAGE) {
|
|||
|
tmpDir->RegHandle[i] = INVALID_HANDLE;
|
|||
|
}
|
|||
|
}
|
|||
|
tmpDir = tmpDir->FreeResReqList;
|
|||
|
}
|
|||
|
IopFreeResourceDir(DirResourceList);
|
|||
|
}
|
|||
|
#endif // _PNP_POWER_
|
|||
|
|
|||
|
VOID
|
|||
|
IopPickupCollisionInTList (
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
IN UCHAR Type,
|
|||
|
IN LONGLONG BAddr,
|
|||
|
IN PTENTRY SEntry,
|
|||
|
IN PLTENTRY List
|
|||
|
)
|
|||
|
{
|
|||
|
TENTRY Source;
|
|||
|
ULONG i, j, conflicts;
|
|||
|
|
|||
|
Source = *SEntry;
|
|||
|
|
|||
|
//
|
|||
|
// If resource already listed in easy collision list, skip it
|
|||
|
//
|
|||
|
|
|||
|
j = CurList->Conflict.NoConflicts;
|
|||
|
if (j > SCONFLICT) {
|
|||
|
j = SCONFLICT;
|
|||
|
}
|
|||
|
|
|||
|
for (i=0; i < j; i++) {
|
|||
|
if (CurList->Conflict.EasyConflict[i].BAddr == BAddr &&
|
|||
|
CurList->Conflict.EasyConflict[i].Type == Type) {
|
|||
|
return ;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add valid, but conflicting, resource setting to failed list
|
|||
|
//
|
|||
|
|
|||
|
conflicts = CurList->Conflict.NoConflicts;
|
|||
|
if (conflicts < SCONFLICT) {
|
|||
|
CurList->Conflict.EasyConflict[conflicts].Type = Type;
|
|||
|
CurList->Conflict.EasyConflict[conflicts].BAddr = BAddr;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find collision
|
|||
|
//
|
|||
|
|
|||
|
while (List) {
|
|||
|
j = List->CurEntries;
|
|||
|
for (i=0; i < j; i++) {
|
|||
|
SEntry = List->Table+i;
|
|||
|
if (DoesTEntryCollide (Source, *SEntry)) {
|
|||
|
|
|||
|
if (SEntry->Owner) {
|
|||
|
if (conflicts < SCONFLICT) {
|
|||
|
CurList->Conflict.EasyConflict[conflicts].Owner = SEntry->Owner;
|
|||
|
SEntry->Owner->InConflict.Flink = (PVOID) -1;
|
|||
|
}
|
|||
|
|
|||
|
if (SEntry->Owner->InConflict.Flink == NULL) {
|
|||
|
//
|
|||
|
// Add owner of this conflict to list of colliding owners
|
|||
|
//
|
|||
|
|
|||
|
InsertTailList (&CurList->Conflict.OtherConflicts, &SEntry->Owner->InConflict);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
CurList->Conflict.NoConflicts += 1;
|
|||
|
return ;
|
|||
|
}
|
|||
|
}
|
|||
|
List = List->Next;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
STATIC PVOID
|
|||
|
IopAllocateDirPool (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocates pool and links the allocation to the DIR_RESREQ_LIST structure so it will be freed
|
|||
|
when the DIR_RESRES_LIST is freed.
|
|||
|
|
|||
|
WARNING: Just like ExAllocatePool this function needs to return memory aligned on 8 byte
|
|||
|
boundaries.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PUSED_HEAP ph;
|
|||
|
|
|||
|
ph = (PUSED_HEAP) ExAllocatePool (PagedPool, Length+sizeof(USED_HEAP));
|
|||
|
if (!ph) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
ph->FreeHeap = (PVOID) ph;
|
|||
|
PushEntryList (&Dir->AllocatedHeap, &ph->FreeLink);
|
|||
|
return (PVOID) (ph+1);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST
|
|||
|
IopGetResourceReqRegistryValue (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PWSTR ValueName
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Looks up the setting for ValueKey in KeyHandle and returns the
|
|||
|
data or NULL. If non-null, the memory was obtained via pool.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PKEY_VALUE_FULL_INFORMATION KeyInformation;
|
|||
|
NTSTATUS status;
|
|||
|
PUCHAR Data;
|
|||
|
ULONG DataLength, Type;
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST p;
|
|||
|
|
|||
|
for (; ;) {
|
|||
|
status = IopGetRegistryValue (KeyHandle, ValueName, &KeyInformation);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get pointer to data & length
|
|||
|
//
|
|||
|
|
|||
|
Type = KeyInformation->Type;
|
|||
|
Data = ((PUCHAR) KeyInformation + KeyInformation->DataOffset);
|
|||
|
DataLength = KeyInformation->DataLength;
|
|||
|
|
|||
|
//
|
|||
|
// Copy data to aligned paged pool buffer, and free non-paged pool
|
|||
|
//
|
|||
|
|
|||
|
p = (PIO_RESOURCE_REQUIREMENTS_LIST) IopAllocateDirPool (Dir, DataLength + sizeof (WCHAR));
|
|||
|
if (!p) {
|
|||
|
ExFreePool (KeyInformation);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory (p, Data, DataLength);
|
|||
|
ExFreePool (KeyInformation);
|
|||
|
|
|||
|
if (Type == REG_SZ) {
|
|||
|
//
|
|||
|
// Forward to different entry - Need to copy name in order to get
|
|||
|
// space at the end to add the NULL terminator
|
|||
|
//
|
|||
|
|
|||
|
ValueName = (PWSTR) p;
|
|||
|
ValueName [DataLength / sizeof (WCHAR)] = 0;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// verify registry entry is of expected type
|
|||
|
if (Type != REG_RESOURCE_REQUIREMENTS_LIST) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
p->ListSize = DataLength;
|
|||
|
return p;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopAssignResourcesPhase1 (
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST *pCopiedList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Copies the callers supplied resource list and passes it to the HAL. The HAL
|
|||
|
then adjusts the requested resource list to be within any bus/system requirements
|
|||
|
the system may have.
|
|||
|
|
|||
|
Arguments:
|
|||
|
IoResources - Callers requested resource list
|
|||
|
*pCopiedList - Returned resource list (allocated from heap)
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PIO_RESOURCE_LIST ResourceList;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG cnt, length;
|
|||
|
PUCHAR FirstAddress, LastAddress;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Verify Version & Revision of data structure is set correctly
|
|||
|
//
|
|||
|
|
|||
|
if (IoResources->AlternativeLists == 0 ||
|
|||
|
IoResources->Reserved[0] != 0 ||
|
|||
|
IoResources->Reserved[1] != 0 ||
|
|||
|
IoResources->Reserved[2] != 0) {
|
|||
|
DBGMSG ("IopAssignResourcesPhase1: Bad structure format\n");
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Pass a copy of the list to the HAL for any adjustments
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Simple sanity check for size of callers RequestedResource list
|
|||
|
//
|
|||
|
|
|||
|
ResourceList = IoResources->List;
|
|||
|
FirstAddress = (PUCHAR) ResourceList;
|
|||
|
LastAddress = (PUCHAR) IoResources + IoResources->ListSize;
|
|||
|
|
|||
|
for (cnt=0; cnt < IoResources->AlternativeLists; cnt++) {
|
|||
|
if (ResourceList->Version != 1 || ResourceList->Revision < 1) {
|
|||
|
DBGMSG ("IopAssignResourcesPhase1: Invalid version #\n");
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
ResourceList = (PIO_RESOURCE_LIST)
|
|||
|
(&ResourceList->Descriptors[ResourceList->Count]);
|
|||
|
|
|||
|
|
|||
|
if ((PUCHAR) ResourceList < FirstAddress ||
|
|||
|
(PUCHAR) ResourceList > LastAddress) {
|
|||
|
DBGMSG ("IopAssignResourcesPhase1: IO_RESOURCE_LIST.ListSize too small\n");
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
length = (ULONG) ((PUCHAR) ResourceList - (PUCHAR) IoResources);
|
|||
|
|
|||
|
//
|
|||
|
// Copy user's passed in list
|
|||
|
//
|
|||
|
|
|||
|
*pCopiedList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool (PagedPool, length);
|
|||
|
|
|||
|
if (!*pCopiedList) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory (*pCopiedList, IoResources, length);
|
|||
|
(*pCopiedList)->ListSize = length;
|
|||
|
|
|||
|
//
|
|||
|
// Let hal adjust the requested list
|
|||
|
//
|
|||
|
|
|||
|
status = HalAdjustResourceList (pCopiedList);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DBGMSG ("IopAssignResourcesPhase1: HalAdjustResourceList failed\n");
|
|||
|
ExFreePool (*pCopiedList);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopAssignResourcesPhase2 (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PUNICODE_STRING DriverClassName,
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
/*
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Reads the ResourceMap in the registry and builds a canonical list of
|
|||
|
all in use resources ranges by resource type.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Dir - InUseResources & InUseShareableResources are filled in by this call.
|
|||
|
|
|||
|
*/
|
|||
|
{
|
|||
|
HANDLE ResourceMap, ClassKeyHandle, DriverKeyHandle;
|
|||
|
ULONG ClassKeyIndex, DriverKeyIndex, DriverValueIndex, Index;
|
|||
|
POBJECT_NAME_INFORMATION ObNameInfo;
|
|||
|
PCM_RESOURCE_LIST CmResList;
|
|||
|
PCM_FULL_RESOURCE_DESCRIPTOR CmFResDesc;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
UNICODE_STRING KeyName, TranslatedName, DriverName, DClassName;
|
|||
|
PVOID p2;
|
|||
|
ULONG BufferSize;
|
|||
|
union {
|
|||
|
PVOID Buffer;
|
|||
|
PKEY_BASIC_INFORMATION KeyBInf;
|
|||
|
PKEY_FULL_INFORMATION KeyFInf;
|
|||
|
PKEY_VALUE_FULL_INFORMATION VKeyFInf;
|
|||
|
} U;
|
|||
|
PUCHAR LastAddr;
|
|||
|
ULONG junk, Length, i, j, TranslatedStrLen, BusTranslatedStrLen;
|
|||
|
PWSTR pw;
|
|||
|
NTSTATUS status;
|
|||
|
BOOLEAN sameClass, sameDriver;
|
|||
|
BOOLEAN flag;
|
|||
|
POWNER Owner;
|
|||
|
LONGLONG li;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a scratch buffer. Use BUFFSERSIZE or the sizeof the largest
|
|||
|
// value in SystemResources\ReservedResources
|
|||
|
//
|
|||
|
|
|||
|
U.Buffer = Dir->Buffer;
|
|||
|
U.KeyFInf->MaxValueNameLen = U.KeyFInf->MaxValueDataLen = 0;
|
|||
|
ZwQueryKey( Dir->RegHandle[HRESERVEDRESOURCES],
|
|||
|
KeyFullInformation,
|
|||
|
U.KeyFInf,
|
|||
|
BUFFERSIZE,
|
|||
|
&junk );
|
|||
|
|
|||
|
Length = sizeof( KEY_VALUE_FULL_INFORMATION ) +
|
|||
|
U.KeyFInf->MaxValueNameLen + U.KeyFInf->MaxValueDataLen + sizeof(UNICODE_NULL);
|
|||
|
|
|||
|
BufferSize = Length > BUFFERSIZE ? Length : BUFFERSIZE;
|
|||
|
U.Buffer = ExAllocatePool (PagedPool, BufferSize);
|
|||
|
if (!U.Buffer) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build translated registry name to watch for
|
|||
|
//
|
|||
|
|
|||
|
ObNameInfo = (POBJECT_NAME_INFORMATION) Dir->Buffer;
|
|||
|
if (DeviceObject) {
|
|||
|
status = ObQueryNameString (DeviceObject, ObNameInfo, BUFFERSIZE, &Length);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
} else {
|
|||
|
ObNameInfo->Name.Length = 0;
|
|||
|
ObNameInfo->Name.Buffer = (PVOID) ((PUCHAR) Dir->Buffer + sizeof(OBJECT_NAME_INFORMATION));
|
|||
|
}
|
|||
|
|
|||
|
ObNameInfo->Name.MaximumLength = BUFFERSIZE - sizeof(OBJECT_NAME_INFORMATION);
|
|||
|
RtlAppendUnicodeToString (&ObNameInfo->Name, IopWstrTranslated);
|
|||
|
|
|||
|
TranslatedName.Length = ObNameInfo->Name.Length;
|
|||
|
TranslatedName.MaximumLength = ObNameInfo->Name.Length;
|
|||
|
TranslatedName.Buffer = IopAllocateDirPool (Dir, TranslatedName.Length);
|
|||
|
if (!TranslatedName.Buffer) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
RtlCopyMemory (TranslatedName.Buffer, ObNameInfo->Name.Buffer, TranslatedName.Length);
|
|||
|
for (TranslatedStrLen=0; IopWstrTranslated[TranslatedStrLen]; TranslatedStrLen++) ;
|
|||
|
for (BusTranslatedStrLen=0; IopWstrBusTranslated[BusTranslatedStrLen]; BusTranslatedStrLen++) ;
|
|||
|
TranslatedStrLen *= sizeof (WCHAR);
|
|||
|
BusTranslatedStrLen *= sizeof (WCHAR);
|
|||
|
|
|||
|
//
|
|||
|
// Build driver name to watch for
|
|||
|
//
|
|||
|
|
|||
|
status = ObQueryNameString (DriverObject, ObNameInfo, BUFFERSIZE, &Length);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
i = 0;
|
|||
|
pw = ObNameInfo->Name.Buffer;
|
|||
|
while (*pw) {
|
|||
|
if (*pw++ == OBJ_NAME_PATH_SEPARATOR) {
|
|||
|
i = pw - ObNameInfo->Name.Buffer;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Length = ObNameInfo->Name.Length - i * sizeof (WCHAR);
|
|||
|
DriverName.Length = (USHORT) Length;
|
|||
|
DriverName.MaximumLength = (USHORT) Length;
|
|||
|
DriverName.Buffer = IopAllocateDirPool (Dir, Length);
|
|||
|
if (!DriverName.Buffer) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
RtlCopyMemory (DriverName.Buffer, ObNameInfo->Name.Buffer + i, Length);
|
|||
|
|
|||
|
//
|
|||
|
// If no give driver class, use default
|
|||
|
//
|
|||
|
|
|||
|
if (!DriverClassName) {
|
|||
|
RtlInitUnicodeString( &DClassName, IopWstrOtherDrivers );
|
|||
|
DriverClassName = &DClassName;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Walk resource map and collect any inuse resources
|
|||
|
//
|
|||
|
|
|||
|
ResourceMap = Dir->RegHandle[HRESOURCE_MAP];
|
|||
|
ClassKeyIndex = 0;
|
|||
|
|
|||
|
ClassKeyHandle = INVALID_HANDLE;
|
|||
|
DriverKeyHandle = INVALID_HANDLE;
|
|||
|
|
|||
|
while (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the class information
|
|||
|
//
|
|||
|
|
|||
|
status = ZwEnumerateKey( ResourceMap,
|
|||
|
ClassKeyIndex++,
|
|||
|
KeyBasicInformation,
|
|||
|
U.KeyBInf,
|
|||
|
BufferSize,
|
|||
|
&junk );
|
|||
|
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Create a UNICODE_STRING using the counted string passed back to
|
|||
|
// us in the information structure, and open the class key.
|
|||
|
//
|
|||
|
|
|||
|
KeyName.Buffer = (PWSTR) U.KeyBInf->Name;
|
|||
|
KeyName.Length = (USHORT) U.KeyBInf->NameLength;
|
|||
|
KeyName.MaximumLength = (USHORT) U.KeyBInf->NameLength;
|
|||
|
|
|||
|
status = IopOpenRegistryKey( &ClassKeyHandle,
|
|||
|
ResourceMap,
|
|||
|
&KeyName,
|
|||
|
KEY_READ,
|
|||
|
FALSE );
|
|||
|
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if we are in the same call node.
|
|||
|
//
|
|||
|
|
|||
|
sameClass = RtlEqualUnicodeString( DriverClassName, &KeyName, TRUE );
|
|||
|
|
|||
|
DriverKeyIndex = 0;
|
|||
|
while (NT_SUCCESS (status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Get the class information
|
|||
|
//
|
|||
|
|
|||
|
status = ZwEnumerateKey( ClassKeyHandle,
|
|||
|
DriverKeyIndex++,
|
|||
|
KeyBasicInformation,
|
|||
|
U.KeyBInf,
|
|||
|
BufferSize,
|
|||
|
&junk );
|
|||
|
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create a UNICODE_STRING using the counted string passed back to
|
|||
|
// us in the information structure, and open the class key.
|
|||
|
//
|
|||
|
// This is read from the key we created, and the name
|
|||
|
// was NULL terminated.
|
|||
|
//
|
|||
|
|
|||
|
KeyName.Buffer = (PWSTR) IopAllocateDirPool (Dir, U.KeyBInf->NameLength);
|
|||
|
if (!KeyName.Buffer) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory (KeyName.Buffer, U.KeyBInf->Name, U.KeyBInf->NameLength);
|
|||
|
KeyName.Length = (USHORT) U.KeyBInf->NameLength;
|
|||
|
KeyName.MaximumLength = (USHORT) U.KeyBInf->NameLength;
|
|||
|
|
|||
|
status = IopOpenRegistryKey( &DriverKeyHandle,
|
|||
|
ClassKeyHandle,
|
|||
|
&KeyName,
|
|||
|
KEY_READ,
|
|||
|
FALSE );
|
|||
|
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
break;
|
|||
|
}
|
|||
|
//
|
|||
|
// Check if we are in the same call node.
|
|||
|
//
|
|||
|
|
|||
|
sameDriver = sameClass && RtlEqualUnicodeString( &DriverName, &KeyName, TRUE );
|
|||
|
|
|||
|
//
|
|||
|
// Get full information for that key so we can get the
|
|||
|
// information about the data stored in the key.
|
|||
|
//
|
|||
|
|
|||
|
status = ZwQueryKey( DriverKeyHandle,
|
|||
|
KeyFullInformation,
|
|||
|
U.KeyFInf,
|
|||
|
BufferSize,
|
|||
|
&junk );
|
|||
|
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Length = sizeof( KEY_VALUE_FULL_INFORMATION ) +
|
|||
|
U.KeyFInf->MaxValueNameLen + U.KeyFInf->MaxValueDataLen + sizeof(UNICODE_NULL);
|
|||
|
|
|||
|
if (Length > BufferSize) {
|
|||
|
|
|||
|
//
|
|||
|
// Get a larger buffer
|
|||
|
//
|
|||
|
|
|||
|
p2 = ExAllocatePool (PagedPool, Length);
|
|||
|
if (!p2) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool (U.Buffer);
|
|||
|
U.Buffer = p2;
|
|||
|
BufferSize = Length;
|
|||
|
}
|
|||
|
|
|||
|
DriverValueIndex = 0;
|
|||
|
for (; ;) {
|
|||
|
status = ZwEnumerateValueKey( DriverKeyHandle,
|
|||
|
DriverValueIndex++,
|
|||
|
KeyValueFullInformation,
|
|||
|
U.VKeyFInf,
|
|||
|
BufferSize,
|
|||
|
&junk );
|
|||
|
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is not a translated resource list, skip it.
|
|||
|
//
|
|||
|
|
|||
|
i = U.VKeyFInf->NameLength;
|
|||
|
if (i < TranslatedStrLen ||
|
|||
|
RtlCompareMemory (
|
|||
|
((PUCHAR) U.VKeyFInf->Name) + i - TranslatedStrLen,
|
|||
|
IopWstrTranslated,
|
|||
|
TranslatedStrLen
|
|||
|
) != TranslatedStrLen
|
|||
|
) {
|
|||
|
// does not end in IopWstrTranslated
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is a bus translated resource list, ????
|
|||
|
//
|
|||
|
|
|||
|
if (i >= BusTranslatedStrLen &&
|
|||
|
RtlCompareMemory (
|
|||
|
((PUCHAR) U.VKeyFInf->Name) + i - BusTranslatedStrLen,
|
|||
|
IopWstrBusTranslated,
|
|||
|
BusTranslatedStrLen
|
|||
|
) == BusTranslatedStrLen
|
|||
|
) {
|
|||
|
|
|||
|
// ends in IopWstrBusTranslated
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If these used resources are from the caller, then skip them
|
|||
|
//
|
|||
|
|
|||
|
if (sameDriver) {
|
|||
|
unicodeString.Buffer = (PWSTR) U.VKeyFInf->Name;
|
|||
|
unicodeString.Length = (USHORT) U.VKeyFInf->NameLength;
|
|||
|
unicodeString.MaximumLength = (USHORT) U.VKeyFInf->NameLength;
|
|||
|
if (RtlEqualUnicodeString (&unicodeString, &TranslatedName, TRUE)) {
|
|||
|
// it's the current allocated resources for this caller.
|
|||
|
// skip this entry.
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build Owner structure for TLIST entries
|
|||
|
//
|
|||
|
|
|||
|
Owner = IopAllocateDirPool (Dir, sizeof (*Owner) + U.VKeyFInf->NameLength);
|
|||
|
if (!Owner) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Owner->InConflict.Flink = NULL;
|
|||
|
Owner->DeviceName.Buffer = NULL;
|
|||
|
|
|||
|
#if _PNP_POWER_
|
|||
|
Owner->DeviceName.Length = 0;
|
|||
|
#endif
|
|||
|
Owner->KeyName.Buffer = KeyName.Buffer;
|
|||
|
Owner->KeyName.Length = KeyName.Length;
|
|||
|
Owner->KeyName.MaximumLength = KeyName.MaximumLength;
|
|||
|
|
|||
|
if (U.VKeyFInf->Name[0] != L'.') {
|
|||
|
// strip off the .Translated part of the string
|
|||
|
U.VKeyFInf->NameLength -= TranslatedStrLen;
|
|||
|
|
|||
|
Owner->DeviceName.Buffer = Owner->UnicodeBuffer;
|
|||
|
Owner->DeviceName.Length = (USHORT) U.VKeyFInf->NameLength;
|
|||
|
Owner->DeviceName.MaximumLength = (USHORT) U.VKeyFInf->NameLength;
|
|||
|
RtlCopyMemory (Owner->UnicodeBuffer, U.VKeyFInf->Name, U.VKeyFInf->NameLength);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Run the CmResourceList and save each InUse resource
|
|||
|
//
|
|||
|
|
|||
|
CmResList = (PCM_RESOURCE_LIST) ( (PUCHAR) U.VKeyFInf + U.VKeyFInf->DataOffset);
|
|||
|
LastAddr = (PUCHAR) CmResList + U.VKeyFInf->DataLength;
|
|||
|
|
|||
|
CmFResDesc = CmResList->List;
|
|||
|
for (i=0; i < CmResList->Count && NT_SUCCESS(status) ; i++) {
|
|||
|
CmDesc = CmFResDesc->PartialResourceList.PartialDescriptors;
|
|||
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|||
|
if (i) {
|
|||
|
DBGMSG ("IopAssignResourcesPhase2: a. CmResourceList in regitry too short\n");
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
for (j=0; j < CmFResDesc->PartialResourceList.Count && NT_SUCCESS(status); j++) {
|
|||
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|||
|
i = CmResList->Count;
|
|||
|
DBGMSG ("IopAssignResourcesPhase2: b. CmResourceList in regitry too short\n");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add this CmDesc to the InUse list
|
|||
|
//
|
|||
|
|
|||
|
if (CmDesc->ShareDisposition == CmResourceShareShared) {
|
|||
|
status = IopAddCmDescriptorToInUseList (
|
|||
|
Dir,
|
|||
|
&Dir->InUseSharableResources,
|
|||
|
CmDesc,
|
|||
|
Owner
|
|||
|
);
|
|||
|
} else {
|
|||
|
status = IopAddCmDescriptorToInUseList (
|
|||
|
Dir,
|
|||
|
&Dir->InUseResources,
|
|||
|
CmDesc,
|
|||
|
Owner
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
CmDesc++;
|
|||
|
}
|
|||
|
|
|||
|
CmFResDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) CmDesc;
|
|||
|
}
|
|||
|
|
|||
|
} // next DriverValueIndex
|
|||
|
|
|||
|
if (DriverKeyHandle != INVALID_HANDLE) {
|
|||
|
ZwClose (DriverKeyHandle);
|
|||
|
DriverKeyHandle = INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
break;
|
|||
|
}
|
|||
|
} // next DriverKeyIndex
|
|||
|
|
|||
|
if (ClassKeyHandle != INVALID_HANDLE) {
|
|||
|
ZwClose (ClassKeyHandle);
|
|||
|
ClassKeyHandle = INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
} // next ClassKeyIndex
|
|||
|
|
|||
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// All reported resources are read in.
|
|||
|
// Now read in ...SystemResources\ReservedResources
|
|||
|
// (note: this infomration could easily be cached if needed)
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Build owner for all ResevedResources
|
|||
|
//
|
|||
|
|
|||
|
Owner = IopAllocateDirPool (Dir, sizeof (*Owner) + U.VKeyFInf->NameLength);
|
|||
|
if (Owner) {
|
|||
|
Owner->InConflict.Flink = NULL;
|
|||
|
Owner->DeviceName.Buffer = NULL;
|
|||
|
#if _PNP_POWER_
|
|||
|
Owner->DeviceName.Length = 0;
|
|||
|
#endif
|
|||
|
RtlInitUnicodeString (&Owner->KeyName, IopWstrReservedResources);
|
|||
|
}
|
|||
|
|
|||
|
Index = 0;
|
|||
|
while (NT_SUCCESS (status)) {
|
|||
|
status = ZwEnumerateValueKey( Dir->RegHandle[HRESERVEDRESOURCES],
|
|||
|
Index++,
|
|||
|
KeyValueFullInformation,
|
|||
|
U.VKeyFInf,
|
|||
|
BufferSize,
|
|||
|
&junk );
|
|||
|
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Run the CmResourceList and save each InUse resource
|
|||
|
//
|
|||
|
|
|||
|
CmResList = (PCM_RESOURCE_LIST) ( (PUCHAR) U.VKeyFInf + U.VKeyFInf->DataOffset);
|
|||
|
LastAddr = (PUCHAR) CmResList + U.VKeyFInf->DataLength;
|
|||
|
|
|||
|
CmFResDesc = CmResList->List;
|
|||
|
for (i=0; i < CmResList->Count && NT_SUCCESS(status) ; i++) {
|
|||
|
CmDesc = CmFResDesc->PartialResourceList.PartialDescriptors;
|
|||
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|||
|
DBGMSG ("IopAssignResourcesPhase2: c. CmResourceList in regitry too short\n");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
for (j=0; j < CmFResDesc->PartialResourceList.Count && NT_SUCCESS(status); j++) {
|
|||
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|||
|
i = CmResList->Count;
|
|||
|
DBGMSG ("IopAssignResourcesPhase2: d. CmResourceList in regitry too short\n");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Translate this descriptor to it's TRANSLATED values
|
|||
|
//
|
|||
|
|
|||
|
switch (CmDesc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
case CmResourceTypeMemory:
|
|||
|
junk = CmDesc->Type == CmResourceTypePort ? 1 : 0;
|
|||
|
li = *((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start);
|
|||
|
flag = HalTranslateBusAddress (
|
|||
|
CmFResDesc->InterfaceType,
|
|||
|
CmFResDesc->BusNumber,
|
|||
|
*((PPHYSICAL_ADDRESS) &li),
|
|||
|
&junk,
|
|||
|
(PPHYSICAL_ADDRESS) &li
|
|||
|
);
|
|||
|
*((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start) = li;
|
|||
|
CmDesc->Type = junk == 1 ? CmResourceTypePort : CmResourceTypeMemory;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
CmDesc->u.Interrupt.Vector = HalGetInterruptVector (
|
|||
|
CmFResDesc->InterfaceType,
|
|||
|
CmFResDesc->BusNumber,
|
|||
|
CmDesc->u.Interrupt.Vector, // bus level
|
|||
|
CmDesc->u.Interrupt.Vector, // bus vector
|
|||
|
(PKIRQL) &junk, // translated level
|
|||
|
&CmDesc->u.Interrupt.Affinity
|
|||
|
);
|
|||
|
flag = CmDesc->u.Interrupt.Affinity == 0 ? FALSE : TRUE;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
// no translation
|
|||
|
flag = TRUE;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
flag = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (flag) {
|
|||
|
|
|||
|
//
|
|||
|
// Add it to the appropiate tlist
|
|||
|
//
|
|||
|
|
|||
|
if (CmDesc->ShareDisposition == CmResourceShareShared) {
|
|||
|
status = IopAddCmDescriptorToInUseList (
|
|||
|
Dir,
|
|||
|
&Dir->ReservedSharableResources,
|
|||
|
CmDesc,
|
|||
|
Owner
|
|||
|
);
|
|||
|
} else {
|
|||
|
status = IopAddCmDescriptorToInUseList (
|
|||
|
Dir,
|
|||
|
&Dir->InUseResources,
|
|||
|
CmDesc,
|
|||
|
Owner
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CmDesc++;
|
|||
|
}
|
|||
|
|
|||
|
CmFResDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) CmDesc;
|
|||
|
}
|
|||
|
|
|||
|
} // Next ReservedResource
|
|||
|
|
|||
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool (U.Buffer);
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
PDIR_RESOURCE_LIST
|
|||
|
IopAssignResourcesPhase3 (
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
All the information to process the requested resource assignments has
|
|||
|
been read in & parsed. Phase3 cranks out the resource assignments.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDIR_RESOURCE_LIST CurList, BestList;
|
|||
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|||
|
ULONG level, i, j;
|
|||
|
LONG BestPref, Pref;
|
|||
|
|
|||
|
//
|
|||
|
// Run each list as pass 1
|
|||
|
//
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|||
|
|
|||
|
// set to pass 1
|
|||
|
for (i=0; i < CurList->NoRequiredResources; i++) {
|
|||
|
#if _PNP_POWER_
|
|||
|
CurList->RequiredResource[i]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[i]->RunLen = 0;
|
|||
|
#endif
|
|||
|
CurList->RequiredResource[i]->PassNo = 1;
|
|||
|
}
|
|||
|
|
|||
|
// find resouce settings for this list
|
|||
|
if (IopGenNextValidResourceList (0, CurList, Dir)) {
|
|||
|
|
|||
|
// found good settings, return them
|
|||
|
return CurList;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Try again - set last checked resource in any given list to pass2 to see if that will
|
|||
|
// unclog the problem.
|
|||
|
//
|
|||
|
|
|||
|
IDBGMSG ("First pass attempt at resource settings failed\n");
|
|||
|
|
|||
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|||
|
for (; ;) {
|
|||
|
//
|
|||
|
// Reset last level tried to look for any settings
|
|||
|
//
|
|||
|
|
|||
|
level = CurList->LastLevel;
|
|||
|
ReqRes = CurList->RequiredResource[level];
|
|||
|
if (ReqRes->PassNo != 1) {
|
|||
|
// already trying pass 2 on this level
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ReqRes->PassNo = 2;
|
|||
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|||
|
ReqRes->IoResourceDescriptor[j]->Option &= ~IO_RESOURCE_PREFERRED;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Back up to failed level and see if this list can now be satisfied
|
|||
|
//
|
|||
|
|
|||
|
level = CurList->NoRequiredResources;
|
|||
|
while (level > CurList->FailedLevel) {
|
|||
|
level--;
|
|||
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[level]->RunLen = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (IopGenNextValidResourceList (level, CurList, Dir)) {
|
|||
|
// found good settings, return them
|
|||
|
return CurList;
|
|||
|
}
|
|||
|
|
|||
|
} // loop and clear next failed level
|
|||
|
} // loop and try next list
|
|||
|
|
|||
|
//
|
|||
|
// Try again, this time allow for a complete search. Clear all preferred settings and
|
|||
|
// move all levels to Pass2
|
|||
|
//
|
|||
|
|
|||
|
IDBGMSG ("Pass 2 attempt at resource settings failed\n");
|
|||
|
|
|||
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|||
|
for (i=0; i < CurList->NoRequiredResources; i++) {
|
|||
|
ReqRes = CurList->RequiredResource[i];
|
|||
|
ReqRes->CurLoc = 0;
|
|||
|
ReqRes->RunLen = 0;
|
|||
|
ReqRes->PassNo = 2;
|
|||
|
|
|||
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|||
|
ReqRes->IoResourceDescriptor[j]->Option &= ~IO_RESOURCE_PREFERRED;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BestPref = -999999;
|
|||
|
BestList = NULL;
|
|||
|
CurList = Dir->Alternative;
|
|||
|
level = 0;
|
|||
|
|
|||
|
while (CurList) {
|
|||
|
|
|||
|
// find resouce settings for this list
|
|||
|
if (IopGenNextValidResourceList (level, CurList, Dir)) {
|
|||
|
|
|||
|
//
|
|||
|
// We have useable settings, check to see how useable
|
|||
|
//
|
|||
|
|
|||
|
if (CurList->CurPref >= 0) {
|
|||
|
//
|
|||
|
// Nothing wrong with these settings, go use them
|
|||
|
//
|
|||
|
|
|||
|
IDBGMSG ("Pass3: Good hit\n");
|
|||
|
return CurList;
|
|||
|
}
|
|||
|
|
|||
|
if (CurList->CurPref > BestPref) {
|
|||
|
|
|||
|
//
|
|||
|
// These are the best so far, remember them
|
|||
|
//
|
|||
|
|
|||
|
BestPref = CurList->CurPref;
|
|||
|
BestList = CurList;
|
|||
|
|
|||
|
for (i = 0; i < CurList->NoRequiredResources; i++) {
|
|||
|
ReqRes = CurList->RequiredResource[i];
|
|||
|
ReqRes->Pass2HoldCurLoc = ReqRes->CurBLoc;
|
|||
|
ReqRes->Pass2HoldBAddr = ReqRes->CurBAddr;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine which level to back up too to continue searching from
|
|||
|
//
|
|||
|
|
|||
|
Pref = CurList->CurPref;
|
|||
|
level = CurList->NoRequiredResources;
|
|||
|
while (level && Pref <= BestPref) {
|
|||
|
level--;
|
|||
|
Pref -= CurList->RequiredResource[level]->CurPref;
|
|||
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[level]->RunLen = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (CurList->RequiredResource[level]->PrefCnt > 16) {
|
|||
|
while (level && CurList->RequiredResource[level]->PrefCnt > 16) {
|
|||
|
level--;
|
|||
|
Pref -= CurList->RequiredResource[level]->CurPref;
|
|||
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[level]->RunLen = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (level == 0) {
|
|||
|
// go with best setting so far
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
CurList->RequiredResource[level]->PrefCnt++;
|
|||
|
continue ;
|
|||
|
}
|
|||
|
|
|||
|
// no (more) valid settings found on this list, try the next
|
|||
|
CurList = CurList->Next;
|
|||
|
level = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (!BestList) {
|
|||
|
// failure
|
|||
|
IDBGMSG ("Pass3: No settings found\n");
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return best settings which were found
|
|||
|
//
|
|||
|
|
|||
|
for (i = 0; i < BestList->NoRequiredResources; i++) {
|
|||
|
ReqRes = BestList->RequiredResource[i];
|
|||
|
ReqRes->CurBLoc = ReqRes->Pass2HoldCurLoc;
|
|||
|
ReqRes->CurBAddr = ReqRes->Pass2HoldBAddr;
|
|||
|
}
|
|||
|
|
|||
|
return BestList;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PCM_RESOURCE_LIST
|
|||
|
IopAssignResourcesPhase4 (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PDIR_RESOURCE_LIST CurList,
|
|||
|
OUT PULONG Length
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The callers request for resources has been calculated. Phase 4 builds
|
|||
|
a CM_RESOURCE_LIST of the allocated resources.
|
|||
|
|
|||
|
This functions need CurDesc->CurBLoc & CurDesc->CurBAddr as passed from Phase3.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PCM_RESOURCE_LIST CmRes;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc;
|
|||
|
PDIR_REQUIRED_RESOURCE DirDesc, *pDirDesc;
|
|||
|
PIO_RESOURCE_DESCRIPTOR IoDesc;
|
|||
|
ULONG i, cnt, len;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
cnt = CurList->NoRequiredResources;
|
|||
|
len = sizeof (CM_RESOURCE_LIST) + cnt * sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|||
|
*Length = len;
|
|||
|
|
|||
|
CmRes = (PCM_RESOURCE_LIST) ExAllocatePool (PagedPool, len);
|
|||
|
if (!CmRes) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory (CmRes, len);
|
|||
|
|
|||
|
CmRes->Count = 1;
|
|||
|
CmRes->List[0].InterfaceType = Dir->IoResourceReq->InterfaceType;
|
|||
|
CmRes->List[0].BusNumber = Dir->IoResourceReq->BusNumber;
|
|||
|
CmRes->List[0].PartialResourceList.Count = CurList->NoRequiredResources;
|
|||
|
|
|||
|
CmDesc = CmRes->List[0].PartialResourceList.PartialDescriptors;
|
|||
|
pDirDesc = CurList->RequiredResource; // return resources in same order they
|
|||
|
// where requested
|
|||
|
#if IDBG
|
|||
|
DbgPrint ("Acquired Resourses - %d\n", CurList->NoRequiredResources);
|
|||
|
#endif
|
|||
|
|
|||
|
for (i=0; i < cnt; i++, CmDesc++, pDirDesc++) {
|
|||
|
DirDesc = *pDirDesc;
|
|||
|
IoDesc = DirDesc->IoResourceDescriptor[DirDesc->CurBLoc];
|
|||
|
|
|||
|
CmDesc->Type = IoDesc->Type;
|
|||
|
CmDesc->ShareDisposition = IoDesc->ShareDisposition;
|
|||
|
CmDesc->Flags = IoDesc->Flags;
|
|||
|
|
|||
|
switch (CmDesc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
CmDesc->u.Port.Start.QuadPart = DirDesc->CurBAddr;
|
|||
|
CmDesc->u.Port.Length = IoDesc->u.Port.Length;
|
|||
|
#if IDBG
|
|||
|
DbgPrint (" IO Start %x:%08x, Len %x\n",
|
|||
|
CmDesc->u.Port.Start.HighPart, CmDesc->u.Port.Start.LowPart,
|
|||
|
CmDesc->u.Port.Length );
|
|||
|
#endif
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
CmDesc->u.Memory.Start.QuadPart = DirDesc->CurBAddr;
|
|||
|
CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
|
|||
|
#if IDBG
|
|||
|
DbgPrint (" MEM Start %x:%08x, Len %x\n",
|
|||
|
CmDesc->u.Memory.Start.HighPart, CmDesc->u.Memory.Start.LowPart,
|
|||
|
CmDesc->u.Memory.Length );
|
|||
|
#endif
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
CmDesc->u.Interrupt.Level = (ULONG) DirDesc->CurBAddr;
|
|||
|
CmDesc->u.Interrupt.Vector = (ULONG) DirDesc->CurBAddr;
|
|||
|
#if IDBG
|
|||
|
DbgPrint (" INT Level %x, Vector %x\n",
|
|||
|
CmDesc->u.Interrupt.Level, CmDesc->u.Interrupt.Vector );
|
|||
|
#endif
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
CmDesc->u.Dma.Channel = (ULONG) DirDesc->CurBAddr;
|
|||
|
#if IDBG
|
|||
|
DbgPrint (" DMA Channel %x\n", CmDesc->u.Dma.Channel);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ExFreePool (CmRes);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return CmRes;
|
|||
|
}
|
|||
|
|
|||
|
STATIC VOID
|
|||
|
IopLogConflict (
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN NTSTATUS FinalStatus
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Resource settings could not be satisfied. Locate first resource
|
|||
|
which can not be assigned and report the conflict.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PIO_ERROR_LOG_PACKET ErrLog;
|
|||
|
PDIR_RESOURCE_LIST CurList;
|
|||
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|||
|
ULONG i, j;
|
|||
|
ULONG len, ErrorLogNumber, ErrLogBufferLeft;
|
|||
|
ULONG ConflictLevel;
|
|||
|
UCHAR s[8];
|
|||
|
PWCHAR pLog;
|
|||
|
POWNER Owner;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
IDBGMSG ("\n****\n");
|
|||
|
IDBGMSG ("Failed to satisfy the following required resource\n");
|
|||
|
|
|||
|
ErrLog = NULL;
|
|||
|
ErrorLogNumber = 0;
|
|||
|
|
|||
|
//
|
|||
|
// There's a conflict in each alternative list
|
|||
|
//
|
|||
|
|
|||
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|||
|
|
|||
|
//
|
|||
|
// Clear position (already on pass 2)
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i < CurList->NoRequiredResources; i++) {
|
|||
|
CurList->RequiredResource[i]->CurLoc = 0;
|
|||
|
CurList->RequiredResource[i]->RunLen = 0;
|
|||
|
CurList->RequiredResource[i]->PassNo = 2;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Look for settings - set ConflictLevel to pass 3 to track where the problem is
|
|||
|
//
|
|||
|
|
|||
|
ConflictLevel = CurList->FailedLevel;
|
|||
|
CurList->RequiredResource[ConflictLevel]->PassNo = 3;
|
|||
|
|
|||
|
InitializeListHead (&CurList->Conflict.OtherConflicts);
|
|||
|
|
|||
|
if (IopGenNextValidResourceList (0, CurList, Dir)) {
|
|||
|
IDBGMSG ("IopLogConflict: internal error\n");
|
|||
|
continue ;
|
|||
|
}
|
|||
|
|
|||
|
#if IDBG
|
|||
|
if (CurList != Dir->Alternative) {
|
|||
|
DbgPrint ("the following alternate resource also failed\n");
|
|||
|
}
|
|||
|
|
|||
|
s[0] = s[1] = s[2] = s[3] = ' ';
|
|||
|
s[4] = 0;
|
|||
|
|
|||
|
ReqRes = CurList->RequiredResource[ConflictLevel];
|
|||
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|||
|
IopDumpIoResourceDescriptor (s, ReqRes->IoResourceDescriptor[j]);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
i = CurList->Conflict.NoConflicts;
|
|||
|
if (i > SCONFLICT) {
|
|||
|
i = SCONFLICT;
|
|||
|
}
|
|||
|
for (j=0; j < i; j++) {
|
|||
|
DbgPrint (" Conflict # %d. ", j+1);
|
|||
|
switch (CurList->Conflict.EasyConflict[j].Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
DbgPrint ("IO Base %08x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
DbgPrint ("MEM Base %08x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
DbgPrint ("INT Line %x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
DbgPrint ("DMA Channel %x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DbgPrint (" with '%Z' ", &CurList->Conflict.EasyConflict[j].Owner->KeyName);
|
|||
|
if (CurList->Conflict.EasyConflict[j].Owner->DeviceName.Buffer) {
|
|||
|
DbgPrint ("'%Z'", &CurList->Conflict.EasyConflict[j].Owner->DeviceName);
|
|||
|
}
|
|||
|
DbgPrint ("\n");
|
|||
|
}
|
|||
|
|
|||
|
if (CurList->Conflict.NoConflicts > SCONFLICT) {
|
|||
|
DbgPrint (" ...\n");
|
|||
|
DbgPrint ("Total Conflicts = %d\n", CurList->Conflict.NoConflicts);
|
|||
|
}
|
|||
|
|
|||
|
if (!IsListEmpty (&CurList->Conflict.OtherConflicts)) {
|
|||
|
DbgPrint ("Possible settings also conflicts with the following list\n");
|
|||
|
// bugbug - not done
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Loop for each easy conflict
|
|||
|
//
|
|||
|
|
|||
|
i = CurList->Conflict.NoConflicts;
|
|||
|
if (i > SCONFLICT) {
|
|||
|
i = SCONFLICT;
|
|||
|
}
|
|||
|
|
|||
|
for (j=0; j < i; j++) {
|
|||
|
if (ErrorLogNumber >= 3) {
|
|||
|
//
|
|||
|
// only add n logs for a given problem
|
|||
|
//
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a new error log structure
|
|||
|
//
|
|||
|
|
|||
|
ErrorLogNumber += 1;
|
|||
|
ErrLog = IoAllocateErrorLogEntry (DriverObject, ERROR_LOG_MAXIMUM_SIZE);
|
|||
|
if (!ErrLog) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize errorlog field and counts to append strings
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory (ErrLog, sizeof (*ErrLog));
|
|||
|
ErrLog->FinalStatus = FinalStatus;
|
|||
|
ErrLog->UniqueErrorValue = ErrorLogNumber;
|
|||
|
ErrLog->NumberOfStrings = 2;
|
|||
|
pLog = (PWCHAR) ErrLog->DumpData;
|
|||
|
ErrLog->StringOffset = (USHORT) ( ((PUCHAR) pLog) - ((PUCHAR) ErrLog) );
|
|||
|
ErrLogBufferLeft = (ERROR_LOG_MAXIMUM_SIZE - ErrLog->StringOffset) / sizeof(WCHAR);
|
|||
|
|
|||
|
switch (CurList->Conflict.EasyConflict[j].Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
ErrLog->ErrorCode = IO_ERR_PORT_RESOURCE_CONFLICT;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
ErrLog->ErrorCode = IO_ERR_MEMORY_RESOURCE_CONFLICT;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
ErrLog->ErrorCode = IO_ERR_INTERRUPT_RESOURCE_CONFLICT;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
ErrLog->ErrorCode = IO_ERR_DMA_RESOURCE_CONFLICT;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (CurList->Conflict.EasyConflict[j].BAddr & 0xffffffff00000000) {
|
|||
|
len = swprintf (pLog, L"%X:%08X",
|
|||
|
(ULONG) (CurList->Conflict.EasyConflict[j].BAddr >> 32),
|
|||
|
(ULONG) CurList->Conflict.EasyConflict[j].BAddr
|
|||
|
);
|
|||
|
} else {
|
|||
|
len = swprintf (pLog, L"%X", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|||
|
}
|
|||
|
|
|||
|
len += 1; // include null
|
|||
|
pLog += len;
|
|||
|
ErrLogBufferLeft -= len;
|
|||
|
|
|||
|
Owner = CurList->Conflict.EasyConflict[j].Owner;
|
|||
|
|
|||
|
len = Owner->KeyName.Length / sizeof(WCHAR);
|
|||
|
if (len > ErrLogBufferLeft) {
|
|||
|
len = ErrLogBufferLeft;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory (pLog, Owner->KeyName.Buffer, len * sizeof(WCHAR) );
|
|||
|
pLog += len;
|
|||
|
ErrLogBufferLeft -= len;
|
|||
|
|
|||
|
if (Owner->DeviceName.Buffer && ErrLogBufferLeft > 11) {
|
|||
|
len = Owner->DeviceName.Length / sizeof(WCHAR);
|
|||
|
if (len > ErrLogBufferLeft) {
|
|||
|
len = ErrLogBufferLeft;
|
|||
|
}
|
|||
|
|
|||
|
*(pLog++) = ' ';
|
|||
|
RtlCopyMemory (pLog, Owner->DeviceName.Buffer, len * sizeof(WCHAR));
|
|||
|
pLog += len;
|
|||
|
ErrLogBufferLeft -= len;
|
|||
|
}
|
|||
|
|
|||
|
*(pLog++) = 0; // null terminate
|
|||
|
|
|||
|
IoWriteErrorLogEntry ( ErrLog );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IDBGMSG ("****\n");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
STATIC PTENTRY
|
|||
|
IopNewTransEntry (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PTENTRIESBYTYPE pTypes,
|
|||
|
IN ULONG Type
|
|||
|
)
|
|||
|
{
|
|||
|
PLTENTRY LEntry, NewTable;
|
|||
|
|
|||
|
LEntry = pTypes->ByType[Type];
|
|||
|
|
|||
|
if (!LEntry || LEntry->CurEntries == MAX_ENTRIES) {
|
|||
|
//
|
|||
|
// Build a new table
|
|||
|
//
|
|||
|
|
|||
|
NewTable = IopAllocateDirPool (Dir, sizeof (LTENTRY));
|
|||
|
|
|||
|
if (!NewTable) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
pTypes->ByType[Type] = NewTable;
|
|||
|
NewTable->Next = LEntry;
|
|||
|
NewTable->CurEntries = 0;
|
|||
|
|
|||
|
LEntry = NewTable;
|
|||
|
}
|
|||
|
|
|||
|
return LEntry->Table + (LEntry->CurEntries++);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
STATIC NTSTATUS
|
|||
|
IopAddCmDescriptorToInUseList (
|
|||
|
IN PDIR_RESREQ_LIST Dir,
|
|||
|
IN PTENTRIESBYTYPE pTypes,
|
|||
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc,
|
|||
|
IN POWNER Owner
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds Translated CmDescriptor to TLIST.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PTENTRY Trans;
|
|||
|
LONGLONG li;
|
|||
|
|
|||
|
if ((CmDesc->Type == CmResourceTypePort && CmDesc->u.Port.Length == 0) ||
|
|||
|
(CmDesc->Type == CmResourceTypeMemory && CmDesc->u.Memory.Length == 0)) {
|
|||
|
// no length?
|
|||
|
IDBGMSG ("IopAddCmDescriptor: Skipping zero length descriptor\n");
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get a new Trans entry in the InUseResource list or the
|
|||
|
// InUseSharableResource list
|
|||
|
//
|
|||
|
|
|||
|
Trans = IopNewTransEntry (Dir, pTypes, CmDesc->Type);
|
|||
|
if (!Trans) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the Trans structure
|
|||
|
//
|
|||
|
|
|||
|
// NOTE: turning TEntries into a splay tree would speed up the collision
|
|||
|
// detect process.
|
|||
|
|
|||
|
Trans->Owner = Owner;
|
|||
|
#if _PNP_POWER_
|
|||
|
Trans->Flags = TENTRY_FLAGS_IN_USE;
|
|||
|
#endif
|
|||
|
switch (CmDesc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
li = CmDesc->u.Port.Length - 1;
|
|||
|
Trans->BAddr = *((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start);
|
|||
|
Trans->EAddr = Trans->BAddr + li;
|
|||
|
Trans->Affinity = (KAFFINITY) -1;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
li = CmDesc->u.Memory.Length - 1;
|
|||
|
Trans->BAddr = *((LONGLONG UNALIGNED *) &CmDesc->u.Memory.Start);
|
|||
|
Trans->EAddr = Trans->BAddr + li;
|
|||
|
Trans->Affinity = (KAFFINITY) -1;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
Trans->BAddr = CmDesc->u.Interrupt.Vector;
|
|||
|
Trans->EAddr = CmDesc->u.Interrupt.Vector;
|
|||
|
Trans->Affinity = CmDesc->u.Interrupt.Affinity;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
Trans->BAddr = CmDesc->u.Dma.Channel;
|
|||
|
Trans->EAddr = CmDesc->u.Dma.Channel;
|
|||
|
Trans->Affinity = (KAFFINITY) -1;
|
|||
|
break;
|
|||
|
}
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopBuildResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST ParentDir,
|
|||
|
IN PDIR_RESREQ_LIST *pDir,
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes an IO_RESOURCE_REQUIREMENTS list and builds a directory for
|
|||
|
it's contents.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDIR_RESREQ_LIST Dir;
|
|||
|
PIO_RESOURCE_LIST ResourceList;
|
|||
|
PIO_RESOURCE_DESCRIPTOR Descriptor, ADescriptor;
|
|||
|
PDIR_RESOURCE_LIST DirResourceList, *AltListTail;
|
|||
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|||
|
ULONG i, j, alt, cnt, acnt;
|
|||
|
PUCHAR FirstAddress, LastAddress;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate and initialize DIR structure
|
|||
|
//
|
|||
|
|
|||
|
Dir = (PDIR_RESREQ_LIST) ExAllocatePool (PagedPool, sizeof(DIR_RESREQ_LIST));
|
|||
|
*pDir = Dir;
|
|||
|
if (!Dir) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory (Dir, sizeof (DIR_RESREQ_LIST));
|
|||
|
for (i=0; i < MAX_REG_HANDLES; i++) {
|
|||
|
Dir->RegHandle[i] = INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
if (ParentDir) {
|
|||
|
Dir->FreeResReqList = ParentDir->FreeResReqList;
|
|||
|
ParentDir->FreeResReqList = Dir;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no IoResources to process, the Dir structure is done
|
|||
|
//
|
|||
|
|
|||
|
if (!IoResources) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Verify ResourceList does not exceede ListSize
|
|||
|
//
|
|||
|
|
|||
|
ResourceList = IoResources->List;
|
|||
|
FirstAddress = (PUCHAR) ResourceList;
|
|||
|
LastAddress = (PUCHAR) IoResources + IoResources->ListSize;
|
|||
|
for (cnt=0; cnt < IoResources->AlternativeLists; cnt++) {
|
|||
|
ResourceList = (PIO_RESOURCE_LIST)
|
|||
|
(&ResourceList->Descriptors[ResourceList->Count]);
|
|||
|
|
|||
|
if ((PUCHAR) ResourceList < FirstAddress ||
|
|||
|
(PUCHAR) ResourceList > LastAddress) {
|
|||
|
DBGMSG ("IopBuildResourceDir: IO_RESOURCE_LIST.ListSize too small\n");
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build a directory of the block stlye structure IO_RESOURCE_REQUIREMENTS_LIST
|
|||
|
//
|
|||
|
|
|||
|
Dir->IoResourceReq = IoResources;
|
|||
|
AltListTail = &Dir->Alternative;
|
|||
|
ResourceList = IoResources->List;
|
|||
|
|
|||
|
for (alt=0; alt < IoResources->AlternativeLists; alt++) {
|
|||
|
|
|||
|
//
|
|||
|
// Count number of non-alternative descriptors on this
|
|||
|
// alternative list
|
|||
|
//
|
|||
|
|
|||
|
cnt = 0;
|
|||
|
Descriptor = ResourceList->Descriptors;
|
|||
|
for (i = ResourceList->Count; i; i--) {
|
|||
|
if (!(Descriptor->Option & IO_RESOURCE_ALTERNATIVE)) {
|
|||
|
cnt++;
|
|||
|
}
|
|||
|
Descriptor++;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Build alternative list structure
|
|||
|
//
|
|||
|
|
|||
|
i = sizeof (DIR_RESOURCE_LIST) + cnt * sizeof(PVOID) * 2;
|
|||
|
DirResourceList = (PDIR_RESOURCE_LIST) IopAllocateDirPool (Dir, i);
|
|||
|
|
|||
|
if (!DirResourceList) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize structure
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory (DirResourceList, i);
|
|||
|
DirResourceList->IoResourceList = ResourceList;
|
|||
|
|
|||
|
// add to tail of single linked list
|
|||
|
*(AltListTail) = DirResourceList;
|
|||
|
AltListTail = &DirResourceList->Next;
|
|||
|
|
|||
|
Descriptor = ResourceList->Descriptors;
|
|||
|
for (i = ResourceList->Count; i; i--) {
|
|||
|
if (!(Descriptor->Option & IO_RESOURCE_ALTERNATIVE)) {
|
|||
|
//
|
|||
|
// Count number of alternative descriptors
|
|||
|
//
|
|||
|
|
|||
|
acnt = 1;
|
|||
|
ADescriptor = Descriptor + 1;
|
|||
|
while (acnt < i && ADescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
|
|||
|
ADescriptor++;
|
|||
|
acnt++;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a required resource list
|
|||
|
//
|
|||
|
|
|||
|
ReqRes = (PDIR_REQUIRED_RESOURCE) IopAllocateDirPool (Dir,
|
|||
|
sizeof (DIR_REQUIRED_RESOURCE) + acnt * sizeof(PVOID));
|
|||
|
|
|||
|
if (!ReqRes) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlZeroMemory (ReqRes, sizeof (DIR_REQUIRED_RESOURCE));
|
|||
|
DirResourceList->RequiredResource[DirResourceList->NoRequiredResources] = ReqRes;
|
|||
|
DirResourceList->NoRequiredResources++;
|
|||
|
|
|||
|
//
|
|||
|
// Fill in all the alternatives for this required resource
|
|||
|
//
|
|||
|
|
|||
|
ReqRes->NoAlternatives = acnt;
|
|||
|
ADescriptor = Descriptor;
|
|||
|
for (j=0; j < acnt; j++) {
|
|||
|
ReqRes->IoResourceDescriptor[j] = ADescriptor;
|
|||
|
if (ADescriptor->Option & IO_RESOURCE_PREFERRED) {
|
|||
|
ReqRes->BestPref = 1;
|
|||
|
}
|
|||
|
ADescriptor++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Next descriptor
|
|||
|
//
|
|||
|
Descriptor++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Next alternative resource list
|
|||
|
//
|
|||
|
|
|||
|
ResourceList = (PIO_RESOURCE_LIST) Descriptor;
|
|||
|
}
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
IopFreeResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST DirResourceList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Frees pool used to track a DIR_RESREQ_LIST and other assiocated
|
|||
|
resources. Also free's all pool for DIR_RESREQ_LIST's on a
|
|||
|
free list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDIR_RESREQ_LIST NextResourceList;
|
|||
|
ULONG i;
|
|||
|
PSINGLE_LIST_ENTRY pe;
|
|||
|
PUSED_HEAP ph;
|
|||
|
|
|||
|
//
|
|||
|
// Free any allocated lists
|
|||
|
//
|
|||
|
|
|||
|
while (DirResourceList) {
|
|||
|
NextResourceList = DirResourceList->FreeResReqList;
|
|||
|
|
|||
|
//
|
|||
|
// Free any allocated heap
|
|||
|
//
|
|||
|
|
|||
|
while (DirResourceList->AllocatedHeap.Next) {
|
|||
|
pe = PopEntryList (&DirResourceList->AllocatedHeap);
|
|||
|
ph = CONTAINING_RECORD(pe, USED_HEAP, FreeLink);
|
|||
|
ExFreePool (ph->FreeHeap);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Close any opened handles
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i< MAX_REG_HANDLES; i++) {
|
|||
|
if (DirResourceList->RegHandle[i] != INVALID_HANDLE) {
|
|||
|
ZwClose (DirResourceList->RegHandle[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Free header
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool (DirResourceList);
|
|||
|
|
|||
|
//
|
|||
|
// Next list
|
|||
|
//
|
|||
|
|
|||
|
DirResourceList = NextResourceList;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if IDBG
|
|||
|
VOID
|
|||
|
IopDumpIoResourceDir (
|
|||
|
IN PDIR_RESREQ_LIST Dir
|
|||
|
)
|
|||
|
{
|
|||
|
PDIR_RESOURCE_LIST ResourceList;
|
|||
|
PIO_RESOURCE_DESCRIPTOR Desc;
|
|||
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|||
|
ULONG alt, i, j;
|
|||
|
UCHAR s[10];
|
|||
|
|
|||
|
|
|||
|
alt = 0;
|
|||
|
for (ResourceList = Dir->Alternative; ResourceList; ResourceList = ResourceList->Next) {
|
|||
|
DbgPrint ("Alternative #%d - %d required resources\n",
|
|||
|
alt++, ResourceList->NoRequiredResources );
|
|||
|
|
|||
|
for (i=0; i < ResourceList->NoRequiredResources; i++) {
|
|||
|
ReqRes = ResourceList->RequiredResource[i];
|
|||
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|||
|
Desc = ReqRes->IoResourceDescriptor[j];
|
|||
|
if (j == 0) {
|
|||
|
s[0] = s[1] = s[2] = '*';
|
|||
|
s[3] = ' ';
|
|||
|
} else {
|
|||
|
s[0] = s[1] = s[2] = s[3] = ' ';
|
|||
|
}
|
|||
|
|
|||
|
s[4] = Desc->Option & IO_RESOURCE_PREFERRED ? 'P' : ' ';
|
|||
|
s[5] = ' ';
|
|||
|
s[6] = 0;
|
|||
|
|
|||
|
IopDumpIoResourceDescriptor (s, Desc);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
IopDumpIoResourceDescriptor (
|
|||
|
IN PUCHAR Indent,
|
|||
|
IN PIO_RESOURCE_DESCRIPTOR Desc
|
|||
|
)
|
|||
|
{
|
|||
|
switch (Desc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
DbgPrint ("%sIO Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart,
|
|||
|
Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart,
|
|||
|
Desc->u.Port.Alignment,
|
|||
|
Desc->u.Port.Length
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
DbgPrint ("%sMEM Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart,
|
|||
|
Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart,
|
|||
|
Desc->u.Memory.Alignment,
|
|||
|
Desc->u.Memory.Length
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
DbgPrint ("%sINT Min: %x, Max: %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Interrupt.MinimumVector,
|
|||
|
Desc->u.Interrupt.MaximumVector
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
DbgPrint ("%sDMA Min: %x, Max: %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Dma.MinimumChannel,
|
|||
|
Desc->u.Dma.MaximumChannel
|
|||
|
);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IopCatagorizeDescriptors (
|
|||
|
IN OUT PDIR_RESREQ_LIST Dir
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes a DIR_RESREQ_LIST and returns a list of resources by
|
|||
|
catagory. It is assumed that such a directory has one list
|
|||
|
of alternative descriptors per resource type.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDIR_RESOURCE_LIST DirResourceList;
|
|||
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|||
|
ULONG i, j, acnt;
|
|||
|
CM_RESOURCE_TYPE type;
|
|||
|
|
|||
|
if (!Dir->Alternative || Dir->Alternative->Next) {
|
|||
|
// there can only be one list
|
|||
|
DBGMSG ("IopCatagorizeDescriptors: too many altenative lists\n");
|
|||
|
return STATUS_INVALID_PARAMETER_MIX;
|
|||
|
}
|
|||
|
|
|||
|
DirResourceList = Dir->Alternative;
|
|||
|
for (i=0; i < DirResourceList->NoRequiredResources; i++) {
|
|||
|
ReqRes = DirResourceList->RequiredResource[i];
|
|||
|
|
|||
|
acnt = ReqRes->NoAlternatives;
|
|||
|
if (!acnt) {
|
|||
|
// shouldn't have a zero count
|
|||
|
DBGMSG ("IopCatagorizeDescriptors: no entries\n");
|
|||
|
return STATUS_INVALID_PARAMETER_MIX;
|
|||
|
}
|
|||
|
|
|||
|
type = ReqRes->IoResourceDescriptor[0]->Type;
|
|||
|
|
|||
|
// verify all entries in this list are of the same type
|
|||
|
for (j=1; j < acnt; j++) {
|
|||
|
if (ReqRes->IoResourceDescriptor[j]->Type != type) {
|
|||
|
DBGMSG ("IopCatagorizeDescriptors: mixed types in alternatives\n");
|
|||
|
return STATUS_INVALID_PARAMETER_MIX;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (type >= CmResourceTypeMaximum) {
|
|||
|
// unkown catagory
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (DirResourceList->ResourceByType[type]) {
|
|||
|
// should only have one list per type
|
|||
|
DBGMSG ("IopCatagorizeDescriptors: multiple lists per resource type\n");
|
|||
|
return STATUS_INVALID_PARAMETER_MIX;
|
|||
|
}
|
|||
|
|
|||
|
DirResourceList->ResourceByType[type] = ReqRes;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
INLINE ULONG
|
|||
|
IopDescriptorSortingWeight (
|
|||
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
Used by IopSortDescriptors
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG w;
|
|||
|
|
|||
|
switch (Descriptor->Type) {
|
|||
|
case CmResourceTypeMemory: w = 4; break;
|
|||
|
case CmResourceTypeInterrupt: w = 3; break;
|
|||
|
case CmResourceTypeDma: w = 2; break;
|
|||
|
case CmResourceTypePort: w = 1; break;
|
|||
|
default: w = 0; break;
|
|||
|
}
|
|||
|
|
|||
|
return w;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IopSortDescriptors (
|
|||
|
IN OUT PDIR_RESREQ_LIST Dir
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Sorts the directory entries for each decsriptor such that they
|
|||
|
descriptors are order by resource type.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PIO_RESOURCE_DESCRIPTOR Descriptor;
|
|||
|
PDIR_RESOURCE_LIST DirResourceList;
|
|||
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|||
|
ULONG i, j, k, acnt;
|
|||
|
ULONG w1, w2;
|
|||
|
|
|||
|
//
|
|||
|
// Sort each require resource list by descriptor type
|
|||
|
//
|
|||
|
|
|||
|
for (DirResourceList = Dir->Alternative; DirResourceList; DirResourceList = DirResourceList->Next) {
|
|||
|
|
|||
|
//
|
|||
|
// Sort the descriptors by type
|
|||
|
//
|
|||
|
|
|||
|
for (k=0; k < DirResourceList->NoRequiredResources; k++) {
|
|||
|
ReqRes = DirResourceList->RequiredResource[k];
|
|||
|
|
|||
|
acnt = ReqRes->NoAlternatives;
|
|||
|
for (i=0; i < acnt; i++) {
|
|||
|
w1 = IopDescriptorSortingWeight (ReqRes->IoResourceDescriptor[i]);
|
|||
|
|
|||
|
for (j = i+1; j < acnt; j++) {
|
|||
|
w2 = IopDescriptorSortingWeight (ReqRes->IoResourceDescriptor[j]);
|
|||
|
|
|||
|
if (w2 > w1) {
|
|||
|
Descriptor = ReqRes->IoResourceDescriptor[i];
|
|||
|
ReqRes->IoResourceDescriptor[i] = ReqRes->IoResourceDescriptor[j];
|
|||
|
ReqRes->IoResourceDescriptor[j] = Descriptor;
|
|||
|
w1 = w2;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|