8962 lines
273 KiB
C
8962 lines
273 KiB
C
/*++
|
||
|
||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
||
Module Name:
|
||
|
||
pnpres.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the plug-and-play resource allocation and translation
|
||
routines
|
||
|
||
Author:
|
||
|
||
Shie-Lin Tzong (shielint) 1-Mar-1997
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
25-Sept-1998 SantoshJ Made IopAssign non-recursive.
|
||
01-Oct-1998 SantoshJ Replaced "complex (broken)" hypercube code and
|
||
replaced with cascading counters. Simple,
|
||
faster, smaller code.
|
||
Added timeouts to IopAssign.
|
||
Added more self-debugging capability by
|
||
generating more meaningful debug spew.
|
||
03-Feb-1999 SantoshJ Do allocation one device at a time.
|
||
Do devices with BOOT config before others.
|
||
Optimize IopFindBusDeviceNode.
|
||
22-Feb-2000 SantoshJ Add level field to arbiter entry. Arbiter list
|
||
gets sorted by depth so there is no need to
|
||
walk the tree while calling arbiters.
|
||
01-Mar-2000 SantoshJ Added look-up table for legacy interface and
|
||
bus numbers. Avoids walking the device tree.
|
||
13-Mar-2000 SantoshJ Cleaned up BOOT allocation related code.
|
||
16-Mar-2000 SantoshJ Replaced all individual references to
|
||
PpRegistrySemaphore with IopXXXResourceManager
|
||
macro.
|
||
17-Mar-2000 SantoshJ Replaced all debug prints with IopDbgPrint
|
||
20-Mar-2000 SantoshJ Removed redundant fields from internal data
|
||
structures.
|
||
21-Mar-2000 SantoshJ Cleaned up all definitions, MACROs etc.
|
||
|
||
--*/
|
||
|
||
#include "pnpmgrp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// CONSTANT defintions.
|
||
//
|
||
//
|
||
// Set this to 1 for maximum instrumentation.
|
||
//
|
||
#define MAXDBG 0
|
||
//
|
||
// Timeout value for IopFindBestConfiguration in milliseconds.
|
||
//
|
||
#define FIND_BEST_CONFIGURATION_TIMEOUT 5000
|
||
//
|
||
// Tag used for memory allocation.
|
||
//
|
||
#define PNP_RESOURCE_TAG 'erpP'
|
||
//
|
||
// Forward typedefs.
|
||
//
|
||
typedef struct _REQ_DESC
|
||
REQ_DESC, *PREQ_DESC;
|
||
typedef struct _REQ_LIST
|
||
REQ_LIST, *PREQ_LIST;
|
||
typedef struct _REQ_ALTERNATIVE
|
||
REQ_ALTERNATIVE, *PREQ_ALTERNATIVE, **PPREQ_ALTERNATIVE;
|
||
typedef struct _DUPLICATE_DETECTION_CONTEXT
|
||
DUPLICATE_DETECTION_CONTEXT, *PDUPLICATE_DETECTION_CONTEXT;
|
||
typedef struct _IOP_POOL
|
||
IOP_POOL, *PIOP_POOL;
|
||
//
|
||
// Structure definitions.
|
||
//
|
||
// REQ_LIST represents a list of logical configurations within the
|
||
// IO_RESOURCE_REQUIREMENTS_LIST.
|
||
//
|
||
struct _REQ_LIST {
|
||
INTERFACE_TYPE InterfaceType;
|
||
ULONG BusNumber;
|
||
PIOP_RESOURCE_REQUEST Request; // Owning request
|
||
PPREQ_ALTERNATIVE SelectedAlternative; // Alternative selected
|
||
PPREQ_ALTERNATIVE BestAlternative; // Best alternative
|
||
ULONG AlternativeCount; // AlternativeTable length
|
||
PREQ_ALTERNATIVE AlternativeTable[1]; // Variable length
|
||
};
|
||
//
|
||
// REQ_ALTERNATIVE represents a logical configuration.
|
||
//
|
||
struct _REQ_ALTERNATIVE {
|
||
ULONG Priority; // Priority for this configuration
|
||
ULONG Position; // Used for sorting if Priority is identical
|
||
PREQ_LIST ReqList; // List containing this configuration
|
||
ULONG ReqAlternativeIndex; // Index within the table in the list
|
||
ULONG DescCount; // Entry count for DescTable
|
||
PREQ_DESC DescTable[1]; // Variable length
|
||
};
|
||
//
|
||
// REQ_DESC represents a resource descriptor within a logical configuration.
|
||
//
|
||
struct _REQ_DESC {
|
||
INTERFACE_TYPE InterfaceType;
|
||
ULONG BusNumber;
|
||
BOOLEAN ArbitrationRequired;
|
||
UCHAR Reserved[3];
|
||
PREQ_ALTERNATIVE ReqAlternative;
|
||
ULONG ReqDescIndex;
|
||
PREQ_DESC TranslatedReqDesc;
|
||
ARBITER_LIST_ENTRY AlternativeTable;
|
||
CM_PARTIAL_RESOURCE_DESCRIPTOR Allocation;
|
||
ARBITER_LIST_ENTRY BestAlternativeTable;
|
||
CM_PARTIAL_RESOURCE_DESCRIPTOR BestAllocation;
|
||
ULONG DevicePrivateCount; // DevicePrivate info
|
||
PIO_RESOURCE_DESCRIPTOR DevicePrivate; // per LogConf
|
||
union {
|
||
PPI_RESOURCE_ARBITER_ENTRY Arbiter; // In original REQ_DESC
|
||
PPI_RESOURCE_TRANSLATOR_ENTRY Translator; // In translated REQ_DESC
|
||
} u;
|
||
};
|
||
//
|
||
// Duplicate_detection_Context
|
||
//
|
||
struct _DUPLICATE_DETECTION_CONTEXT {
|
||
PCM_RESOURCE_LIST TranslatedResources;
|
||
PDEVICE_NODE Duplicate;
|
||
};
|
||
//
|
||
// Pool
|
||
//
|
||
struct _IOP_POOL {
|
||
PUCHAR PoolStart;
|
||
ULONG PoolSize;
|
||
};
|
||
#if DBG_SCOPE
|
||
|
||
typedef struct {
|
||
PDEVICE_NODE devnode;
|
||
CM_PARTIAL_RESOURCE_DESCRIPTOR resource;
|
||
} PNPRESDEBUGTRANSLATIONFAILURE;
|
||
|
||
#endif // DBG_SCOPE
|
||
//
|
||
// MACROS
|
||
//
|
||
// Reused device node fields.
|
||
//
|
||
#define NextDeviceNode Sibling
|
||
#define PreviousDeviceNode Child
|
||
//
|
||
// Call this macro to block other resource allocations and releases in the
|
||
// system.
|
||
//
|
||
#define IopLockResourceManager() { \
|
||
KeEnterCriticalRegion(); \
|
||
KeWaitForSingleObject( \
|
||
&PpRegistrySemaphore, \
|
||
DelayExecution, \
|
||
KernelMode, \
|
||
FALSE, \
|
||
NULL); \
|
||
}
|
||
//
|
||
// Unblock other resource allocations and releases in the system.
|
||
//
|
||
#define IopUnlockResourceManager() { \
|
||
KeReleaseSemaphore( \
|
||
&PpRegistrySemaphore, \
|
||
0, \
|
||
1, \
|
||
FALSE); \
|
||
KeLeaveCriticalRegion(); \
|
||
}
|
||
//
|
||
// Initialize arbiter entry.
|
||
//
|
||
#define IopInitializeArbiterEntryState(a) { \
|
||
(a)->ResourcesChanged = FALSE; \
|
||
(a)->State = 0; \
|
||
InitializeListHead(&(a)->ActiveArbiterList); \
|
||
InitializeListHead(&(a)->BestConfig); \
|
||
InitializeListHead(&(a)->ResourceList); \
|
||
InitializeListHead(&(a)->BestResourceList); \
|
||
}
|
||
|
||
#define IS_TRANSLATED_REQ_DESC(r) (!((r)->ReqAlternative))
|
||
//
|
||
// Pool management MACROs
|
||
//
|
||
#define IopInitPool(Pool,Start,Size) { \
|
||
(Pool)->PoolStart = (Start); \
|
||
(Pool)->PoolSize = (Size); \
|
||
RtlZeroMemory(Start, Size); \
|
||
}
|
||
#define IopAllocPool(M,P,S) { \
|
||
*(M) = (PVOID)(P)->PoolStart; \
|
||
ASSERT((P)->PoolStart + (S) <= (P)->PoolStart + (P)->PoolSize); \
|
||
(P)->PoolStart += (S); \
|
||
}
|
||
//
|
||
// IopReleaseBootResources can only be called for non ROOT enumerated devices
|
||
//
|
||
#define IopReleaseBootResources(DeviceNode) { \
|
||
ASSERT(((DeviceNode)->Flags & DNF_MADEUP) == 0); \
|
||
IopReleaseResourcesInternal(DeviceNode); \
|
||
(DeviceNode)->Flags &= ~DNF_HAS_BOOT_CONFIG; \
|
||
(DeviceNode)->Flags &= ~DNF_BOOT_CONFIG_RESERVED; \
|
||
if ((DeviceNode)->BootResources) { \
|
||
ExFreePool((DeviceNode)->BootResources); \
|
||
(DeviceNode)->BootResources = NULL; \
|
||
} \
|
||
}
|
||
//
|
||
// Debug support
|
||
//
|
||
#ifdef POOL_TAGGING
|
||
|
||
#undef ExAllocatePool
|
||
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,PNP_RESOURCE_TAG)
|
||
|
||
#endif // POOL_TAGGING
|
||
|
||
#if MAXDBG
|
||
|
||
#define ExAllocatePoolAT(a,b) ExAllocatePoolWithTag(a,b,'0rpP')
|
||
#define ExAllocatePoolRD(a,b) ExAllocatePoolWithTag(a,b,'1rpP')
|
||
#define ExAllocatePoolCMRL(a,b) ExAllocatePoolWithTag(a,b,'2rpP')
|
||
#define ExAllocatePoolCMRR(a,b) ExAllocatePoolWithTag(a,b,'3rpP')
|
||
#define ExAllocatePoolAE(a,b) ExAllocatePoolWithTag(a,b,'4rpP')
|
||
#define ExAllocatePoolTE(a,b) ExAllocatePoolWithTag(a,b,'5rpP')
|
||
#define ExAllocatePoolPRD(a,b) ExAllocatePoolWithTag(a,b,'6rpP')
|
||
#define ExAllocatePoolIORD(a,b) ExAllocatePoolWithTag(a,b,'7rpP')
|
||
#define ExAllocatePool1RD(a,b) ExAllocatePoolWithTag(a,b,'8rpP')
|
||
#define ExAllocatePoolPDO(a,b) ExAllocatePoolWithTag(a,b,'9rpP')
|
||
#define ExAllocatePoolIORR(a,b) ExAllocatePoolWithTag(a,b,'ArpP')
|
||
#define ExAllocatePoolIORL(a,b) ExAllocatePoolWithTag(a,b,'BrpP')
|
||
#define ExAllocatePoolIORRR(a,b) ExAllocatePoolWithTag(a,b,'CrpP')
|
||
|
||
#else // MAXDBG
|
||
|
||
#define ExAllocatePoolAT(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolRD(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolCMRL(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolCMRR(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolAE(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolTE(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolPRD(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolIORD(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePool1RD(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolPDO(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolIORR(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolIORL(a,b) ExAllocatePool(a,b)
|
||
#define ExAllocatePoolIORRR(a,b) ExAllocatePool(a,b)
|
||
|
||
#endif // MAXDBG
|
||
|
||
#if DBG_SCOPE
|
||
|
||
#define IopStopOnTimeout() (IopUseTimeout)
|
||
|
||
VOID
|
||
IopDumpResourceDescriptor (
|
||
IN PUCHAR Indent,
|
||
IN PIO_RESOURCE_DESCRIPTOR Desc
|
||
);
|
||
|
||
VOID
|
||
IopDumpResourceRequirementsList (
|
||
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
|
||
);
|
||
|
||
VOID
|
||
IopDumpCmResourceDescriptor (
|
||
IN PUCHAR Indent,
|
||
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc
|
||
);
|
||
|
||
VOID
|
||
IopDumpCmResourceList (
|
||
IN PCM_RESOURCE_LIST CmList
|
||
);
|
||
|
||
VOID
|
||
IopCheckDataStructuresWorker (
|
||
IN PDEVICE_NODE Device
|
||
);
|
||
|
||
VOID
|
||
IopCheckDataStructures (
|
||
IN PDEVICE_NODE DeviceNode
|
||
);
|
||
|
||
#define IopRecordTranslationFailure(d,s) { \
|
||
if (PnpResDebugTranslationFailureCount) { \
|
||
PnpResDebugTranslationFailureCount--; \
|
||
PnpResDebugTranslationFailure->devnode = d; \
|
||
PnpResDebugTranslationFailure->resource = s; \
|
||
PnpResDebugTranslationFailure++; \
|
||
} \
|
||
}
|
||
|
||
#else
|
||
|
||
#define IopStopOnTimeout() 1
|
||
#define IopRecordTranslationFailure(d,s)
|
||
#define IopDumpResourceRequirementsList(x)
|
||
#define IopDumpResourceDescriptor(x,y)
|
||
#define IopDumpCmResourceList(c)
|
||
#define IopDumpCmResourceDescriptor(i,d)
|
||
#define IopCheckDataStructures(x)
|
||
|
||
#endif // DBG_SCOPE
|
||
//
|
||
// Internal/Forward function references
|
||
//
|
||
VOID
|
||
IopRemoveLegacyDeviceNode (
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN PDEVICE_NODE LegacyDeviceNode
|
||
);
|
||
|
||
NTSTATUS
|
||
IopFindLegacyDeviceNode (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
OUT PDEVICE_NODE *LegacyDeviceNode,
|
||
OUT PDEVICE_OBJECT *LegacyPDO
|
||
);
|
||
|
||
NTSTATUS
|
||
IopGetResourceRequirementsForAssignTable (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN PIOP_RESOURCE_REQUEST RequestTableEnd,
|
||
OUT PULONG DeviceCount
|
||
);
|
||
|
||
NTSTATUS
|
||
IopResourceRequirementsListToReqList(
|
||
IN PIOP_RESOURCE_REQUEST Request,
|
||
OUT PVOID *ResReqList
|
||
);
|
||
|
||
VOID
|
||
IopRearrangeReqList (
|
||
IN PREQ_LIST ReqList
|
||
);
|
||
|
||
VOID
|
||
IopRearrangeAssignTable (
|
||
IN PIOP_RESOURCE_REQUEST AssignTable,
|
||
IN ULONG Count
|
||
);
|
||
|
||
int
|
||
__cdecl
|
||
IopCompareReqAlternativePriority (
|
||
const void *arg1,
|
||
const void *arg2
|
||
);
|
||
|
||
int
|
||
__cdecl
|
||
IopCompareResourceRequestPriority(
|
||
const void *arg1,
|
||
const void *arg2
|
||
);
|
||
|
||
VOID
|
||
IopBuildCmResourceLists(
|
||
IN PIOP_RESOURCE_REQUEST AssignTable,
|
||
IN PIOP_RESOURCE_REQUEST AssignTableEnd
|
||
);
|
||
|
||
VOID
|
||
IopBuildCmResourceList (
|
||
IN PIOP_RESOURCE_REQUEST AssignEntry
|
||
);
|
||
|
||
NTSTATUS
|
||
IopSetupArbiterAndTranslators(
|
||
IN PREQ_DESC ReqDesc
|
||
);
|
||
|
||
BOOLEAN
|
||
IopFindResourceHandlerInfo(
|
||
IN RESOURCE_HANDLER_TYPE HandlerType,
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN UCHAR ResourceType,
|
||
OUT PVOID *HandlerEntry
|
||
);
|
||
|
||
NTSTATUS
|
||
IopParentToRawTranslation(
|
||
IN OUT PREQ_DESC ReqDesc
|
||
);
|
||
|
||
NTSTATUS
|
||
IopChildToRootTranslation(
|
||
IN PDEVICE_NODE DeviceNode, OPTIONAL
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber,
|
||
IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
|
||
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
|
||
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *Target
|
||
);
|
||
|
||
NTSTATUS
|
||
IopTranslateAndAdjustReqDesc(
|
||
IN PREQ_DESC ReqDesc,
|
||
IN PPI_RESOURCE_TRANSLATOR_ENTRY TranslatorEntry,
|
||
OUT PREQ_DESC *TranslatedReqDesc
|
||
);
|
||
|
||
NTSTATUS
|
||
IopCallArbiter(
|
||
PPI_RESOURCE_ARBITER_ENTRY ArbiterEntry,
|
||
ARBITER_ACTION Command,
|
||
PVOID Input1,
|
||
PVOID Input2,
|
||
PVOID Input3
|
||
);
|
||
|
||
NTSTATUS
|
||
IopFindResourcesForArbiter (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN UCHAR ResourceType,
|
||
OUT ULONG *Count,
|
||
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmDesc
|
||
);
|
||
|
||
VOID
|
||
IopReleaseResourcesInternal (
|
||
IN PDEVICE_NODE DeviceNode
|
||
);
|
||
|
||
VOID
|
||
IopReleaseResources (
|
||
IN PDEVICE_NODE DeviceNode
|
||
);
|
||
|
||
NTSTATUS
|
||
IopRestoreResourcesInternal (
|
||
IN PDEVICE_NODE DeviceNode
|
||
);
|
||
|
||
VOID
|
||
IopSetLegacyDeviceInstance (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_NODE DeviceNode
|
||
);
|
||
|
||
PCM_RESOURCE_LIST
|
||
IopCombineLegacyResources (
|
||
IN PDEVICE_NODE DeviceNode
|
||
);
|
||
|
||
BOOLEAN
|
||
IopNeedToReleaseBootResources(
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN PCM_RESOURCE_LIST AllocatedResources
|
||
);
|
||
|
||
VOID
|
||
IopReleaseFilteredBootResources(
|
||
IN PIOP_RESOURCE_REQUEST AssignTable,
|
||
IN PIOP_RESOURCE_REQUEST AssignTableEnd
|
||
);
|
||
|
||
NTSTATUS
|
||
IopQueryConflictListInternal(
|
||
PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN PCM_RESOURCE_LIST ResourceList,
|
||
IN ULONG ResourceListSize,
|
||
OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
|
||
IN ULONG ConflictListSize,
|
||
IN ULONG Flags
|
||
);
|
||
|
||
NTSTATUS
|
||
IopQueryConflictFillConflicts(
|
||
PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN ULONG ConflictCount,
|
||
IN PARBITER_CONFLICT_INFO ConflictInfoList,
|
||
OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
|
||
IN ULONG ConflictListSize,
|
||
IN ULONG Flags
|
||
);
|
||
|
||
NTSTATUS
|
||
IopQueryConflictFillString(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PWSTR Buffer,
|
||
IN OUT PULONG Length,
|
||
IN OUT PULONG Flags
|
||
);
|
||
|
||
BOOLEAN
|
||
IopEliminateBogusConflict(
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN PDEVICE_OBJECT ConflictDeviceObject
|
||
);
|
||
|
||
VOID
|
||
IopQueryRebalance (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN ULONG Phase,
|
||
IN PULONG RebalanceCount,
|
||
IN PDEVICE_OBJECT **DeviceTable
|
||
);
|
||
|
||
VOID
|
||
IopQueryRebalanceWorker (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN ULONG RebalancePhase,
|
||
IN PULONG RebalanceCount,
|
||
IN PDEVICE_OBJECT **DeviceTable
|
||
);
|
||
|
||
VOID
|
||
IopTestForReconfiguration (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN ULONG RebalancePhase,
|
||
IN PULONG RebalanceCount,
|
||
IN PDEVICE_OBJECT **DeviceTable
|
||
);
|
||
|
||
NTSTATUS
|
||
IopRebalance (
|
||
IN ULONG AssignTableCont,
|
||
IN PIOP_RESOURCE_REQUEST AssignTable
|
||
);
|
||
|
||
NTSTATUS
|
||
IopTestConfiguration (
|
||
IN OUT PLIST_ENTRY ArbiterList
|
||
);
|
||
|
||
NTSTATUS
|
||
IopRetestConfiguration (
|
||
IN OUT PLIST_ENTRY ArbiterList
|
||
);
|
||
|
||
NTSTATUS
|
||
IopCommitConfiguration (
|
||
IN OUT PLIST_ENTRY ArbiterList
|
||
);
|
||
|
||
VOID
|
||
IopSelectFirstConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList
|
||
);
|
||
|
||
BOOLEAN
|
||
IopSelectNextConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList
|
||
);
|
||
|
||
VOID
|
||
IopCleanupSelectedConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount
|
||
);
|
||
|
||
ULONG
|
||
IopComputeConfigurationPriority (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount
|
||
);
|
||
|
||
VOID
|
||
IopSaveRestoreConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ArbiterList,
|
||
IN BOOLEAN Save
|
||
);
|
||
|
||
VOID
|
||
IopAddRemoveReqDescs (
|
||
IN PREQ_DESC *ReqDescTable,
|
||
IN ULONG ReqDescCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList,
|
||
IN BOOLEAN Add
|
||
);
|
||
|
||
NTSTATUS
|
||
IopFindBestConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList
|
||
);
|
||
|
||
PDEVICE_NODE
|
||
IopFindLegacyBusDeviceNode (
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber
|
||
);
|
||
|
||
NTSTATUS
|
||
IopAllocateBootResourcesInternal (
|
||
IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PCM_RESOURCE_LIST BootResources
|
||
);
|
||
|
||
NTSTATUS
|
||
IopBootAllocation (
|
||
IN PREQ_LIST ReqList
|
||
);
|
||
|
||
PCM_RESOURCE_LIST
|
||
IopCreateCmResourceList(
|
||
IN PCM_RESOURCE_LIST ResourceList,
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber,
|
||
OUT PCM_RESOURCE_LIST *RemainingList
|
||
);
|
||
|
||
PCM_RESOURCE_LIST
|
||
IopCombineCmResourceList(
|
||
IN PCM_RESOURCE_LIST ResourceListA,
|
||
IN PCM_RESOURCE_LIST ResourceListB
|
||
);
|
||
|
||
VOID
|
||
IopFreeReqAlternative (
|
||
IN PREQ_ALTERNATIVE ReqAlternative
|
||
);
|
||
|
||
VOID
|
||
IopFreeReqList (
|
||
IN PREQ_LIST ReqList
|
||
);
|
||
|
||
VOID
|
||
IopFreeResourceRequirementsForAssignTable(
|
||
IN PIOP_RESOURCE_REQUEST AssignTable,
|
||
IN PIOP_RESOURCE_REQUEST AssignTableEnd
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
|
||
#pragma alloc_text(PAGE, IopAllocateResources)
|
||
#pragma alloc_text(PAGE, IopReleaseDeviceResources)
|
||
#pragma alloc_text(PAGE, IopGetResourceRequirementsForAssignTable)
|
||
#pragma alloc_text(PAGE, IopResourceRequirementsListToReqList)
|
||
#pragma alloc_text(PAGE, IopRearrangeReqList)
|
||
#pragma alloc_text(PAGE, IopRearrangeAssignTable)
|
||
#pragma alloc_text(PAGE, IopBuildCmResourceLists)
|
||
#pragma alloc_text(PAGE, IopBuildCmResourceList)
|
||
#pragma alloc_text(PAGE, IopSetupArbiterAndTranslators)
|
||
#pragma alloc_text(PAGE, IopUncacheInterfaceInformation)
|
||
#pragma alloc_text(PAGE, IopFindResourceHandlerInfo)
|
||
#pragma alloc_text(PAGE, IopParentToRawTranslation)
|
||
#pragma alloc_text(PAGE, IopChildToRootTranslation)
|
||
#pragma alloc_text(PAGE, IopTranslateAndAdjustReqDesc)
|
||
#pragma alloc_text(PAGE, IopCallArbiter)
|
||
#pragma alloc_text(PAGE, IopFindResourcesForArbiter)
|
||
#pragma alloc_text(PAGE, IopLegacyResourceAllocation)
|
||
#pragma alloc_text(PAGE, IopFindLegacyDeviceNode)
|
||
#pragma alloc_text(PAGE, IopRemoveLegacyDeviceNode)
|
||
#pragma alloc_text(PAGE, IopDuplicateDetection)
|
||
#pragma alloc_text(PAGE, IopReleaseResourcesInternal)
|
||
#pragma alloc_text(PAGE, IopRestoreResourcesInternal)
|
||
#pragma alloc_text(PAGE, IopSetLegacyDeviceInstance)
|
||
#pragma alloc_text(PAGE, IopCombineLegacyResources)
|
||
#pragma alloc_text(PAGE, IopReleaseResources)
|
||
#pragma alloc_text(PAGE, IopReallocateResources)
|
||
#pragma alloc_text(PAGE, IopReleaseFilteredBootResources)
|
||
#pragma alloc_text(PAGE, IopNeedToReleaseBootResources)
|
||
#pragma alloc_text(PAGE, IopQueryConflictList)
|
||
#pragma alloc_text(PAGE, IopQueryConflictListInternal)
|
||
#pragma alloc_text(PAGE, IopQueryConflictFillConflicts)
|
||
#pragma alloc_text(PAGE, IopQueryConflictFillString)
|
||
#pragma alloc_text(PAGE, IopCompareReqAlternativePriority)
|
||
#pragma alloc_text(PAGE, IopCompareResourceRequestPriority)
|
||
#pragma alloc_text(PAGE, IopQueryRebalance)
|
||
#pragma alloc_text(PAGE, IopQueryRebalanceWorker)
|
||
#pragma alloc_text(PAGE, IopTestForReconfiguration)
|
||
#pragma alloc_text(PAGE, IopRebalance)
|
||
#pragma alloc_text(PAGE, IopTestConfiguration)
|
||
#pragma alloc_text(PAGE, IopRetestConfiguration)
|
||
#pragma alloc_text(PAGE, IopCommitConfiguration)
|
||
#pragma alloc_text(PAGE, IopSelectFirstConfiguration)
|
||
#pragma alloc_text(PAGE, IopSelectNextConfiguration)
|
||
#pragma alloc_text(PAGE, IopCleanupSelectedConfiguration)
|
||
#pragma alloc_text(PAGE, IopComputeConfigurationPriority)
|
||
#pragma alloc_text(PAGE, IopSaveRestoreConfiguration)
|
||
#pragma alloc_text(PAGE, IopAddRemoveReqDescs)
|
||
#pragma alloc_text(PAGE, IopFindBestConfiguration)
|
||
#pragma alloc_text(PAGE, IopInsertLegacyBusDeviceNode)
|
||
#pragma alloc_text(PAGE, IopFindLegacyBusDeviceNode)
|
||
#pragma alloc_text(PAGE, IopAllocateBootResources)
|
||
#pragma alloc_text(INIT, IopReportBootResources)
|
||
#pragma alloc_text(INIT, IopAllocateLegacyBootResources)
|
||
#pragma alloc_text(PAGE, IopAllocateBootResourcesInternal)
|
||
#pragma alloc_text(PAGE, IopBootAllocation)
|
||
#pragma alloc_text(PAGE, IopCreateCmResourceList)
|
||
#pragma alloc_text(PAGE, IopCombineCmResourceList)
|
||
#pragma alloc_text(PAGE, IopFreeReqAlternative)
|
||
#pragma alloc_text(PAGE, IopFreeReqList)
|
||
#pragma alloc_text(PAGE, IopFreeResourceRequirementsForAssignTable)
|
||
#if DBG_SCOPE
|
||
|
||
#pragma alloc_text(PAGE, IopCheckDataStructures)
|
||
#pragma alloc_text(PAGE, IopCheckDataStructuresWorker)
|
||
#pragma alloc_text(PAGE, IopDumpResourceRequirementsList)
|
||
#pragma alloc_text(PAGE, IopDumpResourceDescriptor)
|
||
#pragma alloc_text(PAGE, IopDumpCmResourceDescriptor)
|
||
#pragma alloc_text(PAGE, IopDumpCmResourceList)
|
||
|
||
#endif // DBG_SCOPE
|
||
|
||
#endif // ALLOC_PRAGMA
|
||
//
|
||
// External references
|
||
//
|
||
extern const WCHAR IopWstrTranslated[];
|
||
extern const WCHAR IopWstrRaw[];
|
||
//
|
||
// GLOBAL variables
|
||
//
|
||
PIOP_RESOURCE_REQUEST PiAssignTable;
|
||
ULONG PiAssignTableCount;
|
||
PDEVICE_NODE IopLegacyDeviceNode; // Head of list of made-up
|
||
// devicenodes used for legacy
|
||
// allocation.
|
||
// IoAssignResources &
|
||
// IoReportResourceUsage
|
||
#if DBG_SCOPE
|
||
|
||
ULONG
|
||
PnpResDebugTranslationFailureCount = 32; // get count in both this line and the next.
|
||
PNPRESDEBUGTRANSLATIONFAILURE
|
||
PnpResDebugTranslationFailureArray[32];
|
||
PNPRESDEBUGTRANSLATIONFAILURE
|
||
*PnpResDebugTranslationFailure = PnpResDebugTranslationFailureArray;
|
||
ULONG IopUseTimeout = 0;
|
||
|
||
#endif // DBG_SCOPE
|
||
|
||
NTSTATUS
|
||
IopAllocateResources(
|
||
IN PULONG RequestCount,
|
||
IN OUT PIOP_RESOURCE_REQUEST *Request,
|
||
IN BOOLEAN ResourceManagerLocked,
|
||
IN BOOLEAN DoBootConfigs,
|
||
OUT PBOOLEAN RebalancePerformed
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For each AssignTable entry, this routine queries device's IO resource requirements
|
||
list and converts it to our internal REQ_LIST format; calls worker routine to perform
|
||
the resources assignment.
|
||
|
||
Parameters:
|
||
|
||
AssignTable - supplies a pointer to the first entry of a IOP_RESOURCE_REQUEST table.
|
||
|
||
AssignTableEnd - supplies a pointer to the end of IOP_RESOURCE_REQUEST table.
|
||
|
||
Locked - Indicates whether the PpRegistrySemaphore is acquired by the caller.
|
||
|
||
DoBootConfigs - Indicates whether we should assign BOOT configs.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PIOP_RESOURCE_REQUEST requestTable;
|
||
PIOP_RESOURCE_REQUEST requestTableEnd;
|
||
ULONG deviceCount;
|
||
BOOLEAN attemptRebalance;
|
||
PIOP_RESOURCE_REQUEST requestEntry;
|
||
LIST_ENTRY activeArbiterList;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Lock the resource manager if the caller has not locked already.
|
||
// This is to serialize allocations and releases of resources from the
|
||
// arbiters.
|
||
//
|
||
if (!ResourceManagerLocked) {
|
||
|
||
IopLockResourceManager();
|
||
}
|
||
requestTable = *Request;
|
||
requestTableEnd = requestTable + (deviceCount = *RequestCount);
|
||
status = IopGetResourceRequirementsForAssignTable(requestTable, requestTableEnd, &deviceCount);
|
||
if (deviceCount) {
|
||
|
||
attemptRebalance = ((*RequestCount == 1) && (requestTable->Flags & IOP_ASSIGN_NO_REBALANCE))? FALSE : TRUE;
|
||
if (DoBootConfigs) {
|
||
|
||
if (!IopBootConfigsReserved) {
|
||
|
||
//
|
||
// Process devices with boot config. If there are none, process others.
|
||
//
|
||
for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
|
||
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
|
||
if (deviceNode->Flags & DNF_HAS_BOOT_CONFIG) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
if (requestEntry != requestTableEnd) {
|
||
|
||
//
|
||
// There is at least one device with boot config.
|
||
//
|
||
for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
|
||
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
|
||
if ( !(requestEntry->Flags & IOP_ASSIGN_IGNORE) &&
|
||
!(deviceNode->Flags & DNF_HAS_BOOT_CONFIG) &&
|
||
requestEntry->ResourceRequirements) {
|
||
|
||
IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "Delaying non BOOT config device %wZ...\n", &deviceNode->InstancePath));
|
||
requestEntry->Flags |= IOP_ASSIGN_IGNORE;
|
||
requestEntry->Status = STATUS_RETRY;
|
||
deviceCount--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (deviceCount) {
|
||
|
||
if (deviceCount != (*RequestCount)) {
|
||
//
|
||
// Move the uninteresting devices to the end of the table.
|
||
//
|
||
for (requestEntry = requestTable; requestEntry < requestTableEnd; ) {
|
||
|
||
IOP_RESOURCE_REQUEST temp;
|
||
|
||
if (!(requestEntry->Flags & IOP_ASSIGN_IGNORE)) {
|
||
|
||
requestEntry++;
|
||
continue;
|
||
}
|
||
temp = *requestEntry;
|
||
*requestEntry = *(requestTableEnd - 1);
|
||
*(requestTableEnd - 1) = temp;
|
||
requestTableEnd--;
|
||
}
|
||
}
|
||
ASSERT((ULONG)(requestTableEnd - requestTable) == deviceCount);
|
||
//
|
||
// Sort the AssignTable
|
||
//
|
||
IopRearrangeAssignTable(requestTable, deviceCount);
|
||
//
|
||
// Try one device at a time.
|
||
//
|
||
for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
|
||
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
|
||
IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "Trying to allocate resources for %ws.\n", deviceNode->InstancePath.Buffer));
|
||
status = IopFindBestConfiguration(requestEntry, 1, &activeArbiterList);
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Ask the arbiters to commit this configuration.
|
||
//
|
||
status = IopCommitConfiguration(&activeArbiterList);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
IopBuildCmResourceLists(requestEntry, requestEntry + 1);
|
||
break;
|
||
} else {
|
||
|
||
requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
|
||
}
|
||
} else if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"IopAllocateResource: Failed to allocate Pool.\n"));
|
||
break;
|
||
|
||
} else if (attemptRebalance) {
|
||
|
||
IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "IopAllocateResources: Initiating REBALANCE...\n"));
|
||
|
||
deviceNode->Flags |= DNF_NEEDS_REBALANCE;
|
||
status = IopRebalance(1, requestEntry);
|
||
deviceNode->Flags &= ~DNF_NEEDS_REBALANCE;
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
|
||
} else if (RebalancePerformed) {
|
||
|
||
*RebalancePerformed = TRUE;
|
||
break;
|
||
}
|
||
} else {
|
||
|
||
requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
|
||
}
|
||
}
|
||
//
|
||
// If we ran out of memory, then set the appropriate status
|
||
// on remaining devices. On success, set STATUS_RETRY on the
|
||
// rest so we will attempt allocation again after the current
|
||
// device is started.
|
||
//
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
requestEntry++;
|
||
}
|
||
for (; requestEntry < requestTableEnd; requestEntry++) {
|
||
|
||
if (status == STATUS_INSUFFICIENT_RESOURCES) {
|
||
|
||
requestEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
} else {
|
||
|
||
requestEntry->Status = STATUS_RETRY;
|
||
requestEntry->Flags |= IOP_ASSIGN_IGNORE;
|
||
}
|
||
}
|
||
|
||
for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
|
||
|
||
if (requestEntry->Flags & (IOP_ASSIGN_IGNORE | IOP_ASSIGN_RETRY)) {
|
||
|
||
continue;
|
||
}
|
||
if ( requestEntry->Status == STATUS_SUCCESS &&
|
||
requestEntry->AllocationType == ArbiterRequestPnpEnumerated) {
|
||
|
||
IopReleaseFilteredBootResources(requestEntry, requestEntry + 1);
|
||
}
|
||
if ((requestEntry->Flags & IOP_ASSIGN_EXCLUDE) || requestEntry->ResourceAssignment == NULL) {
|
||
|
||
requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
|
||
}
|
||
}
|
||
} else {
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
} else {
|
||
//
|
||
// Only process devices with no requirements.
|
||
//
|
||
for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
|
||
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
|
||
if (NT_SUCCESS(requestEntry->Status) && requestEntry->ResourceRequirements == NULL) {
|
||
|
||
IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "IopAllocateResources: Processing no resource requiring device %wZ\n", &deviceNode->InstancePath));
|
||
} else {
|
||
|
||
IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "IopAllocateResources: Ignoring resource consuming device %wZ\n", &deviceNode->InstancePath));
|
||
requestEntry->Flags |= IOP_ASSIGN_IGNORE;
|
||
requestEntry->Status = STATUS_RETRY;
|
||
}
|
||
}
|
||
}
|
||
IopFreeResourceRequirementsForAssignTable(requestTable, requestTableEnd);
|
||
}
|
||
if (!ResourceManagerLocked) {
|
||
|
||
IopUnlockResourceManager();
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopReleaseDeviceResources (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN BOOLEAN ReserveResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine releases the resources assigned to a device.
|
||
|
||
Arguments:
|
||
|
||
DeviceNode - Device whose resources are to be released.
|
||
|
||
ReserveResources - TRUE specifies that the BOOT config needs to be
|
||
reserved (after re-query).
|
||
|
||
Return Value:
|
||
|
||
Final status code.
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PCM_RESOURCE_LIST cmResource;
|
||
ULONG cmLength;
|
||
|
||
PAGED_CODE();
|
||
|
||
if ( !DeviceNode->ResourceList &&
|
||
!(DeviceNode->Flags & DNF_BOOT_CONFIG_RESERVED)) {
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
cmResource = NULL;
|
||
cmLength = 0;
|
||
//
|
||
// If needed, re-query for BOOT configs. We need to do this BEFORE we
|
||
// release the BOOT config (otherwise ROOT devices cannot report BOOT
|
||
// config).
|
||
//
|
||
if (ReserveResources && !(DeviceNode->Flags & DNF_MADEUP)) {
|
||
//
|
||
// First query for new BOOT config (order important for ROOT devices).
|
||
//
|
||
status = IopQueryDeviceResources(
|
||
DeviceNode->PhysicalDeviceObject,
|
||
QUERY_RESOURCE_LIST,
|
||
&cmResource,
|
||
&cmLength);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
cmResource = NULL;
|
||
cmLength = 0;
|
||
}
|
||
}
|
||
//
|
||
// Release resources for this device.
|
||
//
|
||
status = IopLegacyResourceAllocation(
|
||
ArbiterRequestUndefined,
|
||
IoPnpDriverObject,
|
||
DeviceNode->PhysicalDeviceObject,
|
||
NULL,
|
||
NULL);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Request reallocation of resources for conflicting devices.
|
||
//
|
||
|
||
PipRequestDeviceAction(NULL, AssignResources, FALSE, 0, NULL, NULL);
|
||
|
||
//
|
||
// If needed, re-query and reserve current BOOT config for this device.
|
||
// We always rereserve the boot config (ie DNF_MADEUP root enumerated
|
||
// and IoReportDetected) devices in IopLegacyResourceAllocation.
|
||
//
|
||
if (ReserveResources && !(DeviceNode->Flags & DNF_MADEUP)) {
|
||
|
||
UNICODE_STRING unicodeName;
|
||
HANDLE logConfHandle;
|
||
HANDLE handle;
|
||
|
||
ASSERT(DeviceNode->BootResources == NULL);
|
||
status = IopDeviceObjectToDeviceInstance(
|
||
DeviceNode->PhysicalDeviceObject,
|
||
&handle,
|
||
KEY_ALL_ACCESS);
|
||
logConfHandle = NULL;
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
|
||
status = IopCreateRegistryKeyEx(
|
||
&logConfHandle,
|
||
handle,
|
||
&unicodeName,
|
||
KEY_ALL_ACCESS,
|
||
REG_OPTION_NON_VOLATILE,
|
||
NULL);
|
||
ZwClose(handle);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
logConfHandle = NULL;
|
||
}
|
||
}
|
||
if (logConfHandle) {
|
||
|
||
PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_BOOTCONFIG);
|
||
PiLockPnpRegistry(FALSE);
|
||
if (cmResource) {
|
||
|
||
ZwSetValueKey(
|
||
logConfHandle,
|
||
&unicodeName,
|
||
TITLE_INDEX_VALUE,
|
||
REG_RESOURCE_LIST,
|
||
cmResource,
|
||
cmLength);
|
||
} else {
|
||
|
||
ZwDeleteValueKey(logConfHandle, &unicodeName);
|
||
}
|
||
PiUnlockPnpRegistry();
|
||
ZwClose(logConfHandle);
|
||
}
|
||
//
|
||
// Reserve any remaining BOOT config.
|
||
//
|
||
if (cmResource) {
|
||
|
||
DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
|
||
//
|
||
// This device consumes BOOT resources. Reserve its boot resources
|
||
//
|
||
(*IopAllocateBootResourcesRoutine)(
|
||
ArbiterRequestPnpEnumerated,
|
||
DeviceNode->PhysicalDeviceObject,
|
||
DeviceNode->BootResources = cmResource);
|
||
}
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopGetResourceRequirementsForAssignTable (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN PIOP_RESOURCE_REQUEST RequestTableEnd,
|
||
OUT PULONG DeviceCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function gets resource requirements for entries in the request table.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Start of request table.
|
||
|
||
RequestTableEnd - End of request table.
|
||
|
||
DeviceCount - Gets number of devices with non-NULL requirements.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if we got one non-NULL requirement, else STATUS_UNSUCCESSFUL.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIOP_RESOURCE_REQUEST request;
|
||
NTSTATUS status;
|
||
PDEVICE_NODE deviceNode;
|
||
ULONG length;
|
||
|
||
PAGED_CODE();
|
||
|
||
*DeviceCount = 0;
|
||
for ( request = RequestTable;
|
||
request < RequestTableEnd;
|
||
request++) {
|
||
//
|
||
// Skip uninteresting entries.
|
||
//
|
||
request->ReqList = NULL;
|
||
if (request->Flags & IOP_ASSIGN_IGNORE) {
|
||
|
||
continue;
|
||
}
|
||
request->ResourceAssignment = NULL;
|
||
request->TranslatedResourceAssignment = NULL;
|
||
deviceNode = PP_DO_TO_DN(
|
||
request->PhysicalDevice);
|
||
if ( (deviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) &&
|
||
deviceNode->ResourceRequirements) {
|
||
|
||
ExFreePool(deviceNode->ResourceRequirements);
|
||
deviceNode->ResourceRequirements = NULL;
|
||
deviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED;
|
||
//
|
||
// Mark that caller needs to clear DNF_RESOURCE_REQUIREMENTS_CHANGED
|
||
// flag on success.
|
||
//
|
||
request->Flags |= IOP_ASSIGN_CLEAR_RESOURCE_REQUIREMENTS_CHANGE_FLAG;
|
||
}
|
||
if (!request->ResourceRequirements) {
|
||
|
||
if ( deviceNode->ResourceRequirements &&
|
||
!(deviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED)) {
|
||
|
||
IopDbgPrint(( IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"Resource requirements list already exists for "
|
||
"%wZ\n",
|
||
&deviceNode->InstancePath));
|
||
request->ResourceRequirements = deviceNode->ResourceRequirements;
|
||
request->AllocationType = ArbiterRequestPnpEnumerated;
|
||
} else {
|
||
|
||
IopDbgPrint(( IOP_RESOURCE_INFO_LEVEL,
|
||
"Query Resource requirements list for %wZ...\n",
|
||
&deviceNode->InstancePath));
|
||
status = IopQueryDeviceResources(
|
||
request->PhysicalDevice,
|
||
QUERY_RESOURCE_REQUIREMENTS,
|
||
&request->ResourceRequirements,
|
||
&length);
|
||
if ( !NT_SUCCESS(status) ||
|
||
!request->ResourceRequirements) {
|
||
//
|
||
// Success with NULL ResourceRequirements means no resource
|
||
// required.
|
||
//
|
||
request->Flags |= IOP_ASSIGN_IGNORE;
|
||
request->Status = status;
|
||
continue;
|
||
}
|
||
if (deviceNode->ResourceRequirements) {
|
||
|
||
ExFreePool(deviceNode->ResourceRequirements);
|
||
deviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED;
|
||
}
|
||
deviceNode->ResourceRequirements = request->ResourceRequirements;
|
||
}
|
||
}
|
||
//
|
||
// For non-stop case, even though the res req list has changed, we need
|
||
// to guarantee that it will get its current setting, even if the new
|
||
// requirements do not cover the current setting.
|
||
//
|
||
if (request->Flags & IOP_ASSIGN_KEEP_CURRENT_CONFIG) {
|
||
|
||
PIO_RESOURCE_REQUIREMENTS_LIST filteredList;
|
||
BOOLEAN exactMatch;
|
||
|
||
ASSERT(
|
||
deviceNode->ResourceRequirements ==
|
||
request->ResourceRequirements);
|
||
status = IopFilterResourceRequirementsList(
|
||
request->ResourceRequirements,
|
||
deviceNode->ResourceList,
|
||
&filteredList,
|
||
&exactMatch);
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// No need to free the original request->ResourceRequirements
|
||
// since its cached in deviceNode->ResourceRequirements.
|
||
//
|
||
request->ResourceRequirements = filteredList;
|
||
} else {
|
||
//
|
||
// Clear the flag so we dont free request->ResourceRequirements.
|
||
//
|
||
request->Flags &= ~IOP_ASSIGN_KEEP_CURRENT_CONFIG;
|
||
}
|
||
}
|
||
IopDumpResourceRequirementsList(request->ResourceRequirements);
|
||
//
|
||
// Convert the requirements list to our internal representation.
|
||
//
|
||
status = IopResourceRequirementsListToReqList(
|
||
request,
|
||
&request->ReqList);
|
||
if (NT_SUCCESS(status) && request->ReqList) {
|
||
|
||
PREQ_LIST reqList = (PREQ_LIST)request->ReqList;
|
||
//
|
||
// Sort the list such that higher priority alternatives are placed
|
||
// in the front of the list.
|
||
//
|
||
IopRearrangeReqList(reqList);
|
||
if (reqList->BestAlternative) {
|
||
//
|
||
// Requests from less flexible devices get higher priority.
|
||
//
|
||
request->Priority = (reqList->AlternativeCount < 3)?
|
||
0 : reqList->AlternativeCount;
|
||
request->Status = status;
|
||
(*DeviceCount)++;
|
||
continue;
|
||
}
|
||
//
|
||
// This device has no soft configuration.
|
||
//
|
||
IopFreeResourceRequirementsForAssignTable(request, request + 1);
|
||
status = STATUS_DEVICE_CONFIGURATION_ERROR;
|
||
}
|
||
request->Status = status;
|
||
request->Flags |= IOP_ASSIGN_IGNORE;
|
||
}
|
||
|
||
return (*DeviceCount)? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopResourceRequirementsListToReqList(
|
||
IN PIOP_RESOURCE_REQUEST Request,
|
||
OUT PVOID *ResReqList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes the input Io resource requirements list and
|
||
generates an internal REQ_LIST and its related structures.
|
||
|
||
Parameters:
|
||
|
||
IoResources - supplies a pointer to the Io resource requirements List.
|
||
|
||
PhysicalDevice - supplies a pointer to the physical device object requesting
|
||
the resources.
|
||
|
||
ReqList - supplies a pointer to a variable to receive the returned REQ_LIST.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
|
||
LONG ioResourceListCount;
|
||
PIO_RESOURCE_LIST ioResourceList;
|
||
PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor;
|
||
PIO_RESOURCE_DESCRIPTOR ioResourceDescriptorEnd;
|
||
PIO_RESOURCE_DESCRIPTOR firstDescriptor;
|
||
PUCHAR coreEnd;
|
||
BOOLEAN noAlternativeDescriptor;
|
||
ULONG reqDescAlternativeCount;
|
||
ULONG alternativeDescriptorCount;
|
||
ULONG reqAlternativeCount;
|
||
PREQ_LIST reqList;
|
||
INTERFACE_TYPE interfaceType;
|
||
ULONG busNumber;
|
||
NTSTATUS status;
|
||
NTSTATUS failureStatus;
|
||
NTSTATUS finalStatus;
|
||
|
||
PAGED_CODE();
|
||
|
||
*ResReqList = NULL;
|
||
//
|
||
// Make sure there is some resource requirement to be converted.
|
||
//
|
||
ioResources = Request->ResourceRequirements;
|
||
ioResourceListCount = (LONG)ioResources->AlternativeLists;
|
||
if (ioResourceListCount == 0) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"No ResReqList to convert to ReqList\n"));
|
||
return STATUS_SUCCESS;
|
||
}
|
||
//
|
||
// ***** Phase 1 *****
|
||
//
|
||
// Parse the requirements list to validate it and determine the sizes of
|
||
// internal structures.
|
||
//
|
||
ioResourceList = ioResources->List;
|
||
coreEnd = (PUCHAR)ioResources + ioResources->ListSize;
|
||
reqDescAlternativeCount = 0;
|
||
alternativeDescriptorCount = 0;
|
||
while (--ioResourceListCount >= 0) {
|
||
|
||
ioResourceDescriptor = ioResourceList->Descriptors;
|
||
ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
|
||
if (ioResourceDescriptor == ioResourceDescriptorEnd) {
|
||
//
|
||
// An alternative list with zero descriptor count.
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
//
|
||
// Perform sanity check. On failure, simply return failure status.
|
||
//
|
||
if ( ioResourceDescriptor > ioResourceDescriptorEnd ||
|
||
(PUCHAR)ioResourceDescriptor > coreEnd ||
|
||
(PUCHAR)ioResourceDescriptorEnd > coreEnd) {
|
||
//
|
||
// The structure header is invalid (excluding the variable length
|
||
// Descriptors array) or,
|
||
// IoResourceDescriptorEnd is the result of arithmetic overflow or,
|
||
// the descriptor array is outside of the valid memory.
|
||
//
|
||
IopDbgPrint((IOP_RESOURCE_ERROR_LEVEL, "Invalid ResReqList\n"));
|
||
goto InvalidParameter;
|
||
}
|
||
if (ioResourceDescriptor->Type == CmResourceTypeConfigData) {
|
||
|
||
ioResourceDescriptor++;
|
||
}
|
||
firstDescriptor = ioResourceDescriptor;
|
||
noAlternativeDescriptor = TRUE;
|
||
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
|
||
|
||
switch (ioResourceDescriptor->Type) {
|
||
case CmResourceTypeConfigData:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Invalid ResReq list !!!\n"
|
||
"\tConfigData descriptors are per-LogConf and should be at "
|
||
"the beginning of an AlternativeList\n"));
|
||
goto InvalidParameter;
|
||
|
||
case CmResourceTypeDevicePrivate:
|
||
|
||
while ( ioResourceDescriptor < ioResourceDescriptorEnd &&
|
||
ioResourceDescriptor->Type == CmResourceTypeDevicePrivate) {
|
||
|
||
if (ioResourceDescriptor == firstDescriptor) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Invalid ResReq list !!!\n"
|
||
"\tThe first descriptor of a LogConf can not be a "
|
||
"DevicePrivate descriptor.\n"));
|
||
goto InvalidParameter;
|
||
}
|
||
reqDescAlternativeCount++;
|
||
ioResourceDescriptor++;
|
||
}
|
||
noAlternativeDescriptor = TRUE;
|
||
break;
|
||
|
||
default:
|
||
|
||
reqDescAlternativeCount++;
|
||
//
|
||
// For non-arbitrated resource type, set its Option to preferred
|
||
// such that we won't get confused.
|
||
//
|
||
if ( (ioResourceDescriptor->Type & CmResourceTypeNonArbitrated) ||
|
||
ioResourceDescriptor->Type == CmResourceTypeNull) {
|
||
|
||
if (ioResourceDescriptor->Type == CmResourceTypeReserved) {
|
||
|
||
reqDescAlternativeCount--;
|
||
}
|
||
ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
|
||
ioResourceDescriptor++;
|
||
noAlternativeDescriptor = TRUE;
|
||
break;
|
||
}
|
||
if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
|
||
|
||
if (noAlternativeDescriptor) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Invalid ResReq list !!!\n"
|
||
"\tAlternative descriptor without Default or "
|
||
"Preferred descriptor.\n"));
|
||
goto InvalidParameter;
|
||
}
|
||
alternativeDescriptorCount++;
|
||
} else {
|
||
|
||
noAlternativeDescriptor = FALSE;
|
||
}
|
||
ioResourceDescriptor++;
|
||
break;
|
||
}
|
||
}
|
||
ASSERT(ioResourceDescriptor == ioResourceDescriptorEnd);
|
||
ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd;
|
||
}
|
||
//
|
||
// ***** Phase 2 *****
|
||
//
|
||
// Allocate structures and initialize them according to caller's Io ResReq list.
|
||
//
|
||
{
|
||
ULONG reqDescCount;
|
||
IOP_POOL reqAlternativePool;
|
||
IOP_POOL reqDescPool;
|
||
ULONG reqListPoolSize;
|
||
ULONG reqAlternativePoolSize;
|
||
ULONG reqDescPoolSize;
|
||
PUCHAR poolStart;
|
||
ULONG poolSize;
|
||
IOP_POOL outerPool;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PPREQ_ALTERNATIVE reqAlternativePP;
|
||
ULONG reqAlternativeIndex;
|
||
PREQ_DESC reqDesc;
|
||
PREQ_DESC *reqDescPP;
|
||
ULONG reqDescIndex;
|
||
PARBITER_LIST_ENTRY arbiterListEntry;
|
||
#if DBG_SCOPE
|
||
|
||
PPREQ_ALTERNATIVE reqAlternativeEndPP;
|
||
|
||
#endif
|
||
failureStatus = STATUS_UNSUCCESSFUL;
|
||
finalStatus = STATUS_SUCCESS;
|
||
ioResourceList = ioResources->List;
|
||
ioResourceListCount = ioResources->AlternativeLists;
|
||
reqAlternativeCount = ioResourceListCount;
|
||
reqDescCount = reqDescAlternativeCount -
|
||
alternativeDescriptorCount;
|
||
reqDescPoolSize = reqDescCount * sizeof(REQ_DESC);
|
||
reqAlternativePoolSize = reqAlternativeCount *
|
||
(sizeof(REQ_ALTERNATIVE) +
|
||
(reqDescCount - 1) *
|
||
sizeof(PREQ_DESC));
|
||
reqListPoolSize = sizeof(REQ_LIST) +
|
||
(reqAlternativeCount - 1) *
|
||
sizeof(PREQ_ALTERNATIVE);
|
||
poolSize = reqListPoolSize + reqAlternativePoolSize + reqDescPoolSize;
|
||
if (!(poolStart = ExAllocatePoolRD(PagedPool | POOL_COLD_ALLOCATION, poolSize))) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
//
|
||
// Initialize the main pool.
|
||
//
|
||
IopInitPool(&outerPool, poolStart, poolSize);
|
||
//
|
||
// First part of the pool is used by REQ_LIST.
|
||
//
|
||
IopAllocPool(&reqList, &outerPool, reqListPoolSize);
|
||
//
|
||
// Second part of the main pool is used by REQ_ALTERNATIVEs.
|
||
//
|
||
IopAllocPool(&poolStart, &outerPool, reqAlternativePoolSize);
|
||
IopInitPool(&reqAlternativePool, poolStart, reqAlternativePoolSize);
|
||
//
|
||
// Last part of the main pool is used by REQ_DESCs.
|
||
//
|
||
IopAllocPool(&poolStart, &outerPool, reqDescPoolSize);
|
||
IopInitPool(&reqDescPool, poolStart, reqDescPoolSize);
|
||
if (ioResources->InterfaceType == InterfaceTypeUndefined) {
|
||
|
||
interfaceType = PnpDefaultInterfaceType;
|
||
} else {
|
||
|
||
interfaceType = ioResources->InterfaceType;
|
||
}
|
||
busNumber = ioResources->BusNumber;
|
||
//
|
||
// Initialize REQ_LIST.
|
||
//
|
||
reqList->AlternativeCount = reqAlternativeCount;
|
||
reqList->Request = Request;
|
||
reqList->BusNumber = busNumber;
|
||
reqList->InterfaceType = interfaceType;
|
||
reqList->SelectedAlternative = NULL;
|
||
//
|
||
// Initialize memory for REQ_ALTERNATIVEs.
|
||
//
|
||
reqAlternativePP = reqList->AlternativeTable;
|
||
RtlZeroMemory(
|
||
reqAlternativePP,
|
||
reqAlternativeCount * sizeof(PREQ_ALTERNATIVE));
|
||
#if DBG_SCOPE
|
||
reqAlternativeEndPP = reqAlternativePP + reqAlternativeCount;
|
||
#endif
|
||
reqAlternativeIndex = 0;
|
||
while (--ioResourceListCount >= 0) {
|
||
|
||
ioResourceDescriptor = ioResourceList->Descriptors;
|
||
ioResourceDescriptorEnd = ioResourceDescriptor +
|
||
ioResourceList->Count;
|
||
IopAllocPool(
|
||
&reqAlternative,
|
||
&reqAlternativePool,
|
||
FIELD_OFFSET(REQ_ALTERNATIVE, DescTable));
|
||
ASSERT(reqAlternativePP < reqAlternativeEndPP);
|
||
*reqAlternativePP++ = reqAlternative;
|
||
reqAlternative->ReqList = reqList;
|
||
reqAlternative->ReqAlternativeIndex = reqAlternativeIndex++;
|
||
reqAlternative->DescCount = 0;
|
||
//
|
||
// First descriptor of CmResourceTypeConfigData contains priority
|
||
// information.
|
||
//
|
||
if (ioResourceDescriptor->Type == CmResourceTypeConfigData) {
|
||
|
||
reqAlternative->Priority = ioResourceDescriptor->u.ConfigData.Priority;
|
||
ioResourceDescriptor++;
|
||
} else {
|
||
|
||
reqAlternative->Priority = LCPRI_NORMAL;
|
||
}
|
||
reqDescPP = reqAlternative->DescTable;
|
||
reqDescIndex = 0;
|
||
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
|
||
|
||
if (ioResourceDescriptor->Type == CmResourceTypeReserved) {
|
||
|
||
interfaceType = ioResourceDescriptor->u.DevicePrivate.Data[0];
|
||
if (interfaceType == InterfaceTypeUndefined) {
|
||
|
||
interfaceType = PnpDefaultInterfaceType;
|
||
}
|
||
busNumber = ioResourceDescriptor->u.DevicePrivate.Data[1];
|
||
ioResourceDescriptor++;
|
||
} else {
|
||
//
|
||
// Allocate and initialize REQ_DESC.
|
||
//
|
||
IopAllocPool(&reqDesc, &reqDescPool, sizeof(REQ_DESC));
|
||
reqAlternative->DescCount++;
|
||
*reqDescPP++ = reqDesc;
|
||
reqDesc->ReqAlternative = reqAlternative;
|
||
reqDesc->TranslatedReqDesc = reqDesc;
|
||
reqDesc->ReqDescIndex = reqDescIndex++;
|
||
reqDesc->DevicePrivateCount = 0;
|
||
reqDesc->DevicePrivate = NULL;
|
||
reqDesc->InterfaceType = interfaceType;
|
||
reqDesc->BusNumber = busNumber;
|
||
reqDesc->ArbitrationRequired =
|
||
(ioResourceDescriptor->Type & CmResourceTypeNonArbitrated ||
|
||
ioResourceDescriptor->Type == CmResourceTypeNull)?
|
||
FALSE : TRUE;
|
||
//
|
||
// Allocate and initialize arbiter entry for this REQ_DESC.
|
||
//
|
||
IopAllocPool(&poolStart, &reqAlternativePool, sizeof(PVOID));
|
||
ASSERT((PREQ_DESC*)poolStart == (reqDescPP - 1));
|
||
arbiterListEntry = &reqDesc->AlternativeTable;
|
||
InitializeListHead(&arbiterListEntry->ListEntry);
|
||
arbiterListEntry->AlternativeCount = 0;
|
||
arbiterListEntry->Alternatives = ioResourceDescriptor;
|
||
arbiterListEntry->PhysicalDeviceObject = Request->PhysicalDevice;
|
||
arbiterListEntry->RequestSource = Request->AllocationType;
|
||
arbiterListEntry->WorkSpace = 0;
|
||
arbiterListEntry->InterfaceType = interfaceType;
|
||
arbiterListEntry->SlotNumber = ioResources->SlotNumber;
|
||
arbiterListEntry->BusNumber = ioResources->BusNumber;
|
||
arbiterListEntry->Assignment = &reqDesc->Allocation;
|
||
arbiterListEntry->Result = ArbiterResultUndefined;
|
||
arbiterListEntry->Flags =
|
||
(reqAlternative->Priority != LCPRI_BOOTCONFIG)?
|
||
0 : ARBITER_FLAG_BOOT_CONFIG;
|
||
if (reqDesc->ArbitrationRequired) {
|
||
//
|
||
// The BestAlternativeTable and BestAllocation are not initialized.
|
||
// They will be initialized when needed.
|
||
|
||
//
|
||
// Initialize the Cm partial resource descriptor to NOT_ALLOCATED.
|
||
//
|
||
reqDesc->Allocation.Type = CmResourceTypeMaximum;
|
||
|
||
ASSERT((ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) == 0);
|
||
|
||
arbiterListEntry->AlternativeCount++;
|
||
ioResourceDescriptor++;
|
||
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
|
||
|
||
if (ioResourceDescriptor->Type == CmResourceTypeDevicePrivate) {
|
||
|
||
reqDesc->DevicePrivate = ioResourceDescriptor;
|
||
while ( ioResourceDescriptor < ioResourceDescriptorEnd &&
|
||
ioResourceDescriptor->Type == CmResourceTypeDevicePrivate) {
|
||
|
||
reqDesc->DevicePrivateCount++;
|
||
ioResourceDescriptor++;
|
||
}
|
||
break;
|
||
}
|
||
if (!(ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE)) {
|
||
|
||
break;
|
||
}
|
||
arbiterListEntry->AlternativeCount++;
|
||
ioResourceDescriptor++;
|
||
}
|
||
//
|
||
// Next query Arbiter and Translator interfaces for the
|
||
// resource descriptor.
|
||
//
|
||
status = IopSetupArbiterAndTranslators(reqDesc);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL, "Unable to setup "
|
||
"Arbiter and Translators\n"));
|
||
reqAlternativeIndex--;
|
||
reqAlternativePP--;
|
||
reqList->AlternativeCount--;
|
||
IopFreeReqAlternative(reqAlternative);
|
||
failureStatus = status;
|
||
break;
|
||
}
|
||
} else {
|
||
|
||
reqDesc->Allocation.Type = ioResourceDescriptor->Type;
|
||
reqDesc->Allocation.ShareDisposition =
|
||
ioResourceDescriptor->ShareDisposition;
|
||
reqDesc->Allocation.Flags = ioResourceDescriptor->Flags;
|
||
reqDesc->Allocation.u.DevicePrivate.Data[0] =
|
||
ioResourceDescriptor->u.DevicePrivate.Data[0];
|
||
reqDesc->Allocation.u.DevicePrivate.Data[1] =
|
||
ioResourceDescriptor->u.DevicePrivate.Data[1];
|
||
reqDesc->Allocation.u.DevicePrivate.Data[2] =
|
||
ioResourceDescriptor->u.DevicePrivate.Data[2];
|
||
ioResourceDescriptor++;
|
||
}
|
||
}
|
||
if (ioResourceDescriptor >= ioResourceDescriptorEnd) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd;
|
||
}
|
||
if (reqAlternativeIndex == 0) {
|
||
|
||
finalStatus = failureStatus;
|
||
IopFreeReqList(reqList);
|
||
}
|
||
}
|
||
|
||
if (finalStatus == STATUS_SUCCESS) {
|
||
|
||
*ResReqList = reqList;
|
||
}
|
||
return finalStatus;
|
||
|
||
InvalidParameter:
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
int
|
||
__cdecl
|
||
IopCompareReqAlternativePriority (
|
||
const void *arg1,
|
||
const void *arg2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is used in C run time sort. It compares the priority of
|
||
REQ_ALTERNATIVE in arg1 and arg2.
|
||
|
||
Parameters:
|
||
|
||
arg1 - LHS PREQ_ALTERNATIVE
|
||
|
||
arg2 - RHS PREQ_ALTERNATIVE
|
||
|
||
Return Value:
|
||
|
||
< 0 if arg1 < arg2
|
||
= 0 if arg1 = arg2
|
||
> 0 if arg1 > arg2
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQ_ALTERNATIVE ra1 = *(PPREQ_ALTERNATIVE)arg1;
|
||
PREQ_ALTERNATIVE ra2 = *(PPREQ_ALTERNATIVE)arg2;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (ra1->Priority == ra2->Priority) {
|
||
|
||
if (ra1->Position > ra2->Position) {
|
||
|
||
return 1;
|
||
} else if (ra1->Position < ra2->Position) {
|
||
|
||
return -1;
|
||
} else {
|
||
|
||
ASSERT(0);
|
||
if ((ULONG_PTR)ra1 < (ULONG_PTR)ra2) {
|
||
|
||
return -1;
|
||
} else {
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
if (ra1->Priority > ra2->Priority) {
|
||
|
||
return 1;
|
||
} else {
|
||
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
int
|
||
__cdecl
|
||
IopCompareResourceRequestPriority (
|
||
const void *arg1,
|
||
const void *arg2
|
||
)
|
||
|
||
/*++
|
||
|
||
This function is used in C run time sort. It compares the priority of
|
||
IOP_RESOURCE_REQUEST in arg1 and arg2.
|
||
|
||
Parameters:
|
||
|
||
arg1 - LHS PIOP_RESOURCE_REQUEST
|
||
|
||
arg2 - RHS PIOP_RESOURCE_REQUEST
|
||
|
||
Return Value:
|
||
|
||
< 0 if arg1 < arg2
|
||
= 0 if arg1 = arg2
|
||
> 0 if arg1 > arg2
|
||
|
||
--*/
|
||
|
||
{
|
||
PIOP_RESOURCE_REQUEST rr1 = (PIOP_RESOURCE_REQUEST)arg1;
|
||
PIOP_RESOURCE_REQUEST rr2 = (PIOP_RESOURCE_REQUEST)arg2;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (rr1->Priority == rr2->Priority) {
|
||
|
||
if (rr1->Position > rr2->Position) {
|
||
|
||
return 1;
|
||
} else if (rr1->Position < rr2->Position) {
|
||
|
||
return -1;
|
||
} else {
|
||
|
||
ASSERT(0);
|
||
if ((ULONG_PTR)rr1 < (ULONG_PTR)rr2) {
|
||
|
||
return -1;
|
||
} else {
|
||
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
if (rr1->Priority > rr2->Priority) {
|
||
|
||
return 1;
|
||
} else {
|
||
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopRearrangeReqList (
|
||
IN PREQ_LIST ReqList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sorts the REQ_LIST in ascending priority order of
|
||
REQ_ALTERNATIVES.
|
||
|
||
Parameters:
|
||
|
||
ReqList - Pointer to the REQ_LIST to be sorted.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PPREQ_ALTERNATIVE alternative;
|
||
PPREQ_ALTERNATIVE lastAlternative;
|
||
ULONG i;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (ReqList->AlternativeCount > 1) {
|
||
|
||
for (i = 0; i < ReqList->AlternativeCount; i++) {
|
||
|
||
ReqList->AlternativeTable[i]->Position = i;
|
||
}
|
||
qsort(
|
||
(void *)ReqList->AlternativeTable,
|
||
ReqList->AlternativeCount,
|
||
sizeof(PREQ_ALTERNATIVE),
|
||
IopCompareReqAlternativePriority);
|
||
}
|
||
//
|
||
// Set the BestAlternative so that we try alternatives with
|
||
// priority <= LCPRI_LASTSOFTCONFIG.
|
||
//
|
||
alternative = &ReqList->AlternativeTable[0];
|
||
for ( lastAlternative = alternative + ReqList->AlternativeCount;
|
||
alternative < lastAlternative;
|
||
alternative++) {
|
||
|
||
if ((*alternative)->Priority > LCPRI_LASTSOFTCONFIG) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (alternative == &ReqList->AlternativeTable[0]) {
|
||
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
deviceNode = PP_DO_TO_DN(ReqList->Request->PhysicalDevice);
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Invalid priorities in the logical configs for %wZ\n",
|
||
&deviceNode->InstancePath));
|
||
ReqList->BestAlternative = NULL;
|
||
} else {
|
||
|
||
ReqList->BestAlternative = alternative;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopRearrangeAssignTable (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sorts the resource requirements table in ascending priority
|
||
order.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resources requests to be sorted.
|
||
|
||
Count - Length of the RequestTable.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (Count > 1) {
|
||
|
||
if (PpCallerInitializesRequestTable == FALSE) {
|
||
|
||
for (i = 0; i < Count; i++) {
|
||
|
||
RequestTable[i].Position = i;
|
||
}
|
||
}
|
||
qsort(
|
||
(void *)RequestTable,
|
||
Count,
|
||
sizeof(IOP_RESOURCE_REQUEST),
|
||
IopCompareResourceRequestPriority);
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopBuildCmResourceList (
|
||
IN PIOP_RESOURCE_REQUEST AssignEntry
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine walks REQ_LIST of the AssignEntry to build a corresponding
|
||
Cm Resource lists. It also reports the resources to ResourceMap.
|
||
|
||
Parameters:
|
||
|
||
AssignEntry - Supplies a pointer to an IOP_ASSIGN_REQUEST structure
|
||
|
||
Return Value:
|
||
|
||
None. The ResourceAssignment in AssignEntry is initialized.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
HANDLE resourceMapKey;
|
||
PDEVICE_OBJECT physicalDevice;
|
||
PREQ_LIST reqList = AssignEntry->ReqList;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_DESC reqDesc, reqDescx;
|
||
PIO_RESOURCE_DESCRIPTOR privateData;
|
||
ULONG count = 0, size, i;
|
||
PCM_RESOURCE_LIST cmResources, cmResourcesRaw;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR cmFullResource, cmFullResourceRaw;
|
||
PCM_PARTIAL_RESOURCE_LIST cmPartialList, cmPartialListRaw;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor, cmDescriptorRaw, assignment, tAssignment;
|
||
#if DBG_SCOPE
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptorEnd, cmDescriptorEndRaw;
|
||
#endif
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Determine the size of the CmResourceList
|
||
//
|
||
|
||
//
|
||
// Determine the size of the CmResourceList
|
||
//
|
||
|
||
reqAlternative = *reqList->SelectedAlternative;
|
||
for (i = 0; i < reqAlternative->DescCount; i++) {
|
||
reqDesc = reqAlternative->DescTable[i];
|
||
count += reqDesc->DevicePrivateCount + 1;
|
||
}
|
||
|
||
size = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (count - 1);
|
||
cmResources = (PCM_RESOURCE_LIST) ExAllocatePoolCMRL(PagedPool, size);
|
||
if (!cmResources) {
|
||
|
||
//
|
||
// If we can not find memory, the resources will not be committed by arbiter.
|
||
//
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Not enough memory to build Translated CmResourceList\n"));
|
||
AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
AssignEntry->ResourceAssignment = NULL;
|
||
AssignEntry->TranslatedResourceAssignment = NULL;
|
||
return;
|
||
}
|
||
cmResourcesRaw = (PCM_RESOURCE_LIST) ExAllocatePoolCMRR(PagedPool, size);
|
||
if (!cmResourcesRaw) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Not enough memory to build Raw CmResourceList\n"));
|
||
ExFreePool(cmResources);
|
||
AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
AssignEntry->ResourceAssignment = NULL;
|
||
AssignEntry->TranslatedResourceAssignment = NULL;
|
||
return;
|
||
}
|
||
cmResources->Count = 1;
|
||
cmFullResource = cmResources->List;
|
||
|
||
//
|
||
// The CmResourceList we build here does not distinguish the
|
||
// Interface Type on descriptor level. This should be fine because
|
||
// for IoReportResourceUsage we ignore the CmResourceList we build
|
||
// here.
|
||
//
|
||
|
||
cmFullResource->InterfaceType = reqList->InterfaceType;
|
||
cmFullResource->BusNumber = reqList->BusNumber;
|
||
cmPartialList = &cmFullResource->PartialResourceList;
|
||
cmPartialList->Version = 0;
|
||
cmPartialList->Revision = 0;
|
||
cmPartialList->Count = count;
|
||
cmDescriptor = cmPartialList->PartialDescriptors;
|
||
#if DBG_SCOPE
|
||
cmDescriptorEnd = cmDescriptor + count;
|
||
#endif
|
||
cmResourcesRaw->Count = 1;
|
||
cmFullResourceRaw = cmResourcesRaw->List;
|
||
cmFullResourceRaw->InterfaceType = reqList->InterfaceType;
|
||
cmFullResourceRaw->BusNumber = reqList->BusNumber;
|
||
cmPartialListRaw = &cmFullResourceRaw->PartialResourceList;
|
||
cmPartialListRaw->Version = 0;
|
||
cmPartialListRaw->Revision = 0;
|
||
cmPartialListRaw->Count = count;
|
||
cmDescriptorRaw = cmPartialListRaw->PartialDescriptors;
|
||
#if DBG_SCOPE
|
||
cmDescriptorEndRaw = cmDescriptorRaw + count;
|
||
#endif
|
||
|
||
for (i = 0; i < reqAlternative->DescCount; i++) {
|
||
reqDesc = reqAlternative->DescTable[i];
|
||
|
||
if (reqDesc->ArbitrationRequired) {
|
||
|
||
//
|
||
// Get raw assignment and copy it to our raw resource list
|
||
//
|
||
|
||
reqDescx = reqDesc->TranslatedReqDesc;
|
||
if (reqDescx->AlternativeTable.Result != ArbiterResultNullRequest) {
|
||
status = IopParentToRawTranslation(reqDescx);
|
||
if (!NT_SUCCESS(status)) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Parent To Raw translation failed\n"));
|
||
ExFreePool(cmResources);
|
||
ExFreePool(cmResourcesRaw);
|
||
AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
AssignEntry->ResourceAssignment = NULL;
|
||
return;
|
||
}
|
||
assignment = reqDesc->AlternativeTable.Assignment;
|
||
} else {
|
||
assignment = reqDescx->AlternativeTable.Assignment;
|
||
}
|
||
*cmDescriptorRaw = *assignment;
|
||
cmDescriptorRaw++;
|
||
|
||
//
|
||
// Translate assignment and copy it to our translated resource list
|
||
//
|
||
if (reqDescx->AlternativeTable.Result != ArbiterResultNullRequest) {
|
||
status = IopChildToRootTranslation(
|
||
PP_DO_TO_DN(reqDesc->AlternativeTable.PhysicalDeviceObject),
|
||
reqDesc->InterfaceType,
|
||
reqDesc->BusNumber,
|
||
reqDesc->AlternativeTable.RequestSource,
|
||
&reqDesc->Allocation,
|
||
&tAssignment
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Child to Root translation failed\n"));
|
||
ExFreePool(cmResources);
|
||
ExFreePool(cmResourcesRaw);
|
||
AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
AssignEntry->ResourceAssignment = NULL;
|
||
return;
|
||
}
|
||
*cmDescriptor = *tAssignment;
|
||
ExFreePool(tAssignment);
|
||
} else {
|
||
*cmDescriptor = *(reqDescx->AlternativeTable.Assignment);
|
||
}
|
||
cmDescriptor++;
|
||
|
||
} else {
|
||
*cmDescriptorRaw = reqDesc->Allocation;
|
||
*cmDescriptor = reqDesc->Allocation;
|
||
cmDescriptorRaw++;
|
||
cmDescriptor++;
|
||
}
|
||
|
||
//
|
||
// Next copy the device private descriptors to CmResourceLists
|
||
//
|
||
|
||
count = reqDesc->DevicePrivateCount;
|
||
privateData = reqDesc->DevicePrivate;
|
||
while (count != 0) {
|
||
|
||
cmDescriptor->Type = cmDescriptorRaw->Type = CmResourceTypeDevicePrivate;
|
||
cmDescriptor->ShareDisposition = cmDescriptorRaw->ShareDisposition =
|
||
CmResourceShareDeviceExclusive;
|
||
cmDescriptor->Flags = cmDescriptorRaw->Flags = privateData->Flags;
|
||
RtlMoveMemory(&cmDescriptorRaw->u.DevicePrivate,
|
||
&privateData->u.DevicePrivate,
|
||
sizeof(cmDescriptorRaw->u.DevicePrivate.Data)
|
||
);
|
||
RtlMoveMemory(&cmDescriptor->u.DevicePrivate,
|
||
&privateData->u.DevicePrivate,
|
||
sizeof(cmDescriptor->u.DevicePrivate.Data)
|
||
);
|
||
privateData++;
|
||
cmDescriptorRaw++;
|
||
cmDescriptor++;
|
||
count--;
|
||
ASSERT(cmDescriptorRaw <= cmDescriptorEndRaw);
|
||
ASSERT(cmDescriptor <= cmDescriptorEnd);
|
||
}
|
||
ASSERT(cmDescriptor <= cmDescriptorEnd);
|
||
ASSERT(cmDescriptorRaw <= cmDescriptorEndRaw);
|
||
|
||
}
|
||
|
||
//
|
||
// report assigned resources to ResourceMap
|
||
//
|
||
|
||
physicalDevice = AssignEntry->PhysicalDevice;
|
||
|
||
//
|
||
// Open ResourceMap key
|
||
//
|
||
|
||
status = IopCreateRegistryKeyEx( &resourceMapKey,
|
||
(HANDLE) NULL,
|
||
&CmRegistryMachineHardwareResourceMapName,
|
||
KEY_READ | KEY_WRITE,
|
||
REG_OPTION_VOLATILE,
|
||
NULL
|
||
);
|
||
if (NT_SUCCESS(status )) {
|
||
WCHAR DeviceBuffer[256];
|
||
POBJECT_NAME_INFORMATION NameInformation;
|
||
ULONG NameLength;
|
||
UNICODE_STRING UnicodeClassName;
|
||
UNICODE_STRING UnicodeDriverName;
|
||
UNICODE_STRING UnicodeDeviceName;
|
||
|
||
PiWstrToUnicodeString(&UnicodeClassName, PNPMGR_STR_PNP_MANAGER);
|
||
|
||
PiWstrToUnicodeString(&UnicodeDriverName, REGSTR_KEY_PNP_DRIVER);
|
||
|
||
NameInformation = (POBJECT_NAME_INFORMATION) DeviceBuffer;
|
||
status = ObQueryNameString( physicalDevice,
|
||
NameInformation,
|
||
sizeof( DeviceBuffer ),
|
||
&NameLength );
|
||
if (NT_SUCCESS(status)) {
|
||
NameInformation->Name.MaximumLength = sizeof(DeviceBuffer) - sizeof(OBJECT_NAME_INFORMATION);
|
||
if (NameInformation->Name.Length == 0) {
|
||
NameInformation->Name.Buffer = (PVOID)((ULONG_PTR)DeviceBuffer + sizeof(OBJECT_NAME_INFORMATION));
|
||
}
|
||
|
||
UnicodeDeviceName = NameInformation->Name;
|
||
RtlAppendUnicodeToString(&UnicodeDeviceName, IopWstrRaw);
|
||
|
||
//
|
||
// IopWriteResourceList should remove all the device private and device
|
||
// specifiec descriptors.
|
||
//
|
||
|
||
status = IopWriteResourceList(
|
||
resourceMapKey,
|
||
&UnicodeClassName,
|
||
&UnicodeDriverName,
|
||
&UnicodeDeviceName,
|
||
cmResourcesRaw,
|
||
size
|
||
);
|
||
if (NT_SUCCESS(status)) {
|
||
UnicodeDeviceName = NameInformation->Name;
|
||
RtlAppendUnicodeToString (&UnicodeDeviceName, IopWstrTranslated);
|
||
status = IopWriteResourceList(
|
||
resourceMapKey,
|
||
&UnicodeClassName,
|
||
&UnicodeDriverName,
|
||
&UnicodeDeviceName,
|
||
cmResources,
|
||
size
|
||
);
|
||
}
|
||
}
|
||
ZwClose(resourceMapKey);
|
||
}
|
||
#if 0 // Ignore the registry writing status.
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(cmResources);
|
||
ExFreePool(cmResourcesRaw);
|
||
cmResources = NULL;
|
||
cmResourcesRaw = NULL;
|
||
}
|
||
#endif
|
||
AssignEntry->ResourceAssignment = cmResourcesRaw;
|
||
AssignEntry->TranslatedResourceAssignment = cmResources;
|
||
}
|
||
|
||
VOID
|
||
IopBuildCmResourceLists(
|
||
IN PIOP_RESOURCE_REQUEST AssignTable,
|
||
IN PIOP_RESOURCE_REQUEST AssignTableEnd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For each AssignTable entry, this routine queries device's IO resource requirements
|
||
list and converts it to our internal REQ_LIST format.
|
||
|
||
Parameters:
|
||
|
||
AssignTable - supplies a pointer to the first entry of a IOP_RESOURCE_REQUEST table.
|
||
|
||
AssignTableEnd - supplies a pointer to the end of IOP_RESOURCE_REQUEST table.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIOP_RESOURCE_REQUEST assignEntry;
|
||
PDEVICE_OBJECT physicalDevice;
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Go thru each entry, for each Physical device object, we build a CmResourceList
|
||
// from its ListOfAssignedResources.
|
||
//
|
||
|
||
for (assignEntry = AssignTable; assignEntry < AssignTableEnd; ++assignEntry) {
|
||
|
||
assignEntry->ResourceAssignment = NULL;
|
||
if (assignEntry->Flags & IOP_ASSIGN_IGNORE || assignEntry->Flags & IOP_ASSIGN_RETRY) {
|
||
continue;
|
||
}
|
||
if (assignEntry->Flags & IOP_ASSIGN_EXCLUDE) {
|
||
assignEntry->Status = STATUS_UNSUCCESSFUL;
|
||
continue;
|
||
}
|
||
assignEntry->Status = STATUS_SUCCESS;
|
||
IopBuildCmResourceList (assignEntry);
|
||
if (assignEntry->ResourceAssignment) {
|
||
physicalDevice = assignEntry->PhysicalDevice;
|
||
deviceNode = PP_DO_TO_DN(physicalDevice);
|
||
IopWriteAllocatedResourcesToRegistry(
|
||
deviceNode,
|
||
assignEntry->ResourceAssignment,
|
||
IopDetermineResourceListSize(assignEntry->ResourceAssignment)
|
||
);
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Building CM resource lists for %ws...\n",
|
||
deviceNode->InstancePath.Buffer));
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Raw resources "));
|
||
IopDumpCmResourceList(assignEntry->ResourceAssignment);
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Translated resources "));
|
||
IopDumpCmResourceList(assignEntry->TranslatedResourceAssignment);
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
IopNeedToReleaseBootResources(
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN PCM_RESOURCE_LIST AllocatedResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks the AllocatedResources against boot allocated resources.
|
||
If the allocated resources do not cover all the resource types in boot resources,
|
||
in another words some types of boot resources have not been released by arbiter,
|
||
we will return TRUE to indicate we need to release the boot resources manually.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - A device node
|
||
|
||
AllocatedResources - the resources assigned to the devicenode by arbiters.
|
||
|
||
Return Value:
|
||
|
||
TRUE or FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc_a, cmFullDesc_b;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor_a, cmDescriptor_b;
|
||
ULONG size_a, size_b, i, j, k;
|
||
BOOLEAN returnValue = FALSE, found;
|
||
PCM_RESOURCE_LIST bootResources;
|
||
|
||
PAGED_CODE();
|
||
|
||
bootResources = DeviceNode->BootResources;
|
||
if (AllocatedResources->Count == 1 && bootResources && bootResources->Count != 0) {
|
||
|
||
cmFullDesc_a = &AllocatedResources->List[0];
|
||
cmFullDesc_b = &bootResources->List[0];
|
||
for (i = 0; i < bootResources->Count; i++) {
|
||
cmDescriptor_b = &cmFullDesc_b->PartialResourceList.PartialDescriptors[0];
|
||
for (j = 0; j < cmFullDesc_b->PartialResourceList.Count; j++) {
|
||
size_b = 0;
|
||
switch (cmDescriptor_b->Type) {
|
||
case CmResourceTypeNull:
|
||
break;
|
||
case CmResourceTypeDeviceSpecific:
|
||
size_b = cmDescriptor_b->u.DeviceSpecificData.DataSize;
|
||
break;
|
||
default:
|
||
if (cmDescriptor_b->Type < CmResourceTypeMaximum) {
|
||
found = FALSE;
|
||
cmDescriptor_a = &cmFullDesc_a->PartialResourceList.PartialDescriptors[0];
|
||
for (k = 0; k < cmFullDesc_a->PartialResourceList.Count; k++) {
|
||
size_a = 0;
|
||
if (cmDescriptor_a->Type == CmResourceTypeDeviceSpecific) {
|
||
size_a = cmDescriptor_a->u.DeviceSpecificData.DataSize;
|
||
} else if (cmDescriptor_b->Type == cmDescriptor_a->Type) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
cmDescriptor_a++;
|
||
cmDescriptor_a = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor_a + size_a);
|
||
}
|
||
if (found == FALSE) {
|
||
returnValue = TRUE;
|
||
goto exit;
|
||
}
|
||
}
|
||
}
|
||
cmDescriptor_b++;
|
||
cmDescriptor_b = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor_b + size_b);
|
||
}
|
||
cmFullDesc_b = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor_b;
|
||
}
|
||
}
|
||
exit:
|
||
return returnValue;
|
||
}
|
||
|
||
VOID
|
||
IopReleaseFilteredBootResources(
|
||
IN PIOP_RESOURCE_REQUEST AssignTable,
|
||
IN PIOP_RESOURCE_REQUEST AssignTableEnd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For each AssignTable entry, this routine checks if we need to manually release the device's
|
||
boot resources.
|
||
|
||
Parameters:
|
||
|
||
AssignTable - supplies a pointer to the first entry of a IOP_RESOURCE_REQUEST table.
|
||
|
||
AssignTableEnd - supplies a pointer to the end of IOP_RESOURCE_REQUEST table.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PIOP_RESOURCE_REQUEST assignEntry;
|
||
PDEVICE_OBJECT physicalDevice;
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Go thru each entry, for each Physical device object, we build a CmResourceList
|
||
// from its ListOfAssignedResources.
|
||
//
|
||
|
||
for (assignEntry = AssignTable; assignEntry < AssignTableEnd; ++assignEntry) {
|
||
|
||
if (assignEntry->ResourceAssignment) {
|
||
physicalDevice = assignEntry->PhysicalDevice;
|
||
deviceNode = PP_DO_TO_DN(physicalDevice);
|
||
|
||
//
|
||
// Release the device's boot resources if desired
|
||
// (If a driver filters its res req list and removes some boot resources, after arbiter satisfies
|
||
// the new res req list, the filtered out boot resources do not get
|
||
// released by arbiters. Because they no longer passed to arbiters. )
|
||
// I am not 100% sure we should release the filtered boot resources. But that's what arbiters try
|
||
// to achieve. So, we will do it.
|
||
//
|
||
|
||
if (IopNeedToReleaseBootResources(deviceNode, assignEntry->ResourceAssignment)) {
|
||
|
||
IopReleaseResourcesInternal(deviceNode);
|
||
//
|
||
// Since we released some resources, try to satisfy devices
|
||
// with resource conflict.
|
||
//
|
||
PipRequestDeviceAction(NULL, AssignResources, FALSE, 0, NULL, NULL);
|
||
|
||
IopAllocateBootResourcesInternal(
|
||
ArbiterRequestPnpEnumerated,
|
||
physicalDevice,
|
||
assignEntry->ResourceAssignment);
|
||
deviceNode->Flags &= ~DNF_BOOT_CONFIG_RESERVED; // Keep DeviceNode->BootResources
|
||
deviceNode->ResourceList = assignEntry->ResourceAssignment;
|
||
status = IopRestoreResourcesInternal(deviceNode);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Possible boot conflict on %ws\n",
|
||
deviceNode->InstancePath.Buffer));
|
||
ASSERT(status == STATUS_SUCCESS);
|
||
assignEntry->Flags = IOP_ASSIGN_EXCLUDE;
|
||
assignEntry->Status = status;
|
||
ExFreePool(assignEntry->ResourceAssignment);
|
||
assignEntry->ResourceAssignment = NULL;
|
||
}
|
||
deviceNode->ResourceList = NULL;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
IopSetupArbiterAndTranslators(
|
||
IN PREQ_DESC ReqDesc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches the arbiter and translators which arbitrates and translate
|
||
the resources for the specified device. This routine tries to find all the
|
||
translator on the path of current device node to root device node
|
||
|
||
Parameters:
|
||
|
||
ReqDesc - supplies a pointer to REQ_DESC which contains all the required information
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS value to indicate success or failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY listHead;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
PDEVICE_OBJECT deviceObject = ReqDesc->AlternativeTable.PhysicalDeviceObject;
|
||
PDEVICE_NODE deviceNode;
|
||
PREQ_DESC reqDesc = ReqDesc, translatedReqDesc;
|
||
BOOLEAN found, arbiterFound = FALSE, restartedAlready;
|
||
BOOLEAN searchTranslator = TRUE, translatorFound = FALSE;
|
||
NTSTATUS status;
|
||
PPI_RESOURCE_TRANSLATOR_ENTRY translatorEntry;
|
||
UCHAR resourceType = ReqDesc->TranslatedReqDesc->AlternativeTable.Alternatives->Type;
|
||
PINTERFACE interface;
|
||
USHORT resourceMask;
|
||
|
||
if ((ReqDesc->AlternativeTable.RequestSource == ArbiterRequestHalReported) &&
|
||
(ReqDesc->InterfaceType == Internal)) {
|
||
|
||
// Trust hal if it says internal bus.
|
||
|
||
restartedAlready = TRUE;
|
||
} else {
|
||
restartedAlready = FALSE;
|
||
}
|
||
|
||
//
|
||
// If ReqDesc contains DeviceObject, this is for regular resources allocation
|
||
// or boot resources preallocation. Otherwise, it is for resources reservation.
|
||
//
|
||
|
||
if (deviceObject && ReqDesc->AlternativeTable.RequestSource != ArbiterRequestHalReported) {
|
||
deviceNode = PP_DO_TO_DN(deviceObject);
|
||
// We want to start with the deviceNode instead of its parent. Because the
|
||
// deviceNode may provide a translator interface.
|
||
// deviceNode = deviceNode->Parent;
|
||
} else {
|
||
|
||
//
|
||
// For resource reservation, we always need to find the arbiter and translators
|
||
// so set the device node to Root.
|
||
//
|
||
|
||
deviceNode = IopRootDeviceNode;
|
||
}
|
||
while (deviceNode) {
|
||
if ((deviceNode == IopRootDeviceNode) && (translatorFound == FALSE)) {
|
||
|
||
//
|
||
// If we reach the root and have not find any translator, the device is on the
|
||
// wrong way.
|
||
//
|
||
|
||
if (restartedAlready == FALSE) {
|
||
restartedAlready = TRUE;
|
||
|
||
deviceNode = IopFindLegacyBusDeviceNode (
|
||
ReqDesc->InterfaceType,
|
||
ReqDesc->BusNumber
|
||
);
|
||
|
||
//
|
||
// If we did not find a PDO, try again with InterfaceType == Isa. This allows
|
||
// drivers that request Internal to get resources even if there is no PDO
|
||
// that is Internal. (but if there is an Internal PDO, they get that one)
|
||
//
|
||
|
||
if ((deviceNode == IopRootDeviceNode) &&
|
||
(ReqDesc->ReqAlternative->ReqList->InterfaceType == Internal)) {
|
||
deviceNode = IopFindLegacyBusDeviceNode(
|
||
Isa,
|
||
0
|
||
);
|
||
}
|
||
|
||
//if ((PVOID)deviceNode == deviceObject->DeviceObjectExtension->DeviceNode) {
|
||
// deviceNode = IopRootDeviceNode;
|
||
//} else {
|
||
continue;
|
||
//}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check is there an arbiter for the device node?
|
||
// if yes, set up ReqDesc->u.Arbiter and set ArbiterFound to true.
|
||
// else move up to the parent of current device node.
|
||
//
|
||
|
||
if ((arbiterFound == FALSE) && (deviceNode->PhysicalDeviceObject != deviceObject)) {
|
||
found = IopFindResourceHandlerInfo(
|
||
ResourceArbiter,
|
||
deviceNode,
|
||
resourceType,
|
||
&arbiterEntry);
|
||
if (found == FALSE) {
|
||
|
||
//
|
||
// no information found on arbiter. Try to query translator interface ...
|
||
//
|
||
|
||
if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
|
||
resourceMask = 1 << resourceType;
|
||
} else {
|
||
resourceMask = 0;
|
||
}
|
||
status = IopQueryResourceHandlerInterface(ResourceArbiter,
|
||
deviceNode->PhysicalDeviceObject,
|
||
resourceType,
|
||
&interface);
|
||
deviceNode->QueryArbiterMask |= resourceMask;
|
||
if (!NT_SUCCESS(status)) {
|
||
deviceNode->NoArbiterMask |= resourceMask;
|
||
if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
|
||
found = TRUE;
|
||
} else {
|
||
interface = NULL;
|
||
}
|
||
}
|
||
if (found == FALSE) {
|
||
arbiterEntry = (PPI_RESOURCE_ARBITER_ENTRY)ExAllocatePoolAE(
|
||
PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(PI_RESOURCE_ARBITER_ENTRY));
|
||
if (!arbiterEntry) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
return status;
|
||
}
|
||
IopInitializeArbiterEntryState(arbiterEntry);
|
||
InitializeListHead(&arbiterEntry->DeviceArbiterList);
|
||
arbiterEntry->ResourceType = resourceType;
|
||
arbiterEntry->Level = deviceNode->Level;
|
||
listHead = &deviceNode->DeviceArbiterList;
|
||
InsertTailList(listHead, &arbiterEntry->DeviceArbiterList);
|
||
arbiterEntry->ArbiterInterface = (PARBITER_INTERFACE)interface;
|
||
if (!interface) {
|
||
|
||
//
|
||
// if interface is NULL we really don't have translator.
|
||
//
|
||
|
||
arbiterEntry = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If there is an desired resourcetype arbiter in the device node, make sure
|
||
// it handle this resource requriements.
|
||
//
|
||
|
||
if (arbiterEntry) {
|
||
arbiterFound = TRUE;
|
||
if (arbiterEntry->ArbiterInterface->Flags & ARBITER_PARTIAL) {
|
||
|
||
//
|
||
// If the arbiter is partial, ask if it handles the resources
|
||
// if not, goto its parent.
|
||
//
|
||
|
||
status = IopCallArbiter(
|
||
arbiterEntry,
|
||
ArbiterActionQueryArbitrate,
|
||
ReqDesc->TranslatedReqDesc,
|
||
NULL,
|
||
NULL
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
arbiterFound = FALSE;
|
||
}
|
||
}
|
||
}
|
||
if (arbiterFound) {
|
||
ReqDesc->u.Arbiter = arbiterEntry;
|
||
|
||
//
|
||
// Initialize the arbiter entry
|
||
//
|
||
|
||
arbiterEntry->State = 0;
|
||
arbiterEntry->ResourcesChanged = FALSE;
|
||
}
|
||
|
||
}
|
||
|
||
if (searchTranslator) {
|
||
//
|
||
// First, check if there is a translator for the device node?
|
||
// If yes, translate the req desc and link it to the front of ReqDesc->TranslatedReqDesc
|
||
// else do nothing.
|
||
//
|
||
|
||
found = IopFindResourceHandlerInfo(
|
||
ResourceTranslator,
|
||
deviceNode,
|
||
resourceType,
|
||
&translatorEntry);
|
||
|
||
if (found == FALSE) {
|
||
|
||
//
|
||
// no information found on translator. Try to query translator interface ...
|
||
//
|
||
|
||
if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
|
||
resourceMask = 1 << resourceType;
|
||
} else {
|
||
resourceMask = 0;
|
||
}
|
||
status = IopQueryResourceHandlerInterface(ResourceTranslator,
|
||
deviceNode->PhysicalDeviceObject,
|
||
resourceType,
|
||
&interface);
|
||
deviceNode->QueryTranslatorMask |= resourceMask;
|
||
if (!NT_SUCCESS(status)) {
|
||
deviceNode->NoTranslatorMask |= resourceMask;
|
||
if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
|
||
found = TRUE;
|
||
} else {
|
||
interface = NULL;
|
||
}
|
||
}
|
||
if (found == FALSE) {
|
||
translatorEntry = (PPI_RESOURCE_TRANSLATOR_ENTRY)ExAllocatePoolTE(
|
||
PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(PI_RESOURCE_TRANSLATOR_ENTRY));
|
||
if (!translatorEntry) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
return status;
|
||
}
|
||
translatorEntry->ResourceType = resourceType;
|
||
InitializeListHead(&translatorEntry->DeviceTranslatorList);
|
||
translatorEntry->TranslatorInterface = (PTRANSLATOR_INTERFACE)interface;
|
||
translatorEntry->DeviceNode = deviceNode;
|
||
listHead = &deviceNode->DeviceTranslatorList;
|
||
InsertTailList(listHead, &translatorEntry->DeviceTranslatorList);
|
||
if (!interface) {
|
||
|
||
//
|
||
// if interface is NULL we really don't have translator.
|
||
//
|
||
|
||
translatorEntry = NULL;
|
||
}
|
||
}
|
||
}
|
||
if (translatorEntry) {
|
||
translatorFound = TRUE;
|
||
}
|
||
if ((arbiterFound == FALSE) && translatorEntry) {
|
||
|
||
//
|
||
// Find a translator to translate the req desc ... Translate it and link it to
|
||
// the front of ReqDesc->TranslatedReqDesc such that the first in the list is for
|
||
// the Arbiter to use.
|
||
//
|
||
|
||
reqDesc = ReqDesc->TranslatedReqDesc;
|
||
status = IopTranslateAndAdjustReqDesc(
|
||
reqDesc,
|
||
translatorEntry,
|
||
&translatedReqDesc);
|
||
if (NT_SUCCESS(status)) {
|
||
ASSERT(translatedReqDesc);
|
||
resourceType = translatedReqDesc->AlternativeTable.Alternatives->Type;
|
||
translatedReqDesc->TranslatedReqDesc = ReqDesc->TranslatedReqDesc;
|
||
ReqDesc->TranslatedReqDesc = translatedReqDesc;
|
||
//
|
||
// If the translator is non-hierarchial and performs a complete
|
||
// translation to root (eg ISA interrups for PCI devices) then
|
||
// don't pass translations to parent.
|
||
//
|
||
|
||
if (status == STATUS_TRANSLATION_COMPLETE) {
|
||
searchTranslator = FALSE;
|
||
}
|
||
} else {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"resreq list TranslationAndAdjusted failed\n"
|
||
));
|
||
return status;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Move up to current device node's parent
|
||
//
|
||
|
||
deviceNode = deviceNode->Parent;
|
||
}
|
||
|
||
if (arbiterFound) {
|
||
|
||
return STATUS_SUCCESS;
|
||
} else {
|
||
//
|
||
// We should BugCheck in this case.
|
||
//
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"can not find resource type %x arbiter\n",
|
||
resourceType));
|
||
|
||
ASSERT(arbiterFound);
|
||
|
||
return STATUS_RESOURCE_TYPE_NOT_FOUND;
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
IopUncacheInterfaceInformation (
|
||
IN PDEVICE_OBJECT DeviceObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function removes all the cached translators and arbiters information
|
||
from the device object.
|
||
|
||
Parameters:
|
||
|
||
DeviceObject - Supplies the device object of the device being removed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_NODE deviceNode;
|
||
PLIST_ENTRY listHead;
|
||
PLIST_ENTRY nextEntry;
|
||
PLIST_ENTRY entry;
|
||
PPI_RESOURCE_TRANSLATOR_ENTRY translatorEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
PINTERFACE interface;
|
||
|
||
deviceNode = PP_DO_TO_DN(DeviceObject);
|
||
//
|
||
// Dereference all the arbiters on this PDO.
|
||
//
|
||
listHead = &deviceNode->DeviceArbiterList;
|
||
nextEntry = listHead->Flink;
|
||
while (nextEntry != listHead) {
|
||
|
||
entry = nextEntry;
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
entry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
DeviceArbiterList);
|
||
|
||
interface = (PINTERFACE)arbiterEntry->ArbiterInterface;
|
||
if (interface != NULL) {
|
||
|
||
(interface->InterfaceDereference)(interface->Context);
|
||
ExFreePool(interface);
|
||
}
|
||
nextEntry = entry->Flink;
|
||
ExFreePool(entry);
|
||
}
|
||
//
|
||
// Dereference all the translators on this PDO.
|
||
//
|
||
listHead = &deviceNode->DeviceTranslatorList;
|
||
nextEntry = listHead->Flink;
|
||
while (nextEntry != listHead) {
|
||
entry = nextEntry;
|
||
translatorEntry = CONTAINING_RECORD(
|
||
entry,
|
||
PI_RESOURCE_TRANSLATOR_ENTRY,
|
||
DeviceTranslatorList);
|
||
interface = (PINTERFACE)translatorEntry->TranslatorInterface;
|
||
if (interface != NULL) {
|
||
|
||
(interface->InterfaceDereference)(interface->Context);
|
||
ExFreePool(interface);
|
||
}
|
||
nextEntry = entry->Flink;
|
||
ExFreePool(entry);
|
||
}
|
||
InitializeListHead(&deviceNode->DeviceArbiterList);
|
||
InitializeListHead(&deviceNode->DeviceTranslatorList);
|
||
deviceNode->NoArbiterMask = 0;
|
||
deviceNode->QueryArbiterMask = 0;
|
||
deviceNode->NoTranslatorMask = 0;
|
||
deviceNode->QueryTranslatorMask = 0;
|
||
}
|
||
|
||
BOOLEAN
|
||
IopFindResourceHandlerInfo (
|
||
IN RESOURCE_HANDLER_TYPE HandlerType,
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN UCHAR ResourceType,
|
||
OUT PVOID *HandlerEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds the desired resource handler interface for the specified
|
||
resource type in the specified Device node.
|
||
|
||
Parameters:
|
||
|
||
HandlerType - Specifies the type of handler needed.
|
||
|
||
DeviceNode - Specifies the devicenode on which to search for handler.
|
||
|
||
ResourceType - Specifies the type of resource.
|
||
|
||
HandlerEntry - Supplies a pointer to a variable to receive the handler.
|
||
|
||
Return Value:
|
||
|
||
TRUE + non-NULL HandlerEntry : Found handler info and there is a handler
|
||
TRUE + NULL HandlerEntry : Found handler info but there is NO handler
|
||
FALSE + NULL HandlerEntry : No handler info found
|
||
|
||
--*/
|
||
{
|
||
USHORT resourceMask;
|
||
USHORT noHandlerMask;
|
||
USHORT queryHandlerMask;
|
||
PLIST_ENTRY listHead;
|
||
PLIST_ENTRY entry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
|
||
*HandlerEntry = NULL;
|
||
switch (HandlerType) {
|
||
case ResourceArbiter:
|
||
|
||
noHandlerMask = DeviceNode->NoArbiterMask;
|
||
queryHandlerMask = DeviceNode->QueryArbiterMask;
|
||
listHead = &DeviceNode->DeviceArbiterList;
|
||
break;
|
||
|
||
case ResourceTranslator:
|
||
|
||
noHandlerMask = DeviceNode->NoTranslatorMask;
|
||
queryHandlerMask = DeviceNode->QueryTranslatorMask;
|
||
listHead = &DeviceNode->DeviceTranslatorList;
|
||
break;
|
||
|
||
default:
|
||
|
||
return FALSE;
|
||
}
|
||
resourceMask = 1 << ResourceType;
|
||
if (noHandlerMask & resourceMask) {
|
||
//
|
||
// There is no desired handler for the resource type.
|
||
//
|
||
return TRUE;
|
||
}
|
||
if ( (queryHandlerMask & resourceMask) ||
|
||
ResourceType > PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
|
||
|
||
entry = listHead->Flink;
|
||
while (entry != listHead) {
|
||
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
entry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
DeviceArbiterList);
|
||
if (arbiterEntry->ResourceType == ResourceType) {
|
||
|
||
if ( ResourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED ||
|
||
arbiterEntry->ArbiterInterface) {
|
||
|
||
*HandlerEntry = arbiterEntry;
|
||
}
|
||
return TRUE;
|
||
}
|
||
entry = entry->Flink;
|
||
}
|
||
if (queryHandlerMask & resourceMask) {
|
||
//
|
||
// There must be one.
|
||
//
|
||
ASSERT(entry != listHead);
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopParentToRawTranslation(
|
||
IN OUT PREQ_DESC ReqDesc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine translates an CmPartialResourceDescriptors
|
||
from their translated form to their raw counterparts..
|
||
|
||
Parameters:
|
||
|
||
ReqDesc - supplies a translated ReqDesc to be translated back to its raw form
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
{
|
||
PTRANSLATOR_INTERFACE translator;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PREQ_DESC rawReqDesc;
|
||
|
||
if (ReqDesc->AlternativeTable.AlternativeCount == 0 ||
|
||
|
||
ReqDesc->Allocation.Type == CmResourceTypeMaximum) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Invalid ReqDesc for parent-to-raw translation.\n"));
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// If this ReqDesc is the raw reqDesc then we are done.
|
||
// Else call its translator to translate the resource and leave the result
|
||
// in its raw (next level) reqdesc.
|
||
//
|
||
|
||
if (IS_TRANSLATED_REQ_DESC(ReqDesc)) {
|
||
rawReqDesc = ReqDesc->TranslatedReqDesc;
|
||
translator = ReqDesc->u.Translator->TranslatorInterface;
|
||
status = (translator->TranslateResources)(
|
||
translator->Context,
|
||
ReqDesc->AlternativeTable.Assignment,
|
||
TranslateParentToChild,
|
||
rawReqDesc->AlternativeTable.AlternativeCount,
|
||
rawReqDesc->AlternativeTable.Alternatives,
|
||
rawReqDesc->AlternativeTable.PhysicalDeviceObject,
|
||
rawReqDesc->AlternativeTable.Assignment
|
||
);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// If the translator is non-hierarchial and performs a complete
|
||
// translation to root (eg ISA interrups for PCI devices) then
|
||
// don't pass translations to parent.
|
||
//
|
||
|
||
ASSERT(status != STATUS_TRANSLATION_COMPLETE);
|
||
status = IopParentToRawTranslation(rawReqDesc);
|
||
}
|
||
}
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopChildToRootTranslation(
|
||
IN PDEVICE_NODE DeviceNode, OPTIONAL
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber,
|
||
IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
|
||
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
|
||
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *Target
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine translates a CmPartialResourceDescriptors from
|
||
their intermediate translated form to their final translated form.
|
||
The translated CM_PARTIAL_RESOURCE_DESCRIPTOR is returned via Target variable.
|
||
|
||
The caller is responsible to release the translated descriptor.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - Specified the device object. If The DeviceNode is specified,
|
||
the InterfaceType and BusNumber are ignored and we will
|
||
use DeviceNode as a starting point to find various translators to
|
||
translate the Source descriptor. If DeviceNode is not specified,
|
||
the InterfaceType and BusNumber must be specified.
|
||
|
||
InterfaceType, BusNumber - must be supplied if DeviceNode is not specified.
|
||
|
||
Source - A pointer to the resource descriptor to be translated.
|
||
|
||
Target - Supplies an address to receive the translated resource descriptor.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_NODE deviceNode;
|
||
PLIST_ENTRY listHead, nextEntry;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR target, source, tmp;
|
||
PPI_RESOURCE_TRANSLATOR_ENTRY translatorEntry;
|
||
PTRANSLATOR_INTERFACE translator;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
BOOLEAN done = FALSE, foundTranslator = FALSE, restartedAlready;
|
||
|
||
if (ArbiterRequestSource == ArbiterRequestHalReported) {
|
||
restartedAlready = TRUE;
|
||
} else {
|
||
restartedAlready = FALSE;
|
||
}
|
||
|
||
source = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ExAllocatePoolPRD(
|
||
PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
||
);
|
||
if (source == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
target = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ExAllocatePoolPRD(
|
||
PagedPool,
|
||
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
||
);
|
||
if (target == NULL) {
|
||
ExFreePool(source);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
*source = *Source;
|
||
|
||
//
|
||
// Move up to current device node's parent to start translation
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(DeviceNode)) {
|
||
deviceNode = IopFindLegacyBusDeviceNode (InterfaceType, BusNumber);
|
||
} else {
|
||
// We want to start with the deviceNode instead of its parent. Because the
|
||
// deviceNode may provide a translator interface.
|
||
deviceNode = DeviceNode;
|
||
}
|
||
while (deviceNode && !done) {
|
||
|
||
if ((deviceNode == IopRootDeviceNode) && (foundTranslator == FALSE)) {
|
||
if (restartedAlready == FALSE) {
|
||
restartedAlready = TRUE;
|
||
deviceNode = IopFindLegacyBusDeviceNode (InterfaceType, BusNumber);
|
||
|
||
//
|
||
// If we did not find a PDO, try again with InterfaceType == Isa. This allows
|
||
// drivers that request Internal to get resources even if there is no PDO
|
||
// that is Internal. (but if there is an Internal PDO, they get that one)
|
||
//
|
||
|
||
if ((deviceNode == IopRootDeviceNode) && (InterfaceType == Internal)) {
|
||
deviceNode = IopFindLegacyBusDeviceNode(Isa, 0);
|
||
}
|
||
|
||
continue;
|
||
}
|
||
}
|
||
//
|
||
// First, check if there is a translator for the device node?
|
||
// If yes, translate the req desc and link it to the front of ReqDesc->TranslatedReqDesc
|
||
// else do nothing.
|
||
//
|
||
|
||
listHead = &deviceNode->DeviceTranslatorList;
|
||
nextEntry = listHead->Flink;
|
||
for (; nextEntry != listHead; nextEntry = nextEntry->Flink) {
|
||
translatorEntry = CONTAINING_RECORD(nextEntry, PI_RESOURCE_TRANSLATOR_ENTRY, DeviceTranslatorList);
|
||
if (translatorEntry->ResourceType == Source->Type) {
|
||
translator = translatorEntry->TranslatorInterface;
|
||
if (translator != NULL) {
|
||
|
||
//
|
||
// Find a translator to translate the req desc ... Translate it and link it to
|
||
// the front of ReqDesc->TranslatedReqDesc.
|
||
//
|
||
|
||
status = (translator->TranslateResources) (
|
||
translator->Context,
|
||
source,
|
||
TranslateChildToParent,
|
||
0,
|
||
NULL,
|
||
DeviceNode ? DeviceNode->PhysicalDeviceObject : NULL,
|
||
target
|
||
);
|
||
if (NT_SUCCESS(status)) {
|
||
tmp = source;
|
||
source = target;
|
||
target = tmp;
|
||
|
||
//
|
||
// If the translator is non-hierarchial and performs a complete
|
||
// translation to root (eg ISA interrups for PCI devices) then
|
||
// don't pass translations to parent.
|
||
//
|
||
|
||
if (status == STATUS_TRANSLATION_COMPLETE) {
|
||
done = TRUE;
|
||
}
|
||
|
||
} else {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Child to Root Translation failed\n"
|
||
" DeviceNode %08x (PDO %08x)\n"
|
||
" Resource Type %02x Data %08x %08x %08x\n",
|
||
DeviceNode,
|
||
DeviceNode->PhysicalDeviceObject,
|
||
source->Type,
|
||
source->u.DevicePrivate.Data[0],
|
||
source->u.DevicePrivate.Data[1],
|
||
source->u.DevicePrivate.Data[2]
|
||
));
|
||
IopRecordTranslationFailure(DeviceNode, *source);
|
||
goto exit;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move up to current device node's parent
|
||
//
|
||
|
||
deviceNode = deviceNode->Parent;
|
||
}
|
||
*Target = source;
|
||
ExFreePool(target);
|
||
return status;
|
||
exit:
|
||
ExFreePool(source);
|
||
ExFreePool(target);
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopTranslateAndAdjustReqDesc(
|
||
IN PREQ_DESC ReqDesc,
|
||
IN PPI_RESOURCE_TRANSLATOR_ENTRY TranslatorEntry,
|
||
OUT PREQ_DESC *TranslatedReqDesc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine translates and adjusts ReqDesc IoResourceDescriptors to
|
||
their translated and adjusted form.
|
||
|
||
Parameters:
|
||
|
||
ReqDesc - supplies a pointer to the REQ_DESC to be translated.
|
||
|
||
TranslatorEntry - supplies a pointer to the translator infor structure.
|
||
|
||
TranslatedReqDesc - supplies a pointer to a variable to receive the
|
||
translated REQ_DESC.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
{
|
||
ULONG i, total = 0, *targetCount;
|
||
PTRANSLATOR_INTERFACE translator = TranslatorEntry->TranslatorInterface;
|
||
PIO_RESOURCE_DESCRIPTOR ioDesc, *target, tIoDesc;
|
||
PREQ_DESC tReqDesc;
|
||
PARBITER_LIST_ENTRY arbiterEntry;
|
||
NTSTATUS status = STATUS_UNSUCCESSFUL, returnStatus = STATUS_SUCCESS;
|
||
BOOLEAN reqTranslated = FALSE;
|
||
|
||
if (ReqDesc->AlternativeTable.AlternativeCount == 0) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
*TranslatedReqDesc = NULL;
|
||
|
||
target = (PIO_RESOURCE_DESCRIPTOR *) ExAllocatePoolIORD(
|
||
PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(PIO_RESOURCE_DESCRIPTOR) * ReqDesc->AlternativeTable.AlternativeCount
|
||
);
|
||
if (target == NULL) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Not Enough memory to perform resreqlist adjustment\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
RtlZeroMemory(target, sizeof(PIO_RESOURCE_DESCRIPTOR) * ReqDesc->AlternativeTable.AlternativeCount);
|
||
|
||
targetCount = (PULONG) ExAllocatePool(
|
||
PagedPool | POOL_COLD_ALLOCATION,
|
||
sizeof(ULONG) * ReqDesc->AlternativeTable.AlternativeCount
|
||
);
|
||
if (targetCount == NULL) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Not Enough memory to perform resreqlist adjustment\n"));
|
||
ExFreePool(target);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(targetCount, sizeof(ULONG) * ReqDesc->AlternativeTable.AlternativeCount);
|
||
|
||
//
|
||
// Determine the number of IO_RESOURCE_DESCRIPTORs after translation.
|
||
//
|
||
|
||
ioDesc = ReqDesc->AlternativeTable.Alternatives;
|
||
for (i = 0; i < ReqDesc->AlternativeTable.AlternativeCount; i++) {
|
||
status = (translator->TranslateResourceRequirements)(
|
||
translator->Context,
|
||
ioDesc,
|
||
ReqDesc->AlternativeTable.PhysicalDeviceObject,
|
||
&targetCount[i],
|
||
&target[i]
|
||
);
|
||
if (!NT_SUCCESS(status) || targetCount[i] == 0) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Translator failed to adjust resreqlist\n"));
|
||
target[i] = ioDesc;
|
||
targetCount[i] = 0;
|
||
total++;
|
||
} else {
|
||
total += targetCount[i];
|
||
reqTranslated = TRUE;
|
||
}
|
||
ioDesc++;
|
||
if (NT_SUCCESS(status) && (returnStatus != STATUS_TRANSLATION_COMPLETE)) {
|
||
returnStatus = status;
|
||
}
|
||
}
|
||
|
||
if (!reqTranslated) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Failed to translate any requirement for %ws!\n",
|
||
PP_DO_TO_DN(ReqDesc->AlternativeTable.PhysicalDeviceObject)->InstancePath.Buffer));
|
||
returnStatus = status;
|
||
}
|
||
|
||
//
|
||
// Allocate memory for the adjusted/translated resources descriptors
|
||
//
|
||
|
||
tIoDesc = (PIO_RESOURCE_DESCRIPTOR) ExAllocatePoolIORD(
|
||
PagedPool | POOL_COLD_ALLOCATION,
|
||
total * sizeof(IO_RESOURCE_DESCRIPTOR));
|
||
if (!tIoDesc) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Not Enough memory to perform resreqlist adjustment\n"));
|
||
returnStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto exit;
|
||
}
|
||
|
||
tReqDesc = (PREQ_DESC) ExAllocatePool1RD (PagedPool | POOL_COLD_ALLOCATION, sizeof(REQ_DESC));
|
||
if (tReqDesc == NULL) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Not Enough memory to perform resreqlist adjustment\n"));
|
||
ExFreePool(tIoDesc);
|
||
returnStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Create and initialize a new REQ_DESC for the translated/adjusted io resources
|
||
//
|
||
|
||
RtlCopyMemory(tReqDesc, ReqDesc, sizeof(REQ_DESC));
|
||
|
||
//
|
||
// Set the translated req desc's ReqAlternative to NULL to indicated this
|
||
// is not the original req desc.
|
||
//
|
||
|
||
tReqDesc->ReqAlternative = NULL;
|
||
|
||
tReqDesc->u.Translator = TranslatorEntry;
|
||
tReqDesc->TranslatedReqDesc = NULL;
|
||
arbiterEntry = &tReqDesc->AlternativeTable;
|
||
InitializeListHead(&arbiterEntry->ListEntry);
|
||
arbiterEntry->AlternativeCount = total;
|
||
arbiterEntry->Alternatives = tIoDesc;
|
||
arbiterEntry->Assignment = &tReqDesc->Allocation;
|
||
|
||
ioDesc = ReqDesc->AlternativeTable.Alternatives;
|
||
for (i = 0; i < ReqDesc->AlternativeTable.AlternativeCount; i++) {
|
||
if (targetCount[i] != 0) {
|
||
RtlCopyMemory(tIoDesc, target[i], targetCount[i] * sizeof(IO_RESOURCE_DESCRIPTOR));
|
||
tIoDesc += targetCount[i];
|
||
} else {
|
||
|
||
//
|
||
// Make it become impossible to satisfy.
|
||
//
|
||
|
||
RtlCopyMemory(tIoDesc, ioDesc, sizeof(IO_RESOURCE_DESCRIPTOR));
|
||
switch (tIoDesc->Type) {
|
||
case CmResourceTypePort:
|
||
case CmResourceTypeMemory:
|
||
tIoDesc->u.Port.MinimumAddress.LowPart = 2;
|
||
tIoDesc->u.Port.MinimumAddress.HighPart = 0;
|
||
tIoDesc->u.Port.MaximumAddress.LowPart = 1;
|
||
tIoDesc->u.Port.MaximumAddress.HighPart = 0;
|
||
break;
|
||
case CmResourceTypeBusNumber:
|
||
tIoDesc->u.BusNumber.MinBusNumber = 2;
|
||
tIoDesc->u.BusNumber.MaxBusNumber = 1;
|
||
break;
|
||
|
||
case CmResourceTypeInterrupt:
|
||
tIoDesc->u.Interrupt.MinimumVector = 2;
|
||
tIoDesc->u.Interrupt.MaximumVector = 1;
|
||
break;
|
||
|
||
case CmResourceTypeDma:
|
||
tIoDesc->u.Dma.MinimumChannel = 2;
|
||
tIoDesc->u.Dma.MaximumChannel = 1;
|
||
break;
|
||
default:
|
||
ASSERT(0);
|
||
break;
|
||
}
|
||
tIoDesc += 1;
|
||
}
|
||
ioDesc++;
|
||
|
||
}
|
||
|
||
#if DBG_SCOPE
|
||
//
|
||
// Verify the adjusted resource descriptors are valid
|
||
//
|
||
|
||
ioDesc = arbiterEntry->Alternatives;
|
||
ASSERT((ioDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0);
|
||
ioDesc++;
|
||
for (i = 1; i < total; i++) {
|
||
ASSERT(ioDesc->Option & IO_RESOURCE_ALTERNATIVE);
|
||
ioDesc++;
|
||
}
|
||
#endif
|
||
*TranslatedReqDesc = tReqDesc;
|
||
exit:
|
||
for (i = 0; i < ReqDesc->AlternativeTable.AlternativeCount; i++) {
|
||
if (targetCount[i] != 0) {
|
||
ASSERT(target[i]);
|
||
ExFreePool(target[i]);
|
||
}
|
||
}
|
||
ExFreePool(target);
|
||
ExFreePool(targetCount);
|
||
return returnStatus;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopCallArbiter(
|
||
PPI_RESOURCE_ARBITER_ENTRY ArbiterEntry,
|
||
ARBITER_ACTION Command,
|
||
PVOID Input1,
|
||
PVOID Input2,
|
||
PVOID Input3
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine builds a Parameter block from Input structure and calls specified
|
||
arbiter to carry out the Command.
|
||
|
||
Parameters:
|
||
|
||
ArbiterEntry - Supplies a pointer to our PI_RESOURCE_ARBITER_ENTRY such that
|
||
we know everything about the arbiter.
|
||
|
||
Command - Supplies the Action code for the arbiter.
|
||
|
||
Input - Supplies a PVOID pointer to a structure.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
{
|
||
ARBITER_PARAMETERS parameters;
|
||
PARBITER_INTERFACE arbiterInterface = ArbiterEntry->ArbiterInterface;
|
||
NTSTATUS status;
|
||
PARBITER_LIST_ENTRY arbiterListEntry;
|
||
LIST_ENTRY listHead;
|
||
PVOID *ExtParams;
|
||
|
||
switch (Command) {
|
||
case ArbiterActionTestAllocation:
|
||
case ArbiterActionRetestAllocation:
|
||
|
||
//
|
||
// For ArbiterActionTestAllocation, the Input is a pointer to the doubly
|
||
// linked list of ARBITER_LIST_ENTRY's.
|
||
//
|
||
|
||
parameters.Parameters.TestAllocation.ArbitrationList = (PLIST_ENTRY)Input1;
|
||
parameters.Parameters.TestAllocation.AllocateFromCount = (ULONG)((ULONG_PTR)Input2);
|
||
parameters.Parameters.TestAllocation.AllocateFrom =
|
||
(PCM_PARTIAL_RESOURCE_DESCRIPTOR)Input3;
|
||
status = (arbiterInterface->ArbiterHandler)(
|
||
arbiterInterface->Context,
|
||
Command,
|
||
¶meters
|
||
);
|
||
break;
|
||
|
||
case ArbiterActionBootAllocation:
|
||
|
||
//
|
||
// For ArbiterActionBootAllocation, the input is a pointer to the doubly
|
||
// linked list of ARBITER_LIST_ENTRY'S.
|
||
//
|
||
|
||
parameters.Parameters.BootAllocation.ArbitrationList = (PLIST_ENTRY)Input1;
|
||
|
||
status = (arbiterInterface->ArbiterHandler)(
|
||
arbiterInterface->Context,
|
||
Command,
|
||
¶meters
|
||
);
|
||
break;
|
||
|
||
case ArbiterActionQueryArbitrate:
|
||
|
||
//
|
||
// For QueryArbiter, the input is a pointer to REQ_DESC
|
||
//
|
||
|
||
arbiterListEntry = &((PREQ_DESC)Input1)->AlternativeTable;
|
||
ASSERT(IsListEmpty(&arbiterListEntry->ListEntry));
|
||
listHead = arbiterListEntry->ListEntry;
|
||
arbiterListEntry->ListEntry.Flink = arbiterListEntry->ListEntry.Blink = &listHead;
|
||
parameters.Parameters.QueryArbitrate.ArbitrationList = &listHead;
|
||
status = (arbiterInterface->ArbiterHandler)(
|
||
arbiterInterface->Context,
|
||
Command,
|
||
¶meters
|
||
);
|
||
arbiterListEntry->ListEntry = listHead;
|
||
break;
|
||
|
||
case ArbiterActionCommitAllocation:
|
||
case ArbiterActionWriteReservedResources:
|
||
|
||
//
|
||
// Commit, Rollback and WriteReserved do not have parmater.
|
||
//
|
||
|
||
status = (arbiterInterface->ArbiterHandler)(
|
||
arbiterInterface->Context,
|
||
Command,
|
||
NULL
|
||
);
|
||
break;
|
||
|
||
case ArbiterActionQueryAllocatedResources:
|
||
status = STATUS_NOT_IMPLEMENTED;
|
||
break;
|
||
|
||
case ArbiterActionQueryConflict:
|
||
//
|
||
// For QueryConflict
|
||
// Ex0 is PDO
|
||
// Ex1 is PIO_RESOURCE_DESCRIPTOR
|
||
// Ex2 is PULONG
|
||
// Ex3 is PARBITER_CONFLICT_INFO *
|
||
ExtParams = (PVOID*)Input1;
|
||
|
||
parameters.Parameters.QueryConflict.PhysicalDeviceObject = (PDEVICE_OBJECT)ExtParams[0];
|
||
parameters.Parameters.QueryConflict.ConflictingResource = (PIO_RESOURCE_DESCRIPTOR)ExtParams[1];
|
||
parameters.Parameters.QueryConflict.ConflictCount = (PULONG)ExtParams[2];
|
||
parameters.Parameters.QueryConflict.Conflicts = (PARBITER_CONFLICT_INFO *)ExtParams[3];
|
||
status = (arbiterInterface->ArbiterHandler)(
|
||
arbiterInterface->Context,
|
||
Command,
|
||
¶meters
|
||
);
|
||
break;
|
||
|
||
default:
|
||
status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopFindResourcesForArbiter (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN UCHAR ResourceType,
|
||
OUT ULONG *Count,
|
||
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmDesc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the resources required by the ResourceType arbiter in DeviceNode.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode -specifies the device node whose ResourceType arbiter is requesting for resources
|
||
|
||
ResourceType - specifies the resource type
|
||
|
||
Count - specifies a pointer to a varaible to receive the count of Cm descriptors returned
|
||
|
||
CmDesc - specifies a pointer to a varibble to receive the returned cm descriptor.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIOP_RESOURCE_REQUEST assignEntry;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_DESC reqDesc;
|
||
ULONG i, count = 0;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor;
|
||
|
||
*Count = 0;
|
||
*CmDesc = NULL;
|
||
|
||
if (DeviceNode->State == DeviceNodeStarted) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Find this device node's IOP_RESOURCE_REQUEST structure first
|
||
//
|
||
|
||
for (assignEntry = PiAssignTable + PiAssignTableCount - 1;
|
||
assignEntry >= PiAssignTable;
|
||
assignEntry--) {
|
||
if (assignEntry->PhysicalDevice == DeviceNode->PhysicalDeviceObject) {
|
||
break;
|
||
}
|
||
}
|
||
if (assignEntry < PiAssignTable) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Rebalance: No resreqlist for Arbiter? Can not find Arbiter assign"
|
||
" table entry\n"));
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
reqAlternative = *((PREQ_LIST)assignEntry->ReqList)->SelectedAlternative;
|
||
for (i = 0; i < reqAlternative->DescCount; i++) {
|
||
reqDesc = reqAlternative->DescTable[i]->TranslatedReqDesc;
|
||
if (reqDesc->Allocation.Type == ResourceType) {
|
||
count++;
|
||
}
|
||
}
|
||
|
||
cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ExAllocatePoolPRD(
|
||
PagedPool,
|
||
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * count
|
||
);
|
||
if (!cmDescriptor) {
|
||
|
||
//
|
||
// If we can not find memory, the resources will not be committed by arbiter.
|
||
//
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Rebalance: Not enough memory to perform rebalance\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
*Count = count;
|
||
*CmDesc = cmDescriptor;
|
||
|
||
for (i = 0; i < reqAlternative->DescCount; i++) {
|
||
reqDesc = reqAlternative->DescTable[i]->TranslatedReqDesc;
|
||
if (reqDesc->Allocation.Type == ResourceType) {
|
||
*cmDescriptor = reqDesc->Allocation;
|
||
cmDescriptor++;
|
||
}
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopRestoreResourcesInternal (
|
||
IN PDEVICE_NODE DeviceNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine reassigns the released resources for device specified by DeviceNode.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - specifies the device node whose resources are goint to be released.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
IOP_RESOURCE_REQUEST requestTable;
|
||
NTSTATUS status;
|
||
LIST_ENTRY activeArbiterList;
|
||
|
||
if (DeviceNode->ResourceList == NULL) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
requestTable.ResourceRequirements =
|
||
IopCmResourcesToIoResources (0, DeviceNode->ResourceList, LCPRI_FORCECONFIG);
|
||
if (requestTable.ResourceRequirements == NULL) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Not enough memory to clean up rebalance failure\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
requestTable.Priority = 0;
|
||
requestTable.Flags = 0;
|
||
requestTable.AllocationType = ArbiterRequestPnpEnumerated;
|
||
requestTable.PhysicalDevice = DeviceNode->PhysicalDeviceObject;
|
||
requestTable.ReqList = NULL;
|
||
requestTable.ResourceAssignment = NULL;
|
||
requestTable.TranslatedResourceAssignment = NULL;
|
||
requestTable.Status = 0;
|
||
|
||
//
|
||
// rebuild internal representation of the resource requirements list
|
||
//
|
||
|
||
status = IopResourceRequirementsListToReqList(
|
||
&requestTable,
|
||
&requestTable.ReqList);
|
||
|
||
if (!NT_SUCCESS(status) || requestTable.ReqList == NULL) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Not enough memory to restore previous resources\n"));
|
||
ExFreePool (requestTable.ResourceRequirements);
|
||
return status;
|
||
} else {
|
||
PREQ_LIST reqList;
|
||
|
||
reqList = (PREQ_LIST)requestTable.ReqList;
|
||
|
||
//
|
||
// Sort the ReqList such that the higher priority Alternative list are
|
||
// placed in the front of the list.
|
||
//
|
||
|
||
IopRearrangeReqList(reqList);
|
||
if (reqList->BestAlternative == NULL) {
|
||
|
||
IopFreeResourceRequirementsForAssignTable(&requestTable, (&requestTable) + 1);
|
||
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||
|
||
}
|
||
}
|
||
|
||
status = IopFindBestConfiguration(&requestTable, 1, &activeArbiterList);
|
||
IopFreeResourceRequirementsForAssignTable(&requestTable, (&requestTable) + 1);
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Ask the arbiters to commit this configuration.
|
||
//
|
||
status = IopCommitConfiguration(&activeArbiterList);
|
||
}
|
||
if (!NT_SUCCESS(status)) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"IopRestoreResourcesInternal: BOOT conflict for %ws\n",
|
||
DeviceNode->InstancePath.Buffer));
|
||
}
|
||
if (requestTable.ResourceAssignment) {
|
||
ExFreePool(requestTable.ResourceAssignment);
|
||
}
|
||
if (requestTable.TranslatedResourceAssignment) {
|
||
ExFreePool(requestTable.TranslatedResourceAssignment);
|
||
}
|
||
IopWriteAllocatedResourcesToRegistry (
|
||
DeviceNode,
|
||
DeviceNode->ResourceList,
|
||
IopDetermineResourceListSize(DeviceNode->ResourceList)
|
||
);
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
IopReleaseResourcesInternal (
|
||
IN PDEVICE_NODE DeviceNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine releases the assigned resources for device specified by DeviceNode.
|
||
Note, this routine does not reset the resource related fields in DeviceNode structure.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - specifies the device node whose resources are goint to be released.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_NODE device;
|
||
PLIST_ENTRY listHead, listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
ARBITER_LIST_ENTRY arbiterListEntry;
|
||
INTERFACE_TYPE interfaceType;
|
||
ULONG busNumber, listCount, i, j, size;
|
||
PCM_RESOURCE_LIST resourceList;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
|
||
BOOLEAN search = TRUE;
|
||
#if DBG_SCOPE
|
||
NTSTATUS status;
|
||
#endif
|
||
|
||
InitializeListHead(&arbiterListEntry.ListEntry);
|
||
arbiterListEntry.AlternativeCount = 0;
|
||
arbiterListEntry.Alternatives = NULL;
|
||
arbiterListEntry.PhysicalDeviceObject = DeviceNode->PhysicalDeviceObject;
|
||
arbiterListEntry.Flags = 0;
|
||
arbiterListEntry.WorkSpace = 0;
|
||
arbiterListEntry.Assignment = NULL;
|
||
arbiterListEntry.RequestSource = ArbiterRequestPnpEnumerated;
|
||
|
||
resourceList = DeviceNode->ResourceList;
|
||
if (resourceList == NULL) {
|
||
resourceList = DeviceNode->BootResources;
|
||
}
|
||
if (resourceList && resourceList->Count > 0) {
|
||
listCount = resourceList->Count;
|
||
cmFullDesc = &resourceList->List[0];
|
||
} else {
|
||
listCount = 1;
|
||
resourceList = NULL;
|
||
}
|
||
for (i = 0; i < listCount; i++) {
|
||
|
||
if (resourceList) {
|
||
interfaceType = cmFullDesc->InterfaceType;
|
||
busNumber = cmFullDesc->BusNumber;
|
||
if (interfaceType == InterfaceTypeUndefined) {
|
||
interfaceType = PnpDefaultInterfaceType;
|
||
}
|
||
} else {
|
||
interfaceType = PnpDefaultInterfaceType;
|
||
busNumber = 0;
|
||
}
|
||
|
||
device = DeviceNode->Parent;
|
||
while (device) {
|
||
if ((device == IopRootDeviceNode) && search) {
|
||
device = IopFindLegacyBusDeviceNode (
|
||
interfaceType,
|
||
busNumber
|
||
);
|
||
|
||
//
|
||
// If we did not find a PDO, try again with InterfaceType == Isa. This allows
|
||
// drivers that request Internal to get resources even if there is no PDO
|
||
// that is Internal. (but if there is an Internal PDO, they get that one)
|
||
//
|
||
|
||
if ((device == IopRootDeviceNode) && (interfaceType == Internal)) {
|
||
device = IopFindLegacyBusDeviceNode(Isa, 0);
|
||
}
|
||
search = FALSE;
|
||
|
||
}
|
||
listHead = &device->DeviceArbiterList;
|
||
listEntry = listHead->Flink;
|
||
while (listEntry != listHead) {
|
||
arbiterEntry = CONTAINING_RECORD(listEntry, PI_RESOURCE_ARBITER_ENTRY, DeviceArbiterList);
|
||
if (arbiterEntry->ArbiterInterface != NULL) {
|
||
search = FALSE;
|
||
ASSERT(IsListEmpty(&arbiterEntry->ResourceList));
|
||
InitializeListHead(&arbiterEntry->ResourceList); // Recover from assert
|
||
InsertTailList(&arbiterEntry->ResourceList, &arbiterListEntry.ListEntry);
|
||
#if DBG_SCOPE
|
||
status =
|
||
#endif
|
||
IopCallArbiter(arbiterEntry,
|
||
ArbiterActionTestAllocation,
|
||
&arbiterEntry->ResourceList,
|
||
NULL,
|
||
NULL
|
||
);
|
||
#if DBG_SCOPE
|
||
ASSERT(status == STATUS_SUCCESS);
|
||
status =
|
||
#endif
|
||
IopCallArbiter(arbiterEntry,
|
||
ArbiterActionCommitAllocation,
|
||
NULL,
|
||
NULL,
|
||
NULL
|
||
);
|
||
#if DBG_SCOPE
|
||
ASSERT(status == STATUS_SUCCESS);
|
||
#endif
|
||
RemoveEntryList(&arbiterListEntry.ListEntry);
|
||
InitializeListHead(&arbiterListEntry.ListEntry);
|
||
}
|
||
listEntry = listEntry->Flink;
|
||
}
|
||
device = device->Parent;
|
||
}
|
||
|
||
//
|
||
// If there are more than 1 list, move to next list
|
||
//
|
||
|
||
if (listCount > 1) {
|
||
cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
|
||
for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
|
||
size = 0;
|
||
switch (cmPartDesc->Type) {
|
||
case CmResourceTypeDeviceSpecific:
|
||
size = cmPartDesc->u.DeviceSpecificData.DataSize;
|
||
break;
|
||
}
|
||
cmPartDesc++;
|
||
cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
|
||
}
|
||
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
|
||
}
|
||
}
|
||
|
||
IopWriteAllocatedResourcesToRegistry(DeviceNode, NULL, 0);
|
||
}
|
||
|
||
NTSTATUS
|
||
IopFindLegacyDeviceNode (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
OUT PDEVICE_NODE *LegacyDeviceNode,
|
||
OUT PDEVICE_OBJECT *LegacyPDO
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches for the device node and device object created for legacy resource
|
||
allocation for the DriverObject and DeviceObject.
|
||
|
||
Parameters:
|
||
|
||
DriverObject - specifies the driver object doing the legacy allocation.
|
||
|
||
DeviceObject - specifies the device object.
|
||
|
||
LegacyDeviceNode - receives the pointer to the legacy device node if found.
|
||
|
||
LegacyDeviceObject - receives the pointer to the legacy device object if found.
|
||
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
ASSERT(LegacyDeviceNode && LegacyPDO);
|
||
|
||
|
||
//
|
||
// Use the device object if it exists.
|
||
//
|
||
|
||
if (DeviceObject) {
|
||
|
||
deviceNode = PP_DO_TO_DN(DeviceObject);
|
||
if (deviceNode) {
|
||
|
||
*LegacyPDO = DeviceObject;
|
||
*LegacyDeviceNode = deviceNode;
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else if (!(DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE)) {
|
||
|
||
status = PipAllocateDeviceNode(DeviceObject, &deviceNode);
|
||
if (deviceNode) {
|
||
|
||
if (status == STATUS_SYSTEM_HIVE_TOO_LARGE) {
|
||
|
||
IopDestroyDeviceNode(deviceNode);
|
||
} else {
|
||
|
||
deviceNode->Flags |= DNF_LEGACY_RESOURCE_DEVICENODE;
|
||
IopSetLegacyDeviceInstance (DriverObject, deviceNode);
|
||
*LegacyPDO = DeviceObject;
|
||
*LegacyDeviceNode = deviceNode;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
} else {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Failed to allocate device node for PDO %08X\n",
|
||
DeviceObject));
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"%08X PDO without a device node!\n",
|
||
DeviceObject));
|
||
ASSERT(PP_DO_TO_DN(DeviceObject));
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Search our list of legacy device nodes.
|
||
//
|
||
|
||
for ( deviceNode = IopLegacyDeviceNode;
|
||
deviceNode && deviceNode->DuplicatePDO != (PDEVICE_OBJECT)DriverObject;
|
||
deviceNode = deviceNode->NextDeviceNode);
|
||
|
||
if (deviceNode) {
|
||
|
||
*LegacyPDO = deviceNode->PhysicalDeviceObject;
|
||
*LegacyDeviceNode = deviceNode;
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
PDEVICE_OBJECT pdo;
|
||
|
||
//
|
||
// We are seeing this for the first time.
|
||
// Create a madeup device node.
|
||
//
|
||
|
||
status = IoCreateDevice( IoPnpDriverObject,
|
||
sizeof(IOPNP_DEVICE_EXTENSION),
|
||
NULL,
|
||
FILE_DEVICE_CONTROLLER,
|
||
FILE_AUTOGENERATED_DEVICE_NAME,
|
||
FALSE,
|
||
&pdo);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
|
||
PipAllocateDeviceNode(pdo, &deviceNode);
|
||
if (status != STATUS_SYSTEM_HIVE_TOO_LARGE && deviceNode) {
|
||
|
||
//
|
||
// Change driver object to the caller even though the owner
|
||
// of the pdo is IoPnpDriverObject. This is to support
|
||
// DriverExclusive for legacy interface.
|
||
//
|
||
|
||
pdo->DriverObject = DriverObject;
|
||
deviceNode->Flags = DNF_MADEUP | DNF_LEGACY_RESOURCE_DEVICENODE;
|
||
|
||
PipSetDevNodeState(deviceNode, DeviceNodeInitialized, NULL);
|
||
|
||
deviceNode->DuplicatePDO = (PDEVICE_OBJECT)DriverObject;
|
||
IopSetLegacyDeviceInstance (DriverObject, deviceNode);
|
||
|
||
//
|
||
// Add it to our list of legacy device nodes rather than adding it to the HW tree.
|
||
//
|
||
|
||
deviceNode->NextDeviceNode = IopLegacyDeviceNode;
|
||
if (IopLegacyDeviceNode) {
|
||
|
||
IopLegacyDeviceNode->PreviousDeviceNode = deviceNode;
|
||
|
||
}
|
||
IopLegacyDeviceNode = deviceNode;
|
||
*LegacyPDO = pdo;
|
||
*LegacyDeviceNode = deviceNode;
|
||
|
||
} else {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Failed to allocate device node for PDO %08X\n",
|
||
pdo));
|
||
IoDeleteDevice(pdo);
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"IoCreateDevice failed with status %08X\n",
|
||
status));
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
IopRemoveLegacyDeviceNode (
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN PDEVICE_NODE LegacyDeviceNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine removes the device node and device object created for legacy resource
|
||
allocation for the DeviceObject.
|
||
|
||
Parameters:
|
||
|
||
DeviceObject - specifies the device object.
|
||
|
||
LegacyDeviceNode - receives the pointer to the legacy device node if found.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
ASSERT(LegacyDeviceNode);
|
||
|
||
|
||
if (!DeviceObject) {
|
||
|
||
if (LegacyDeviceNode->DuplicatePDO) {
|
||
|
||
LegacyDeviceNode->DuplicatePDO = NULL;
|
||
if (LegacyDeviceNode->PreviousDeviceNode) {
|
||
|
||
LegacyDeviceNode->PreviousDeviceNode->NextDeviceNode = LegacyDeviceNode->NextDeviceNode;
|
||
|
||
}
|
||
|
||
if (LegacyDeviceNode->NextDeviceNode) {
|
||
|
||
LegacyDeviceNode->NextDeviceNode->PreviousDeviceNode = LegacyDeviceNode->PreviousDeviceNode;
|
||
|
||
}
|
||
|
||
if (IopLegacyDeviceNode == LegacyDeviceNode) {
|
||
|
||
IopLegacyDeviceNode = LegacyDeviceNode->NextDeviceNode;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"%ws does not have a duplicate PDO\n",
|
||
LegacyDeviceNode->InstancePath.Buffer));
|
||
ASSERT(LegacyDeviceNode->DuplicatePDO);
|
||
return;
|
||
|
||
}
|
||
}
|
||
|
||
if (!(DeviceObject && (DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE))) {
|
||
|
||
PDEVICE_NODE resourceDeviceNode;
|
||
PDEVICE_OBJECT pdo;
|
||
|
||
for ( resourceDeviceNode = (PDEVICE_NODE)LegacyDeviceNode->OverUsed1.LegacyDeviceNode;
|
||
resourceDeviceNode;
|
||
resourceDeviceNode = resourceDeviceNode->OverUsed2.NextResourceDeviceNode) {
|
||
|
||
if (resourceDeviceNode->OverUsed2.NextResourceDeviceNode == LegacyDeviceNode) {
|
||
|
||
resourceDeviceNode->OverUsed2.NextResourceDeviceNode = LegacyDeviceNode->OverUsed2.NextResourceDeviceNode;
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
LegacyDeviceNode->Parent = LegacyDeviceNode->Sibling =
|
||
LegacyDeviceNode->Child = LegacyDeviceNode->LastChild = NULL;
|
||
|
||
//
|
||
// Delete the dummy PDO and device node.
|
||
//
|
||
|
||
pdo = LegacyDeviceNode->PhysicalDeviceObject;
|
||
LegacyDeviceNode->Flags &= ~DNF_LEGACY_RESOURCE_DEVICENODE;
|
||
IopDestroyDeviceNode(LegacyDeviceNode);
|
||
|
||
if (!DeviceObject) {
|
||
|
||
pdo->DriverObject = IoPnpDriverObject;
|
||
IoDeleteDevice(pdo);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
IopSetLegacyResourcesFlag(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
{
|
||
KIRQL irql;
|
||
|
||
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
|
||
//
|
||
// Once tainted, a driver can never lose it's legacy history
|
||
// (unless unloaded). This is because the device object
|
||
// field is optional, and we don't bother counting here...
|
||
//
|
||
DriverObject->Flags |= DRVO_LEGACY_RESOURCES;
|
||
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
IopLegacyResourceAllocation (
|
||
IN ARBITER_REQUEST_SOURCE AllocationType,
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements,
|
||
IN OUT PCM_RESOURCE_LIST *AllocatedResources OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles legacy interface IoAssignResources and IoReportResourcesUsage,
|
||
It converts the request to call IopAllocateResources.
|
||
|
||
Parameters:
|
||
|
||
AllocationType - Allocation type for the legacy request.
|
||
|
||
DriverObject - Driver object doing the legacy allocation.
|
||
|
||
DeviceObject - Device object.
|
||
|
||
ResourceRequirements - Legacy resource requirements. If NULL, caller want to free resources.
|
||
|
||
AllocatedResources - Pointer to a variable that receives pointer to allocated resources.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT pdo;
|
||
PDEVICE_NODE deviceNode;
|
||
PDEVICE_NODE legacyDeviceNode;
|
||
NTSTATUS status;
|
||
PCM_RESOURCE_LIST combinedResources;
|
||
|
||
ASSERT(DriverObject);
|
||
|
||
//
|
||
// Grab the IO registry semaphore to make sure no other device is
|
||
// reporting it's resource usage while we are searching for conflicts.
|
||
//
|
||
|
||
IopLockResourceManager();
|
||
status = IopFindLegacyDeviceNode(DriverObject, DeviceObject, &deviceNode, &pdo);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
legacyDeviceNode = NULL;
|
||
if (!deviceNode->Parent && ResourceRequirements) {
|
||
|
||
//
|
||
// Make IopRootDeviceNode the bus pdo so we will search the right bus pdo
|
||
// on resource descriptor level.
|
||
//
|
||
|
||
if (ResourceRequirements->InterfaceType == InterfaceTypeUndefined) {
|
||
|
||
ResourceRequirements->InterfaceType = PnpDefaultInterfaceType;
|
||
|
||
}
|
||
deviceNode->Parent = IopRootDeviceNode;
|
||
|
||
}
|
||
|
||
//
|
||
// Release resources for this device node.
|
||
//
|
||
|
||
if ( (!ResourceRequirements && deviceNode->Parent) ||
|
||
deviceNode->ResourceList ||
|
||
deviceNode->BootResources) {
|
||
|
||
IopReleaseResources(deviceNode);
|
||
}
|
||
|
||
if (ResourceRequirements) {
|
||
|
||
IOP_RESOURCE_REQUEST requestTable;
|
||
IOP_RESOURCE_REQUEST *requestTablep;
|
||
ULONG count;
|
||
|
||
//
|
||
// Try to allocate these resource requirements.
|
||
//
|
||
|
||
count = 1;
|
||
RtlZeroMemory(&requestTable, sizeof(IOP_RESOURCE_REQUEST));
|
||
requestTable.ResourceRequirements = ResourceRequirements;
|
||
requestTable.PhysicalDevice = pdo;
|
||
requestTable.Flags = IOP_ASSIGN_NO_REBALANCE;
|
||
requestTable.AllocationType = AllocationType;
|
||
|
||
requestTablep = &requestTable;
|
||
IopAllocateResources(&count, &requestTablep, TRUE, TRUE, NULL);
|
||
|
||
status = requestTable.Status;
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
deviceNode->ResourceListTranslated = requestTable.TranslatedResourceAssignment;
|
||
count = IopDetermineResourceListSize((*AllocatedResources) ? *AllocatedResources : requestTable.ResourceAssignment);
|
||
deviceNode->ResourceList = ExAllocatePoolIORL(PagedPool, count);
|
||
if (deviceNode->ResourceList) {
|
||
|
||
if (*AllocatedResources) {
|
||
|
||
//
|
||
// We got called from IoReportResourceUsage.
|
||
//
|
||
|
||
ASSERT(requestTable.ResourceAssignment);
|
||
ExFreePool(requestTable.ResourceAssignment);
|
||
|
||
} else {
|
||
|
||
//
|
||
// We got called from IoAssignResources.
|
||
//
|
||
|
||
*AllocatedResources = requestTable.ResourceAssignment;
|
||
|
||
}
|
||
RtlCopyMemory(deviceNode->ResourceList, *AllocatedResources, count);
|
||
legacyDeviceNode = (PDEVICE_NODE)deviceNode->OverUsed1.LegacyDeviceNode;
|
||
|
||
} else {
|
||
|
||
deviceNode->ResourceList = requestTable.ResourceAssignment;
|
||
IopReleaseResources(deviceNode);
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Remove the madeup PDO and device node if there was some error.
|
||
//
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
IopRemoveLegacyDeviceNode(DeviceObject, deviceNode);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Caller wants to release resources.
|
||
//
|
||
|
||
legacyDeviceNode = (PDEVICE_NODE)deviceNode->OverUsed1.LegacyDeviceNode;
|
||
IopRemoveLegacyDeviceNode(DeviceObject, deviceNode);
|
||
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
if (legacyDeviceNode) {
|
||
|
||
//
|
||
// After the resource is modified, update the allocated resource list
|
||
// for the Root\Legacy_xxxx\0000 device instance.
|
||
//
|
||
|
||
combinedResources = IopCombineLegacyResources(legacyDeviceNode);
|
||
if (combinedResources) {
|
||
|
||
IopWriteAllocatedResourcesToRegistry( legacyDeviceNode,
|
||
combinedResources,
|
||
IopDetermineResourceListSize(combinedResources));
|
||
ExFreePool(combinedResources);
|
||
}
|
||
}
|
||
|
||
if (AllocationType != ArbiterRequestPnpDetected) {
|
||
|
||
//
|
||
// Modify the DRVOBJ flags.
|
||
//
|
||
if (ResourceRequirements) {
|
||
|
||
IopSetLegacyResourcesFlag(DriverObject);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
IopUnlockResourceManager();
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopDuplicateDetection (
|
||
IN INTERFACE_TYPE LegacyBusType,
|
||
IN ULONG BusNumber,
|
||
IN ULONG SlotNumber,
|
||
OUT PDEVICE_NODE *DeviceNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches for the bus device driver for a given legacy device,
|
||
sends a query interface IRP for legacy device detection, and if the driver
|
||
implements this interface, requests the PDO for the given legacy device.
|
||
|
||
Parameters:
|
||
|
||
LegacyBusType - The legacy device's interface type.
|
||
|
||
BusNumber - The legacy device's bus number.
|
||
|
||
SlotNumber - The legacy device's slot number.
|
||
|
||
DeviceNode - specifies a pointer to a variable to receive the duplicated device node
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS code.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_NODE deviceNode;
|
||
PDEVICE_OBJECT busDeviceObject;
|
||
PLEGACY_DEVICE_DETECTION_INTERFACE interface;
|
||
NTSTATUS status;
|
||
PDEVICE_OBJECT deviceObject;
|
||
|
||
UNREFERENCED_PARAMETER(SlotNumber);
|
||
//
|
||
// Initialize return parameter to "not found".
|
||
//
|
||
*DeviceNode = NULL;
|
||
//
|
||
// Search the device tree for the bus of the legacy device.
|
||
//
|
||
deviceNode = IopFindLegacyBusDeviceNode(
|
||
LegacyBusType,
|
||
BusNumber);
|
||
//
|
||
// Either a bus driver does not exist (or more likely, the legacy bus
|
||
// type and bus number were unspecified). Either way, we can't make
|
||
// any further progress.
|
||
//
|
||
if (deviceNode == NULL) {
|
||
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
//
|
||
// We found the legacy device's bus driver. Query it to determine
|
||
// whether it implements the LEGACY_DEVICE_DETECTION interface.
|
||
//
|
||
|
||
busDeviceObject = deviceNode->PhysicalDeviceObject;
|
||
status = IopQueryResourceHandlerInterface(
|
||
ResourceLegacyDeviceDetection,
|
||
busDeviceObject,
|
||
0,
|
||
(PINTERFACE *)&interface);
|
||
//
|
||
// If it doesn't, we're stuck.
|
||
//
|
||
if (!NT_SUCCESS(status) || interface == NULL) {
|
||
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
//
|
||
// Invoke the bus driver's legacy device detection method.
|
||
//
|
||
status = (*interface->LegacyDeviceDetection)(
|
||
interface->Context,
|
||
LegacyBusType,
|
||
BusNumber,
|
||
SlotNumber,
|
||
&deviceObject);
|
||
//
|
||
// If it found a legacy device, update the return parameter.
|
||
//
|
||
if (NT_SUCCESS(status) && deviceObject != NULL) {
|
||
|
||
*DeviceNode = PP_DO_TO_DN(deviceObject);
|
||
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
//
|
||
// Free the interface.
|
||
//
|
||
(*interface->InterfaceDereference)(interface->Context);
|
||
|
||
ExFreePool(interface);
|
||
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
IopSetLegacyDeviceInstance (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_NODE DeviceNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the Root\Legacy_xxxx\0000 device instance path to the
|
||
madeup PDO (i.e. DeviceNode) which is created only for legacy resource allocation.
|
||
This routine also links the madeup PDO to the Root\Legacy_xxxx\0000 device node
|
||
to keep track what resources are assigned to the driver which services the
|
||
root\legacy_xxxx\0000 device.
|
||
|
||
Parameters:
|
||
|
||
P1 -
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
UNICODE_STRING instancePath, rootString;
|
||
HANDLE handle;
|
||
PDEVICE_NODE legacyDeviceNode;
|
||
PDEVICE_OBJECT legacyPdo;
|
||
|
||
PAGED_CODE();
|
||
|
||
DeviceNode->OverUsed1.LegacyDeviceNode = 0;
|
||
instancePath.Length = 0;
|
||
instancePath.Buffer = NULL;
|
||
|
||
status = PipServiceInstanceToDeviceInstance (
|
||
NULL,
|
||
&DriverObject->DriverExtension->ServiceKeyName,
|
||
0,
|
||
&instancePath,
|
||
&handle,
|
||
KEY_READ
|
||
);
|
||
if (NT_SUCCESS(status) && (instancePath.Length != 0)) {
|
||
PiWstrToUnicodeString(&rootString, L"ROOT\\LEGACY");
|
||
if (RtlPrefixUnicodeString(&rootString, &instancePath, TRUE) == FALSE) {
|
||
RtlFreeUnicodeString(&instancePath);
|
||
} else {
|
||
DeviceNode->InstancePath = instancePath;
|
||
legacyPdo = IopDeviceObjectFromDeviceInstance (&instancePath);
|
||
if (legacyPdo) {
|
||
legacyDeviceNode = PP_DO_TO_DN(legacyPdo);
|
||
DeviceNode->OverUsed2.NextResourceDeviceNode =
|
||
legacyDeviceNode->OverUsed2.NextResourceDeviceNode;
|
||
legacyDeviceNode->OverUsed2.NextResourceDeviceNode = DeviceNode;
|
||
DeviceNode->OverUsed1.LegacyDeviceNode = legacyDeviceNode;
|
||
}
|
||
}
|
||
ZwClose(handle);
|
||
}
|
||
}
|
||
|
||
PCM_RESOURCE_LIST
|
||
IopCombineLegacyResources (
|
||
IN PDEVICE_NODE DeviceNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the Root\Legacy_xxxx\0000 device instance path to the
|
||
madeup PDO (i.e. DeviceNode) which is created only for legacy resource allocation.
|
||
This routine also links the madeup PDO to the Root\Legacy_xxxx\0000 device node
|
||
to keep track what resources are assigned to the driver which services the
|
||
root\legacy_xxxx\0000 device.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - The legacy device node whose resources need to be combined.
|
||
|
||
Return Value:
|
||
|
||
Return the combined resource list.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_RESOURCE_LIST combinedList = NULL;
|
||
PDEVICE_NODE devNode = DeviceNode;
|
||
ULONG size = 0;
|
||
PUCHAR p;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (DeviceNode) {
|
||
|
||
//
|
||
// First determine how much memory is needed for the new combined list.
|
||
//
|
||
|
||
while (devNode) {
|
||
if (devNode->ResourceList) {
|
||
size += IopDetermineResourceListSize(devNode->ResourceList);
|
||
}
|
||
devNode = (PDEVICE_NODE)devNode->OverUsed2.NextResourceDeviceNode;
|
||
}
|
||
if (size != 0) {
|
||
combinedList = (PCM_RESOURCE_LIST) ExAllocatePoolCMRL(PagedPool, size);
|
||
devNode = DeviceNode;
|
||
if (combinedList) {
|
||
combinedList->Count = 0;
|
||
p = (PUCHAR)combinedList;
|
||
p += sizeof(ULONG); // Skip Count
|
||
while (devNode) {
|
||
if (devNode->ResourceList) {
|
||
size = IopDetermineResourceListSize(devNode->ResourceList);
|
||
if (size != 0) {
|
||
size -= sizeof(ULONG);
|
||
RtlCopyMemory(
|
||
p,
|
||
devNode->ResourceList->List,
|
||
size
|
||
);
|
||
p += size;
|
||
combinedList->Count += devNode->ResourceList->Count;
|
||
}
|
||
}
|
||
devNode = (PDEVICE_NODE)devNode->OverUsed2.NextResourceDeviceNode;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return combinedList;
|
||
}
|
||
|
||
VOID
|
||
IopReleaseResources (
|
||
IN PDEVICE_NODE DeviceNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
IopReleaseResources releases resources owned by the device and release
|
||
the memory pool. We also release the cached resource requirements list.
|
||
If the device is a root enumerated device with BOOT config, we will preallocate
|
||
boot config resources for this device.
|
||
|
||
NOTE, this is a routine INTERNAL to this file. NO one should call this function
|
||
outside of this file. Outside of this file, IopReleaseDeviceResources should be
|
||
used.
|
||
|
||
Arguments:
|
||
|
||
DeviceNode - Supplies a pointer to the device node.object. If present, caller wants to
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Release the resources owned by the device
|
||
//
|
||
|
||
IopReleaseResourcesInternal(DeviceNode);
|
||
|
||
#if DBG_SCOPE
|
||
|
||
if (DeviceNode->PreviousResourceList) {
|
||
ExFreePool(DeviceNode->PreviousResourceList);
|
||
DeviceNode->PreviousResourceList = NULL;
|
||
}
|
||
if (DeviceNode->PreviousResourceRequirements) {
|
||
ExFreePool(DeviceNode->PreviousResourceRequirements);
|
||
DeviceNode->PreviousResourceRequirements = NULL;
|
||
}
|
||
#endif
|
||
|
||
if (DeviceNode->ResourceList) {
|
||
|
||
#if DBG_SCOPE
|
||
if (!NT_SUCCESS(DeviceNode->FailureStatus)) {
|
||
DeviceNode->PreviousResourceList = DeviceNode->ResourceList;
|
||
} else {
|
||
ExFreePool(DeviceNode->ResourceList);
|
||
}
|
||
#else
|
||
ExFreePool(DeviceNode->ResourceList);
|
||
#endif
|
||
|
||
DeviceNode->ResourceList = NULL;
|
||
}
|
||
if (DeviceNode->ResourceListTranslated) {
|
||
ExFreePool(DeviceNode->ResourceListTranslated);
|
||
DeviceNode->ResourceListTranslated = NULL;
|
||
}
|
||
|
||
//
|
||
// If this device is a root enumerated device, preallocate its BOOT resources
|
||
//
|
||
|
||
if ((DeviceNode->Flags & (DNF_MADEUP | DNF_DEVICE_GONE)) == DNF_MADEUP) {
|
||
if (DeviceNode->Flags & DNF_HAS_BOOT_CONFIG && DeviceNode->BootResources) {
|
||
IopAllocateBootResourcesInternal(ArbiterRequestPnpEnumerated,
|
||
DeviceNode->PhysicalDeviceObject,
|
||
DeviceNode->BootResources);
|
||
}
|
||
} else {
|
||
DeviceNode->Flags &= ~(DNF_HAS_BOOT_CONFIG | DNF_BOOT_CONFIG_RESERVED);
|
||
if (DeviceNode->BootResources) {
|
||
ExFreePool(DeviceNode->BootResources);
|
||
DeviceNode->BootResources = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopReallocateResources(
|
||
IN PDEVICE_NODE DeviceNode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs the real work for IoInvalidateDeviceState - ResourceRequirementsChanged.
|
||
|
||
Arguments:
|
||
|
||
DeviceNode - Supplies a pointer to the device node.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
IOP_RESOURCE_REQUEST requestTable, *requestTablep;
|
||
ULONG deviceCount, oldFlags;
|
||
NTSTATUS status;
|
||
LIST_ENTRY activeArbiterList;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Grab the IO registry semaphore to make sure no other device is
|
||
// reporting it's resource usage while we are searching for conflicts.
|
||
//
|
||
|
||
IopLockResourceManager();
|
||
|
||
//
|
||
// Check the flags after acquiring the semaphore.
|
||
//
|
||
|
||
if (DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) {
|
||
//
|
||
// Save the flags which we may have to restore in case of failure.
|
||
//
|
||
|
||
oldFlags = DeviceNode->Flags & DNF_NO_RESOURCE_REQUIRED;
|
||
DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
|
||
|
||
if (DeviceNode->Flags & DNF_NON_STOPPED_REBALANCE) {
|
||
|
||
//
|
||
// Set up parameters to call real routine
|
||
//
|
||
|
||
RtlZeroMemory(&requestTable, sizeof(IOP_RESOURCE_REQUEST));
|
||
requestTable.PhysicalDevice = DeviceNode->PhysicalDeviceObject;
|
||
requestTablep = &requestTable;
|
||
requestTable.Flags |= IOP_ASSIGN_NO_REBALANCE + IOP_ASSIGN_KEEP_CURRENT_CONFIG;
|
||
|
||
status = IopGetResourceRequirementsForAssignTable( requestTablep,
|
||
requestTablep + 1,
|
||
&deviceCount);
|
||
if (deviceCount) {
|
||
|
||
//
|
||
// Release the current resources to the arbiters.
|
||
// Memory for ResourceList is not released.
|
||
//
|
||
|
||
if (DeviceNode->ResourceList) {
|
||
|
||
IopReleaseResourcesInternal(DeviceNode);
|
||
}
|
||
|
||
//
|
||
// Try to do the assignment.
|
||
//
|
||
|
||
status = IopFindBestConfiguration(
|
||
requestTablep,
|
||
deviceCount,
|
||
&activeArbiterList);
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Ask the arbiters to commit this configuration.
|
||
//
|
||
status = IopCommitConfiguration(&activeArbiterList);
|
||
}
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
DeviceNode->Flags &= ~(DNF_RESOURCE_REQUIREMENTS_CHANGED | DNF_NON_STOPPED_REBALANCE);
|
||
|
||
IopBuildCmResourceLists(requestTablep, requestTablep + 1);
|
||
|
||
//
|
||
// We need to release the pool space for ResourceList and ResourceListTranslated.
|
||
// Because the earlier IopReleaseResourcesInternal does not release the pool.
|
||
//
|
||
|
||
if (DeviceNode->ResourceList) {
|
||
|
||
ExFreePool(DeviceNode->ResourceList);
|
||
|
||
}
|
||
if (DeviceNode->ResourceListTranslated) {
|
||
|
||
ExFreePool(DeviceNode->ResourceListTranslated);
|
||
|
||
}
|
||
|
||
DeviceNode->ResourceList = requestTablep->ResourceAssignment;
|
||
DeviceNode->ResourceListTranslated = requestTablep->TranslatedResourceAssignment;
|
||
|
||
ASSERT(DeviceNode->State == DeviceNodeStarted);
|
||
|
||
status = IopStartDevice(DeviceNode->PhysicalDeviceObject);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
PipRequestDeviceRemoval(DeviceNode, FALSE, CM_PROB_NORMAL_CONFLICT);
|
||
}
|
||
|
||
} else {
|
||
|
||
NTSTATUS restoreResourcesStatus;
|
||
|
||
restoreResourcesStatus = IopRestoreResourcesInternal(DeviceNode);
|
||
if (!NT_SUCCESS(restoreResourcesStatus)) {
|
||
|
||
ASSERT(NT_SUCCESS(restoreResourcesStatus));
|
||
PipRequestDeviceRemoval(DeviceNode, FALSE, CM_PROB_NEED_RESTART);
|
||
}
|
||
}
|
||
|
||
IopFreeResourceRequirementsForAssignTable(requestTablep, requestTablep + 1);
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// The device needs to be stopped to change resources.
|
||
//
|
||
|
||
status = IopRebalance(0, NULL);
|
||
|
||
}
|
||
|
||
//
|
||
// Restore the flags in case of failure.
|
||
//
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
|
||
DeviceNode->Flags |= oldFlags;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Resource requirements not changed in "
|
||
"IopReallocateResources, returning error!\n"));
|
||
}
|
||
|
||
IopUnlockResourceManager();
|
||
}
|
||
|
||
NTSTATUS
|
||
IopQueryConflictList(
|
||
PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN PCM_RESOURCE_LIST ResourceList,
|
||
IN ULONG ResourceListSize,
|
||
OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
|
||
IN ULONG ConflictListSize,
|
||
IN ULONG Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs the querying of device conflicts
|
||
returning data in ConflictList
|
||
|
||
Arguments:
|
||
|
||
PhysicalDeviceObject PDO of device to Query
|
||
ResourceList CM resource list containing single resource to query
|
||
ResourceListSize Size of ResourceList
|
||
ConflictList Conflict list to fill query details in
|
||
ConflictListSize Size of buffer that we can fill with Conflict information
|
||
Flags Currently unused (zero) for future passing of flags
|
||
|
||
Return Value:
|
||
|
||
Should be success in most cases
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
IopLockResourceManager();
|
||
|
||
status = IopQueryConflictListInternal(PhysicalDeviceObject, ResourceList, ResourceListSize, ConflictList, ConflictListSize, Flags);
|
||
|
||
IopUnlockResourceManager();
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
IopEliminateBogusConflict(
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN PDEVICE_OBJECT ConflictDeviceObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determine if we're really conflicting with ourselves
|
||
if this is the case, we ignore it
|
||
|
||
Arguments:
|
||
|
||
PhysicalDeviceObject PDO we're performing the test for
|
||
ConflictDeviceObject The object we've determined is conflicting
|
||
|
||
Return Value:
|
||
|
||
TRUE to eliminate the conflict
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_NODE deviceNode;
|
||
PDRIVER_OBJECT driverObject;
|
||
KIRQL irql;
|
||
PDEVICE_OBJECT attachedDevice;
|
||
|
||
//
|
||
// simple cases
|
||
//
|
||
if (PhysicalDeviceObject == NULL || ConflictDeviceObject == NULL) {
|
||
return FALSE;
|
||
}
|
||
//
|
||
// if ConflictDeviceObject is on PDO's stack, this is a non-conflict
|
||
// nb at least PDO has to be checked
|
||
//
|
||
irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
|
||
|
||
for (attachedDevice = PhysicalDeviceObject;
|
||
attachedDevice;
|
||
attachedDevice = attachedDevice->AttachedDevice) {
|
||
|
||
if (attachedDevice == ConflictDeviceObject) {
|
||
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
|
||
|
||
//
|
||
// legacy case
|
||
//
|
||
deviceNode = PP_DO_TO_DN(PhysicalDeviceObject);
|
||
ASSERT(deviceNode);
|
||
if (deviceNode->Flags & DNF_LEGACY_DRIVER) {
|
||
//
|
||
// hmmm, let's see if our ConflictDeviceObject is resources associated with a legacy device
|
||
//
|
||
if (ConflictDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) {
|
||
//
|
||
// if not, we have a legacy conflicting with non-legacy, we're interested!
|
||
//
|
||
return FALSE;
|
||
}
|
||
//
|
||
// FDO, report driver name
|
||
//
|
||
driverObject = ConflictDeviceObject->DriverObject;
|
||
if(driverObject == NULL) {
|
||
//
|
||
// should not be NULL
|
||
//
|
||
ASSERT(driverObject);
|
||
return FALSE;
|
||
}
|
||
//
|
||
// compare deviceNode->Service with driverObject->Service
|
||
//
|
||
if (deviceNode->ServiceName.Length != 0 &&
|
||
deviceNode->ServiceName.Length == driverObject->DriverExtension->ServiceKeyName.Length &&
|
||
RtlCompareUnicodeString(&deviceNode->ServiceName,&driverObject->DriverExtension->ServiceKeyName,TRUE)==0) {
|
||
//
|
||
// the driver's service name is the same that this PDO is associated with
|
||
// by ignoring it we could end up ignoring conflicts of simular types of legacy devices
|
||
// but since these have to be hand-config'd anyhow, it's prob better than having false conflicts
|
||
//
|
||
return TRUE;
|
||
}
|
||
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
IopQueryConflictFillString(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PWSTR Buffer,
|
||
IN OUT PULONG Length,
|
||
IN OUT PULONG Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtain string or string-length for details of conflicting device
|
||
|
||
Arguments:
|
||
|
||
DeviceObject Device object we want Device-Instance-String or Service Name
|
||
Buffer Buffer to Fill, NULL if we just want length
|
||
Length Filled with length of Buffer, including terminated NULL (Words)
|
||
Flags Apropriate flags set describing what the string represents
|
||
|
||
Return Value:
|
||
|
||
Should be success in most cases
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_NODE deviceNode;
|
||
PDRIVER_OBJECT driverObject;
|
||
PUNICODE_STRING infoString = NULL;
|
||
ULONG MaxLength = 0; // words
|
||
ULONG ReqLength = 0; // words
|
||
ULONG flags = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (Length != NULL) {
|
||
MaxLength = *Length;
|
||
}
|
||
|
||
if (Flags != NULL) {
|
||
flags = *Flags;
|
||
}
|
||
|
||
if (DeviceObject == NULL) {
|
||
//
|
||
// unknown
|
||
//
|
||
goto final;
|
||
|
||
}
|
||
|
||
if ((DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) == 0 ) {
|
||
//
|
||
// FDO, report driver name
|
||
//
|
||
driverObject = DeviceObject->DriverObject;
|
||
if(driverObject == NULL) {
|
||
//
|
||
// should not be NULL
|
||
//
|
||
ASSERT(driverObject);
|
||
goto final;
|
||
}
|
||
infoString = & (driverObject->DriverName);
|
||
flags |= PNP_CE_LEGACY_DRIVER;
|
||
goto final;
|
||
}
|
||
|
||
//
|
||
// we should in actual fact have a PDO
|
||
//
|
||
if (DeviceObject->DeviceObjectExtension == NULL) {
|
||
//
|
||
// should not be NULL
|
||
//
|
||
ASSERT(DeviceObject->DeviceObjectExtension);
|
||
goto final;
|
||
}
|
||
|
||
deviceNode = PP_DO_TO_DN(DeviceObject);
|
||
if (deviceNode == NULL) {
|
||
//
|
||
// should not be NULL
|
||
//
|
||
ASSERT(deviceNode);
|
||
goto final;
|
||
}
|
||
|
||
if (deviceNode == IopRootDeviceNode) {
|
||
//
|
||
// owned by root device
|
||
//
|
||
flags |= PNP_CE_ROOT_OWNED;
|
||
|
||
} else if (deviceNode -> Parent == NULL) {
|
||
//
|
||
// faked out PDO - must be legacy device
|
||
//
|
||
driverObject = (PDRIVER_OBJECT)(deviceNode->DuplicatePDO);
|
||
if(driverObject == NULL) {
|
||
//
|
||
// should not be NULL
|
||
//
|
||
ASSERT(driverObject);
|
||
goto final;
|
||
}
|
||
infoString = & (driverObject->DriverName);
|
||
flags |= PNP_CE_LEGACY_DRIVER;
|
||
goto final;
|
||
}
|
||
|
||
//
|
||
// we should be happy with what we have
|
||
//
|
||
infoString = &deviceNode->InstancePath;
|
||
|
||
final:
|
||
|
||
if (infoString != NULL) {
|
||
//
|
||
// we have a string to copy
|
||
//
|
||
if ((Buffer != NULL) && (MaxLength*sizeof(WCHAR) > infoString->Length)) {
|
||
RtlCopyMemory(Buffer, infoString->Buffer, infoString->Length);
|
||
}
|
||
ReqLength += infoString->Length / sizeof(WCHAR);
|
||
}
|
||
|
||
if ((Buffer != NULL) && (MaxLength > ReqLength)) {
|
||
Buffer[ReqLength] = 0;
|
||
}
|
||
|
||
ReqLength++;
|
||
|
||
if (Length != NULL) {
|
||
*Length = ReqLength;
|
||
}
|
||
if (Flags != NULL) {
|
||
*Flags = flags;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
IopQueryConflictFillConflicts(
|
||
PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN ULONG ConflictCount,
|
||
IN PARBITER_CONFLICT_INFO ConflictInfoList,
|
||
OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
|
||
IN ULONG ConflictListSize,
|
||
IN ULONG Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fill ConflictList with information on as many conflicts as possible
|
||
|
||
Arguments:
|
||
|
||
PhysicalDeviceObject The PDO we're performing the test on
|
||
ConflictCount Number of Conflicts.
|
||
ConflictInfoList List of conflicting device info, can be NULL if ConflictCount is 0
|
||
ConflictList Structure to fill in with conflicts
|
||
ConflictListSize Size of Conflict List
|
||
Flags if non-zero, dummy conflict is created
|
||
|
||
Return Value:
|
||
|
||
Should be success in most cases
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG ConflictListIdealSize;
|
||
ULONG ConflictListCount;
|
||
ULONG Index;
|
||
ULONG ConflictIndex;
|
||
ULONG EntrySize;
|
||
ULONG ConflictStringsOffset;
|
||
ULONG stringSize;
|
||
ULONG stringTotalSize;
|
||
ULONG DummyCount;
|
||
PPLUGPLAY_CONTROL_CONFLICT_STRINGS ConfStrings;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// determine how many conflicts we can
|
||
//
|
||
// for each conflict
|
||
// translate to bus/resource/address in respect to conflicting device
|
||
// add to conflict list
|
||
//
|
||
//
|
||
|
||
//
|
||
// preprocessing - given our ConflictInfoList and ConflictCount
|
||
// remove any that appear to be bogus - ie, that are the same device that we are testing against
|
||
// this stops mostly legacy issues
|
||
//
|
||
for(Index = 0;Index < ConflictCount; Index++) {
|
||
if (IopEliminateBogusConflict(PhysicalDeviceObject,ConflictInfoList[Index].OwningObject)) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: eliminating \"identical\" PDO"
|
||
" %08x conflicting with self (%08x)\n",
|
||
ConflictInfoList[Index].OwningObject,
|
||
PhysicalDeviceObject));
|
||
//
|
||
// move the last listed conflict into this space
|
||
//
|
||
if (Index+1 < ConflictCount) {
|
||
RtlCopyMemory(&ConflictInfoList[Index],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
|
||
}
|
||
//
|
||
// account for deleting this item
|
||
//
|
||
ConflictCount--;
|
||
Index--;
|
||
}
|
||
}
|
||
|
||
//
|
||
// preprocessing - in our conflict list, we may have PDO's for legacy devices, and resource nodes for the same
|
||
// or other duplicate entities (we only ever want to report a conflict once, even if there's multiple conflicting ranges)
|
||
//
|
||
|
||
RestartScan:
|
||
|
||
for(Index = 0;Index < ConflictCount; Index++) {
|
||
if (ConflictInfoList[Index].OwningObject != NULL) {
|
||
|
||
ULONG Index2;
|
||
|
||
for (Index2 = Index+1; Index2 < ConflictCount; Index2++) {
|
||
if (IopEliminateBogusConflict(ConflictInfoList[Index].OwningObject,ConflictInfoList[Index2].OwningObject)) {
|
||
//
|
||
// Index2 is considered a dup of Index
|
||
//
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: eliminating \"identical\" PDO"
|
||
" %08x conflicting with PDO %08x\n",
|
||
ConflictInfoList[Index2].OwningObject,
|
||
ConflictInfoList[Index].OwningObject));
|
||
//
|
||
// move the last listed conflict into this space
|
||
//
|
||
if (Index2+1 < ConflictCount) {
|
||
RtlCopyMemory(&ConflictInfoList[Index2],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
|
||
}
|
||
//
|
||
// account for deleting this item
|
||
//
|
||
ConflictCount--;
|
||
Index2--;
|
||
} else if (IopEliminateBogusConflict(ConflictInfoList[Index2].OwningObject,ConflictInfoList[Index].OwningObject)) {
|
||
//
|
||
// Index is considered a dup of Index2 (some legacy case)
|
||
//
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: eliminating \"identical\" PDO"
|
||
" %08x conflicting with PDO %08x\n",
|
||
ConflictInfoList[Index2].OwningObject,
|
||
ConflictInfoList[Index].OwningObject));
|
||
//
|
||
// move the one we want (Index2) into the space occupied by Index
|
||
//
|
||
RtlCopyMemory(&ConflictInfoList[Index],&ConflictInfoList[Index2],sizeof(ARBITER_CONFLICT_INFO));
|
||
//
|
||
// move the last listed conflict into the space we just created
|
||
//
|
||
if (Index2+1 < ConflictCount) {
|
||
RtlCopyMemory(&ConflictInfoList[Index2],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
|
||
}
|
||
//
|
||
// account for deleting this item
|
||
//
|
||
ConflictCount--;
|
||
//
|
||
// but as this is quirky, restart the scan
|
||
//
|
||
goto RestartScan;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// preprocessing - if we have any known reported conflicts, don't report back any unknown
|
||
//
|
||
|
||
for(Index = 0;Index < ConflictCount; Index++) {
|
||
//
|
||
// find first unknown
|
||
//
|
||
if (ConflictInfoList[Index].OwningObject == NULL) {
|
||
//
|
||
// eliminate all other unknowns
|
||
//
|
||
|
||
ULONG Index2;
|
||
|
||
for (Index2 = Index+1; Index2 < ConflictCount; Index2++) {
|
||
if (ConflictInfoList[Index2].OwningObject == NULL) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: eliminating extra"
|
||
" unknown\n"));
|
||
//
|
||
// move the last listed conflict into this space
|
||
//
|
||
if (Index2+1 < ConflictCount) {
|
||
RtlCopyMemory(&ConflictInfoList[Index2],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
|
||
}
|
||
//
|
||
// account for deleting this item
|
||
//
|
||
ConflictCount--;
|
||
Index2--;
|
||
}
|
||
}
|
||
|
||
if(ConflictCount != 1) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: eliminating first unknown\n"
|
||
));
|
||
//
|
||
// there were others, so ignore the unknown
|
||
//
|
||
if (Index+1 < ConflictCount) {
|
||
RtlCopyMemory(&ConflictInfoList[Index],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
|
||
}
|
||
ConflictCount --;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// set number of actual and listed conflicts
|
||
//
|
||
|
||
ConflictListIdealSize = (sizeof(PLUGPLAY_CONTROL_CONFLICT_LIST) - sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY)) + sizeof(PLUGPLAY_CONTROL_CONFLICT_STRINGS);
|
||
ConflictListCount = 0;
|
||
stringTotalSize = 0;
|
||
DummyCount = 0;
|
||
|
||
ASSERT(ConflictListSize >= ConflictListIdealSize); // we should have checked to see if buffer is at least this big
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: Detected %d conflicts\n",
|
||
ConflictCount));
|
||
|
||
//
|
||
// estimate sizes
|
||
//
|
||
if (Flags) {
|
||
//
|
||
// flags entry required (ie resource not available for some specified reason)
|
||
//
|
||
stringSize = 1; // null-length string
|
||
DummyCount ++;
|
||
EntrySize = sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY);
|
||
EntrySize += sizeof(WCHAR) * stringSize;
|
||
|
||
if((ConflictListIdealSize+EntrySize) <= ConflictListSize) {
|
||
//
|
||
// we can fit this one in
|
||
//
|
||
ConflictListCount++;
|
||
stringTotalSize += stringSize;
|
||
}
|
||
ConflictListIdealSize += EntrySize;
|
||
}
|
||
//
|
||
// report conflicts
|
||
//
|
||
for(Index = 0; Index < ConflictCount; Index ++) {
|
||
|
||
stringSize = 0;
|
||
IopQueryConflictFillString(ConflictInfoList[Index].OwningObject,NULL,&stringSize,NULL);
|
||
|
||
//
|
||
// account for entry
|
||
//
|
||
EntrySize = sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY);
|
||
EntrySize += sizeof(WCHAR) * stringSize;
|
||
|
||
if((ConflictListIdealSize+EntrySize) <= ConflictListSize) {
|
||
//
|
||
// we can fit this one in
|
||
//
|
||
ConflictListCount++;
|
||
stringTotalSize += stringSize;
|
||
}
|
||
ConflictListIdealSize += EntrySize;
|
||
}
|
||
|
||
ConflictList->ConflictsCounted = ConflictCount+DummyCount; // number of conflicts detected including any dummy conflict
|
||
ConflictList->ConflictsListed = ConflictListCount; // how many we could fit in
|
||
ConflictList->RequiredBufferSize = ConflictListIdealSize; // how much buffer space to supply on next call
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: Listing %d conflicts\n",
|
||
ConflictListCount));
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: Need %08x bytes to list all conflicts\n",
|
||
ConflictListIdealSize));
|
||
|
||
ConfStrings = (PPLUGPLAY_CONTROL_CONFLICT_STRINGS)&(ConflictList->ConflictEntry[ConflictListCount]);
|
||
ConfStrings->NullDeviceInstance = (ULONG)(-1);
|
||
ConflictStringsOffset = 0;
|
||
|
||
for(ConflictIndex = 0; ConflictIndex < DummyCount; ConflictIndex++) {
|
||
//
|
||
// flags entry required (ie resource not available for some specified reason)
|
||
//
|
||
if (Flags && ConflictIndex == 0) {
|
||
ConflictList->ConflictEntry[ConflictIndex].DeviceInstance = ConflictStringsOffset;
|
||
ConflictList->ConflictEntry[ConflictIndex].DeviceFlags = Flags;
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceType = 0;
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceStart = 0;
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceEnd = 0;
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceFlags = 0;
|
||
|
||
ConfStrings->DeviceInstanceStrings[ConflictStringsOffset] = 0; // null string
|
||
stringTotalSize --;
|
||
ConflictStringsOffset ++;
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: Listing flags %08x\n",
|
||
Flags));
|
||
}
|
||
}
|
||
//
|
||
// get/fill in details for all those we can fit into the buffer
|
||
//
|
||
for(Index = 0; ConflictIndex < ConflictListCount ; Index ++, ConflictIndex++) {
|
||
|
||
ASSERT(Index < ConflictCount);
|
||
//
|
||
// assign conflict information
|
||
//
|
||
ConflictList->ConflictEntry[ConflictIndex].DeviceInstance = ConflictStringsOffset;
|
||
ConflictList->ConflictEntry[ConflictIndex].DeviceFlags = 0;
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceType = 0; // NYI
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceStart = (ULONGLONG)(1); // for now, return totally invalid range (1-0)
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceEnd = 0;
|
||
ConflictList->ConflictEntry[ConflictIndex].ResourceFlags = 0;
|
||
|
||
//
|
||
// fill string details
|
||
//
|
||
stringSize = stringTotalSize;
|
||
IopQueryConflictFillString(ConflictInfoList[Index].OwningObject,
|
||
&(ConfStrings->DeviceInstanceStrings[ConflictStringsOffset]),
|
||
&stringSize,
|
||
&(ConflictList->ConflictEntry[ConflictIndex].DeviceFlags));
|
||
stringTotalSize -= stringSize;
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopQueryConflictFillConflicts: Listing \"%S\"\n",
|
||
&(ConfStrings->DeviceInstanceStrings[ConflictStringsOffset])));
|
||
ConflictStringsOffset += stringSize;
|
||
}
|
||
|
||
//
|
||
// another NULL at end of strings (this is accounted for in the PPLUGPLAY_CONTROL_CONFLICT_STRINGS structure)
|
||
//
|
||
ConfStrings->DeviceInstanceStrings[ConflictStringsOffset] = 0;
|
||
|
||
//Clean0:
|
||
;
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
IopQueryConflictListInternal(
|
||
PDEVICE_OBJECT PhysicalDeviceObject,
|
||
IN PCM_RESOURCE_LIST ResourceList,
|
||
IN ULONG ResourceListSize,
|
||
OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
|
||
IN ULONG ConflictListSize,
|
||
IN ULONG Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Version of IopQueryConflictList without the locking
|
||
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_NODE deviceNode = NULL;
|
||
PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
|
||
PREQ_LIST reqList;
|
||
PREQ_DESC reqDesc, reqDescTranslated;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
PREQ_ALTERNATIVE RA;
|
||
PPREQ_ALTERNATIVE reqAlternative;
|
||
ULONG ConflictCount = 0;
|
||
PARBITER_CONFLICT_INFO ConflictInfoList = NULL;
|
||
PIO_RESOURCE_DESCRIPTOR ConflictDesc = NULL;
|
||
ULONG ReqDescCount = 0;
|
||
PREQ_DESC *ReqDescTable = NULL;
|
||
PIO_RESOURCE_REQUIREMENTS_LIST pIoReqList = NULL;
|
||
PVOID ExtParams[4];
|
||
IOP_RESOURCE_REQUEST request;
|
||
|
||
UNREFERENCED_PARAMETER( Flags );
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT(PhysicalDeviceObject);
|
||
ASSERT(ResourceList);
|
||
ASSERT(ResourceListSize);
|
||
//
|
||
// these parameters were generated by umpnpmgr
|
||
// so should be correct - one resource, and one resource only
|
||
//
|
||
ASSERT(ResourceList->Count == 1);
|
||
ASSERT(ResourceList->List[0].PartialResourceList.Count == 1);
|
||
|
||
if (ConflictList == NULL || (ConflictListSize < (sizeof(PLUGPLAY_CONTROL_CONFLICT_LIST) - sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY)) + sizeof(PLUGPLAY_CONTROL_CONFLICT_STRINGS))) {
|
||
//
|
||
// sanity check
|
||
//
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
goto Clean0;
|
||
}
|
||
//
|
||
// whatever other error we return, ensure that ConflictList is interpretable
|
||
//
|
||
|
||
ConflictList->ConflictsCounted = 0;
|
||
ConflictList->ConflictsListed = 0;
|
||
ConflictList->RequiredBufferSize = (sizeof(PLUGPLAY_CONTROL_CONFLICT_LIST) - sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY)) + sizeof(PLUGPLAY_CONTROL_CONFLICT_STRINGS);
|
||
|
||
//
|
||
// Retrieve the devnode from the PDO
|
||
//
|
||
deviceNode = PP_DO_TO_DN(PhysicalDeviceObject);
|
||
if (!deviceNode) {
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// type-specific validation
|
||
//
|
||
switch(ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type) {
|
||
case CmResourceTypePort:
|
||
case CmResourceTypeMemory:
|
||
if(ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Generic.Length == 0) {
|
||
//
|
||
// zero-range resource can never conflict
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
goto Clean0;
|
||
}
|
||
break;
|
||
case CmResourceTypeInterrupt:
|
||
case CmResourceTypeDma:
|
||
break;
|
||
default:
|
||
ASSERT(0);
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto Clean0;
|
||
}
|
||
|
||
//
|
||
// apply bus details from node
|
||
//
|
||
if (deviceNode->ChildInterfaceType == InterfaceTypeUndefined) {
|
||
//
|
||
// we have to grovel around to find real Interface Type
|
||
//
|
||
pIoReqList = deviceNode->ResourceRequirements;
|
||
if (pIoReqList != NULL && pIoReqList->InterfaceType != InterfaceTypeUndefined) {
|
||
ResourceList->List[0].InterfaceType = pIoReqList->InterfaceType;
|
||
} else {
|
||
//
|
||
// we should never get here
|
||
// if we do, I need to look at this more
|
||
//
|
||
#if MAXDBG
|
||
ASSERT(0);
|
||
#endif
|
||
ResourceList->List[0].InterfaceType = PnpDefaultInterfaceType;
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// we trust the deviceNode to tell us Interface Type
|
||
//
|
||
ResourceList->List[0].InterfaceType = deviceNode->ChildInterfaceType;
|
||
}
|
||
//
|
||
// Some bus-types we are better off considered as default
|
||
//
|
||
switch(ResourceList->List[0].InterfaceType) {
|
||
case InterfaceTypeUndefined:
|
||
case PCMCIABus:
|
||
ResourceList->List[0].InterfaceType = PnpDefaultInterfaceType;
|
||
}
|
||
if ((deviceNode->ChildBusNumber & 0x80000000) == 0x80000000) {
|
||
//
|
||
// we have to grovel around to find real Bus Number
|
||
//
|
||
pIoReqList = deviceNode->ResourceRequirements;
|
||
if (pIoReqList != NULL && (pIoReqList->BusNumber & 0x80000000) != 0x80000000) {
|
||
ResourceList->List[0].BusNumber = pIoReqList->BusNumber;
|
||
} else {
|
||
//
|
||
// a resonable default, but assert is here so I remember to look at this more
|
||
//
|
||
#if MAXDBG
|
||
ASSERT(0);
|
||
#endif
|
||
ResourceList->List[0].BusNumber = 0;
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// we trust the deviceNode to tell us Bus Number
|
||
//
|
||
ResourceList->List[0].BusNumber = deviceNode->ChildBusNumber;
|
||
}
|
||
|
||
//
|
||
// from our CM Resource List, obtain an IO Resource Requirements List
|
||
//
|
||
ioResources = IopCmResourcesToIoResources(0, ResourceList, LCPRI_FORCECONFIG);
|
||
if (!ioResources) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
goto Clean0;
|
||
}
|
||
//
|
||
// Convert ioResources to a Request list
|
||
// and in the processess, determine any Arbiters/Translators to use
|
||
//
|
||
request.AllocationType = ArbiterRequestUndefined;
|
||
request.ResourceRequirements = ioResources;
|
||
request.PhysicalDevice = PhysicalDeviceObject;
|
||
status = IopResourceRequirementsListToReqList(
|
||
&request,
|
||
&reqList);
|
||
|
||
//
|
||
// get arbitrator/translator for current device/bus
|
||
//
|
||
|
||
if (NT_SUCCESS(status) && reqList) {
|
||
|
||
reqAlternative = reqList->AlternativeTable;
|
||
RA = *reqAlternative;
|
||
reqList->SelectedAlternative = reqAlternative;
|
||
|
||
ReqDescCount = RA->DescCount;
|
||
ReqDescTable = RA->DescTable;
|
||
|
||
//
|
||
// we should have got only one descriptor, use only the first one
|
||
//
|
||
if (ReqDescCount>0) {
|
||
|
||
//
|
||
// get first descriptor & it's arbitor
|
||
//
|
||
|
||
reqDesc = *ReqDescTable;
|
||
if (reqDesc->ArbitrationRequired) {
|
||
reqDescTranslated = reqDesc->TranslatedReqDesc; // Could be reqDesc itself
|
||
|
||
arbiterEntry = reqDesc->u.Arbiter;
|
||
ASSERT(arbiterEntry);
|
||
//
|
||
// the descriptor of interest - translated, first alternative in the table
|
||
//
|
||
ConflictDesc = reqDescTranslated->AlternativeTable.Alternatives;
|
||
//
|
||
// skip special descriptor
|
||
// to get to the actual descriptor
|
||
//
|
||
if(ConflictDesc->Type == CmResourceTypeConfigData || ConflictDesc->Type == CmResourceTypeReserved)
|
||
ConflictDesc++;
|
||
|
||
//
|
||
// finally we can call the arbiter to get a conflict list (returning PDO's and Global Address Ranges)
|
||
//
|
||
ExtParams[0] = PhysicalDeviceObject;
|
||
ExtParams[1] = ConflictDesc;
|
||
ExtParams[2] = &ConflictCount;
|
||
ExtParams[3] = &ConflictInfoList;
|
||
status = IopCallArbiter(arbiterEntry, ArbiterActionQueryConflict , ExtParams, NULL , NULL);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// fill in user-memory buffer with conflict
|
||
//
|
||
status = IopQueryConflictFillConflicts(PhysicalDeviceObject,ConflictCount,ConflictInfoList,ConflictList,ConflictListSize,0);
|
||
if(ConflictInfoList != NULL) {
|
||
ExFreePool(ConflictInfoList);
|
||
}
|
||
}
|
||
else if(status == STATUS_RANGE_NOT_FOUND) {
|
||
//
|
||
// fill in with flag indicating bad range (this means range is not available)
|
||
// ConflictInfoList should not be allocated
|
||
//
|
||
status = IopQueryConflictFillConflicts(NULL,0,NULL,ConflictList,ConflictListSize,PNP_CE_TRANSLATE_FAILED);
|
||
}
|
||
|
||
} else {
|
||
#if MAXDBG
|
||
ASSERT(0); // For now
|
||
#endif
|
||
status = STATUS_INVALID_PARAMETER; // if we failed, it's prob because ResourceList was invalid
|
||
}
|
||
} else {
|
||
#if MAXDBG
|
||
ASSERT(0); // For now
|
||
#endif
|
||
status = STATUS_INVALID_PARAMETER; // if we failed, it's prob because ResourceList was invalid
|
||
}
|
||
|
||
IopCheckDataStructures(IopRootDeviceNode);
|
||
|
||
IopFreeReqList(reqList);
|
||
} else {
|
||
#if MAXDBG
|
||
ASSERT(0); // For now
|
||
#endif
|
||
if(NT_SUCCESS(status)) {
|
||
//
|
||
// it was NULL because we had a zero resource count, must be invalid parameter
|
||
//
|
||
status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
}
|
||
ExFreePool(ioResources);
|
||
|
||
Clean0:
|
||
;
|
||
|
||
return status;
|
||
}
|
||
|
||
/*++
|
||
|
||
SECTION = REBALANCE.
|
||
|
||
Description:
|
||
|
||
This section contains code that implements functions to performa
|
||
resource rebalance.
|
||
|
||
--*/
|
||
|
||
VOID
|
||
IopQueryRebalance (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN ULONG Phase,
|
||
IN PULONG RebalanceCount,
|
||
IN PDEVICE_OBJECT **DeviceTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine walks hardware tree depth first. For each device node it visits,
|
||
it call IopQueryReconfigureDevice to query-stop device for resource
|
||
reconfiguration.
|
||
|
||
Note, Under rebalancing situation, all the participated devices will be asked to
|
||
stop. Even they support non-stopped rebalancing.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - supplies a pionter a device node which is the root of the tree to
|
||
be tested.
|
||
|
||
Phase - Supplies a value to specify the phase of the rebalance.
|
||
|
||
RebalanceCount - supplies a pointer to a variable to receive the number of devices
|
||
participating the rebalance.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT *deviceList, *deviceTable, *device;
|
||
ULONG count;
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
|
||
//
|
||
// Call worker routine to get a list of devices to be rebalanced.
|
||
//
|
||
|
||
deviceTable = *DeviceTable;
|
||
IopQueryRebalanceWorker (DeviceNode, Phase, RebalanceCount, DeviceTable);
|
||
|
||
count = *RebalanceCount;
|
||
if (count != 0 && Phase == 0) {
|
||
|
||
//
|
||
// At phase 0, we did not actually query-stop the device.
|
||
// We need to do it now.
|
||
//
|
||
|
||
deviceList = (PDEVICE_OBJECT *)ExAllocatePoolPDO(PagedPool, count * sizeof(PDEVICE_OBJECT));
|
||
if (deviceList == NULL) {
|
||
*RebalanceCount = 0;
|
||
return;
|
||
}
|
||
RtlCopyMemory(deviceList, deviceTable, sizeof(PDEVICE_OBJECT) * count);
|
||
|
||
//
|
||
// Rebuild the returned device list
|
||
//
|
||
|
||
*RebalanceCount = 0;
|
||
*DeviceTable = deviceTable;
|
||
for (device = deviceList; device < (deviceList + count); device++) {
|
||
deviceNode = PP_DO_TO_DN(*device);
|
||
IopQueryRebalanceWorker (deviceNode, 1, RebalanceCount, DeviceTable);
|
||
}
|
||
ExFreePool(deviceList);
|
||
}
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
IopQueryRebalanceWorker (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN ULONG Phase,
|
||
IN PULONG RebalanceCount,
|
||
IN PDEVICE_OBJECT **DeviceTable
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine walks hardware tree depth first. For each device node it visits,
|
||
it call IopQueryReconfigureDevice to query-stop and stop device for resource
|
||
reconfiguration.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - supplies a pionter a device node which is the root of the tree to
|
||
be tested.
|
||
|
||
Phase - Supplies a value to specify the phase of the rebalance.
|
||
|
||
RebalanceCount - supplies a pointer to a variable to receive the number of devices
|
||
participating the rebalance.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_NODE node;
|
||
|
||
ASSERT(DeviceNode);
|
||
|
||
//
|
||
// We dont include following in rebalance
|
||
// a. non-started devices
|
||
// b. devices with problem
|
||
// c. devices with legacy driver
|
||
//
|
||
if ( DeviceNode == NULL ||
|
||
DeviceNode->State != DeviceNodeStarted ||
|
||
PipDoesDevNodeHaveProblem(DeviceNode) ||
|
||
(DeviceNode->Flags & DNF_LEGACY_DRIVER)) {
|
||
|
||
return;
|
||
}
|
||
//
|
||
// Recursively test the entire subtree.
|
||
//
|
||
for (node = DeviceNode->Child; node; node = node->Sibling) {
|
||
|
||
IopQueryRebalanceWorker(node, Phase, RebalanceCount, DeviceTable);
|
||
}
|
||
//
|
||
// Test the root of the subtree.
|
||
//
|
||
IopTestForReconfiguration(DeviceNode, Phase, RebalanceCount, DeviceTable);
|
||
}
|
||
|
||
VOID
|
||
IopTestForReconfiguration (
|
||
IN PDEVICE_NODE DeviceNode,
|
||
IN ULONG Phase,
|
||
IN PULONG RebalanceCount,
|
||
IN PDEVICE_OBJECT **DeviceTable
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine query-stops a device which is started and owns resources.
|
||
Note the resources for the device are not released at this point.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - supplies a pointer to the device node to be tested for reconfiguration.
|
||
|
||
Phase - Supplies a value to specify the phase of the rebalance.
|
||
|
||
RebalanceCount - supplies a pointer to a variable to receive the number of devices
|
||
participating the rebalance.
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_NODE nodex;
|
||
NTSTATUS status;
|
||
BOOLEAN addToList = FALSE;
|
||
|
||
if (Phase == 0) {
|
||
|
||
//
|
||
// At phase zero, this routine only wants to find out which devices's resource
|
||
// requirements lists chagned. No one actually gets stopped.
|
||
//
|
||
|
||
if ((DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) &&
|
||
!(DeviceNode->Flags & DNF_NON_STOPPED_REBALANCE) ) {
|
||
|
||
//
|
||
// It's too hard to handle non-stop rebalancing devices during rebalance.
|
||
// So, We will skip it.
|
||
//
|
||
|
||
addToList = TRUE;
|
||
} else {
|
||
|
||
if (DeviceNode->State == DeviceNodeStarted) {
|
||
status = IopQueryReconfiguration (IRP_MN_QUERY_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
|
||
if (NT_SUCCESS(status)) {
|
||
if (status == STATUS_RESOURCE_REQUIREMENTS_CHANGED) {
|
||
|
||
//
|
||
// If we find out a device's resource requirements changed this way,
|
||
// it will be stopped and reassigned resources even if it supports
|
||
// non-stopped rebalance.
|
||
//
|
||
|
||
DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED;
|
||
addToList = TRUE;
|
||
}
|
||
}
|
||
IopQueryReconfiguration (IRP_MN_CANCEL_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
|
||
}
|
||
}
|
||
if (addToList) {
|
||
*RebalanceCount = *RebalanceCount + 1;
|
||
**DeviceTable = DeviceNode->PhysicalDeviceObject;
|
||
*DeviceTable = *DeviceTable + 1;
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Phase 1
|
||
//
|
||
|
||
if (DeviceNode->State == DeviceNodeStarted) {
|
||
|
||
//
|
||
// Make sure all the resources required children of the DeviceNode are stopped.
|
||
//
|
||
|
||
nodex = DeviceNode->Child;
|
||
while (nodex) {
|
||
if (nodex->State == DeviceNodeUninitialized ||
|
||
nodex->State == DeviceNodeInitialized ||
|
||
nodex->State == DeviceNodeDriversAdded ||
|
||
nodex->State == DeviceNodeQueryStopped ||
|
||
nodex->State == DeviceNodeRemovePendingCloses ||
|
||
nodex->State == DeviceNodeRemoved ||
|
||
(nodex->Flags & DNF_NEEDS_REBALANCE)) {
|
||
nodex = nodex->Sibling;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (nodex) {
|
||
|
||
//
|
||
// If any resource required child of the DeviceNode is not stopped,
|
||
// we won't ask the DeviceNode to stop.
|
||
//
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Rebalance: Child %ws not stopped for %ws\n",
|
||
nodex->InstancePath.Buffer,
|
||
DeviceNode->InstancePath.Buffer));
|
||
return;
|
||
}
|
||
} else if (DeviceNode->State != DeviceNodeDriversAdded ||
|
||
!(DeviceNode->Flags & DNF_HAS_BOOT_CONFIG) ||
|
||
(DeviceNode->Flags & DNF_MADEUP)) {
|
||
|
||
//
|
||
// The device is not started and has no boot config. There is no need to query-stop it.
|
||
// Or if the device has BOOT config but there is no driver installed for it. We don't query
|
||
// stop it. (There may be legacy drivers are using the resources.)
|
||
// We also don't want to query stop root enumerated devices (for performance reason.)
|
||
//
|
||
|
||
return;
|
||
}
|
||
|
||
status = IopQueryReconfiguration (IRP_MN_QUERY_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
|
||
if (NT_SUCCESS(status)) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Rebalance: %ws succeeded QueryStop\n",
|
||
DeviceNode->InstancePath.Buffer));
|
||
|
||
if (DeviceNode->State == DeviceNodeStarted) {
|
||
|
||
PipSetDevNodeState(DeviceNode, DeviceNodeQueryStopped, NULL);
|
||
|
||
*RebalanceCount = *RebalanceCount + 1;
|
||
**DeviceTable = DeviceNode->PhysicalDeviceObject;
|
||
|
||
//
|
||
// Add a reference to the device object such that it won't disapear during rebalance.
|
||
//
|
||
|
||
ObReferenceObject(DeviceNode->PhysicalDeviceObject);
|
||
*DeviceTable = *DeviceTable + 1;
|
||
} else {
|
||
|
||
//
|
||
// We need to release the device's prealloc boot config. This device will NOT
|
||
// participate in resource rebalancing.
|
||
//
|
||
|
||
ASSERT(DeviceNode->Flags & DNF_HAS_BOOT_CONFIG);
|
||
status = IopQueryReconfiguration (IRP_MN_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
|
||
ASSERT(NT_SUCCESS(status));
|
||
IopReleaseBootResources(DeviceNode);
|
||
|
||
//
|
||
// Reset BOOT CONFIG flags.
|
||
//
|
||
|
||
DeviceNode->Flags &= ~(DNF_HAS_BOOT_CONFIG + DNF_BOOT_CONFIG_RESERVED);
|
||
}
|
||
} else {
|
||
IopQueryReconfiguration (IRP_MN_CANCEL_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
IopRebalance(
|
||
IN ULONG AssignTableCount,
|
||
IN PIOP_RESOURCE_REQUEST AssignTable
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs rebalancing operation. There are two rebalance phases:
|
||
In the phase 0, we only consider the devices whoes resource requirements changed
|
||
and their children; in phase 1, we consider anyone who succeeds the query-stop.
|
||
|
||
Parameters:
|
||
|
||
AssignTableCount,
|
||
AssignTable - Supplies the number of origianl AssignTableCout and AssignTable which
|
||
triggers the rebalance operation.
|
||
|
||
(if AssignTableCount == 0, we are processing device state change.)
|
||
|
||
Return Value:
|
||
|
||
Status code that indicates whether or not the function was successful.
|
||
|
||
--*/
|
||
{
|
||
ULONG i;
|
||
PIOP_RESOURCE_REQUEST table = NULL, tableEnd, newEntry;
|
||
PIOP_RESOURCE_REQUEST requestTable = NULL, requestTableEnd, entry1, entry2;
|
||
ULONG phase0RebalanceCount = 0, rebalanceCount = 0, deviceCount;
|
||
NTSTATUS status;
|
||
PDEVICE_OBJECT *deviceTable, *deviceTablex;
|
||
PDEVICE_NODE deviceNode;
|
||
ULONG rebalancePhase = 0;
|
||
LIST_ENTRY activeArbiterList;
|
||
|
||
//
|
||
// Query all the device nodes to see who are willing to participate the rebalance
|
||
// process.
|
||
//
|
||
|
||
deviceTable = (PDEVICE_OBJECT *) ExAllocatePoolPDO(
|
||
PagedPool,
|
||
sizeof(PDEVICE_OBJECT) * IopNumberDeviceNodes);
|
||
if (deviceTable == NULL) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Rebalance: Not enough memory to perform rebalance\n"));
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
|
||
tryAgain:
|
||
deviceTablex = deviceTable + phase0RebalanceCount;
|
||
|
||
//
|
||
// Walk device node tree depth-first to query-stop and stop devices.
|
||
// At this point the resources of the stopped devices are not released yet.
|
||
// Also, the leaf nodes are in the front of the device table and non leaf nodes
|
||
// are at the end of the table.
|
||
//
|
||
|
||
IopQueryRebalance (IopRootDeviceNode, rebalancePhase, &rebalanceCount, &deviceTablex);
|
||
if (rebalanceCount == 0) {
|
||
|
||
//
|
||
// If no one is interested and we are not processing resources req change,
|
||
// move to next phase.
|
||
//
|
||
|
||
if (rebalancePhase == 0 && AssignTableCount != 0) {
|
||
rebalancePhase = 1;
|
||
goto tryAgain;
|
||
}
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Rebalance: No device participates in rebalance phase %x\n",
|
||
rebalancePhase));
|
||
ExFreePool(deviceTable);
|
||
deviceTable = NULL;
|
||
status = STATUS_UNSUCCESSFUL;
|
||
goto exit;
|
||
}
|
||
if (rebalanceCount == phase0RebalanceCount) {
|
||
|
||
//
|
||
// Phase 0 failed and no new device participates. failed the rebalance.
|
||
//
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
goto exit;
|
||
}
|
||
if (rebalancePhase == 0) {
|
||
phase0RebalanceCount = rebalanceCount;
|
||
}
|
||
|
||
//
|
||
// Allocate pool for the new reconfiguration requests and the original requests.
|
||
//
|
||
|
||
table = (PIOP_RESOURCE_REQUEST) ExAllocatePoolIORR(
|
||
PagedPool,
|
||
sizeof(IOP_RESOURCE_REQUEST) * (AssignTableCount + rebalanceCount)
|
||
);
|
||
if (table == NULL) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Rebalance: Not enough memory to perform rebalance\n"));
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto exit;
|
||
}
|
||
tableEnd = table + AssignTableCount + rebalanceCount;
|
||
|
||
//
|
||
// Build a new resource request table. The original requests will be at the beginning
|
||
// of the table and new requests (reconfigured devices) are at the end.
|
||
// After the new request table is built, the leaf nodes will be in front of the table,
|
||
// and non leaf nodes will be close to the end of the table. This is for optimization.
|
||
//
|
||
|
||
//
|
||
// Copy the original request to the front of our new request table.
|
||
//
|
||
|
||
if (AssignTableCount != 0) {
|
||
RtlCopyMemory(table, AssignTable, sizeof(IOP_RESOURCE_REQUEST) * AssignTableCount);
|
||
}
|
||
|
||
//
|
||
// Initialize all the new entries of our new request table,
|
||
//
|
||
|
||
newEntry = table + AssignTableCount;
|
||
RtlZeroMemory(newEntry, sizeof(IOP_RESOURCE_REQUEST) * rebalanceCount);
|
||
for (i = 0, deviceTablex = deviceTable; i < rebalanceCount; i++, deviceTablex++) {
|
||
newEntry[i].AllocationType = ArbiterRequestPnpEnumerated;
|
||
newEntry[i].PhysicalDevice = *deviceTablex;
|
||
}
|
||
|
||
status = IopGetResourceRequirementsForAssignTable(
|
||
newEntry,
|
||
tableEnd ,
|
||
&deviceCount);
|
||
if (deviceCount == 0) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"Rebalance: GetResourceRequirementsForAssignTable failed\n"));
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Process the AssignTable to remove any entry which is marked as IOP_ASSIGN_IGNORE
|
||
//
|
||
|
||
if (deviceCount != rebalanceCount) {
|
||
|
||
deviceCount += AssignTableCount;
|
||
requestTable = (PIOP_RESOURCE_REQUEST) ExAllocatePoolIORR(
|
||
PagedPool,
|
||
sizeof(IOP_RESOURCE_REQUEST) * deviceCount
|
||
);
|
||
if (requestTable == NULL) {
|
||
IopFreeResourceRequirementsForAssignTable(newEntry, tableEnd);
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto exit;
|
||
}
|
||
for (entry1 = table, entry2 = requestTable; entry1 < tableEnd; entry1++) {
|
||
|
||
if (!(entry1->Flags & IOP_ASSIGN_IGNORE)) {
|
||
|
||
*entry2 = *entry1;
|
||
entry2++;
|
||
} else {
|
||
|
||
ASSERT(entry1 >= newEntry);
|
||
}
|
||
}
|
||
requestTableEnd = requestTable + deviceCount;
|
||
} else {
|
||
requestTable = table;
|
||
requestTableEnd = tableEnd;
|
||
deviceCount += AssignTableCount;
|
||
}
|
||
|
||
//
|
||
// DO NOT Sort the AssignTable
|
||
//
|
||
|
||
//IopRearrangeAssignTable(requestTable, deviceCount);
|
||
|
||
#if 0
|
||
|
||
//
|
||
// We are about to perform rebalance. Release the resources of the reconfiguration devices
|
||
//
|
||
|
||
for (entry1 = newEntry; entry1 < tableEnd; entry1++) {
|
||
if (!(entry1->Flags & IOP_ASSIGN_IGNORE) &&
|
||
!(entry1->Flags & IOP_ASSIGN_RESOURCES_RELEASED)) {
|
||
deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
|
||
if (deviceNode->ResourceList) {
|
||
|
||
//
|
||
// Call IopReleaseResourcesInternal instead of IopReleaseResources such that
|
||
// the pool for devicenode->ResourceList is not freed. We need it to restart
|
||
// the reconfigured devices in case rebalance failed.
|
||
//
|
||
|
||
IopReleaseResourcesInternal(deviceNode);
|
||
entry1->Flags |= IOP_ASSIGN_RESOURCES_RELEASED;
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// Assign the resources. If we succeed, or if
|
||
// there is a memory shortage return immediately.
|
||
//
|
||
|
||
status = IopFindBestConfiguration(
|
||
requestTable,
|
||
deviceCount,
|
||
&activeArbiterList);
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// If the rebalance succeeded, we need to restart all the reconfigured devices.
|
||
// For the original devices, we will return and let IopAllocateResources to deal
|
||
// with them.
|
||
//
|
||
|
||
IopBuildCmResourceLists(requestTable, requestTableEnd);
|
||
|
||
//
|
||
// Copy the new status back to the original AssignTable.
|
||
//
|
||
|
||
if (AssignTableCount != 0) {
|
||
RtlCopyMemory(AssignTable, requestTable, sizeof(IOP_RESOURCE_REQUEST) * AssignTableCount);
|
||
}
|
||
//
|
||
// free resource requirements we allocated while here
|
||
//
|
||
IopFreeResourceRequirementsForAssignTable(requestTable+AssignTableCount, requestTableEnd);
|
||
|
||
if (table != requestTable) {
|
||
|
||
//
|
||
// If we switched request table ... copy the contents of new table back to
|
||
// the old table.
|
||
//
|
||
|
||
for (entry1 = table, entry2 = requestTable; entry2 < requestTableEnd;) {
|
||
|
||
if (entry1->Flags & IOP_ASSIGN_IGNORE) {
|
||
entry1++;
|
||
continue;
|
||
}
|
||
*entry1 = *entry2;
|
||
if (entry2->Flags & IOP_ASSIGN_EXCLUDE) {
|
||
entry1->Status = STATUS_CONFLICTING_ADDRESSES;
|
||
}
|
||
entry2++;
|
||
entry1++;
|
||
}
|
||
}
|
||
//
|
||
// Go thru the origianl request table to stop each query-stopped/reconfigured device.
|
||
//
|
||
for (entry1 = newEntry; entry1 < tableEnd; entry1++) {
|
||
|
||
deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
|
||
if (NT_SUCCESS(entry1->Status)) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"STOPPING %wZ during REBALANCE\n",
|
||
&deviceNode->InstancePath));
|
||
IopQueryReconfiguration(
|
||
IRP_MN_STOP_DEVICE,
|
||
entry1->PhysicalDevice);
|
||
|
||
PipSetDevNodeState(deviceNode, DeviceNodeStopped, NULL);
|
||
} else {
|
||
|
||
IopQueryReconfiguration(
|
||
IRP_MN_CANCEL_STOP_DEVICE,
|
||
entry1->PhysicalDevice);
|
||
|
||
PipRestoreDevNodeState(deviceNode);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Ask the arbiters to commit this configuration.
|
||
//
|
||
status = IopCommitConfiguration(&activeArbiterList);
|
||
//
|
||
// Go thru the origianl request table to start each stopped/reconfigured device.
|
||
//
|
||
|
||
for (entry1 = tableEnd - 1; entry1 >= newEntry; entry1--) {
|
||
deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
|
||
|
||
if (NT_SUCCESS(entry1->Status)) {
|
||
|
||
//
|
||
// We need to release the pool space for ResourceList and ResourceListTranslated.
|
||
// Because the earlier IopReleaseResourcesInternal does not release the pool.
|
||
//
|
||
|
||
if (deviceNode->ResourceList) {
|
||
ExFreePool(deviceNode->ResourceList);
|
||
}
|
||
deviceNode->ResourceList = entry1->ResourceAssignment;
|
||
if (deviceNode->ResourceListTranslated) {
|
||
ExFreePool(deviceNode->ResourceListTranslated);
|
||
}
|
||
deviceNode->ResourceListTranslated = entry1->TranslatedResourceAssignment;
|
||
if (deviceNode->ResourceList == NULL) {
|
||
deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
|
||
}
|
||
if (entry1->Flags & IOP_ASSIGN_CLEAR_RESOURCE_REQUIREMENTS_CHANGE_FLAG) {
|
||
|
||
//
|
||
// If we are processing the resource requirements change request,
|
||
// clear its related flags.
|
||
//
|
||
|
||
deviceNode->Flags &= ~(DNF_RESOURCE_REQUIREMENTS_CHANGED | DNF_NON_STOPPED_REBALANCE);
|
||
}
|
||
}
|
||
}
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
|
||
//
|
||
// Rebalance failed. Free our internal representation of the rebalance
|
||
// candidates' resource requirements lists.
|
||
//
|
||
|
||
IopFreeResourceRequirementsForAssignTable(requestTable + AssignTableCount, requestTableEnd);
|
||
if (rebalancePhase == 0) {
|
||
rebalancePhase++;
|
||
if (requestTable) {
|
||
ExFreePool(requestTable);
|
||
}
|
||
if (table && (table != requestTable)) {
|
||
ExFreePool(table);
|
||
}
|
||
table = requestTable = NULL;
|
||
goto tryAgain;
|
||
}
|
||
|
||
for (entry1 = newEntry; entry1 < tableEnd; entry1++) {
|
||
|
||
IopQueryReconfiguration (
|
||
IRP_MN_CANCEL_STOP_DEVICE,
|
||
entry1->PhysicalDevice);
|
||
deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
|
||
|
||
PipRestoreDevNodeState(deviceNode);
|
||
}
|
||
}
|
||
//
|
||
// Finally release the references of the reconfigured device objects
|
||
//
|
||
for (deviceTablex = (deviceTable + rebalanceCount - 1);
|
||
deviceTablex >= deviceTable;
|
||
deviceTablex--) {
|
||
ObDereferenceObject(*deviceTablex);
|
||
}
|
||
ExFreePool(deviceTable);
|
||
deviceTable = NULL;
|
||
|
||
exit:
|
||
|
||
if (!NT_SUCCESS(status) && deviceTable) {
|
||
|
||
//
|
||
// If we failed before trying to perform resource assignment,
|
||
// we will end up here.
|
||
//
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Rebalance: Rebalance failed\n"));
|
||
|
||
//
|
||
// Somehow we failed to start the rebalance operation.
|
||
// We will cancel the query-stop request for the query-stopped devices bredth first.
|
||
//
|
||
|
||
for (deviceTablex = (deviceTable + rebalanceCount - 1);
|
||
deviceTablex >= deviceTable;
|
||
deviceTablex--) {
|
||
|
||
deviceNode = PP_DO_TO_DN(*deviceTablex);
|
||
IopQueryReconfiguration (IRP_MN_CANCEL_STOP_DEVICE, *deviceTablex);
|
||
PipRestoreDevNodeState(deviceNode);
|
||
ObDereferenceObject(*deviceTablex);
|
||
}
|
||
}
|
||
if (deviceTable) {
|
||
ExFreePool(deviceTable);
|
||
}
|
||
if (requestTable) {
|
||
ExFreePool(requestTable);
|
||
}
|
||
if (table && (table != requestTable)) {
|
||
ExFreePool(table);
|
||
}
|
||
return status;
|
||
}
|
||
|
||
/*++
|
||
|
||
SECTION = OUTER ARBITRATION LOOP.
|
||
|
||
Description:
|
||
|
||
This section contains code that implements functions to call arbiters
|
||
and come up with the best possible configuration.
|
||
--*/
|
||
|
||
NTSTATUS
|
||
IopTestConfiguration (
|
||
IN OUT PLIST_ENTRY ArbiterList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calls the arbiters in the specified list for TestAllocation.
|
||
|
||
Parameters:
|
||
|
||
ArbiterList - Head of list of arbiters to be called.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all arbiters succeed, else first failure code.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS status;
|
||
PLIST_ENTRY listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
ARBITER_PARAMETERS p;
|
||
PARBITER_INTERFACE arbiterInterface;
|
||
|
||
PAGED_CODE();
|
||
|
||
status = STATUS_SUCCESS;
|
||
for ( listEntry = ArbiterList->Flink;
|
||
listEntry != ArbiterList;
|
||
listEntry = listEntry->Flink) {
|
||
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
listEntry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
ActiveArbiterList);
|
||
ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
|
||
if (arbiterEntry->ResourcesChanged == FALSE) {
|
||
|
||
if (arbiterEntry->State & PI_ARBITER_TEST_FAILED) {
|
||
//
|
||
// If the resource requirements are the same and
|
||
// it failed before, return failure.
|
||
//
|
||
status = STATUS_UNSUCCESSFUL;
|
||
break;
|
||
}
|
||
} else {
|
||
|
||
arbiterInterface = arbiterEntry->ArbiterInterface;
|
||
//
|
||
// Call the arbiter to test the new configuration.
|
||
//
|
||
p.Parameters.TestAllocation.ArbitrationList =
|
||
&arbiterEntry->ResourceList;
|
||
p.Parameters.TestAllocation.AllocateFromCount = 0;
|
||
p.Parameters.TestAllocation.AllocateFrom = NULL;
|
||
status = arbiterInterface->ArbiterHandler(
|
||
arbiterInterface->Context,
|
||
ArbiterActionTestAllocation,
|
||
&p);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
arbiterEntry->State &= ~PI_ARBITER_TEST_FAILED;
|
||
arbiterEntry->State |= PI_ARBITER_HAS_SOMETHING;
|
||
arbiterEntry->ResourcesChanged = FALSE;
|
||
} else {
|
||
//
|
||
// This configuration does not work
|
||
// (no need to try other arbiters).
|
||
//
|
||
arbiterEntry->State |= PI_ARBITER_TEST_FAILED;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopRetestConfiguration (
|
||
IN OUT PLIST_ENTRY ArbiterList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calls the arbiters in the specified list for RetestAllocation.
|
||
|
||
Parameters:
|
||
|
||
ArbiterList - Head of list of arbiters to be called.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all arbiters succeed, else first failure code.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS retestStatus;
|
||
PLIST_ENTRY listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
ARBITER_PARAMETERS p;
|
||
PARBITER_INTERFACE arbiterInterface;
|
||
|
||
PAGED_CODE();
|
||
|
||
retestStatus = STATUS_UNSUCCESSFUL;
|
||
listEntry = ArbiterList->Flink;
|
||
while (listEntry != ArbiterList) {
|
||
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
listEntry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
ActiveArbiterList);
|
||
listEntry = listEntry->Flink;
|
||
if (arbiterEntry->ResourcesChanged == FALSE) {
|
||
|
||
continue;
|
||
}
|
||
ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
|
||
arbiterInterface = arbiterEntry->ArbiterInterface;
|
||
//
|
||
// Call the arbiter to retest the configuration.
|
||
//
|
||
p.Parameters.RetestAllocation.ArbitrationList =
|
||
&arbiterEntry->ResourceList;
|
||
p.Parameters.RetestAllocation.AllocateFromCount = 0;
|
||
p.Parameters.RetestAllocation.AllocateFrom = NULL;
|
||
retestStatus = arbiterInterface->ArbiterHandler(
|
||
arbiterInterface->Context,
|
||
ArbiterActionRetestAllocation,
|
||
&p);
|
||
if (!NT_SUCCESS(retestStatus)) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT(NT_SUCCESS(retestStatus));
|
||
|
||
return retestStatus;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopCommitConfiguration (
|
||
IN OUT PLIST_ENTRY ArbiterList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calls the arbiters in the specified list for CommitAllocation.
|
||
|
||
Parameters:
|
||
|
||
ArbiterList - Head of list of arbiters to be called.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if all arbiters succeed, else first failure code.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS commitStatus;
|
||
PLIST_ENTRY listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
PARBITER_INTERFACE arbiterInterface;
|
||
|
||
PAGED_CODE();
|
||
|
||
commitStatus = STATUS_SUCCESS;
|
||
listEntry = ArbiterList->Flink;
|
||
while (listEntry != ArbiterList) {
|
||
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
listEntry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
ActiveArbiterList);
|
||
listEntry = listEntry->Flink;
|
||
ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
|
||
arbiterInterface = arbiterEntry->ArbiterInterface;
|
||
//
|
||
// Call the arbiter to commit the configuration.
|
||
//
|
||
commitStatus = arbiterInterface->ArbiterHandler(
|
||
arbiterInterface->Context,
|
||
ArbiterActionCommitAllocation,
|
||
NULL);
|
||
IopInitializeArbiterEntryState(arbiterEntry);
|
||
if (!NT_SUCCESS(commitStatus)) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT(NT_SUCCESS(commitStatus));
|
||
|
||
IopCheckDataStructures(IopRootDeviceNode);
|
||
return commitStatus;
|
||
}
|
||
|
||
VOID
|
||
IopSelectFirstConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine selects the first possible configuration and adds the
|
||
descriptors to their corresponding arbiter lists. The arbiters used are
|
||
linked into the list of active arbiters.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resource requests.
|
||
|
||
RequestTableCount - Number of requests in the request table.
|
||
|
||
ActiveArbiterList - Head of list which contains arbiters used for the
|
||
first selected configuration.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG tableIndex;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_LIST reqList;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// For each entry in the request table, set the first configuration
|
||
// as the selected configuration.
|
||
// Update the arbiters with all the descriptors in the selected
|
||
// configuration.
|
||
//
|
||
for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
|
||
|
||
reqList = RequestTable[tableIndex].ReqList;
|
||
reqList->SelectedAlternative = &reqList->AlternativeTable[0];
|
||
reqAlternative = *(reqList->SelectedAlternative);
|
||
IopAddRemoveReqDescs(
|
||
reqAlternative->DescTable,
|
||
reqAlternative->DescCount,
|
||
ActiveArbiterList,
|
||
TRUE);
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
IopSelectNextConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine selects the next possible configuration and adds the
|
||
descriptors to their corresponding arbiter lists. The arbiters used are
|
||
linked into the list of active arbiters.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resource requests.
|
||
|
||
RequestTableCount - Number of requests in the request table.
|
||
|
||
ActiveArbiterList - Head of list which contains arbiters used for the
|
||
currently selected configuration.
|
||
|
||
Return Value:
|
||
|
||
FALSE if this the currently selected configuration is the last possible,
|
||
else TRUE.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG tableIndex;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_LIST reqList;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// Remove all the descriptors from the currently selected alternative
|
||
// for the first entry in the request table.
|
||
// Update the selected configuration to the next possible.
|
||
// Reset the selected configuration to the first possible one if
|
||
// all configurations have been tried and go to the next entry
|
||
// in the request table.
|
||
//
|
||
for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
|
||
|
||
reqList = RequestTable[tableIndex].ReqList;
|
||
reqAlternative = *(reqList->SelectedAlternative);
|
||
IopAddRemoveReqDescs(
|
||
reqAlternative->DescTable,
|
||
reqAlternative->DescCount,
|
||
NULL,
|
||
FALSE);
|
||
if (++reqList->SelectedAlternative < reqList->BestAlternative) {
|
||
|
||
break;
|
||
}
|
||
reqList->SelectedAlternative = &reqList->AlternativeTable[0];
|
||
}
|
||
//
|
||
// We are done if there is no next possible configuration.
|
||
//
|
||
if (tableIndex == RequestTableCount) {
|
||
|
||
return FALSE;
|
||
}
|
||
//
|
||
// For each entry in the request table, add all the descriptors in
|
||
// the currently selected alternative.
|
||
//
|
||
for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
|
||
|
||
reqList = RequestTable[tableIndex].ReqList;
|
||
reqAlternative = *(reqList->SelectedAlternative);
|
||
IopAddRemoveReqDescs(
|
||
reqAlternative->DescTable,
|
||
reqAlternative->DescCount,
|
||
ActiveArbiterList,
|
||
TRUE);
|
||
if (reqList->SelectedAlternative != &reqList->AlternativeTable[0]) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
VOID
|
||
IopCleanupSelectedConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine removes the descriptors from their corresponding arbiter
|
||
lists.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resource requests.
|
||
|
||
RequestTableCount - Number of requests in the request table.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG tableIndex;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_LIST reqList;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// For each entry in the request table, remove all the descriptors
|
||
// from the currently selected alternative.
|
||
//
|
||
for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
|
||
|
||
reqList = RequestTable[tableIndex].ReqList;
|
||
reqAlternative = *(reqList->SelectedAlternative);
|
||
IopAddRemoveReqDescs(
|
||
reqAlternative->DescTable,
|
||
reqAlternative->DescCount,
|
||
NULL,
|
||
FALSE);
|
||
}
|
||
}
|
||
|
||
ULONG
|
||
IopComputeConfigurationPriority (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine computes the overall priority of the set of selected
|
||
configurations for all requests in the request table.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resource requests.
|
||
|
||
RequestTableCount - Number of requests in the request table.
|
||
|
||
Return Value:
|
||
|
||
Computed priority for this configuration.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG tableIndex;
|
||
ULONG priority;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_LIST reqList;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// Compute the current configurations overall priority
|
||
// as the sum of the priorities of currently selected
|
||
// configuration in the request table.
|
||
//
|
||
priority = 0;
|
||
for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
|
||
|
||
reqList = RequestTable[tableIndex].ReqList;
|
||
reqAlternative = *(reqList->SelectedAlternative);
|
||
priority += reqAlternative->Priority;
|
||
}
|
||
|
||
return priority;
|
||
}
|
||
|
||
VOID
|
||
IopSaveRestoreConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ArbiterList,
|
||
IN BOOLEAN Save
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine saves\restores the currently selected configuration.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resource requests.
|
||
|
||
RequestTableCount - Number of requests in the request table.
|
||
|
||
ArbiterList - Head of list which contains arbiters used for the
|
||
currently selected configuration.
|
||
|
||
Save - Specifies if the configuration is to be saved or
|
||
restored.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG tableIndex;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_DESC reqDesc;
|
||
PREQ_DESC *reqDescpp;
|
||
PREQ_DESC *reqDescTableEnd;
|
||
PLIST_ENTRY listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
PREQ_LIST reqList;
|
||
|
||
PAGED_CODE();
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_TRACE_LEVEL,
|
||
"%s configuration\n",
|
||
(Save)? "Saving" : "Restoring"));
|
||
//
|
||
// For each entry in the request table, save information for
|
||
// following RETEST.
|
||
//
|
||
for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
|
||
|
||
reqList = RequestTable[tableIndex].ReqList;
|
||
if (Save) {
|
||
|
||
reqList->BestAlternative = reqList->SelectedAlternative;
|
||
} else {
|
||
|
||
reqList->SelectedAlternative = reqList->BestAlternative;
|
||
}
|
||
reqAlternative = *(reqList->BestAlternative);
|
||
reqDescTableEnd = reqAlternative->DescTable +
|
||
reqAlternative->DescCount;
|
||
for ( reqDescpp = reqAlternative->DescTable;
|
||
reqDescpp < reqDescTableEnd;
|
||
reqDescpp++) {
|
||
|
||
if ((*reqDescpp)->ArbitrationRequired == FALSE) {
|
||
|
||
continue;
|
||
}
|
||
//
|
||
// Save\restore information for the descriptor.
|
||
//
|
||
reqDesc = (*reqDescpp)->TranslatedReqDesc;
|
||
if (Save == TRUE) {
|
||
|
||
reqDesc->BestAlternativeTable = reqDesc->AlternativeTable;
|
||
reqDesc->BestAllocation = reqDesc->Allocation;
|
||
} else {
|
||
|
||
reqDesc->AlternativeTable = reqDesc->BestAlternativeTable;
|
||
reqDesc->Allocation = reqDesc->BestAllocation;
|
||
}
|
||
}
|
||
}
|
||
//
|
||
// For each entry in the currently active arbiter list,
|
||
// save information for following RETEST.
|
||
//
|
||
listEntry = ArbiterList->Flink;
|
||
while (listEntry != ArbiterList) {
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
listEntry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
ActiveArbiterList);
|
||
if (Save == TRUE) {
|
||
arbiterEntry->BestResourceList = arbiterEntry->ResourceList;
|
||
arbiterEntry->BestConfig = arbiterEntry->ActiveArbiterList;
|
||
} else {
|
||
arbiterEntry->ResourceList = arbiterEntry->BestResourceList;
|
||
arbiterEntry->ActiveArbiterList = arbiterEntry->BestConfig;
|
||
}
|
||
listEntry = listEntry->Flink;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopAddRemoveReqDescs (
|
||
IN PREQ_DESC *ReqDescTable,
|
||
IN ULONG ReqDescCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList,
|
||
IN BOOLEAN Add
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds\removes the descriptors to\from the arbiter lists. It
|
||
also updates the list of arbiters involved.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resource requests.
|
||
|
||
RequestTableCount - Number of requests in the request table.
|
||
|
||
ActiveArbiterList - Head of list which contains arbiters used for the
|
||
currently selected configuration.
|
||
|
||
Add - Specifies if the descriptors are to be added or
|
||
removed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG tableIndex;
|
||
PREQ_DESC reqDesc;
|
||
PREQ_DESC reqDescTranslated;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
PREQ_ALTERNATIVE reqAlternative;
|
||
PREQ_LIST reqList;
|
||
PDEVICE_NODE deviceNode;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (ReqDescCount == 0) {
|
||
|
||
return;
|
||
}
|
||
|
||
reqList = ReqDescTable[0]->ReqAlternative->ReqList;
|
||
reqAlternative = *reqList->SelectedAlternative;
|
||
deviceNode = PP_DO_TO_DN(reqList->Request->PhysicalDevice);
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"%s %d/%d req alt %s the arbiters for %wZ\n",
|
||
(Add)? "Adding" : "Removing",
|
||
reqAlternative->ReqAlternativeIndex + 1,
|
||
reqList->AlternativeCount,
|
||
(Add)? "to" : "from",
|
||
&deviceNode->InstancePath));
|
||
for (tableIndex = 0; tableIndex < ReqDescCount; tableIndex++) {
|
||
|
||
reqDesc = ReqDescTable[tableIndex];
|
||
if (reqDesc->ArbitrationRequired == FALSE) {
|
||
|
||
continue;
|
||
}
|
||
arbiterEntry = reqDesc->u.Arbiter;
|
||
ASSERT(arbiterEntry);
|
||
if (arbiterEntry->State & PI_ARBITER_HAS_SOMETHING) {
|
||
|
||
arbiterEntry->State &= ~PI_ARBITER_HAS_SOMETHING;
|
||
arbiterEntry->ArbiterInterface->ArbiterHandler(
|
||
arbiterEntry->ArbiterInterface->Context,
|
||
ArbiterActionRollbackAllocation,
|
||
NULL);
|
||
}
|
||
arbiterEntry->ResourcesChanged = TRUE;
|
||
reqDescTranslated = reqDesc->TranslatedReqDesc;
|
||
if (Add == TRUE) {
|
||
|
||
InitializeListHead(&reqDescTranslated->AlternativeTable.ListEntry);
|
||
InsertTailList(
|
||
&arbiterEntry->ResourceList,
|
||
&reqDescTranslated->AlternativeTable.ListEntry);
|
||
if (IsListEmpty(&arbiterEntry->ActiveArbiterList)) {
|
||
|
||
PLIST_ENTRY listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY entry;
|
||
//
|
||
// Insert the entry into the sorted list
|
||
// (sorted by depth in the tree).
|
||
//
|
||
for ( listEntry = ActiveArbiterList->Flink;
|
||
listEntry != ActiveArbiterList;
|
||
listEntry = listEntry->Flink) {
|
||
|
||
entry = CONTAINING_RECORD(
|
||
listEntry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
ActiveArbiterList);
|
||
if (entry->Level >= arbiterEntry->Level) {
|
||
|
||
break;
|
||
}
|
||
}
|
||
arbiterEntry->ActiveArbiterList.Flink = listEntry;
|
||
arbiterEntry->ActiveArbiterList.Blink = listEntry->Blink;
|
||
listEntry->Blink->Flink = &arbiterEntry->ActiveArbiterList;
|
||
listEntry->Blink = &arbiterEntry->ActiveArbiterList;
|
||
}
|
||
} else {
|
||
|
||
ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
|
||
RemoveEntryList(&reqDescTranslated->AlternativeTable.ListEntry);
|
||
InitializeListHead(&reqDescTranslated->AlternativeTable.ListEntry);
|
||
if (IsListEmpty(&arbiterEntry->ResourceList)) {
|
||
|
||
RemoveEntryList(&arbiterEntry->ActiveArbiterList);
|
||
InitializeListHead(&arbiterEntry->ActiveArbiterList);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
IopFindBestConfiguration (
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN ULONG RequestTableCount,
|
||
IN OUT PLIST_ENTRY ActiveArbiterList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine attempts to satisfy the resource requests for all the entries
|
||
in the request table. It also attempts to find the best possible overall
|
||
solution.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Table of resource requests.
|
||
|
||
RequestTableCount - Number of requests in the request table.
|
||
|
||
Return Value:
|
||
|
||
Final status.
|
||
|
||
--*/
|
||
|
||
{
|
||
LIST_ENTRY bestArbiterList;
|
||
LARGE_INTEGER startTime;
|
||
LARGE_INTEGER currentTime;
|
||
ULONG timeDiff;
|
||
NTSTATUS status;
|
||
ULONG priority;
|
||
ULONG bestPriority;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// Initialize the arbiter lists used during the search for the best
|
||
// configuration.
|
||
//
|
||
InitializeListHead(ActiveArbiterList);
|
||
InitializeListHead(&bestArbiterList);
|
||
//
|
||
// Start the search from the first possible configuration.
|
||
// Possible configurations are already sorted by priority.
|
||
//
|
||
IopSelectFirstConfiguration(
|
||
RequestTable,
|
||
RequestTableCount,
|
||
ActiveArbiterList);
|
||
//
|
||
// Search for all configurations that work, updating
|
||
// the best configuration until we have tried all
|
||
// possible configurations or timeout has expired.
|
||
//
|
||
KeQuerySystemTime(&startTime);
|
||
bestPriority = (ULONG)-1;
|
||
do {
|
||
//
|
||
// Test the arbiters for this combination.
|
||
//
|
||
status = IopTestConfiguration(ActiveArbiterList);
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Since the configurations are sorted, we dont need to try others
|
||
// if there is only one entry in the request table.
|
||
//
|
||
bestArbiterList = *ActiveArbiterList;
|
||
if (RequestTableCount == 1) {
|
||
|
||
break;
|
||
}
|
||
//
|
||
// Save this configuration if it is better than the best one found
|
||
// so far.
|
||
//
|
||
priority = IopComputeConfigurationPriority(
|
||
RequestTable,
|
||
RequestTableCount);
|
||
if (priority < bestPriority) {
|
||
|
||
bestPriority = priority;
|
||
IopSaveRestoreConfiguration(
|
||
RequestTable,
|
||
RequestTableCount,
|
||
ActiveArbiterList,
|
||
TRUE);
|
||
}
|
||
}
|
||
//
|
||
// Check if timeout has expired.
|
||
//
|
||
KeQuerySystemTime(¤tTime);
|
||
timeDiff = (ULONG)((currentTime.QuadPart - startTime.QuadPart) / 10000);
|
||
if (timeDiff >= FIND_BEST_CONFIGURATION_TIMEOUT) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
"IopFindBestConfiguration: Timeout expired"));
|
||
if (IopStopOnTimeout()) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_WARNING_LEVEL,
|
||
", terminating search!\n"));
|
||
IopCleanupSelectedConfiguration(
|
||
RequestTable,
|
||
RequestTableCount);
|
||
break;
|
||
} else {
|
||
//
|
||
// Re-initialize start time so we spew only every timeout
|
||
// interval.
|
||
//
|
||
startTime = currentTime;
|
||
IopDbgPrint((IOP_RESOURCE_WARNING_LEVEL, "\n"));
|
||
}
|
||
}
|
||
//
|
||
// Select the next possible combination of configurations.
|
||
//
|
||
} while (IopSelectNextConfiguration(
|
||
RequestTable,
|
||
RequestTableCount,
|
||
ActiveArbiterList) == TRUE);
|
||
//
|
||
// Check if we found any working configuration.
|
||
//
|
||
if (IsListEmpty(&bestArbiterList)) {
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
} else {
|
||
|
||
status = STATUS_SUCCESS;
|
||
//
|
||
// Restore the saved configuration.
|
||
//
|
||
if (RequestTableCount != 1) {
|
||
|
||
*ActiveArbiterList = bestArbiterList;
|
||
IopSaveRestoreConfiguration(
|
||
RequestTable,
|
||
RequestTableCount,
|
||
ActiveArbiterList,
|
||
FALSE);
|
||
//
|
||
// Retest this configuration since this may not be the
|
||
// last one tested.
|
||
//
|
||
status = IopRetestConfiguration(ActiveArbiterList);
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
/*++
|
||
|
||
SECTION = LEGACY BUS INFORMATION TABLE.
|
||
|
||
Description:
|
||
|
||
This section contains code that implements functions to maintain and
|
||
access the table of Legacy Bus Information.
|
||
|
||
--*/
|
||
|
||
VOID
|
||
IopInsertLegacyBusDeviceNode (
|
||
IN PDEVICE_NODE BusDeviceNode,
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine inserts the specified BusDeviceNode in the table according to
|
||
its InterfaceType and BusNumber.
|
||
|
||
Parameters:
|
||
|
||
BusDeviceNode - Device with the specified InterfaceType and BusNumber.
|
||
|
||
InterfaceType - Specifies the bus devicenode's interface type.
|
||
|
||
BusNumber - Specifies the bus devicenode's bus number.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
ASSERT(InterfaceType < MaximumInterfaceType && InterfaceType > InterfaceTypeUndefined);
|
||
if ( InterfaceType < MaximumInterfaceType &&
|
||
InterfaceType > InterfaceTypeUndefined &&
|
||
InterfaceType != PNPBus) {
|
||
|
||
PLIST_ENTRY listEntry;
|
||
//
|
||
// Eisa == Isa.
|
||
//
|
||
if (InterfaceType == Eisa) {
|
||
|
||
InterfaceType = Isa;
|
||
}
|
||
IopLockResourceManager();
|
||
listEntry = IopLegacyBusInformationTable[InterfaceType].Flink;
|
||
while (listEntry != &IopLegacyBusInformationTable[InterfaceType]) {
|
||
|
||
PDEVICE_NODE deviceNode = CONTAINING_RECORD(
|
||
listEntry,
|
||
DEVICE_NODE,
|
||
LegacyBusListEntry);
|
||
if (deviceNode->BusNumber == BusNumber) {
|
||
|
||
if (deviceNode != BusDeviceNode) {
|
||
//
|
||
// There better not be two bus devicenodes with same
|
||
// interface and bus number.
|
||
//
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Identical legacy bus devicenodes with "
|
||
"interface=%08X & bus=%08X...\n"
|
||
"\t%wZ\n"
|
||
"\t%wZ\n",
|
||
InterfaceType,
|
||
BusNumber,
|
||
&deviceNode->InstancePath,
|
||
&BusDeviceNode->InstancePath));
|
||
}
|
||
IopUnlockResourceManager();
|
||
return;
|
||
} else if (deviceNode->BusNumber > BusNumber) {
|
||
|
||
break;
|
||
}
|
||
listEntry = listEntry->Flink;
|
||
}
|
||
//
|
||
// Insert the new devicenode before the one with the higher bus number.
|
||
//
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopInsertLegacyBusDeviceNode: Inserting %wZ with "
|
||
"interface=%08X & bus=%08X into the legacy bus information table\n",
|
||
&BusDeviceNode->InstancePath,
|
||
InterfaceType, BusNumber));
|
||
BusDeviceNode->LegacyBusListEntry.Blink = listEntry->Blink;
|
||
BusDeviceNode->LegacyBusListEntry.Flink = listEntry;
|
||
listEntry->Blink->Flink = &BusDeviceNode->LegacyBusListEntry;
|
||
listEntry->Blink = &BusDeviceNode->LegacyBusListEntry;
|
||
IopUnlockResourceManager();
|
||
}
|
||
}
|
||
|
||
PDEVICE_NODE
|
||
IopFindLegacyBusDeviceNode (
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds the bus devicenode with the specified InterfaceType
|
||
and BusNumber.
|
||
|
||
Parameters:
|
||
|
||
InterfaceType - Specifies the bus devicenode's interface type.
|
||
|
||
BusNumber - Specifies the bus devicenode's bus number.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the bus devicenode.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_NODE busDeviceNode;
|
||
|
||
PAGED_CODE();
|
||
|
||
busDeviceNode = IopRootDeviceNode;
|
||
if ( InterfaceType < MaximumInterfaceType &&
|
||
InterfaceType > InterfaceTypeUndefined &&
|
||
InterfaceType != PNPBus) {
|
||
|
||
PLIST_ENTRY listEntry;
|
||
//
|
||
// Eisa == Isa.
|
||
//
|
||
if (InterfaceType == Eisa) {
|
||
|
||
InterfaceType = Isa;
|
||
}
|
||
//
|
||
// Search our table...
|
||
//
|
||
listEntry = IopLegacyBusInformationTable[InterfaceType].Flink;
|
||
while (listEntry != &IopLegacyBusInformationTable[InterfaceType]) {
|
||
|
||
PDEVICE_NODE deviceNode = CONTAINING_RECORD(
|
||
listEntry,
|
||
DEVICE_NODE,
|
||
LegacyBusListEntry);
|
||
if (deviceNode->BusNumber == BusNumber) {
|
||
//
|
||
// Return the bus devicenode matching the bus number and
|
||
// interface.
|
||
//
|
||
busDeviceNode = deviceNode;
|
||
break;
|
||
} else if (deviceNode->BusNumber > BusNumber) {
|
||
//
|
||
// We are done since our list of bus numbers is sorted.
|
||
//
|
||
break;
|
||
}
|
||
listEntry = listEntry->Flink;
|
||
}
|
||
}
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IopFindLegacyBusDeviceNode() Found %wZ with "
|
||
"interface=%08X & bus=%08X\n",
|
||
&busDeviceNode->InstancePath,
|
||
InterfaceType,
|
||
BusNumber));
|
||
|
||
return busDeviceNode;
|
||
}
|
||
|
||
/*++
|
||
|
||
SECTION = BOOT CONFIG.
|
||
|
||
Description:
|
||
|
||
This section contains code that implements BOOT config allocation and
|
||
release.
|
||
|
||
--*/
|
||
|
||
NTSTATUS
|
||
IopAllocateBootResources (
|
||
IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PCM_RESOURCE_LIST BootResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates boot resources.
|
||
Before all Boot Bux Extenders are processed, this routine is called only
|
||
for non-madeup devices since arbiters for their boot resources should
|
||
already be initialized by the time the time they got enumerated.
|
||
After all Boot Bus Extenders are processed, this routine is used for all
|
||
boot allocations.
|
||
|
||
Parameters:
|
||
|
||
ArbiterRequestSource - Source of this resource request.
|
||
|
||
DeviceObject - If non-NULL, the boot resources are
|
||
pre-allocated. These resources will not be given out until they are
|
||
released to the arbiters. If NULL, the boot resources get reserved and
|
||
may be given out if there is no other choice.
|
||
|
||
BootResources - Supplies a pointer to the BOOT resources. If
|
||
DeviceObject is NULL, caller should release this pool.
|
||
|
||
Return Value:
|
||
|
||
The status returned is the final completion status of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Allocating boot resources...\n"));
|
||
//
|
||
// Claim the lock so no other resource allocations\releases can take place.
|
||
//
|
||
IopLockResourceManager();
|
||
//
|
||
// Call the function that does the real work.
|
||
//
|
||
status = IopAllocateBootResourcesInternal(
|
||
ArbiterRequestSource,
|
||
DeviceObject,
|
||
BootResources);
|
||
//
|
||
// Unblock other resource allocations\releases.
|
||
//
|
||
IopUnlockResourceManager();
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopReportBootResources (
|
||
IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PCM_RESOURCE_LIST BootResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to report boot resources.
|
||
This routine gets called before all Boot Bus Extenders are processed. It
|
||
calls the actual allocation function for non-madeup devices. For others,
|
||
it delays the allocation. The postponed allocations take place when the
|
||
arbiters come online by calling IopAllocateLegacyBootResources. Once all
|
||
Boot Bus Extenders are processed, the calls get routed to
|
||
IopAllocateBootResources directly.
|
||
|
||
Parameters:
|
||
|
||
ArbiterRequestSource - Source of this resource request.
|
||
|
||
DeviceObject - If non-NULL, the boot resources are
|
||
pre-allocated. These resources will not be given out until they are
|
||
released to the arbiters. If NULL, the boot resources get reserved and
|
||
may be given out if there is no other choice.
|
||
|
||
BootResources - Supplies a pointer to the BOOT resources. If
|
||
DeviceObject is NULL, caller should release this pool.
|
||
|
||
Return Value:
|
||
|
||
The status returned is the final completion status of the operation.
|
||
|
||
--*/
|
||
{
|
||
ULONG size;
|
||
PDEVICE_NODE deviceNode;
|
||
PIOP_RESERVED_RESOURCES_RECORD resourceRecord;
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Reporting boot resources...\n"));
|
||
if ((size = IopDetermineResourceListSize(BootResources)) == 0) {
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
if (DeviceObject) {
|
||
|
||
deviceNode = PP_DO_TO_DN(DeviceObject);
|
||
ASSERT(deviceNode);
|
||
if (!(deviceNode->Flags & DNF_MADEUP)) {
|
||
//
|
||
// Allocate BOOT configs for non-madeup devices right away.
|
||
//
|
||
return IopAllocateBootResources(
|
||
ArbiterRequestSource,
|
||
DeviceObject,
|
||
BootResources);
|
||
}
|
||
if (!deviceNode->BootResources) {
|
||
|
||
deviceNode->BootResources = ExAllocatePoolIORL(PagedPool, size);
|
||
if (!deviceNode->BootResources) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
RtlCopyMemory(deviceNode->BootResources, BootResources, size);
|
||
}
|
||
} else {
|
||
|
||
deviceNode = NULL;
|
||
}
|
||
//
|
||
// Delay BOOT allocation since arbiters may not be around.
|
||
//
|
||
resourceRecord = (PIOP_RESERVED_RESOURCES_RECORD) ExAllocatePoolIORRR(
|
||
PagedPool,
|
||
sizeof(IOP_RESERVED_RESOURCES_RECORD));
|
||
if (!resourceRecord) {
|
||
//
|
||
// Free memory we allocated and return failure.
|
||
//
|
||
if (deviceNode && deviceNode->BootResources) {
|
||
|
||
ExFreePool(deviceNode->BootResources);
|
||
deviceNode->BootResources = NULL;
|
||
}
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
if (deviceNode) {
|
||
|
||
resourceRecord->ReservedResources = deviceNode->BootResources;
|
||
} else {
|
||
|
||
resourceRecord->ReservedResources = BootResources;
|
||
}
|
||
resourceRecord->DeviceObject = DeviceObject;
|
||
//
|
||
// Link this record into our list.
|
||
//
|
||
resourceRecord->Next = IopInitReservedResourceList;
|
||
IopInitReservedResourceList = resourceRecord;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopAllocateLegacyBootResources (
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to reserve legacy BOOT resources for the specified
|
||
InterfaceType and BusNumber. This is done everytime a new bus with a legacy
|
||
InterfaceType gets enumerated.
|
||
|
||
Parameters:
|
||
|
||
InterfaceType - Legacy InterfaceType.
|
||
|
||
BusNumber - Legacy BusNumber.
|
||
|
||
Return Value:
|
||
|
||
The status returned is the final completion status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
PIOP_RESERVED_RESOURCES_RECORD resourceRecord;
|
||
PIOP_RESERVED_RESOURCES_RECORD prevRecord;
|
||
PCM_RESOURCE_LIST newList;
|
||
PCM_RESOURCE_LIST remainingList;
|
||
PCM_RESOURCE_LIST resourceList;
|
||
|
||
if (IopInitHalDeviceNode && IopInitHalResources) {
|
||
|
||
remainingList = NULL;
|
||
newList = IopCreateCmResourceList(
|
||
IopInitHalResources,
|
||
InterfaceType,
|
||
BusNumber,
|
||
&remainingList);
|
||
if (newList) {
|
||
//
|
||
// Sanity check that there was no error.
|
||
//
|
||
if (remainingList == NULL) {
|
||
//
|
||
// Full match.
|
||
//
|
||
ASSERT(newList == IopInitHalResources);
|
||
} else {
|
||
//
|
||
// Partial match.
|
||
//
|
||
ASSERT(IopInitHalResources != newList);
|
||
ASSERT(IopInitHalResources != remainingList);
|
||
}
|
||
if (remainingList) {
|
||
|
||
ExFreePool(IopInitHalResources);
|
||
}
|
||
IopInitHalResources = remainingList;
|
||
remainingList = IopInitHalDeviceNode->BootResources;
|
||
IopInitHalDeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Allocating HAL reported resources on interface=%x and "
|
||
"bus number=%x...\n", InterfaceType, BusNumber));
|
||
status = IopAllocateBootResources(
|
||
ArbiterRequestHalReported,
|
||
IopInitHalDeviceNode->PhysicalDeviceObject,
|
||
newList);
|
||
IopInitHalDeviceNode->BootResources = IopCombineCmResourceList(
|
||
remainingList,
|
||
newList);
|
||
ASSERT(IopInitHalDeviceNode->BootResources);
|
||
//
|
||
// Free previous BOOT config if any.
|
||
//
|
||
if (remainingList) {
|
||
|
||
ExFreePool(remainingList);
|
||
}
|
||
} else {
|
||
//
|
||
// No match. Sanity check that there was no error.
|
||
//
|
||
ASSERT(remainingList && remainingList == IopInitHalResources);
|
||
}
|
||
}
|
||
prevRecord = NULL;
|
||
resourceRecord = IopInitReservedResourceList;
|
||
while (resourceRecord) {
|
||
|
||
resourceList = resourceRecord->ReservedResources;
|
||
if ( resourceList->List[0].InterfaceType == InterfaceType &&
|
||
resourceList->List[0].BusNumber == BusNumber) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_INFO_LEVEL,
|
||
"Allocating boot config for made-up device on interface=%x and"
|
||
" bus number=%x...\n", InterfaceType, BusNumber));
|
||
status = IopAllocateBootResources(
|
||
ArbiterRequestPnpEnumerated,
|
||
resourceRecord->DeviceObject,
|
||
resourceList);
|
||
if (resourceRecord->DeviceObject == NULL) {
|
||
|
||
ExFreePool(resourceList);
|
||
}
|
||
if (prevRecord) {
|
||
|
||
prevRecord->Next = resourceRecord->Next;
|
||
} else {
|
||
|
||
IopInitReservedResourceList = resourceRecord->Next;
|
||
}
|
||
ExFreePool(resourceRecord);
|
||
if (prevRecord) {
|
||
|
||
resourceRecord = prevRecord->Next;
|
||
} else {
|
||
|
||
resourceRecord = IopInitReservedResourceList;
|
||
}
|
||
} else {
|
||
|
||
prevRecord = resourceRecord;
|
||
resourceRecord = resourceRecord->Next;
|
||
}
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopAllocateBootResourcesInternal (
|
||
IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PCM_RESOURCE_LIST BootResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine reports boot resources for the specified device to
|
||
arbiters.
|
||
|
||
Parameters:
|
||
|
||
ArbiterRequestSource - Source of this resource request.
|
||
|
||
DeviceObject - If non-NULL, the boot resources are
|
||
pre-allocated. These resources will not be given out until they are
|
||
released to the arbiters. If NULL, the boot resources get reserved and
|
||
may be given out if there is no other choice.
|
||
|
||
BootResources - Supplies a pointer to the BOOT resources. If
|
||
DeviceObject is NULL, caller should release this pool.
|
||
|
||
Return Value:
|
||
|
||
The status returned is the final completion status of the operation.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_NODE deviceNode;
|
||
PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
|
||
PREQ_LIST reqList;
|
||
IOP_RESOURCE_REQUEST request;
|
||
|
||
PAGED_CODE();
|
||
|
||
ioResources = IopCmResourcesToIoResources(
|
||
0,
|
||
BootResources,
|
||
LCPRI_BOOTCONFIG);
|
||
if (ioResources) {
|
||
|
||
deviceNode = PP_DO_TO_DN(DeviceObject);
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"\n===================================\n"
|
||
));
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"Boot Resource List:: "));
|
||
IopDumpResourceRequirementsList(ioResources);
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
" ++++++++++++++++++++++++++++++\n"));
|
||
request.AllocationType = ArbiterRequestSource;
|
||
request.ResourceRequirements = ioResources;
|
||
request.PhysicalDevice = DeviceObject;
|
||
status = IopResourceRequirementsListToReqList(
|
||
&request,
|
||
&reqList);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
if (reqList) {
|
||
|
||
status = IopBootAllocation(reqList);
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
if (deviceNode) {
|
||
|
||
deviceNode->Flags |= DNF_BOOT_CONFIG_RESERVED;
|
||
if (!deviceNode->BootResources) {
|
||
|
||
ULONG size;
|
||
|
||
size = IopDetermineResourceListSize(BootResources);
|
||
deviceNode->BootResources = ExAllocatePoolIORL(
|
||
PagedPool,
|
||
size);
|
||
if (!deviceNode->BootResources) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
RtlCopyMemory(
|
||
deviceNode->BootResources,
|
||
BootResources,
|
||
size);
|
||
}
|
||
}
|
||
}
|
||
IopFreeReqList(reqList);
|
||
} else {
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
ExFreePool(ioResources);
|
||
} else {
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"IopAllocateBootResourcesInternal: Failed with status = %08X\n",
|
||
status));
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopBootAllocation (
|
||
IN PREQ_LIST ReqList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calls the arbiters for the ReqList to do BootAllocation.
|
||
|
||
Parameters:
|
||
|
||
ReqList - List of BOOT resources in internal format.
|
||
|
||
Return Value:
|
||
|
||
The status returned is the final completion status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
NTSTATUS returnStatus;
|
||
LIST_ENTRY activeArbiterList;
|
||
PLIST_ENTRY listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
ARBITER_PARAMETERS p;
|
||
|
||
PAGED_CODE();
|
||
|
||
returnStatus = STATUS_SUCCESS;
|
||
InitializeListHead(&activeArbiterList);
|
||
ReqList->SelectedAlternative = ReqList->AlternativeTable;
|
||
IopAddRemoveReqDescs( (*ReqList->SelectedAlternative)->DescTable,
|
||
(*ReqList->SelectedAlternative)->DescCount,
|
||
&activeArbiterList,
|
||
TRUE);
|
||
listEntry = activeArbiterList.Flink;
|
||
while (listEntry != &activeArbiterList){
|
||
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
listEntry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
ActiveArbiterList);
|
||
listEntry = listEntry->Flink;
|
||
if (arbiterEntry->ResourcesChanged == FALSE) {
|
||
|
||
continue;
|
||
}
|
||
ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
|
||
p.Parameters.BootAllocation.ArbitrationList =
|
||
&arbiterEntry->ResourceList;
|
||
status = arbiterEntry->ArbiterInterface->ArbiterHandler(
|
||
arbiterEntry->ArbiterInterface->Context,
|
||
ArbiterActionBootAllocation,
|
||
&p);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
PARBITER_LIST_ENTRY arbiterListEntry;
|
||
|
||
arbiterListEntry = (PARBITER_LIST_ENTRY)
|
||
arbiterEntry->ResourceList.Flink;
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Allocate Boot Resources Failed ::\n\tCount = %x, PDO = %x\n",
|
||
arbiterListEntry->AlternativeCount,
|
||
arbiterListEntry->PhysicalDeviceObject));
|
||
IopDumpResourceDescriptor("\t", arbiterListEntry->Alternatives);
|
||
returnStatus = status;
|
||
}
|
||
IopInitializeArbiterEntryState(arbiterEntry);
|
||
}
|
||
|
||
IopCheckDataStructures(IopRootDeviceNode);
|
||
|
||
return returnStatus;
|
||
}
|
||
|
||
PCM_RESOURCE_LIST
|
||
IopCreateCmResourceList (
|
||
IN PCM_RESOURCE_LIST ResourceList,
|
||
IN INTERFACE_TYPE InterfaceType,
|
||
IN ULONG BusNumber,
|
||
OUT PCM_RESOURCE_LIST *RemainingList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the CM_RESOURCE_LIST portion out of the specified list
|
||
that matches the specified BusNumber and InterfaceType.
|
||
|
||
Parameters:
|
||
|
||
ResourceList - Input resource list.
|
||
|
||
InterfaceType - Interface type.
|
||
|
||
BusNumber - Bus number.
|
||
|
||
RemainingList - Portion not matching BusNumber and InterfaceType.
|
||
|
||
Return Value:
|
||
|
||
Returns the matching CM_RESOURCE_LIST if successful, else NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
ULONG j;
|
||
ULONG totalSize;
|
||
ULONG matchSize;
|
||
ULONG listSize;
|
||
PCM_RESOURCE_LIST newList;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR newFullResourceDesc;
|
||
PCM_FULL_RESOURCE_DESCRIPTOR remainingFullResourceDesc;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
|
||
|
||
PAGED_CODE();
|
||
|
||
fullResourceDesc = &ResourceList->List[0];
|
||
totalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
|
||
matchSize = 0;
|
||
//
|
||
// Determine the size of memory to be allocated for the matching resource
|
||
// list.
|
||
//
|
||
for (i = 0; i < ResourceList->Count; i++) {
|
||
//
|
||
// Add the size of this descriptor.
|
||
//
|
||
listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
|
||
PartialResourceList) +
|
||
FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
|
||
PartialDescriptors);
|
||
partialDescriptor =
|
||
&fullResourceDesc->PartialResourceList.PartialDescriptors[0];
|
||
for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) {
|
||
|
||
ULONG descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
|
||
if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) {
|
||
|
||
descriptorSize +=
|
||
partialDescriptor->u.DeviceSpecificData.DataSize;
|
||
}
|
||
listSize += descriptorSize;
|
||
partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
|
||
((PUCHAR)partialDescriptor +
|
||
descriptorSize);
|
||
}
|
||
if ( fullResourceDesc->InterfaceType == InterfaceType &&
|
||
fullResourceDesc->BusNumber == BusNumber) {
|
||
|
||
matchSize += listSize;
|
||
}
|
||
totalSize += listSize;
|
||
fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
||
((PUCHAR)fullResourceDesc + listSize);
|
||
}
|
||
if (!matchSize) {
|
||
|
||
*RemainingList = ResourceList;
|
||
return NULL;
|
||
}
|
||
matchSize += FIELD_OFFSET(CM_RESOURCE_LIST, List);
|
||
if (matchSize == totalSize) {
|
||
|
||
*RemainingList = NULL;
|
||
return ResourceList;
|
||
}
|
||
//
|
||
// Allocate memory for both lists.
|
||
//
|
||
newList = (PCM_RESOURCE_LIST)ExAllocatePoolIORRR(PagedPool, matchSize);
|
||
if (newList == NULL) {
|
||
|
||
*RemainingList = NULL;
|
||
return NULL;
|
||
}
|
||
*RemainingList = (PCM_RESOURCE_LIST)
|
||
ExAllocatePoolIORRR(
|
||
PagedPool,
|
||
totalSize - matchSize +
|
||
FIELD_OFFSET(CM_RESOURCE_LIST, List));
|
||
if (*RemainingList == NULL) {
|
||
|
||
ExFreePool(newList);
|
||
return NULL;
|
||
}
|
||
newList->Count = 0;
|
||
(*RemainingList)->Count = 0;
|
||
newFullResourceDesc = &newList->List[0];
|
||
remainingFullResourceDesc = &(*RemainingList)->List[0];
|
||
fullResourceDesc = &ResourceList->List[0];
|
||
for (i = 0; i < ResourceList->Count; i++) {
|
||
|
||
listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
|
||
PartialResourceList) +
|
||
FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
|
||
PartialDescriptors);
|
||
partialDescriptor =
|
||
&fullResourceDesc->PartialResourceList.PartialDescriptors[0];
|
||
for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) {
|
||
|
||
ULONG descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
|
||
if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) {
|
||
|
||
descriptorSize +=
|
||
partialDescriptor->u.DeviceSpecificData.DataSize;
|
||
}
|
||
listSize += descriptorSize;
|
||
partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
|
||
((PUCHAR)partialDescriptor +
|
||
descriptorSize);
|
||
}
|
||
if ( fullResourceDesc->InterfaceType == InterfaceType &&
|
||
fullResourceDesc->BusNumber == BusNumber) {
|
||
|
||
newList->Count++;
|
||
RtlCopyMemory(newFullResourceDesc, fullResourceDesc, listSize);
|
||
newFullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
||
((PUCHAR)newFullResourceDesc +
|
||
listSize);
|
||
} else {
|
||
|
||
(*RemainingList)->Count++;
|
||
RtlCopyMemory(
|
||
remainingFullResourceDesc,
|
||
fullResourceDesc,
|
||
listSize);
|
||
remainingFullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
||
((PUCHAR)remainingFullResourceDesc +
|
||
listSize);
|
||
}
|
||
fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
||
((PUCHAR)fullResourceDesc +
|
||
listSize);
|
||
}
|
||
|
||
return newList;
|
||
}
|
||
|
||
PCM_RESOURCE_LIST
|
||
IopCombineCmResourceList (
|
||
IN PCM_RESOURCE_LIST ResourceListA,
|
||
IN PCM_RESOURCE_LIST ResourceListB
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine combines the two CM_RESOURCE_LISTs and returns the resulting
|
||
CM_RESOURCE_LIST.
|
||
|
||
Parameters:
|
||
|
||
ResourceListA - ListA.
|
||
|
||
ResourceListB - ListB.
|
||
|
||
Return Value:
|
||
|
||
Returns the combined CM_RESOURCE_LIST if successful, else NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCM_RESOURCE_LIST newList;
|
||
ULONG sizeA;
|
||
ULONG sizeB;
|
||
ULONG size;
|
||
ULONG diff;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (ResourceListA == NULL) {
|
||
|
||
return ResourceListB;
|
||
}
|
||
|
||
if (ResourceListB == NULL) {
|
||
|
||
return ResourceListA;
|
||
}
|
||
newList = NULL;
|
||
sizeA = IopDetermineResourceListSize(ResourceListA);
|
||
sizeB = IopDetermineResourceListSize(ResourceListB);
|
||
if (sizeA && sizeB) {
|
||
|
||
diff = sizeof(CM_RESOURCE_LIST) - sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
|
||
size = sizeA + sizeB - diff;
|
||
newList = (PCM_RESOURCE_LIST)ExAllocatePoolIORRR(PagedPool, size);
|
||
if (newList) {
|
||
|
||
RtlCopyMemory(newList, ResourceListA, sizeA);
|
||
RtlCopyMemory(
|
||
(PUCHAR)newList + sizeA,
|
||
(PUCHAR)ResourceListB + diff,
|
||
sizeB - diff);
|
||
newList->Count += ResourceListB->Count;
|
||
}
|
||
}
|
||
|
||
return newList;
|
||
}
|
||
|
||
/*++
|
||
|
||
SECTION = CLEANUP.
|
||
|
||
Description:
|
||
|
||
This section contains code that performs clean up like releasing storage
|
||
for various data structures..
|
||
|
||
--*/
|
||
|
||
VOID
|
||
IopFreeReqAlternative (
|
||
IN PREQ_ALTERNATIVE ReqAlternative
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine release the storage for the ReqAlternative by freeing the
|
||
contained descriptors.
|
||
|
||
Parameters:
|
||
|
||
ReqList - REQ_ALTERNATIVE to be freed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PREQ_DESC reqDesc;
|
||
PREQ_DESC reqDescx;
|
||
ULONG i;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (ReqAlternative) {
|
||
//
|
||
// Free all REQ_DESC making this REQ_ALTERNATIVE.
|
||
//
|
||
for (i = 0; i < ReqAlternative->DescCount; i++) {
|
||
//
|
||
// Free the list of translated REQ_DESCs for this REQ_DESC.
|
||
//
|
||
reqDesc = ReqAlternative->DescTable[i];
|
||
reqDescx = reqDesc->TranslatedReqDesc;
|
||
while (reqDescx && IS_TRANSLATED_REQ_DESC(reqDescx)) {
|
||
//
|
||
// Free storage for alternative descriptors if any.
|
||
//
|
||
if (reqDescx->AlternativeTable.Alternatives) {
|
||
|
||
ExFreePool(reqDescx->AlternativeTable.Alternatives);
|
||
}
|
||
reqDesc = reqDescx;
|
||
reqDescx = reqDescx->TranslatedReqDesc;
|
||
ExFreePool(reqDesc);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopFreeReqList (
|
||
IN PREQ_LIST ReqList
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine release the storage for the ReqList by freeing the contained
|
||
alternatives.
|
||
|
||
Parameters:
|
||
|
||
ReqList - REQ_LIST to be freed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (ReqList) {
|
||
//
|
||
// Free all alternatives making this REQ_LIST.
|
||
//
|
||
for (i = 0; i < ReqList->AlternativeCount; i++) {
|
||
|
||
IopFreeReqAlternative(ReqList->AlternativeTable[i]);
|
||
}
|
||
ExFreePool(ReqList);
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopFreeResourceRequirementsForAssignTable(
|
||
IN PIOP_RESOURCE_REQUEST RequestTable,
|
||
IN PIOP_RESOURCE_REQUEST RequestTableEnd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For each resource request in the table, this routine frees its
|
||
associated REQ_LIST.
|
||
|
||
Parameters:
|
||
|
||
RequestTable - Start of request table.
|
||
|
||
RequestTableEnd - End of request table.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIOP_RESOURCE_REQUEST request;
|
||
|
||
PAGED_CODE();
|
||
|
||
for (request = RequestTable; request < RequestTableEnd; request++) {
|
||
|
||
IopFreeReqList(request->ReqList);
|
||
request->ReqList = NULL;
|
||
if ( request->Flags & IOP_ASSIGN_KEEP_CURRENT_CONFIG &&
|
||
request->ResourceRequirements) {
|
||
//
|
||
// The REAL resreq list is cached in DeviceNode->ResourceRequirements.
|
||
// We need to free the filtered list.
|
||
//
|
||
ExFreePool(request->ResourceRequirements);
|
||
request->ResourceRequirements = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
#if DBG_SCOPE
|
||
VOID
|
||
IopCheckDataStructures (
|
||
IN PDEVICE_NODE DeviceNode
|
||
)
|
||
|
||
{
|
||
PDEVICE_NODE sibling;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Process all the siblings.
|
||
//
|
||
for (sibling = DeviceNode; sibling; sibling = sibling->Sibling) {
|
||
|
||
IopCheckDataStructuresWorker(sibling);
|
||
}
|
||
for (sibling = DeviceNode; sibling; sibling = sibling->Sibling) {
|
||
//
|
||
// Recursively check all the children.
|
||
//
|
||
if (sibling->Child) {
|
||
IopCheckDataStructures(sibling->Child);
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopCheckDataStructuresWorker (
|
||
IN PDEVICE_NODE Device
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sanity checks the arbiter related data structures for the
|
||
specified device.
|
||
|
||
Parameters:
|
||
|
||
DeviceNode - Device node whose structures are to be checked.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY listHead, listEntry;
|
||
PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
|
||
|
||
PAGED_CODE();
|
||
|
||
listHead = &Device->DeviceArbiterList;
|
||
listEntry = listHead->Flink;
|
||
while (listEntry != listHead) {
|
||
|
||
arbiterEntry = CONTAINING_RECORD(
|
||
listEntry,
|
||
PI_RESOURCE_ARBITER_ENTRY,
|
||
DeviceArbiterList);
|
||
if (arbiterEntry->ArbiterInterface != NULL) {
|
||
|
||
if (!IsListEmpty(&arbiterEntry->ResourceList)) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Arbiter on %wZ should have empty resource list\n",
|
||
&Device->InstancePath));
|
||
}
|
||
if (!IsListEmpty(&arbiterEntry->ActiveArbiterList)) {
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_ERROR_LEVEL,
|
||
"Arbiter on %wZ should not be in the active arbiter list\n",
|
||
&Device->InstancePath));
|
||
}
|
||
}
|
||
listEntry = listEntry->Flink;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopDumpResourceRequirementsList (
|
||
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine dumps IoResources
|
||
|
||
Parameters:
|
||
|
||
IoResources - Supplies a pointer to the IO resource requirements list
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_RESOURCE_LIST IoResourceList;
|
||
PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor;
|
||
PIO_RESOURCE_DESCRIPTOR IoResourceDescriptorEnd;
|
||
LONG IoResourceListCount;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (IoResources == NULL) {
|
||
|
||
return;
|
||
}
|
||
IoResourceList = IoResources->List;
|
||
IoResourceListCount = (LONG) IoResources->AlternativeLists;
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"ResReqList: Interface: %x, Bus: %x, Slot: %x, AlternativeLists: %x\n",
|
||
IoResources->InterfaceType,
|
||
IoResources->BusNumber,
|
||
IoResources->SlotNumber,
|
||
IoResources->AlternativeLists));
|
||
while (--IoResourceListCount >= 0) {
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
" Alternative List: DescCount: %x\n",
|
||
IoResourceList->Count));
|
||
IoResourceDescriptor = IoResourceList->Descriptors;
|
||
IoResourceDescriptorEnd = IoResourceDescriptor + IoResourceList->Count;
|
||
while(IoResourceDescriptor < IoResourceDescriptorEnd) {
|
||
|
||
IopDumpResourceDescriptor(" ", IoResourceDescriptor++);
|
||
}
|
||
IoResourceList = (PIO_RESOURCE_LIST) IoResourceDescriptorEnd;
|
||
}
|
||
IopDbgPrint((IOP_RESOURCE_VERBOSE_LEVEL,"\n"));
|
||
}
|
||
|
||
VOID
|
||
IopDumpResourceDescriptor (
|
||
IN PUCHAR Indent,
|
||
IN PIO_RESOURCE_DESCRIPTOR Desc
|
||
)
|
||
{
|
||
PAGED_CODE();
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"%sOpt: %x, Share: %x\t",
|
||
Indent,
|
||
Desc->Option,
|
||
Desc->ShareDisposition));
|
||
switch (Desc->Type) {
|
||
case CmResourceTypePort:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"IO Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
||
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:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"MEM Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
||
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:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"INT Min: %x, Max: %x\n",
|
||
Desc->u.Interrupt.MinimumVector,
|
||
Desc->u.Interrupt.MaximumVector));
|
||
break;
|
||
|
||
case CmResourceTypeDma:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"DMA Min: %x, Max: %x\n",
|
||
Desc->u.Dma.MinimumChannel,
|
||
Desc->u.Dma.MaximumChannel));
|
||
break;
|
||
|
||
case CmResourceTypeDevicePrivate:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"DevicePrivate Data: %x, %x, %x\n",
|
||
Desc->u.DevicePrivate.Data[0],
|
||
Desc->u.DevicePrivate.Data[1],
|
||
Desc->u.DevicePrivate.Data[2]));
|
||
break;
|
||
|
||
default:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"Unknown Descriptor type %x\n",
|
||
Desc->Type));
|
||
break;
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopDumpCmResourceList (
|
||
IN PCM_RESOURCE_LIST CmList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine displays CM resource list.
|
||
|
||
Arguments:
|
||
|
||
CmList - CM resource list to be dumped.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PCM_FULL_RESOURCE_DESCRIPTOR fullDesc;
|
||
PCM_PARTIAL_RESOURCE_LIST partialDesc;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
|
||
ULONG count;
|
||
ULONG i;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (CmList->Count > 0) {
|
||
|
||
if (CmList) {
|
||
|
||
fullDesc = &CmList->List[0];
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"Cm Resource List -\n"));
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
" List Count = %x, Bus Number = %x\n",
|
||
CmList->Count,
|
||
fullDesc->BusNumber));
|
||
partialDesc = &fullDesc->PartialResourceList;
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
" Version = %x, Revision = %x, Desc count = %x\n",
|
||
partialDesc->Version,
|
||
partialDesc->Revision,
|
||
partialDesc->Count));
|
||
count = partialDesc->Count;
|
||
desc = &partialDesc->PartialDescriptors[0];
|
||
for (i = 0; i < count; i++) {
|
||
|
||
IopDumpCmResourceDescriptor(" ", desc);
|
||
desc++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID
|
||
IopDumpCmResourceDescriptor (
|
||
IN PUCHAR Indent,
|
||
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine displays a IO_RESOURCE_DESCRIPTOR.
|
||
|
||
Parameters:
|
||
|
||
Indent - # char of indentation.
|
||
|
||
Desc - CM_RESOURCE_DESCRIPTOR to be displayed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
|
||
switch (Desc->Type) {
|
||
case CmResourceTypePort:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"%sIO Start: %x:%08x, Length: %x\n",
|
||
Indent,
|
||
Desc->u.Port.Start.HighPart,
|
||
Desc->u.Port.Start.LowPart,
|
||
Desc->u.Port.Length));
|
||
break;
|
||
|
||
case CmResourceTypeMemory:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"%sMEM Start: %x:%08x, Length: %x\n",
|
||
Indent,
|
||
Desc->u.Memory.Start.HighPart,
|
||
Desc->u.Memory.Start.LowPart,
|
||
Desc->u.Memory.Length));
|
||
break;
|
||
|
||
case CmResourceTypeInterrupt:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"%sINT Level: %x, Vector: %x, Affinity: %x\n",
|
||
Indent,
|
||
Desc->u.Interrupt.Level,
|
||
Desc->u.Interrupt.Vector,
|
||
Desc->u.Interrupt.Affinity));
|
||
break;
|
||
|
||
case CmResourceTypeDma:
|
||
|
||
IopDbgPrint((
|
||
IOP_RESOURCE_VERBOSE_LEVEL,
|
||
"%sDMA Channel: %x, Port: %x\n",
|
||
Indent,
|
||
Desc->u.Dma.Channel,
|
||
Desc->u.Dma.Port));
|
||
break;
|
||
}
|
||
}
|
||
|
||
#endif
|