Windows2000/private/ntos/io/assign.c

3012 lines
96 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
assign.c
Abstract:
IoAssignResources
Author:
Ken Reneris
Environment:
EDIT IN 110 COLUMN MODE
Revision History:
Add PnP support - shielint
--*/
#include "iop.h"
#define IDBG DBG
#define PAGED 1
#define INLINE __inline
#define STATIC static
//#define IDBG 1
//#define DBG 1
//#define PAGED
//#define INLINE
//#define STATIC
/*
* IDBG - Internal debugging. Turn on for runtime DbgPrints of calls to IoAssignResources
* PAGED - Declare functions as pageable or not. (usefull for debugging)
* INLINE - Inline functions
* STATIC - internal functions to this module which are static
*/
extern WCHAR IopWstrOtherDrivers[];
extern WCHAR IopWstrAssignedResources[];
extern WCHAR IopWstrRequestedResources[];
extern WCHAR IopWstrSystemResources[];
extern WCHAR IopWstrReservedResources[];
extern WCHAR IopWstrAssignmentOrdering[];
extern WCHAR IopWstrBusValues[];
extern WCHAR IopWstrTranslated[];
extern WCHAR IopWstrBusTranslated[];
#define HRESOURCE_MAP 0
#define HDEVICE_STORAGE 1
#define HCURRENT_CONTROL_SET 2
#define HSYSTEMRESOURCES 3
#define HORDERING 4
#define HRESERVEDRESOURCES 5
#define HBUSVALUES 6
#define HOWNER_MAP 7
#define MAX_REG_HANDLES 8
#define INVALID_HANDLE (HANDLE) -1
#define BUFFERSIZE (2048 + sizeof( KEY_FULL_INFORMATION ))
#define MAX_ENTRIES 50
#define SCONFLICT 5
// Wrapper structures around IO_RESOURCE lists
// owner of TENTRY
typedef struct {
LIST_ENTRY InConflict;
UNICODE_STRING KeyName;
UNICODE_STRING DeviceName;
WCHAR UnicodeBuffer[1]; // Must be last!
} *POWNER;
// 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 IDBG
ULONG na[2];
#endif
} 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
} 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;
// 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,
IN PLTENTRY List
);
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 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 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
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.
--*/
{
if (DeviceObject) {
if (DeviceObject->DeviceObjectExtension->DeviceNode &&
!(((PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode)->Flags & DNF_LEGACY_RESOURCE_DEVICENODE)) {
KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, PNP_ERR_INVALID_PDO, (ULONG_PTR)DeviceObject, 0, 0);
}
}
if (RequestedResources) {
if (RequestedResources->AlternativeLists == 0 || RequestedResources->List[0].Count == 0) {
RequestedResources = NULL;
}
}
if (pAllocatedResources) {
*pAllocatedResources = NULL;
}
return IopLegacyResourceAllocation(ArbiterRequestLegacyAssigned,
DriverObject,
DeviceObject,
RequestedResources,
pAllocatedResources);
}
#if 0
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;
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 (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
)
/*++
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;
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;
}
// Check InUse system resources to verify this range is available.
j = IopFindCollisionInTList (&Trans, Dir->InUseResources.ByType[TType]);
if (j) {
if (Res->PassNo == 3) {
// Track this collision
IopPickupCollisionInTList (
CurList,
Res->Type,
BAddr,
&Trans,
Dir->InUseResources.ByType[TType]
);
}
// 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
j = IopFindCollisionInTList (&Trans, Dir->InUseSharableResources.ByType[TType]);
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
j = IopFindCollisionInTList (&Trans, Dir->ReservedSharableResources.ByType[TType]);
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,
IN PLTENTRY List
)
/*++
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 (DoesTEntryCollide (Source, *SEntry)) {
LiTmp = Source.EAddr - SEntry->BAddr;
return (ULONG) LiTmp + 1;
}
}
List = List->Next;
}
return 0;
}
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;
}
}
#endif
#if 0
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));
}
// Handle the case when the DeviceObject was created
// without a name
if (ObNameInfo->Name.Buffer == NULL) {
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;
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;
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;
}
#if 0
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.
--*/
{
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++) {
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.
--*/
{
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.
--*/
{
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 '%wZ' ", &CurList->Conflict.EasyConflict[j].Owner->KeyName);
if (CurList->Conflict.EasyConflict[j].Owner->DeviceName.Buffer) {
DbgPrint ("'%wZ'", &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");
}
#endif
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.
--*/
{
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;
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.
--*/
{
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++;
}
}
Descriptor++;// Next 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.
--*/
{
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]);
}
}
ExFreePool (DirResourceList);// Free header
DirResourceList = NextResourceList;// Next list
}
}
#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.
--*/
{
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.
--*/
{
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;
}
}
}
}
}
}
#endif