NT4/private/ntos/io/assign.c
2020-09-30 17:12:29 +02:00

5871 lines
179 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 = &regList->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;
}
}
}
}
}
}