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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|