Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8961 lines
273 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. pnpres.c
  5. Abstract:
  6. This module contains the plug-and-play resource allocation and translation
  7. routines
  8. Author:
  9. Shie-Lin Tzong (shielint) 1-Mar-1997
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. 25-Sept-1998 SantoshJ Made IopAssign non-recursive.
  14. 01-Oct-1998 SantoshJ Replaced "complex (broken)" hypercube code and
  15. replaced with cascading counters. Simple,
  16. faster, smaller code.
  17. Added timeouts to IopAssign.
  18. Added more self-debugging capability by
  19. generating more meaningful debug spew.
  20. 03-Feb-1999 SantoshJ Do allocation one device at a time.
  21. Do devices with BOOT config before others.
  22. Optimize IopFindBusDeviceNode.
  23. 22-Feb-2000 SantoshJ Add level field to arbiter entry. Arbiter list
  24. gets sorted by depth so there is no need to
  25. walk the tree while calling arbiters.
  26. 01-Mar-2000 SantoshJ Added look-up table for legacy interface and
  27. bus numbers. Avoids walking the device tree.
  28. 13-Mar-2000 SantoshJ Cleaned up BOOT allocation related code.
  29. 16-Mar-2000 SantoshJ Replaced all individual references to
  30. PpRegistrySemaphore with IopXXXResourceManager
  31. macro.
  32. 17-Mar-2000 SantoshJ Replaced all debug prints with IopDbgPrint
  33. 20-Mar-2000 SantoshJ Removed redundant fields from internal data
  34. structures.
  35. 21-Mar-2000 SantoshJ Cleaned up all definitions, MACROs etc.
  36. --*/
  37. #include "pnpmgrp.h"
  38. #pragma hdrstop
  39. //
  40. // CONSTANT defintions.
  41. //
  42. //
  43. // Set this to 1 for maximum instrumentation.
  44. //
  45. #define MAXDBG 0
  46. //
  47. // Timeout value for IopFindBestConfiguration in milliseconds.
  48. //
  49. #define FIND_BEST_CONFIGURATION_TIMEOUT 5000
  50. //
  51. // Tag used for memory allocation.
  52. //
  53. #define PNP_RESOURCE_TAG 'erpP'
  54. //
  55. // Forward typedefs.
  56. //
  57. typedef struct _REQ_DESC
  58. REQ_DESC, *PREQ_DESC;
  59. typedef struct _REQ_LIST
  60. REQ_LIST, *PREQ_LIST;
  61. typedef struct _REQ_ALTERNATIVE
  62. REQ_ALTERNATIVE, *PREQ_ALTERNATIVE, **PPREQ_ALTERNATIVE;
  63. typedef struct _DUPLICATE_DETECTION_CONTEXT
  64. DUPLICATE_DETECTION_CONTEXT, *PDUPLICATE_DETECTION_CONTEXT;
  65. typedef struct _IOP_POOL
  66. IOP_POOL, *PIOP_POOL;
  67. //
  68. // Structure definitions.
  69. //
  70. // REQ_LIST represents a list of logical configurations within the
  71. // IO_RESOURCE_REQUIREMENTS_LIST.
  72. //
  73. struct _REQ_LIST {
  74. INTERFACE_TYPE InterfaceType;
  75. ULONG BusNumber;
  76. PIOP_RESOURCE_REQUEST Request; // Owning request
  77. PPREQ_ALTERNATIVE SelectedAlternative; // Alternative selected
  78. PPREQ_ALTERNATIVE BestAlternative; // Best alternative
  79. ULONG AlternativeCount; // AlternativeTable length
  80. PREQ_ALTERNATIVE AlternativeTable[1]; // Variable length
  81. };
  82. //
  83. // REQ_ALTERNATIVE represents a logical configuration.
  84. //
  85. struct _REQ_ALTERNATIVE {
  86. ULONG Priority; // Priority for this configuration
  87. ULONG Position; // Used for sorting if Priority is identical
  88. PREQ_LIST ReqList; // List containing this configuration
  89. ULONG ReqAlternativeIndex; // Index within the table in the list
  90. ULONG DescCount; // Entry count for DescTable
  91. PREQ_DESC DescTable[1]; // Variable length
  92. };
  93. //
  94. // REQ_DESC represents a resource descriptor within a logical configuration.
  95. //
  96. struct _REQ_DESC {
  97. INTERFACE_TYPE InterfaceType;
  98. ULONG BusNumber;
  99. BOOLEAN ArbitrationRequired;
  100. UCHAR Reserved[3];
  101. PREQ_ALTERNATIVE ReqAlternative;
  102. ULONG ReqDescIndex;
  103. PREQ_DESC TranslatedReqDesc;
  104. ARBITER_LIST_ENTRY AlternativeTable;
  105. CM_PARTIAL_RESOURCE_DESCRIPTOR Allocation;
  106. ARBITER_LIST_ENTRY BestAlternativeTable;
  107. CM_PARTIAL_RESOURCE_DESCRIPTOR BestAllocation;
  108. ULONG DevicePrivateCount; // DevicePrivate info
  109. PIO_RESOURCE_DESCRIPTOR DevicePrivate; // per LogConf
  110. union {
  111. PPI_RESOURCE_ARBITER_ENTRY Arbiter; // In original REQ_DESC
  112. PPI_RESOURCE_TRANSLATOR_ENTRY Translator; // In translated REQ_DESC
  113. } u;
  114. };
  115. //
  116. // Duplicate_detection_Context
  117. //
  118. struct _DUPLICATE_DETECTION_CONTEXT {
  119. PCM_RESOURCE_LIST TranslatedResources;
  120. PDEVICE_NODE Duplicate;
  121. };
  122. //
  123. // Pool
  124. //
  125. struct _IOP_POOL {
  126. PUCHAR PoolStart;
  127. ULONG PoolSize;
  128. };
  129. #if DBG_SCOPE
  130. typedef struct {
  131. PDEVICE_NODE devnode;
  132. CM_PARTIAL_RESOURCE_DESCRIPTOR resource;
  133. } PNPRESDEBUGTRANSLATIONFAILURE;
  134. #endif // DBG_SCOPE
  135. //
  136. // MACROS
  137. //
  138. // Reused device node fields.
  139. //
  140. #define NextDeviceNode Sibling
  141. #define PreviousDeviceNode Child
  142. //
  143. // Call this macro to block other resource allocations and releases in the
  144. // system.
  145. //
  146. #define IopLockResourceManager() { \
  147. KeEnterCriticalRegion(); \
  148. KeWaitForSingleObject( \
  149. &PpRegistrySemaphore, \
  150. DelayExecution, \
  151. KernelMode, \
  152. FALSE, \
  153. NULL); \
  154. }
  155. //
  156. // Unblock other resource allocations and releases in the system.
  157. //
  158. #define IopUnlockResourceManager() { \
  159. KeReleaseSemaphore( \
  160. &PpRegistrySemaphore, \
  161. 0, \
  162. 1, \
  163. FALSE); \
  164. KeLeaveCriticalRegion(); \
  165. }
  166. //
  167. // Initialize arbiter entry.
  168. //
  169. #define IopInitializeArbiterEntryState(a) { \
  170. (a)->ResourcesChanged = FALSE; \
  171. (a)->State = 0; \
  172. InitializeListHead(&(a)->ActiveArbiterList); \
  173. InitializeListHead(&(a)->BestConfig); \
  174. InitializeListHead(&(a)->ResourceList); \
  175. InitializeListHead(&(a)->BestResourceList); \
  176. }
  177. #define IS_TRANSLATED_REQ_DESC(r) (!((r)->ReqAlternative))
  178. //
  179. // Pool management MACROs
  180. //
  181. #define IopInitPool(Pool,Start,Size) { \
  182. (Pool)->PoolStart = (Start); \
  183. (Pool)->PoolSize = (Size); \
  184. RtlZeroMemory(Start, Size); \
  185. }
  186. #define IopAllocPool(M,P,S) { \
  187. *(M) = (PVOID)(P)->PoolStart; \
  188. ASSERT((P)->PoolStart + (S) <= (P)->PoolStart + (P)->PoolSize); \
  189. (P)->PoolStart += (S); \
  190. }
  191. //
  192. // IopReleaseBootResources can only be called for non ROOT enumerated devices
  193. //
  194. #define IopReleaseBootResources(DeviceNode) { \
  195. ASSERT(((DeviceNode)->Flags & DNF_MADEUP) == 0); \
  196. IopReleaseResourcesInternal(DeviceNode); \
  197. (DeviceNode)->Flags &= ~DNF_HAS_BOOT_CONFIG; \
  198. (DeviceNode)->Flags &= ~DNF_BOOT_CONFIG_RESERVED; \
  199. if ((DeviceNode)->BootResources) { \
  200. ExFreePool((DeviceNode)->BootResources); \
  201. (DeviceNode)->BootResources = NULL; \
  202. } \
  203. }
  204. //
  205. // Debug support
  206. //
  207. #ifdef POOL_TAGGING
  208. #undef ExAllocatePool
  209. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,PNP_RESOURCE_TAG)
  210. #endif // POOL_TAGGING
  211. #if MAXDBG
  212. #define ExAllocatePoolAT(a,b) ExAllocatePoolWithTag(a,b,'0rpP')
  213. #define ExAllocatePoolRD(a,b) ExAllocatePoolWithTag(a,b,'1rpP')
  214. #define ExAllocatePoolCMRL(a,b) ExAllocatePoolWithTag(a,b,'2rpP')
  215. #define ExAllocatePoolCMRR(a,b) ExAllocatePoolWithTag(a,b,'3rpP')
  216. #define ExAllocatePoolAE(a,b) ExAllocatePoolWithTag(a,b,'4rpP')
  217. #define ExAllocatePoolTE(a,b) ExAllocatePoolWithTag(a,b,'5rpP')
  218. #define ExAllocatePoolPRD(a,b) ExAllocatePoolWithTag(a,b,'6rpP')
  219. #define ExAllocatePoolIORD(a,b) ExAllocatePoolWithTag(a,b,'7rpP')
  220. #define ExAllocatePool1RD(a,b) ExAllocatePoolWithTag(a,b,'8rpP')
  221. #define ExAllocatePoolPDO(a,b) ExAllocatePoolWithTag(a,b,'9rpP')
  222. #define ExAllocatePoolIORR(a,b) ExAllocatePoolWithTag(a,b,'ArpP')
  223. #define ExAllocatePoolIORL(a,b) ExAllocatePoolWithTag(a,b,'BrpP')
  224. #define ExAllocatePoolIORRR(a,b) ExAllocatePoolWithTag(a,b,'CrpP')
  225. #else // MAXDBG
  226. #define ExAllocatePoolAT(a,b) ExAllocatePool(a,b)
  227. #define ExAllocatePoolRD(a,b) ExAllocatePool(a,b)
  228. #define ExAllocatePoolCMRL(a,b) ExAllocatePool(a,b)
  229. #define ExAllocatePoolCMRR(a,b) ExAllocatePool(a,b)
  230. #define ExAllocatePoolAE(a,b) ExAllocatePool(a,b)
  231. #define ExAllocatePoolTE(a,b) ExAllocatePool(a,b)
  232. #define ExAllocatePoolPRD(a,b) ExAllocatePool(a,b)
  233. #define ExAllocatePoolIORD(a,b) ExAllocatePool(a,b)
  234. #define ExAllocatePool1RD(a,b) ExAllocatePool(a,b)
  235. #define ExAllocatePoolPDO(a,b) ExAllocatePool(a,b)
  236. #define ExAllocatePoolIORR(a,b) ExAllocatePool(a,b)
  237. #define ExAllocatePoolIORL(a,b) ExAllocatePool(a,b)
  238. #define ExAllocatePoolIORRR(a,b) ExAllocatePool(a,b)
  239. #endif // MAXDBG
  240. #if DBG_SCOPE
  241. #define IopStopOnTimeout() (IopUseTimeout)
  242. VOID
  243. IopDumpResourceDescriptor (
  244. IN PUCHAR Indent,
  245. IN PIO_RESOURCE_DESCRIPTOR Desc
  246. );
  247. VOID
  248. IopDumpResourceRequirementsList (
  249. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
  250. );
  251. VOID
  252. IopDumpCmResourceDescriptor (
  253. IN PUCHAR Indent,
  254. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc
  255. );
  256. VOID
  257. IopDumpCmResourceList (
  258. IN PCM_RESOURCE_LIST CmList
  259. );
  260. VOID
  261. IopCheckDataStructuresWorker (
  262. IN PDEVICE_NODE Device
  263. );
  264. VOID
  265. IopCheckDataStructures (
  266. IN PDEVICE_NODE DeviceNode
  267. );
  268. #define IopRecordTranslationFailure(d,s) { \
  269. if (PnpResDebugTranslationFailureCount) { \
  270. PnpResDebugTranslationFailureCount--; \
  271. PnpResDebugTranslationFailure->devnode = d; \
  272. PnpResDebugTranslationFailure->resource = s; \
  273. PnpResDebugTranslationFailure++; \
  274. } \
  275. }
  276. #else
  277. #define IopStopOnTimeout() 1
  278. #define IopRecordTranslationFailure(d,s)
  279. #define IopDumpResourceRequirementsList(x)
  280. #define IopDumpResourceDescriptor(x,y)
  281. #define IopDumpCmResourceList(c)
  282. #define IopDumpCmResourceDescriptor(i,d)
  283. #define IopCheckDataStructures(x)
  284. #endif // DBG_SCOPE
  285. //
  286. // Internal/Forward function references
  287. //
  288. VOID
  289. IopRemoveLegacyDeviceNode (
  290. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  291. IN PDEVICE_NODE LegacyDeviceNode
  292. );
  293. NTSTATUS
  294. IopFindLegacyDeviceNode (
  295. IN PDRIVER_OBJECT DriverObject,
  296. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  297. OUT PDEVICE_NODE *LegacyDeviceNode,
  298. OUT PDEVICE_OBJECT *LegacyPDO
  299. );
  300. NTSTATUS
  301. IopGetResourceRequirementsForAssignTable (
  302. IN PIOP_RESOURCE_REQUEST RequestTable,
  303. IN PIOP_RESOURCE_REQUEST RequestTableEnd,
  304. OUT PULONG DeviceCount
  305. );
  306. NTSTATUS
  307. IopResourceRequirementsListToReqList(
  308. IN PIOP_RESOURCE_REQUEST Request,
  309. OUT PVOID *ResReqList
  310. );
  311. VOID
  312. IopRearrangeReqList (
  313. IN PREQ_LIST ReqList
  314. );
  315. VOID
  316. IopRearrangeAssignTable (
  317. IN PIOP_RESOURCE_REQUEST AssignTable,
  318. IN ULONG Count
  319. );
  320. int
  321. __cdecl
  322. IopCompareReqAlternativePriority (
  323. const void *arg1,
  324. const void *arg2
  325. );
  326. int
  327. __cdecl
  328. IopCompareResourceRequestPriority(
  329. const void *arg1,
  330. const void *arg2
  331. );
  332. VOID
  333. IopBuildCmResourceLists(
  334. IN PIOP_RESOURCE_REQUEST AssignTable,
  335. IN PIOP_RESOURCE_REQUEST AssignTableEnd
  336. );
  337. VOID
  338. IopBuildCmResourceList (
  339. IN PIOP_RESOURCE_REQUEST AssignEntry
  340. );
  341. NTSTATUS
  342. IopSetupArbiterAndTranslators(
  343. IN PREQ_DESC ReqDesc
  344. );
  345. BOOLEAN
  346. IopFindResourceHandlerInfo(
  347. IN RESOURCE_HANDLER_TYPE HandlerType,
  348. IN PDEVICE_NODE DeviceNode,
  349. IN UCHAR ResourceType,
  350. OUT PVOID *HandlerEntry
  351. );
  352. NTSTATUS
  353. IopParentToRawTranslation(
  354. IN OUT PREQ_DESC ReqDesc
  355. );
  356. NTSTATUS
  357. IopChildToRootTranslation(
  358. IN PDEVICE_NODE DeviceNode, OPTIONAL
  359. IN INTERFACE_TYPE InterfaceType,
  360. IN ULONG BusNumber,
  361. IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
  362. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  363. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *Target
  364. );
  365. NTSTATUS
  366. IopTranslateAndAdjustReqDesc(
  367. IN PREQ_DESC ReqDesc,
  368. IN PPI_RESOURCE_TRANSLATOR_ENTRY TranslatorEntry,
  369. OUT PREQ_DESC *TranslatedReqDesc
  370. );
  371. NTSTATUS
  372. IopCallArbiter(
  373. PPI_RESOURCE_ARBITER_ENTRY ArbiterEntry,
  374. ARBITER_ACTION Command,
  375. PVOID Input1,
  376. PVOID Input2,
  377. PVOID Input3
  378. );
  379. NTSTATUS
  380. IopFindResourcesForArbiter (
  381. IN PDEVICE_NODE DeviceNode,
  382. IN UCHAR ResourceType,
  383. OUT ULONG *Count,
  384. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmDesc
  385. );
  386. VOID
  387. IopReleaseResourcesInternal (
  388. IN PDEVICE_NODE DeviceNode
  389. );
  390. VOID
  391. IopReleaseResources (
  392. IN PDEVICE_NODE DeviceNode
  393. );
  394. NTSTATUS
  395. IopRestoreResourcesInternal (
  396. IN PDEVICE_NODE DeviceNode
  397. );
  398. VOID
  399. IopSetLegacyDeviceInstance (
  400. IN PDRIVER_OBJECT DriverObject,
  401. IN PDEVICE_NODE DeviceNode
  402. );
  403. PCM_RESOURCE_LIST
  404. IopCombineLegacyResources (
  405. IN PDEVICE_NODE DeviceNode
  406. );
  407. BOOLEAN
  408. IopNeedToReleaseBootResources(
  409. IN PDEVICE_NODE DeviceNode,
  410. IN PCM_RESOURCE_LIST AllocatedResources
  411. );
  412. VOID
  413. IopReleaseFilteredBootResources(
  414. IN PIOP_RESOURCE_REQUEST AssignTable,
  415. IN PIOP_RESOURCE_REQUEST AssignTableEnd
  416. );
  417. NTSTATUS
  418. IopQueryConflictListInternal(
  419. PDEVICE_OBJECT PhysicalDeviceObject,
  420. IN PCM_RESOURCE_LIST ResourceList,
  421. IN ULONG ResourceListSize,
  422. OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
  423. IN ULONG ConflictListSize,
  424. IN ULONG Flags
  425. );
  426. NTSTATUS
  427. IopQueryConflictFillConflicts(
  428. PDEVICE_OBJECT PhysicalDeviceObject,
  429. IN ULONG ConflictCount,
  430. IN PARBITER_CONFLICT_INFO ConflictInfoList,
  431. OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
  432. IN ULONG ConflictListSize,
  433. IN ULONG Flags
  434. );
  435. NTSTATUS
  436. IopQueryConflictFillString(
  437. IN PDEVICE_OBJECT DeviceObject,
  438. IN PWSTR Buffer,
  439. IN OUT PULONG Length,
  440. IN OUT PULONG Flags
  441. );
  442. BOOLEAN
  443. IopEliminateBogusConflict(
  444. IN PDEVICE_OBJECT PhysicalDeviceObject,
  445. IN PDEVICE_OBJECT ConflictDeviceObject
  446. );
  447. VOID
  448. IopQueryRebalance (
  449. IN PDEVICE_NODE DeviceNode,
  450. IN ULONG Phase,
  451. IN PULONG RebalanceCount,
  452. IN PDEVICE_OBJECT **DeviceTable
  453. );
  454. VOID
  455. IopQueryRebalanceWorker (
  456. IN PDEVICE_NODE DeviceNode,
  457. IN ULONG RebalancePhase,
  458. IN PULONG RebalanceCount,
  459. IN PDEVICE_OBJECT **DeviceTable
  460. );
  461. VOID
  462. IopTestForReconfiguration (
  463. IN PDEVICE_NODE DeviceNode,
  464. IN ULONG RebalancePhase,
  465. IN PULONG RebalanceCount,
  466. IN PDEVICE_OBJECT **DeviceTable
  467. );
  468. NTSTATUS
  469. IopRebalance (
  470. IN ULONG AssignTableCont,
  471. IN PIOP_RESOURCE_REQUEST AssignTable
  472. );
  473. NTSTATUS
  474. IopTestConfiguration (
  475. IN OUT PLIST_ENTRY ArbiterList
  476. );
  477. NTSTATUS
  478. IopRetestConfiguration (
  479. IN OUT PLIST_ENTRY ArbiterList
  480. );
  481. NTSTATUS
  482. IopCommitConfiguration (
  483. IN OUT PLIST_ENTRY ArbiterList
  484. );
  485. VOID
  486. IopSelectFirstConfiguration (
  487. IN PIOP_RESOURCE_REQUEST RequestTable,
  488. IN ULONG RequestTableCount,
  489. IN OUT PLIST_ENTRY ActiveArbiterList
  490. );
  491. BOOLEAN
  492. IopSelectNextConfiguration (
  493. IN PIOP_RESOURCE_REQUEST RequestTable,
  494. IN ULONG RequestTableCount,
  495. IN OUT PLIST_ENTRY ActiveArbiterList
  496. );
  497. VOID
  498. IopCleanupSelectedConfiguration (
  499. IN PIOP_RESOURCE_REQUEST RequestTable,
  500. IN ULONG RequestTableCount
  501. );
  502. ULONG
  503. IopComputeConfigurationPriority (
  504. IN PIOP_RESOURCE_REQUEST RequestTable,
  505. IN ULONG RequestTableCount
  506. );
  507. VOID
  508. IopSaveRestoreConfiguration (
  509. IN PIOP_RESOURCE_REQUEST RequestTable,
  510. IN ULONG RequestTableCount,
  511. IN OUT PLIST_ENTRY ArbiterList,
  512. IN BOOLEAN Save
  513. );
  514. VOID
  515. IopAddRemoveReqDescs (
  516. IN PREQ_DESC *ReqDescTable,
  517. IN ULONG ReqDescCount,
  518. IN OUT PLIST_ENTRY ActiveArbiterList,
  519. IN BOOLEAN Add
  520. );
  521. NTSTATUS
  522. IopFindBestConfiguration (
  523. IN PIOP_RESOURCE_REQUEST RequestTable,
  524. IN ULONG RequestTableCount,
  525. IN OUT PLIST_ENTRY ActiveArbiterList
  526. );
  527. PDEVICE_NODE
  528. IopFindLegacyBusDeviceNode (
  529. IN INTERFACE_TYPE InterfaceType,
  530. IN ULONG BusNumber
  531. );
  532. NTSTATUS
  533. IopAllocateBootResourcesInternal (
  534. IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
  535. IN PDEVICE_OBJECT DeviceObject,
  536. IN PCM_RESOURCE_LIST BootResources
  537. );
  538. NTSTATUS
  539. IopBootAllocation (
  540. IN PREQ_LIST ReqList
  541. );
  542. PCM_RESOURCE_LIST
  543. IopCreateCmResourceList(
  544. IN PCM_RESOURCE_LIST ResourceList,
  545. IN INTERFACE_TYPE InterfaceType,
  546. IN ULONG BusNumber,
  547. OUT PCM_RESOURCE_LIST *RemainingList
  548. );
  549. PCM_RESOURCE_LIST
  550. IopCombineCmResourceList(
  551. IN PCM_RESOURCE_LIST ResourceListA,
  552. IN PCM_RESOURCE_LIST ResourceListB
  553. );
  554. VOID
  555. IopFreeReqAlternative (
  556. IN PREQ_ALTERNATIVE ReqAlternative
  557. );
  558. VOID
  559. IopFreeReqList (
  560. IN PREQ_LIST ReqList
  561. );
  562. VOID
  563. IopFreeResourceRequirementsForAssignTable(
  564. IN PIOP_RESOURCE_REQUEST AssignTable,
  565. IN PIOP_RESOURCE_REQUEST AssignTableEnd
  566. );
  567. #ifdef ALLOC_PRAGMA
  568. #pragma alloc_text(PAGE, IopAllocateResources)
  569. #pragma alloc_text(PAGE, IopReleaseDeviceResources)
  570. #pragma alloc_text(PAGE, IopGetResourceRequirementsForAssignTable)
  571. #pragma alloc_text(PAGE, IopResourceRequirementsListToReqList)
  572. #pragma alloc_text(PAGE, IopRearrangeReqList)
  573. #pragma alloc_text(PAGE, IopRearrangeAssignTable)
  574. #pragma alloc_text(PAGE, IopBuildCmResourceLists)
  575. #pragma alloc_text(PAGE, IopBuildCmResourceList)
  576. #pragma alloc_text(PAGE, IopSetupArbiterAndTranslators)
  577. #pragma alloc_text(PAGE, IopUncacheInterfaceInformation)
  578. #pragma alloc_text(PAGE, IopFindResourceHandlerInfo)
  579. #pragma alloc_text(PAGE, IopParentToRawTranslation)
  580. #pragma alloc_text(PAGE, IopChildToRootTranslation)
  581. #pragma alloc_text(PAGE, IopTranslateAndAdjustReqDesc)
  582. #pragma alloc_text(PAGE, IopCallArbiter)
  583. #pragma alloc_text(PAGE, IopFindResourcesForArbiter)
  584. #pragma alloc_text(PAGE, IopLegacyResourceAllocation)
  585. #pragma alloc_text(PAGE, IopFindLegacyDeviceNode)
  586. #pragma alloc_text(PAGE, IopRemoveLegacyDeviceNode)
  587. #pragma alloc_text(PAGE, IopDuplicateDetection)
  588. #pragma alloc_text(PAGE, IopReleaseResourcesInternal)
  589. #pragma alloc_text(PAGE, IopRestoreResourcesInternal)
  590. #pragma alloc_text(PAGE, IopSetLegacyDeviceInstance)
  591. #pragma alloc_text(PAGE, IopCombineLegacyResources)
  592. #pragma alloc_text(PAGE, IopReleaseResources)
  593. #pragma alloc_text(PAGE, IopReallocateResources)
  594. #pragma alloc_text(PAGE, IopReleaseFilteredBootResources)
  595. #pragma alloc_text(PAGE, IopNeedToReleaseBootResources)
  596. #pragma alloc_text(PAGE, IopQueryConflictList)
  597. #pragma alloc_text(PAGE, IopQueryConflictListInternal)
  598. #pragma alloc_text(PAGE, IopQueryConflictFillConflicts)
  599. #pragma alloc_text(PAGE, IopQueryConflictFillString)
  600. #pragma alloc_text(PAGE, IopCompareReqAlternativePriority)
  601. #pragma alloc_text(PAGE, IopCompareResourceRequestPriority)
  602. #pragma alloc_text(PAGE, IopQueryRebalance)
  603. #pragma alloc_text(PAGE, IopQueryRebalanceWorker)
  604. #pragma alloc_text(PAGE, IopTestForReconfiguration)
  605. #pragma alloc_text(PAGE, IopRebalance)
  606. #pragma alloc_text(PAGE, IopTestConfiguration)
  607. #pragma alloc_text(PAGE, IopRetestConfiguration)
  608. #pragma alloc_text(PAGE, IopCommitConfiguration)
  609. #pragma alloc_text(PAGE, IopSelectFirstConfiguration)
  610. #pragma alloc_text(PAGE, IopSelectNextConfiguration)
  611. #pragma alloc_text(PAGE, IopCleanupSelectedConfiguration)
  612. #pragma alloc_text(PAGE, IopComputeConfigurationPriority)
  613. #pragma alloc_text(PAGE, IopSaveRestoreConfiguration)
  614. #pragma alloc_text(PAGE, IopAddRemoveReqDescs)
  615. #pragma alloc_text(PAGE, IopFindBestConfiguration)
  616. #pragma alloc_text(PAGE, IopInsertLegacyBusDeviceNode)
  617. #pragma alloc_text(PAGE, IopFindLegacyBusDeviceNode)
  618. #pragma alloc_text(PAGE, IopAllocateBootResources)
  619. #pragma alloc_text(INIT, IopReportBootResources)
  620. #pragma alloc_text(INIT, IopAllocateLegacyBootResources)
  621. #pragma alloc_text(PAGE, IopAllocateBootResourcesInternal)
  622. #pragma alloc_text(PAGE, IopBootAllocation)
  623. #pragma alloc_text(PAGE, IopCreateCmResourceList)
  624. #pragma alloc_text(PAGE, IopCombineCmResourceList)
  625. #pragma alloc_text(PAGE, IopFreeReqAlternative)
  626. #pragma alloc_text(PAGE, IopFreeReqList)
  627. #pragma alloc_text(PAGE, IopFreeResourceRequirementsForAssignTable)
  628. #if DBG_SCOPE
  629. #pragma alloc_text(PAGE, IopCheckDataStructures)
  630. #pragma alloc_text(PAGE, IopCheckDataStructuresWorker)
  631. #pragma alloc_text(PAGE, IopDumpResourceRequirementsList)
  632. #pragma alloc_text(PAGE, IopDumpResourceDescriptor)
  633. #pragma alloc_text(PAGE, IopDumpCmResourceDescriptor)
  634. #pragma alloc_text(PAGE, IopDumpCmResourceList)
  635. #endif // DBG_SCOPE
  636. #endif // ALLOC_PRAGMA
  637. //
  638. // External references
  639. //
  640. extern const WCHAR IopWstrTranslated[];
  641. extern const WCHAR IopWstrRaw[];
  642. //
  643. // GLOBAL variables
  644. //
  645. PIOP_RESOURCE_REQUEST PiAssignTable;
  646. ULONG PiAssignTableCount;
  647. PDEVICE_NODE IopLegacyDeviceNode; // Head of list of made-up
  648. // devicenodes used for legacy
  649. // allocation.
  650. // IoAssignResources &
  651. // IoReportResourceUsage
  652. #if DBG_SCOPE
  653. ULONG
  654. PnpResDebugTranslationFailureCount = 32; // get count in both this line and the next.
  655. PNPRESDEBUGTRANSLATIONFAILURE
  656. PnpResDebugTranslationFailureArray[32];
  657. PNPRESDEBUGTRANSLATIONFAILURE
  658. *PnpResDebugTranslationFailure = PnpResDebugTranslationFailureArray;
  659. ULONG IopUseTimeout = 0;
  660. #endif // DBG_SCOPE
  661. NTSTATUS
  662. IopAllocateResources(
  663. IN PULONG RequestCount,
  664. IN OUT PIOP_RESOURCE_REQUEST *Request,
  665. IN BOOLEAN ResourceManagerLocked,
  666. IN BOOLEAN DoBootConfigs,
  667. OUT PBOOLEAN RebalancePerformed
  668. )
  669. /*++
  670. Routine Description:
  671. For each AssignTable entry, this routine queries device's IO resource requirements
  672. list and converts it to our internal REQ_LIST format; calls worker routine to perform
  673. the resources assignment.
  674. Parameters:
  675. AssignTable - supplies a pointer to the first entry of a IOP_RESOURCE_REQUEST table.
  676. AssignTableEnd - supplies a pointer to the end of IOP_RESOURCE_REQUEST table.
  677. Locked - Indicates whether the PpRegistrySemaphore is acquired by the caller.
  678. DoBootConfigs - Indicates whether we should assign BOOT configs.
  679. Return Value:
  680. Status code that indicates whether or not the function was successful.
  681. --*/
  682. {
  683. NTSTATUS status;
  684. PIOP_RESOURCE_REQUEST requestTable;
  685. PIOP_RESOURCE_REQUEST requestTableEnd;
  686. ULONG deviceCount;
  687. BOOLEAN attemptRebalance;
  688. PIOP_RESOURCE_REQUEST requestEntry;
  689. LIST_ENTRY activeArbiterList;
  690. PAGED_CODE();
  691. //
  692. // Lock the resource manager if the caller has not locked already.
  693. // This is to serialize allocations and releases of resources from the
  694. // arbiters.
  695. //
  696. if (!ResourceManagerLocked) {
  697. IopLockResourceManager();
  698. }
  699. requestTable = *Request;
  700. requestTableEnd = requestTable + (deviceCount = *RequestCount);
  701. status = IopGetResourceRequirementsForAssignTable(requestTable, requestTableEnd, &deviceCount);
  702. if (deviceCount) {
  703. attemptRebalance = ((*RequestCount == 1) && (requestTable->Flags & IOP_ASSIGN_NO_REBALANCE))? FALSE : TRUE;
  704. if (DoBootConfigs) {
  705. if (!IopBootConfigsReserved) {
  706. //
  707. // Process devices with boot config. If there are none, process others.
  708. //
  709. for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
  710. PDEVICE_NODE deviceNode;
  711. deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
  712. if (deviceNode->Flags & DNF_HAS_BOOT_CONFIG) {
  713. break;
  714. }
  715. }
  716. if (requestEntry != requestTableEnd) {
  717. //
  718. // There is at least one device with boot config.
  719. //
  720. for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
  721. PDEVICE_NODE deviceNode;
  722. deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
  723. if ( !(requestEntry->Flags & IOP_ASSIGN_IGNORE) &&
  724. !(deviceNode->Flags & DNF_HAS_BOOT_CONFIG) &&
  725. requestEntry->ResourceRequirements) {
  726. IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "Delaying non BOOT config device %wZ...\n", &deviceNode->InstancePath));
  727. requestEntry->Flags |= IOP_ASSIGN_IGNORE;
  728. requestEntry->Status = STATUS_RETRY;
  729. deviceCount--;
  730. }
  731. }
  732. }
  733. }
  734. if (deviceCount) {
  735. if (deviceCount != (*RequestCount)) {
  736. //
  737. // Move the uninteresting devices to the end of the table.
  738. //
  739. for (requestEntry = requestTable; requestEntry < requestTableEnd; ) {
  740. IOP_RESOURCE_REQUEST temp;
  741. if (!(requestEntry->Flags & IOP_ASSIGN_IGNORE)) {
  742. requestEntry++;
  743. continue;
  744. }
  745. temp = *requestEntry;
  746. *requestEntry = *(requestTableEnd - 1);
  747. *(requestTableEnd - 1) = temp;
  748. requestTableEnd--;
  749. }
  750. }
  751. ASSERT((ULONG)(requestTableEnd - requestTable) == deviceCount);
  752. //
  753. // Sort the AssignTable
  754. //
  755. IopRearrangeAssignTable(requestTable, deviceCount);
  756. //
  757. // Try one device at a time.
  758. //
  759. for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
  760. PDEVICE_NODE deviceNode;
  761. deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
  762. IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "Trying to allocate resources for %ws.\n", deviceNode->InstancePath.Buffer));
  763. status = IopFindBestConfiguration(requestEntry, 1, &activeArbiterList);
  764. if (NT_SUCCESS(status)) {
  765. //
  766. // Ask the arbiters to commit this configuration.
  767. //
  768. status = IopCommitConfiguration(&activeArbiterList);
  769. if (NT_SUCCESS(status)) {
  770. IopBuildCmResourceLists(requestEntry, requestEntry + 1);
  771. break;
  772. } else {
  773. requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
  774. }
  775. } else if (status == STATUS_INSUFFICIENT_RESOURCES) {
  776. IopDbgPrint((
  777. IOP_RESOURCE_WARNING_LEVEL,
  778. "IopAllocateResource: Failed to allocate Pool.\n"));
  779. break;
  780. } else if (attemptRebalance) {
  781. IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "IopAllocateResources: Initiating REBALANCE...\n"));
  782. deviceNode->Flags |= DNF_NEEDS_REBALANCE;
  783. status = IopRebalance(1, requestEntry);
  784. deviceNode->Flags &= ~DNF_NEEDS_REBALANCE;
  785. if (!NT_SUCCESS(status)) {
  786. requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
  787. } else if (RebalancePerformed) {
  788. *RebalancePerformed = TRUE;
  789. break;
  790. }
  791. } else {
  792. requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
  793. }
  794. }
  795. //
  796. // If we ran out of memory, then set the appropriate status
  797. // on remaining devices. On success, set STATUS_RETRY on the
  798. // rest so we will attempt allocation again after the current
  799. // device is started.
  800. //
  801. if (NT_SUCCESS(status)) {
  802. requestEntry++;
  803. }
  804. for (; requestEntry < requestTableEnd; requestEntry++) {
  805. if (status == STATUS_INSUFFICIENT_RESOURCES) {
  806. requestEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
  807. } else {
  808. requestEntry->Status = STATUS_RETRY;
  809. requestEntry->Flags |= IOP_ASSIGN_IGNORE;
  810. }
  811. }
  812. for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
  813. if (requestEntry->Flags & (IOP_ASSIGN_IGNORE | IOP_ASSIGN_RETRY)) {
  814. continue;
  815. }
  816. if ( requestEntry->Status == STATUS_SUCCESS &&
  817. requestEntry->AllocationType == ArbiterRequestPnpEnumerated) {
  818. IopReleaseFilteredBootResources(requestEntry, requestEntry + 1);
  819. }
  820. if ((requestEntry->Flags & IOP_ASSIGN_EXCLUDE) || requestEntry->ResourceAssignment == NULL) {
  821. requestEntry->Status = STATUS_CONFLICTING_ADDRESSES;
  822. }
  823. }
  824. } else {
  825. status = STATUS_UNSUCCESSFUL;
  826. }
  827. } else {
  828. //
  829. // Only process devices with no requirements.
  830. //
  831. for (requestEntry = requestTable; requestEntry < requestTableEnd; requestEntry++) {
  832. PDEVICE_NODE deviceNode;
  833. deviceNode = PP_DO_TO_DN(requestEntry->PhysicalDevice);
  834. if (NT_SUCCESS(requestEntry->Status) && requestEntry->ResourceRequirements == NULL) {
  835. IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "IopAllocateResources: Processing no resource requiring device %wZ\n", &deviceNode->InstancePath));
  836. } else {
  837. IopDbgPrint((IOP_RESOURCE_INFO_LEVEL, "IopAllocateResources: Ignoring resource consuming device %wZ\n", &deviceNode->InstancePath));
  838. requestEntry->Flags |= IOP_ASSIGN_IGNORE;
  839. requestEntry->Status = STATUS_RETRY;
  840. }
  841. }
  842. }
  843. IopFreeResourceRequirementsForAssignTable(requestTable, requestTableEnd);
  844. }
  845. if (!ResourceManagerLocked) {
  846. IopUnlockResourceManager();
  847. }
  848. return status;
  849. }
  850. NTSTATUS
  851. IopReleaseDeviceResources (
  852. IN PDEVICE_NODE DeviceNode,
  853. IN BOOLEAN ReserveResources
  854. )
  855. /*++
  856. Routine Description:
  857. This routine releases the resources assigned to a device.
  858. Arguments:
  859. DeviceNode - Device whose resources are to be released.
  860. ReserveResources - TRUE specifies that the BOOT config needs to be
  861. reserved (after re-query).
  862. Return Value:
  863. Final status code.
  864. --*/
  865. {
  866. NTSTATUS status;
  867. PCM_RESOURCE_LIST cmResource;
  868. ULONG cmLength;
  869. PAGED_CODE();
  870. if ( !DeviceNode->ResourceList &&
  871. !(DeviceNode->Flags & DNF_BOOT_CONFIG_RESERVED)) {
  872. return STATUS_SUCCESS;
  873. }
  874. cmResource = NULL;
  875. cmLength = 0;
  876. //
  877. // If needed, re-query for BOOT configs. We need to do this BEFORE we
  878. // release the BOOT config (otherwise ROOT devices cannot report BOOT
  879. // config).
  880. //
  881. if (ReserveResources && !(DeviceNode->Flags & DNF_MADEUP)) {
  882. //
  883. // First query for new BOOT config (order important for ROOT devices).
  884. //
  885. status = IopQueryDeviceResources(
  886. DeviceNode->PhysicalDeviceObject,
  887. QUERY_RESOURCE_LIST,
  888. &cmResource,
  889. &cmLength);
  890. if (!NT_SUCCESS(status)) {
  891. cmResource = NULL;
  892. cmLength = 0;
  893. }
  894. }
  895. //
  896. // Release resources for this device.
  897. //
  898. status = IopLegacyResourceAllocation(
  899. ArbiterRequestUndefined,
  900. IoPnpDriverObject,
  901. DeviceNode->PhysicalDeviceObject,
  902. NULL,
  903. NULL);
  904. if (!NT_SUCCESS(status)) {
  905. return status;
  906. }
  907. //
  908. // Request reallocation of resources for conflicting devices.
  909. //
  910. PipRequestDeviceAction(NULL, AssignResources, FALSE, 0, NULL, NULL);
  911. //
  912. // If needed, re-query and reserve current BOOT config for this device.
  913. // We always rereserve the boot config (ie DNF_MADEUP root enumerated
  914. // and IoReportDetected) devices in IopLegacyResourceAllocation.
  915. //
  916. if (ReserveResources && !(DeviceNode->Flags & DNF_MADEUP)) {
  917. UNICODE_STRING unicodeName;
  918. HANDLE logConfHandle;
  919. HANDLE handle;
  920. ASSERT(DeviceNode->BootResources == NULL);
  921. status = IopDeviceObjectToDeviceInstance(
  922. DeviceNode->PhysicalDeviceObject,
  923. &handle,
  924. KEY_ALL_ACCESS);
  925. logConfHandle = NULL;
  926. if (NT_SUCCESS(status)) {
  927. PiWstrToUnicodeString(&unicodeName, REGSTR_KEY_LOG_CONF);
  928. status = IopCreateRegistryKeyEx(
  929. &logConfHandle,
  930. handle,
  931. &unicodeName,
  932. KEY_ALL_ACCESS,
  933. REG_OPTION_NON_VOLATILE,
  934. NULL);
  935. ZwClose(handle);
  936. if (!NT_SUCCESS(status)) {
  937. logConfHandle = NULL;
  938. }
  939. }
  940. if (logConfHandle) {
  941. PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_BOOTCONFIG);
  942. PiLockPnpRegistry(FALSE);
  943. if (cmResource) {
  944. ZwSetValueKey(
  945. logConfHandle,
  946. &unicodeName,
  947. TITLE_INDEX_VALUE,
  948. REG_RESOURCE_LIST,
  949. cmResource,
  950. cmLength);
  951. } else {
  952. ZwDeleteValueKey(logConfHandle, &unicodeName);
  953. }
  954. PiUnlockPnpRegistry();
  955. ZwClose(logConfHandle);
  956. }
  957. //
  958. // Reserve any remaining BOOT config.
  959. //
  960. if (cmResource) {
  961. DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
  962. //
  963. // This device consumes BOOT resources. Reserve its boot resources
  964. //
  965. (*IopAllocateBootResourcesRoutine)(
  966. ArbiterRequestPnpEnumerated,
  967. DeviceNode->PhysicalDeviceObject,
  968. DeviceNode->BootResources = cmResource);
  969. }
  970. }
  971. return STATUS_SUCCESS;
  972. }
  973. NTSTATUS
  974. IopGetResourceRequirementsForAssignTable (
  975. IN PIOP_RESOURCE_REQUEST RequestTable,
  976. IN PIOP_RESOURCE_REQUEST RequestTableEnd,
  977. OUT PULONG DeviceCount
  978. )
  979. /*++
  980. Routine Description:
  981. This function gets resource requirements for entries in the request table.
  982. Parameters:
  983. RequestTable - Start of request table.
  984. RequestTableEnd - End of request table.
  985. DeviceCount - Gets number of devices with non-NULL requirements.
  986. Return Value:
  987. STATUS_SUCCESS if we got one non-NULL requirement, else STATUS_UNSUCCESSFUL.
  988. --*/
  989. {
  990. PIOP_RESOURCE_REQUEST request;
  991. NTSTATUS status;
  992. PDEVICE_NODE deviceNode;
  993. ULONG length;
  994. PAGED_CODE();
  995. *DeviceCount = 0;
  996. for ( request = RequestTable;
  997. request < RequestTableEnd;
  998. request++) {
  999. //
  1000. // Skip uninteresting entries.
  1001. //
  1002. request->ReqList = NULL;
  1003. if (request->Flags & IOP_ASSIGN_IGNORE) {
  1004. continue;
  1005. }
  1006. request->ResourceAssignment = NULL;
  1007. request->TranslatedResourceAssignment = NULL;
  1008. deviceNode = PP_DO_TO_DN(
  1009. request->PhysicalDevice);
  1010. if ( (deviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) &&
  1011. deviceNode->ResourceRequirements) {
  1012. ExFreePool(deviceNode->ResourceRequirements);
  1013. deviceNode->ResourceRequirements = NULL;
  1014. deviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED;
  1015. //
  1016. // Mark that caller needs to clear DNF_RESOURCE_REQUIREMENTS_CHANGED
  1017. // flag on success.
  1018. //
  1019. request->Flags |= IOP_ASSIGN_CLEAR_RESOURCE_REQUIREMENTS_CHANGE_FLAG;
  1020. }
  1021. if (!request->ResourceRequirements) {
  1022. if ( deviceNode->ResourceRequirements &&
  1023. !(deviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED)) {
  1024. IopDbgPrint(( IOP_RESOURCE_VERBOSE_LEVEL,
  1025. "Resource requirements list already exists for "
  1026. "%wZ\n",
  1027. &deviceNode->InstancePath));
  1028. request->ResourceRequirements = deviceNode->ResourceRequirements;
  1029. request->AllocationType = ArbiterRequestPnpEnumerated;
  1030. } else {
  1031. IopDbgPrint(( IOP_RESOURCE_INFO_LEVEL,
  1032. "Query Resource requirements list for %wZ...\n",
  1033. &deviceNode->InstancePath));
  1034. status = IopQueryDeviceResources(
  1035. request->PhysicalDevice,
  1036. QUERY_RESOURCE_REQUIREMENTS,
  1037. &request->ResourceRequirements,
  1038. &length);
  1039. if ( !NT_SUCCESS(status) ||
  1040. !request->ResourceRequirements) {
  1041. //
  1042. // Success with NULL ResourceRequirements means no resource
  1043. // required.
  1044. //
  1045. request->Flags |= IOP_ASSIGN_IGNORE;
  1046. request->Status = status;
  1047. continue;
  1048. }
  1049. if (deviceNode->ResourceRequirements) {
  1050. ExFreePool(deviceNode->ResourceRequirements);
  1051. deviceNode->Flags &= ~DNF_RESOURCE_REQUIREMENTS_NEED_FILTERED;
  1052. }
  1053. deviceNode->ResourceRequirements = request->ResourceRequirements;
  1054. }
  1055. }
  1056. //
  1057. // For non-stop case, even though the res req list has changed, we need
  1058. // to guarantee that it will get its current setting, even if the new
  1059. // requirements do not cover the current setting.
  1060. //
  1061. if (request->Flags & IOP_ASSIGN_KEEP_CURRENT_CONFIG) {
  1062. PIO_RESOURCE_REQUIREMENTS_LIST filteredList;
  1063. BOOLEAN exactMatch;
  1064. ASSERT(
  1065. deviceNode->ResourceRequirements ==
  1066. request->ResourceRequirements);
  1067. status = IopFilterResourceRequirementsList(
  1068. request->ResourceRequirements,
  1069. deviceNode->ResourceList,
  1070. &filteredList,
  1071. &exactMatch);
  1072. if (NT_SUCCESS(status)) {
  1073. //
  1074. // No need to free the original request->ResourceRequirements
  1075. // since its cached in deviceNode->ResourceRequirements.
  1076. //
  1077. request->ResourceRequirements = filteredList;
  1078. } else {
  1079. //
  1080. // Clear the flag so we dont free request->ResourceRequirements.
  1081. //
  1082. request->Flags &= ~IOP_ASSIGN_KEEP_CURRENT_CONFIG;
  1083. }
  1084. }
  1085. IopDumpResourceRequirementsList(request->ResourceRequirements);
  1086. //
  1087. // Convert the requirements list to our internal representation.
  1088. //
  1089. status = IopResourceRequirementsListToReqList(
  1090. request,
  1091. &request->ReqList);
  1092. if (NT_SUCCESS(status) && request->ReqList) {
  1093. PREQ_LIST reqList = (PREQ_LIST)request->ReqList;
  1094. //
  1095. // Sort the list such that higher priority alternatives are placed
  1096. // in the front of the list.
  1097. //
  1098. IopRearrangeReqList(reqList);
  1099. if (reqList->BestAlternative) {
  1100. //
  1101. // Requests from less flexible devices get higher priority.
  1102. //
  1103. request->Priority = (reqList->AlternativeCount < 3)?
  1104. 0 : reqList->AlternativeCount;
  1105. request->Status = status;
  1106. (*DeviceCount)++;
  1107. continue;
  1108. }
  1109. //
  1110. // This device has no soft configuration.
  1111. //
  1112. IopFreeResourceRequirementsForAssignTable(request, request + 1);
  1113. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  1114. }
  1115. request->Status = status;
  1116. request->Flags |= IOP_ASSIGN_IGNORE;
  1117. }
  1118. return (*DeviceCount)? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
  1119. }
  1120. NTSTATUS
  1121. IopResourceRequirementsListToReqList(
  1122. IN PIOP_RESOURCE_REQUEST Request,
  1123. OUT PVOID *ResReqList
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. This routine processes the input Io resource requirements list and
  1128. generates an internal REQ_LIST and its related structures.
  1129. Parameters:
  1130. IoResources - supplies a pointer to the Io resource requirements List.
  1131. PhysicalDevice - supplies a pointer to the physical device object requesting
  1132. the resources.
  1133. ReqList - supplies a pointer to a variable to receive the returned REQ_LIST.
  1134. Return Value:
  1135. Status code that indicates whether or not the function was successful.
  1136. --*/
  1137. {
  1138. PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
  1139. LONG ioResourceListCount;
  1140. PIO_RESOURCE_LIST ioResourceList;
  1141. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor;
  1142. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptorEnd;
  1143. PIO_RESOURCE_DESCRIPTOR firstDescriptor;
  1144. PUCHAR coreEnd;
  1145. BOOLEAN noAlternativeDescriptor;
  1146. ULONG reqDescAlternativeCount;
  1147. ULONG alternativeDescriptorCount;
  1148. ULONG reqAlternativeCount;
  1149. PREQ_LIST reqList;
  1150. INTERFACE_TYPE interfaceType;
  1151. ULONG busNumber;
  1152. NTSTATUS status;
  1153. NTSTATUS failureStatus;
  1154. NTSTATUS finalStatus;
  1155. PAGED_CODE();
  1156. *ResReqList = NULL;
  1157. //
  1158. // Make sure there is some resource requirement to be converted.
  1159. //
  1160. ioResources = Request->ResourceRequirements;
  1161. ioResourceListCount = (LONG)ioResources->AlternativeLists;
  1162. if (ioResourceListCount == 0) {
  1163. IopDbgPrint((
  1164. IOP_RESOURCE_INFO_LEVEL,
  1165. "No ResReqList to convert to ReqList\n"));
  1166. return STATUS_SUCCESS;
  1167. }
  1168. //
  1169. // ***** Phase 1 *****
  1170. //
  1171. // Parse the requirements list to validate it and determine the sizes of
  1172. // internal structures.
  1173. //
  1174. ioResourceList = ioResources->List;
  1175. coreEnd = (PUCHAR)ioResources + ioResources->ListSize;
  1176. reqDescAlternativeCount = 0;
  1177. alternativeDescriptorCount = 0;
  1178. while (--ioResourceListCount >= 0) {
  1179. ioResourceDescriptor = ioResourceList->Descriptors;
  1180. ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
  1181. if (ioResourceDescriptor == ioResourceDescriptorEnd) {
  1182. //
  1183. // An alternative list with zero descriptor count.
  1184. //
  1185. return STATUS_SUCCESS;
  1186. }
  1187. //
  1188. // Perform sanity check. On failure, simply return failure status.
  1189. //
  1190. if ( ioResourceDescriptor > ioResourceDescriptorEnd ||
  1191. (PUCHAR)ioResourceDescriptor > coreEnd ||
  1192. (PUCHAR)ioResourceDescriptorEnd > coreEnd) {
  1193. //
  1194. // The structure header is invalid (excluding the variable length
  1195. // Descriptors array) or,
  1196. // IoResourceDescriptorEnd is the result of arithmetic overflow or,
  1197. // the descriptor array is outside of the valid memory.
  1198. //
  1199. IopDbgPrint((IOP_RESOURCE_ERROR_LEVEL, "Invalid ResReqList\n"));
  1200. goto InvalidParameter;
  1201. }
  1202. if (ioResourceDescriptor->Type == CmResourceTypeConfigData) {
  1203. ioResourceDescriptor++;
  1204. }
  1205. firstDescriptor = ioResourceDescriptor;
  1206. noAlternativeDescriptor = TRUE;
  1207. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1208. switch (ioResourceDescriptor->Type) {
  1209. case CmResourceTypeConfigData:
  1210. IopDbgPrint((
  1211. IOP_RESOURCE_ERROR_LEVEL,
  1212. "Invalid ResReq list !!!\n"
  1213. "\tConfigData descriptors are per-LogConf and should be at "
  1214. "the beginning of an AlternativeList\n"));
  1215. goto InvalidParameter;
  1216. case CmResourceTypeDevicePrivate:
  1217. while ( ioResourceDescriptor < ioResourceDescriptorEnd &&
  1218. ioResourceDescriptor->Type == CmResourceTypeDevicePrivate) {
  1219. if (ioResourceDescriptor == firstDescriptor) {
  1220. IopDbgPrint((
  1221. IOP_RESOURCE_ERROR_LEVEL,
  1222. "Invalid ResReq list !!!\n"
  1223. "\tThe first descriptor of a LogConf can not be a "
  1224. "DevicePrivate descriptor.\n"));
  1225. goto InvalidParameter;
  1226. }
  1227. reqDescAlternativeCount++;
  1228. ioResourceDescriptor++;
  1229. }
  1230. noAlternativeDescriptor = TRUE;
  1231. break;
  1232. default:
  1233. reqDescAlternativeCount++;
  1234. //
  1235. // For non-arbitrated resource type, set its Option to preferred
  1236. // such that we won't get confused.
  1237. //
  1238. if ( (ioResourceDescriptor->Type & CmResourceTypeNonArbitrated) ||
  1239. ioResourceDescriptor->Type == CmResourceTypeNull) {
  1240. if (ioResourceDescriptor->Type == CmResourceTypeReserved) {
  1241. reqDescAlternativeCount--;
  1242. }
  1243. ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
  1244. ioResourceDescriptor++;
  1245. noAlternativeDescriptor = TRUE;
  1246. break;
  1247. }
  1248. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  1249. if (noAlternativeDescriptor) {
  1250. IopDbgPrint((
  1251. IOP_RESOURCE_ERROR_LEVEL,
  1252. "Invalid ResReq list !!!\n"
  1253. "\tAlternative descriptor without Default or "
  1254. "Preferred descriptor.\n"));
  1255. goto InvalidParameter;
  1256. }
  1257. alternativeDescriptorCount++;
  1258. } else {
  1259. noAlternativeDescriptor = FALSE;
  1260. }
  1261. ioResourceDescriptor++;
  1262. break;
  1263. }
  1264. }
  1265. ASSERT(ioResourceDescriptor == ioResourceDescriptorEnd);
  1266. ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd;
  1267. }
  1268. //
  1269. // ***** Phase 2 *****
  1270. //
  1271. // Allocate structures and initialize them according to caller's Io ResReq list.
  1272. //
  1273. {
  1274. ULONG reqDescCount;
  1275. IOP_POOL reqAlternativePool;
  1276. IOP_POOL reqDescPool;
  1277. ULONG reqListPoolSize;
  1278. ULONG reqAlternativePoolSize;
  1279. ULONG reqDescPoolSize;
  1280. PUCHAR poolStart;
  1281. ULONG poolSize;
  1282. IOP_POOL outerPool;
  1283. PREQ_ALTERNATIVE reqAlternative;
  1284. PPREQ_ALTERNATIVE reqAlternativePP;
  1285. ULONG reqAlternativeIndex;
  1286. PREQ_DESC reqDesc;
  1287. PREQ_DESC *reqDescPP;
  1288. ULONG reqDescIndex;
  1289. PARBITER_LIST_ENTRY arbiterListEntry;
  1290. #if DBG_SCOPE
  1291. PPREQ_ALTERNATIVE reqAlternativeEndPP;
  1292. #endif
  1293. failureStatus = STATUS_UNSUCCESSFUL;
  1294. finalStatus = STATUS_SUCCESS;
  1295. ioResourceList = ioResources->List;
  1296. ioResourceListCount = ioResources->AlternativeLists;
  1297. reqAlternativeCount = ioResourceListCount;
  1298. reqDescCount = reqDescAlternativeCount -
  1299. alternativeDescriptorCount;
  1300. reqDescPoolSize = reqDescCount * sizeof(REQ_DESC);
  1301. reqAlternativePoolSize = reqAlternativeCount *
  1302. (sizeof(REQ_ALTERNATIVE) +
  1303. (reqDescCount - 1) *
  1304. sizeof(PREQ_DESC));
  1305. reqListPoolSize = sizeof(REQ_LIST) +
  1306. (reqAlternativeCount - 1) *
  1307. sizeof(PREQ_ALTERNATIVE);
  1308. poolSize = reqListPoolSize + reqAlternativePoolSize + reqDescPoolSize;
  1309. if (!(poolStart = ExAllocatePoolRD(PagedPool | POOL_COLD_ALLOCATION, poolSize))) {
  1310. return STATUS_INSUFFICIENT_RESOURCES;
  1311. }
  1312. //
  1313. // Initialize the main pool.
  1314. //
  1315. IopInitPool(&outerPool, poolStart, poolSize);
  1316. //
  1317. // First part of the pool is used by REQ_LIST.
  1318. //
  1319. IopAllocPool(&reqList, &outerPool, reqListPoolSize);
  1320. //
  1321. // Second part of the main pool is used by REQ_ALTERNATIVEs.
  1322. //
  1323. IopAllocPool(&poolStart, &outerPool, reqAlternativePoolSize);
  1324. IopInitPool(&reqAlternativePool, poolStart, reqAlternativePoolSize);
  1325. //
  1326. // Last part of the main pool is used by REQ_DESCs.
  1327. //
  1328. IopAllocPool(&poolStart, &outerPool, reqDescPoolSize);
  1329. IopInitPool(&reqDescPool, poolStart, reqDescPoolSize);
  1330. if (ioResources->InterfaceType == InterfaceTypeUndefined) {
  1331. interfaceType = PnpDefaultInterfaceType;
  1332. } else {
  1333. interfaceType = ioResources->InterfaceType;
  1334. }
  1335. busNumber = ioResources->BusNumber;
  1336. //
  1337. // Initialize REQ_LIST.
  1338. //
  1339. reqList->AlternativeCount = reqAlternativeCount;
  1340. reqList->Request = Request;
  1341. reqList->BusNumber = busNumber;
  1342. reqList->InterfaceType = interfaceType;
  1343. reqList->SelectedAlternative = NULL;
  1344. //
  1345. // Initialize memory for REQ_ALTERNATIVEs.
  1346. //
  1347. reqAlternativePP = reqList->AlternativeTable;
  1348. RtlZeroMemory(
  1349. reqAlternativePP,
  1350. reqAlternativeCount * sizeof(PREQ_ALTERNATIVE));
  1351. #if DBG_SCOPE
  1352. reqAlternativeEndPP = reqAlternativePP + reqAlternativeCount;
  1353. #endif
  1354. reqAlternativeIndex = 0;
  1355. while (--ioResourceListCount >= 0) {
  1356. ioResourceDescriptor = ioResourceList->Descriptors;
  1357. ioResourceDescriptorEnd = ioResourceDescriptor +
  1358. ioResourceList->Count;
  1359. IopAllocPool(
  1360. &reqAlternative,
  1361. &reqAlternativePool,
  1362. FIELD_OFFSET(REQ_ALTERNATIVE, DescTable));
  1363. ASSERT(reqAlternativePP < reqAlternativeEndPP);
  1364. *reqAlternativePP++ = reqAlternative;
  1365. reqAlternative->ReqList = reqList;
  1366. reqAlternative->ReqAlternativeIndex = reqAlternativeIndex++;
  1367. reqAlternative->DescCount = 0;
  1368. //
  1369. // First descriptor of CmResourceTypeConfigData contains priority
  1370. // information.
  1371. //
  1372. if (ioResourceDescriptor->Type == CmResourceTypeConfigData) {
  1373. reqAlternative->Priority = ioResourceDescriptor->u.ConfigData.Priority;
  1374. ioResourceDescriptor++;
  1375. } else {
  1376. reqAlternative->Priority = LCPRI_NORMAL;
  1377. }
  1378. reqDescPP = reqAlternative->DescTable;
  1379. reqDescIndex = 0;
  1380. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1381. if (ioResourceDescriptor->Type == CmResourceTypeReserved) {
  1382. interfaceType = ioResourceDescriptor->u.DevicePrivate.Data[0];
  1383. if (interfaceType == InterfaceTypeUndefined) {
  1384. interfaceType = PnpDefaultInterfaceType;
  1385. }
  1386. busNumber = ioResourceDescriptor->u.DevicePrivate.Data[1];
  1387. ioResourceDescriptor++;
  1388. } else {
  1389. //
  1390. // Allocate and initialize REQ_DESC.
  1391. //
  1392. IopAllocPool(&reqDesc, &reqDescPool, sizeof(REQ_DESC));
  1393. reqAlternative->DescCount++;
  1394. *reqDescPP++ = reqDesc;
  1395. reqDesc->ReqAlternative = reqAlternative;
  1396. reqDesc->TranslatedReqDesc = reqDesc;
  1397. reqDesc->ReqDescIndex = reqDescIndex++;
  1398. reqDesc->DevicePrivateCount = 0;
  1399. reqDesc->DevicePrivate = NULL;
  1400. reqDesc->InterfaceType = interfaceType;
  1401. reqDesc->BusNumber = busNumber;
  1402. reqDesc->ArbitrationRequired =
  1403. (ioResourceDescriptor->Type & CmResourceTypeNonArbitrated ||
  1404. ioResourceDescriptor->Type == CmResourceTypeNull)?
  1405. FALSE : TRUE;
  1406. //
  1407. // Allocate and initialize arbiter entry for this REQ_DESC.
  1408. //
  1409. IopAllocPool(&poolStart, &reqAlternativePool, sizeof(PVOID));
  1410. ASSERT((PREQ_DESC*)poolStart == (reqDescPP - 1));
  1411. arbiterListEntry = &reqDesc->AlternativeTable;
  1412. InitializeListHead(&arbiterListEntry->ListEntry);
  1413. arbiterListEntry->AlternativeCount = 0;
  1414. arbiterListEntry->Alternatives = ioResourceDescriptor;
  1415. arbiterListEntry->PhysicalDeviceObject = Request->PhysicalDevice;
  1416. arbiterListEntry->RequestSource = Request->AllocationType;
  1417. arbiterListEntry->WorkSpace = 0;
  1418. arbiterListEntry->InterfaceType = interfaceType;
  1419. arbiterListEntry->SlotNumber = ioResources->SlotNumber;
  1420. arbiterListEntry->BusNumber = ioResources->BusNumber;
  1421. arbiterListEntry->Assignment = &reqDesc->Allocation;
  1422. arbiterListEntry->Result = ArbiterResultUndefined;
  1423. arbiterListEntry->Flags =
  1424. (reqAlternative->Priority != LCPRI_BOOTCONFIG)?
  1425. 0 : ARBITER_FLAG_BOOT_CONFIG;
  1426. if (reqDesc->ArbitrationRequired) {
  1427. //
  1428. // The BestAlternativeTable and BestAllocation are not initialized.
  1429. // They will be initialized when needed.
  1430. //
  1431. // Initialize the Cm partial resource descriptor to NOT_ALLOCATED.
  1432. //
  1433. reqDesc->Allocation.Type = CmResourceTypeMaximum;
  1434. ASSERT((ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) == 0);
  1435. arbiterListEntry->AlternativeCount++;
  1436. ioResourceDescriptor++;
  1437. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1438. if (ioResourceDescriptor->Type == CmResourceTypeDevicePrivate) {
  1439. reqDesc->DevicePrivate = ioResourceDescriptor;
  1440. while ( ioResourceDescriptor < ioResourceDescriptorEnd &&
  1441. ioResourceDescriptor->Type == CmResourceTypeDevicePrivate) {
  1442. reqDesc->DevicePrivateCount++;
  1443. ioResourceDescriptor++;
  1444. }
  1445. break;
  1446. }
  1447. if (!(ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE)) {
  1448. break;
  1449. }
  1450. arbiterListEntry->AlternativeCount++;
  1451. ioResourceDescriptor++;
  1452. }
  1453. //
  1454. // Next query Arbiter and Translator interfaces for the
  1455. // resource descriptor.
  1456. //
  1457. status = IopSetupArbiterAndTranslators(reqDesc);
  1458. if (!NT_SUCCESS(status)) {
  1459. IopDbgPrint((
  1460. IOP_RESOURCE_ERROR_LEVEL, "Unable to setup "
  1461. "Arbiter and Translators\n"));
  1462. reqAlternativeIndex--;
  1463. reqAlternativePP--;
  1464. reqList->AlternativeCount--;
  1465. IopFreeReqAlternative(reqAlternative);
  1466. failureStatus = status;
  1467. break;
  1468. }
  1469. } else {
  1470. reqDesc->Allocation.Type = ioResourceDescriptor->Type;
  1471. reqDesc->Allocation.ShareDisposition =
  1472. ioResourceDescriptor->ShareDisposition;
  1473. reqDesc->Allocation.Flags = ioResourceDescriptor->Flags;
  1474. reqDesc->Allocation.u.DevicePrivate.Data[0] =
  1475. ioResourceDescriptor->u.DevicePrivate.Data[0];
  1476. reqDesc->Allocation.u.DevicePrivate.Data[1] =
  1477. ioResourceDescriptor->u.DevicePrivate.Data[1];
  1478. reqDesc->Allocation.u.DevicePrivate.Data[2] =
  1479. ioResourceDescriptor->u.DevicePrivate.Data[2];
  1480. ioResourceDescriptor++;
  1481. }
  1482. }
  1483. if (ioResourceDescriptor >= ioResourceDescriptorEnd) {
  1484. break;
  1485. }
  1486. }
  1487. ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd;
  1488. }
  1489. if (reqAlternativeIndex == 0) {
  1490. finalStatus = failureStatus;
  1491. IopFreeReqList(reqList);
  1492. }
  1493. }
  1494. if (finalStatus == STATUS_SUCCESS) {
  1495. *ResReqList = reqList;
  1496. }
  1497. return finalStatus;
  1498. InvalidParameter:
  1499. return STATUS_INVALID_PARAMETER;
  1500. }
  1501. int
  1502. __cdecl
  1503. IopCompareReqAlternativePriority (
  1504. const void *arg1,
  1505. const void *arg2
  1506. )
  1507. /*++
  1508. Routine Description:
  1509. This function is used in C run time sort. It compares the priority of
  1510. REQ_ALTERNATIVE in arg1 and arg2.
  1511. Parameters:
  1512. arg1 - LHS PREQ_ALTERNATIVE
  1513. arg2 - RHS PREQ_ALTERNATIVE
  1514. Return Value:
  1515. < 0 if arg1 < arg2
  1516. = 0 if arg1 = arg2
  1517. > 0 if arg1 > arg2
  1518. --*/
  1519. {
  1520. PREQ_ALTERNATIVE ra1 = *(PPREQ_ALTERNATIVE)arg1;
  1521. PREQ_ALTERNATIVE ra2 = *(PPREQ_ALTERNATIVE)arg2;
  1522. PAGED_CODE();
  1523. if (ra1->Priority == ra2->Priority) {
  1524. if (ra1->Position > ra2->Position) {
  1525. return 1;
  1526. } else if (ra1->Position < ra2->Position) {
  1527. return -1;
  1528. } else {
  1529. ASSERT(0);
  1530. if ((ULONG_PTR)ra1 < (ULONG_PTR)ra2) {
  1531. return -1;
  1532. } else {
  1533. return 1;
  1534. }
  1535. }
  1536. }
  1537. if (ra1->Priority > ra2->Priority) {
  1538. return 1;
  1539. } else {
  1540. return -1;
  1541. }
  1542. }
  1543. int
  1544. __cdecl
  1545. IopCompareResourceRequestPriority (
  1546. const void *arg1,
  1547. const void *arg2
  1548. )
  1549. /*++
  1550. This function is used in C run time sort. It compares the priority of
  1551. IOP_RESOURCE_REQUEST in arg1 and arg2.
  1552. Parameters:
  1553. arg1 - LHS PIOP_RESOURCE_REQUEST
  1554. arg2 - RHS PIOP_RESOURCE_REQUEST
  1555. Return Value:
  1556. < 0 if arg1 < arg2
  1557. = 0 if arg1 = arg2
  1558. > 0 if arg1 > arg2
  1559. --*/
  1560. {
  1561. PIOP_RESOURCE_REQUEST rr1 = (PIOP_RESOURCE_REQUEST)arg1;
  1562. PIOP_RESOURCE_REQUEST rr2 = (PIOP_RESOURCE_REQUEST)arg2;
  1563. PAGED_CODE();
  1564. if (rr1->Priority == rr2->Priority) {
  1565. if (rr1->Position > rr2->Position) {
  1566. return 1;
  1567. } else if (rr1->Position < rr2->Position) {
  1568. return -1;
  1569. } else {
  1570. ASSERT(0);
  1571. if ((ULONG_PTR)rr1 < (ULONG_PTR)rr2) {
  1572. return -1;
  1573. } else {
  1574. return 1;
  1575. }
  1576. }
  1577. }
  1578. if (rr1->Priority > rr2->Priority) {
  1579. return 1;
  1580. } else {
  1581. return -1;
  1582. }
  1583. }
  1584. VOID
  1585. IopRearrangeReqList (
  1586. IN PREQ_LIST ReqList
  1587. )
  1588. /*++
  1589. Routine Description:
  1590. This routine sorts the REQ_LIST in ascending priority order of
  1591. REQ_ALTERNATIVES.
  1592. Parameters:
  1593. ReqList - Pointer to the REQ_LIST to be sorted.
  1594. Return Value:
  1595. None.
  1596. --*/
  1597. {
  1598. PPREQ_ALTERNATIVE alternative;
  1599. PPREQ_ALTERNATIVE lastAlternative;
  1600. ULONG i;
  1601. PAGED_CODE();
  1602. if (ReqList->AlternativeCount > 1) {
  1603. for (i = 0; i < ReqList->AlternativeCount; i++) {
  1604. ReqList->AlternativeTable[i]->Position = i;
  1605. }
  1606. qsort(
  1607. (void *)ReqList->AlternativeTable,
  1608. ReqList->AlternativeCount,
  1609. sizeof(PREQ_ALTERNATIVE),
  1610. IopCompareReqAlternativePriority);
  1611. }
  1612. //
  1613. // Set the BestAlternative so that we try alternatives with
  1614. // priority <= LCPRI_LASTSOFTCONFIG.
  1615. //
  1616. alternative = &ReqList->AlternativeTable[0];
  1617. for ( lastAlternative = alternative + ReqList->AlternativeCount;
  1618. alternative < lastAlternative;
  1619. alternative++) {
  1620. if ((*alternative)->Priority > LCPRI_LASTSOFTCONFIG) {
  1621. break;
  1622. }
  1623. }
  1624. if (alternative == &ReqList->AlternativeTable[0]) {
  1625. PDEVICE_NODE deviceNode;
  1626. deviceNode = PP_DO_TO_DN(ReqList->Request->PhysicalDevice);
  1627. IopDbgPrint((
  1628. IOP_RESOURCE_WARNING_LEVEL,
  1629. "Invalid priorities in the logical configs for %wZ\n",
  1630. &deviceNode->InstancePath));
  1631. ReqList->BestAlternative = NULL;
  1632. } else {
  1633. ReqList->BestAlternative = alternative;
  1634. }
  1635. }
  1636. VOID
  1637. IopRearrangeAssignTable (
  1638. IN PIOP_RESOURCE_REQUEST RequestTable,
  1639. IN ULONG Count
  1640. )
  1641. /*++
  1642. Routine Description:
  1643. This routine sorts the resource requirements table in ascending priority
  1644. order.
  1645. Parameters:
  1646. RequestTable - Table of resources requests to be sorted.
  1647. Count - Length of the RequestTable.
  1648. Return Value:
  1649. None.
  1650. --*/
  1651. {
  1652. ULONG i;
  1653. PAGED_CODE();
  1654. if (Count > 1) {
  1655. if (PpCallerInitializesRequestTable == FALSE) {
  1656. for (i = 0; i < Count; i++) {
  1657. RequestTable[i].Position = i;
  1658. }
  1659. }
  1660. qsort(
  1661. (void *)RequestTable,
  1662. Count,
  1663. sizeof(IOP_RESOURCE_REQUEST),
  1664. IopCompareResourceRequestPriority);
  1665. }
  1666. }
  1667. VOID
  1668. IopBuildCmResourceList (
  1669. IN PIOP_RESOURCE_REQUEST AssignEntry
  1670. )
  1671. /*++
  1672. Routine Description:
  1673. This routine walks REQ_LIST of the AssignEntry to build a corresponding
  1674. Cm Resource lists. It also reports the resources to ResourceMap.
  1675. Parameters:
  1676. AssignEntry - Supplies a pointer to an IOP_ASSIGN_REQUEST structure
  1677. Return Value:
  1678. None. The ResourceAssignment in AssignEntry is initialized.
  1679. --*/
  1680. {
  1681. NTSTATUS status;
  1682. HANDLE resourceMapKey;
  1683. PDEVICE_OBJECT physicalDevice;
  1684. PREQ_LIST reqList = AssignEntry->ReqList;
  1685. PREQ_ALTERNATIVE reqAlternative;
  1686. PREQ_DESC reqDesc, reqDescx;
  1687. PIO_RESOURCE_DESCRIPTOR privateData;
  1688. ULONG count = 0, size, i;
  1689. PCM_RESOURCE_LIST cmResources, cmResourcesRaw;
  1690. PCM_FULL_RESOURCE_DESCRIPTOR cmFullResource, cmFullResourceRaw;
  1691. PCM_PARTIAL_RESOURCE_LIST cmPartialList, cmPartialListRaw;
  1692. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor, cmDescriptorRaw, assignment, tAssignment;
  1693. #if DBG_SCOPE
  1694. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptorEnd, cmDescriptorEndRaw;
  1695. #endif
  1696. PAGED_CODE();
  1697. //
  1698. // Determine the size of the CmResourceList
  1699. //
  1700. //
  1701. // Determine the size of the CmResourceList
  1702. //
  1703. reqAlternative = *reqList->SelectedAlternative;
  1704. for (i = 0; i < reqAlternative->DescCount; i++) {
  1705. reqDesc = reqAlternative->DescTable[i];
  1706. count += reqDesc->DevicePrivateCount + 1;
  1707. }
  1708. size = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (count - 1);
  1709. cmResources = (PCM_RESOURCE_LIST) ExAllocatePoolCMRL(PagedPool, size);
  1710. if (!cmResources) {
  1711. //
  1712. // If we can not find memory, the resources will not be committed by arbiter.
  1713. //
  1714. IopDbgPrint((
  1715. IOP_RESOURCE_WARNING_LEVEL,
  1716. "Not enough memory to build Translated CmResourceList\n"));
  1717. AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
  1718. AssignEntry->ResourceAssignment = NULL;
  1719. AssignEntry->TranslatedResourceAssignment = NULL;
  1720. return;
  1721. }
  1722. cmResourcesRaw = (PCM_RESOURCE_LIST) ExAllocatePoolCMRR(PagedPool, size);
  1723. if (!cmResourcesRaw) {
  1724. IopDbgPrint((
  1725. IOP_RESOURCE_WARNING_LEVEL,
  1726. "Not enough memory to build Raw CmResourceList\n"));
  1727. ExFreePool(cmResources);
  1728. AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
  1729. AssignEntry->ResourceAssignment = NULL;
  1730. AssignEntry->TranslatedResourceAssignment = NULL;
  1731. return;
  1732. }
  1733. cmResources->Count = 1;
  1734. cmFullResource = cmResources->List;
  1735. //
  1736. // The CmResourceList we build here does not distinguish the
  1737. // Interface Type on descriptor level. This should be fine because
  1738. // for IoReportResourceUsage we ignore the CmResourceList we build
  1739. // here.
  1740. //
  1741. cmFullResource->InterfaceType = reqList->InterfaceType;
  1742. cmFullResource->BusNumber = reqList->BusNumber;
  1743. cmPartialList = &cmFullResource->PartialResourceList;
  1744. cmPartialList->Version = 0;
  1745. cmPartialList->Revision = 0;
  1746. cmPartialList->Count = count;
  1747. cmDescriptor = cmPartialList->PartialDescriptors;
  1748. #if DBG_SCOPE
  1749. cmDescriptorEnd = cmDescriptor + count;
  1750. #endif
  1751. cmResourcesRaw->Count = 1;
  1752. cmFullResourceRaw = cmResourcesRaw->List;
  1753. cmFullResourceRaw->InterfaceType = reqList->InterfaceType;
  1754. cmFullResourceRaw->BusNumber = reqList->BusNumber;
  1755. cmPartialListRaw = &cmFullResourceRaw->PartialResourceList;
  1756. cmPartialListRaw->Version = 0;
  1757. cmPartialListRaw->Revision = 0;
  1758. cmPartialListRaw->Count = count;
  1759. cmDescriptorRaw = cmPartialListRaw->PartialDescriptors;
  1760. #if DBG_SCOPE
  1761. cmDescriptorEndRaw = cmDescriptorRaw + count;
  1762. #endif
  1763. for (i = 0; i < reqAlternative->DescCount; i++) {
  1764. reqDesc = reqAlternative->DescTable[i];
  1765. if (reqDesc->ArbitrationRequired) {
  1766. //
  1767. // Get raw assignment and copy it to our raw resource list
  1768. //
  1769. reqDescx = reqDesc->TranslatedReqDesc;
  1770. if (reqDescx->AlternativeTable.Result != ArbiterResultNullRequest) {
  1771. status = IopParentToRawTranslation(reqDescx);
  1772. if (!NT_SUCCESS(status)) {
  1773. IopDbgPrint((
  1774. IOP_RESOURCE_WARNING_LEVEL,
  1775. "Parent To Raw translation failed\n"));
  1776. ExFreePool(cmResources);
  1777. ExFreePool(cmResourcesRaw);
  1778. AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
  1779. AssignEntry->ResourceAssignment = NULL;
  1780. return;
  1781. }
  1782. assignment = reqDesc->AlternativeTable.Assignment;
  1783. } else {
  1784. assignment = reqDescx->AlternativeTable.Assignment;
  1785. }
  1786. *cmDescriptorRaw = *assignment;
  1787. cmDescriptorRaw++;
  1788. //
  1789. // Translate assignment and copy it to our translated resource list
  1790. //
  1791. if (reqDescx->AlternativeTable.Result != ArbiterResultNullRequest) {
  1792. status = IopChildToRootTranslation(
  1793. PP_DO_TO_DN(reqDesc->AlternativeTable.PhysicalDeviceObject),
  1794. reqDesc->InterfaceType,
  1795. reqDesc->BusNumber,
  1796. reqDesc->AlternativeTable.RequestSource,
  1797. &reqDesc->Allocation,
  1798. &tAssignment
  1799. );
  1800. if (!NT_SUCCESS(status)) {
  1801. IopDbgPrint((
  1802. IOP_RESOURCE_WARNING_LEVEL,
  1803. "Child to Root translation failed\n"));
  1804. ExFreePool(cmResources);
  1805. ExFreePool(cmResourcesRaw);
  1806. AssignEntry->Status = STATUS_INSUFFICIENT_RESOURCES;
  1807. AssignEntry->ResourceAssignment = NULL;
  1808. return;
  1809. }
  1810. *cmDescriptor = *tAssignment;
  1811. ExFreePool(tAssignment);
  1812. } else {
  1813. *cmDescriptor = *(reqDescx->AlternativeTable.Assignment);
  1814. }
  1815. cmDescriptor++;
  1816. } else {
  1817. *cmDescriptorRaw = reqDesc->Allocation;
  1818. *cmDescriptor = reqDesc->Allocation;
  1819. cmDescriptorRaw++;
  1820. cmDescriptor++;
  1821. }
  1822. //
  1823. // Next copy the device private descriptors to CmResourceLists
  1824. //
  1825. count = reqDesc->DevicePrivateCount;
  1826. privateData = reqDesc->DevicePrivate;
  1827. while (count != 0) {
  1828. cmDescriptor->Type = cmDescriptorRaw->Type = CmResourceTypeDevicePrivate;
  1829. cmDescriptor->ShareDisposition = cmDescriptorRaw->ShareDisposition =
  1830. CmResourceShareDeviceExclusive;
  1831. cmDescriptor->Flags = cmDescriptorRaw->Flags = privateData->Flags;
  1832. RtlMoveMemory(&cmDescriptorRaw->u.DevicePrivate,
  1833. &privateData->u.DevicePrivate,
  1834. sizeof(cmDescriptorRaw->u.DevicePrivate.Data)
  1835. );
  1836. RtlMoveMemory(&cmDescriptor->u.DevicePrivate,
  1837. &privateData->u.DevicePrivate,
  1838. sizeof(cmDescriptor->u.DevicePrivate.Data)
  1839. );
  1840. privateData++;
  1841. cmDescriptorRaw++;
  1842. cmDescriptor++;
  1843. count--;
  1844. ASSERT(cmDescriptorRaw <= cmDescriptorEndRaw);
  1845. ASSERT(cmDescriptor <= cmDescriptorEnd);
  1846. }
  1847. ASSERT(cmDescriptor <= cmDescriptorEnd);
  1848. ASSERT(cmDescriptorRaw <= cmDescriptorEndRaw);
  1849. }
  1850. //
  1851. // report assigned resources to ResourceMap
  1852. //
  1853. physicalDevice = AssignEntry->PhysicalDevice;
  1854. //
  1855. // Open ResourceMap key
  1856. //
  1857. status = IopCreateRegistryKeyEx( &resourceMapKey,
  1858. (HANDLE) NULL,
  1859. &CmRegistryMachineHardwareResourceMapName,
  1860. KEY_READ | KEY_WRITE,
  1861. REG_OPTION_VOLATILE,
  1862. NULL
  1863. );
  1864. if (NT_SUCCESS(status )) {
  1865. WCHAR DeviceBuffer[256];
  1866. POBJECT_NAME_INFORMATION NameInformation;
  1867. ULONG NameLength;
  1868. UNICODE_STRING UnicodeClassName;
  1869. UNICODE_STRING UnicodeDriverName;
  1870. UNICODE_STRING UnicodeDeviceName;
  1871. PiWstrToUnicodeString(&UnicodeClassName, PNPMGR_STR_PNP_MANAGER);
  1872. PiWstrToUnicodeString(&UnicodeDriverName, REGSTR_KEY_PNP_DRIVER);
  1873. NameInformation = (POBJECT_NAME_INFORMATION) DeviceBuffer;
  1874. status = ObQueryNameString( physicalDevice,
  1875. NameInformation,
  1876. sizeof( DeviceBuffer ),
  1877. &NameLength );
  1878. if (NT_SUCCESS(status)) {
  1879. NameInformation->Name.MaximumLength = sizeof(DeviceBuffer) - sizeof(OBJECT_NAME_INFORMATION);
  1880. if (NameInformation->Name.Length == 0) {
  1881. NameInformation->Name.Buffer = (PVOID)((ULONG_PTR)DeviceBuffer + sizeof(OBJECT_NAME_INFORMATION));
  1882. }
  1883. UnicodeDeviceName = NameInformation->Name;
  1884. RtlAppendUnicodeToString(&UnicodeDeviceName, IopWstrRaw);
  1885. //
  1886. // IopWriteResourceList should remove all the device private and device
  1887. // specifiec descriptors.
  1888. //
  1889. status = IopWriteResourceList(
  1890. resourceMapKey,
  1891. &UnicodeClassName,
  1892. &UnicodeDriverName,
  1893. &UnicodeDeviceName,
  1894. cmResourcesRaw,
  1895. size
  1896. );
  1897. if (NT_SUCCESS(status)) {
  1898. UnicodeDeviceName = NameInformation->Name;
  1899. RtlAppendUnicodeToString (&UnicodeDeviceName, IopWstrTranslated);
  1900. status = IopWriteResourceList(
  1901. resourceMapKey,
  1902. &UnicodeClassName,
  1903. &UnicodeDriverName,
  1904. &UnicodeDeviceName,
  1905. cmResources,
  1906. size
  1907. );
  1908. }
  1909. }
  1910. ZwClose(resourceMapKey);
  1911. }
  1912. #if 0 // Ignore the registry writing status.
  1913. if (!NT_SUCCESS(status)) {
  1914. ExFreePool(cmResources);
  1915. ExFreePool(cmResourcesRaw);
  1916. cmResources = NULL;
  1917. cmResourcesRaw = NULL;
  1918. }
  1919. #endif
  1920. AssignEntry->ResourceAssignment = cmResourcesRaw;
  1921. AssignEntry->TranslatedResourceAssignment = cmResources;
  1922. }
  1923. VOID
  1924. IopBuildCmResourceLists(
  1925. IN PIOP_RESOURCE_REQUEST AssignTable,
  1926. IN PIOP_RESOURCE_REQUEST AssignTableEnd
  1927. )
  1928. /*++
  1929. Routine Description:
  1930. For each AssignTable entry, this routine queries device's IO resource requirements
  1931. list and converts it to our internal REQ_LIST format.
  1932. Parameters:
  1933. AssignTable - supplies a pointer to the first entry of a IOP_RESOURCE_REQUEST table.
  1934. AssignTableEnd - supplies a pointer to the end of IOP_RESOURCE_REQUEST table.
  1935. Return Value:
  1936. Status code that indicates whether or not the function was successful.
  1937. --*/
  1938. {
  1939. PIOP_RESOURCE_REQUEST assignEntry;
  1940. PDEVICE_OBJECT physicalDevice;
  1941. PDEVICE_NODE deviceNode;
  1942. PAGED_CODE();
  1943. //
  1944. // Go thru each entry, for each Physical device object, we build a CmResourceList
  1945. // from its ListOfAssignedResources.
  1946. //
  1947. for (assignEntry = AssignTable; assignEntry < AssignTableEnd; ++assignEntry) {
  1948. assignEntry->ResourceAssignment = NULL;
  1949. if (assignEntry->Flags & IOP_ASSIGN_IGNORE || assignEntry->Flags & IOP_ASSIGN_RETRY) {
  1950. continue;
  1951. }
  1952. if (assignEntry->Flags & IOP_ASSIGN_EXCLUDE) {
  1953. assignEntry->Status = STATUS_UNSUCCESSFUL;
  1954. continue;
  1955. }
  1956. assignEntry->Status = STATUS_SUCCESS;
  1957. IopBuildCmResourceList (assignEntry);
  1958. if (assignEntry->ResourceAssignment) {
  1959. physicalDevice = assignEntry->PhysicalDevice;
  1960. deviceNode = PP_DO_TO_DN(physicalDevice);
  1961. IopWriteAllocatedResourcesToRegistry(
  1962. deviceNode,
  1963. assignEntry->ResourceAssignment,
  1964. IopDetermineResourceListSize(assignEntry->ResourceAssignment)
  1965. );
  1966. IopDbgPrint((
  1967. IOP_RESOURCE_INFO_LEVEL,
  1968. "Building CM resource lists for %ws...\n",
  1969. deviceNode->InstancePath.Buffer));
  1970. IopDbgPrint((
  1971. IOP_RESOURCE_INFO_LEVEL,
  1972. "Raw resources "));
  1973. IopDumpCmResourceList(assignEntry->ResourceAssignment);
  1974. IopDbgPrint((
  1975. IOP_RESOURCE_INFO_LEVEL,
  1976. "Translated resources "));
  1977. IopDumpCmResourceList(assignEntry->TranslatedResourceAssignment);
  1978. }
  1979. }
  1980. }
  1981. BOOLEAN
  1982. IopNeedToReleaseBootResources(
  1983. IN PDEVICE_NODE DeviceNode,
  1984. IN PCM_RESOURCE_LIST AllocatedResources
  1985. )
  1986. /*++
  1987. Routine Description:
  1988. This routine checks the AllocatedResources against boot allocated resources.
  1989. If the allocated resources do not cover all the resource types in boot resources,
  1990. in another words some types of boot resources have not been released by arbiter,
  1991. we will return TRUE to indicate we need to release the boot resources manually.
  1992. Parameters:
  1993. DeviceNode - A device node
  1994. AllocatedResources - the resources assigned to the devicenode by arbiters.
  1995. Return Value:
  1996. TRUE or FALSE.
  1997. --*/
  1998. {
  1999. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc_a, cmFullDesc_b;
  2000. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor_a, cmDescriptor_b;
  2001. ULONG size_a, size_b, i, j, k;
  2002. BOOLEAN returnValue = FALSE, found;
  2003. PCM_RESOURCE_LIST bootResources;
  2004. PAGED_CODE();
  2005. bootResources = DeviceNode->BootResources;
  2006. if (AllocatedResources->Count == 1 && bootResources && bootResources->Count != 0) {
  2007. cmFullDesc_a = &AllocatedResources->List[0];
  2008. cmFullDesc_b = &bootResources->List[0];
  2009. for (i = 0; i < bootResources->Count; i++) {
  2010. cmDescriptor_b = &cmFullDesc_b->PartialResourceList.PartialDescriptors[0];
  2011. for (j = 0; j < cmFullDesc_b->PartialResourceList.Count; j++) {
  2012. size_b = 0;
  2013. switch (cmDescriptor_b->Type) {
  2014. case CmResourceTypeNull:
  2015. break;
  2016. case CmResourceTypeDeviceSpecific:
  2017. size_b = cmDescriptor_b->u.DeviceSpecificData.DataSize;
  2018. break;
  2019. default:
  2020. if (cmDescriptor_b->Type < CmResourceTypeMaximum) {
  2021. found = FALSE;
  2022. cmDescriptor_a = &cmFullDesc_a->PartialResourceList.PartialDescriptors[0];
  2023. for (k = 0; k < cmFullDesc_a->PartialResourceList.Count; k++) {
  2024. size_a = 0;
  2025. if (cmDescriptor_a->Type == CmResourceTypeDeviceSpecific) {
  2026. size_a = cmDescriptor_a->u.DeviceSpecificData.DataSize;
  2027. } else if (cmDescriptor_b->Type == cmDescriptor_a->Type) {
  2028. found = TRUE;
  2029. break;
  2030. }
  2031. cmDescriptor_a++;
  2032. cmDescriptor_a = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor_a + size_a);
  2033. }
  2034. if (found == FALSE) {
  2035. returnValue = TRUE;
  2036. goto exit;
  2037. }
  2038. }
  2039. }
  2040. cmDescriptor_b++;
  2041. cmDescriptor_b = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor_b + size_b);
  2042. }
  2043. cmFullDesc_b = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor_b;
  2044. }
  2045. }
  2046. exit:
  2047. return returnValue;
  2048. }
  2049. VOID
  2050. IopReleaseFilteredBootResources(
  2051. IN PIOP_RESOURCE_REQUEST AssignTable,
  2052. IN PIOP_RESOURCE_REQUEST AssignTableEnd
  2053. )
  2054. /*++
  2055. Routine Description:
  2056. For each AssignTable entry, this routine checks if we need to manually release the device's
  2057. boot resources.
  2058. Parameters:
  2059. AssignTable - supplies a pointer to the first entry of a IOP_RESOURCE_REQUEST table.
  2060. AssignTableEnd - supplies a pointer to the end of IOP_RESOURCE_REQUEST table.
  2061. Return Value:
  2062. None.
  2063. --*/
  2064. {
  2065. NTSTATUS status;
  2066. PIOP_RESOURCE_REQUEST assignEntry;
  2067. PDEVICE_OBJECT physicalDevice;
  2068. PDEVICE_NODE deviceNode;
  2069. PAGED_CODE();
  2070. //
  2071. // Go thru each entry, for each Physical device object, we build a CmResourceList
  2072. // from its ListOfAssignedResources.
  2073. //
  2074. for (assignEntry = AssignTable; assignEntry < AssignTableEnd; ++assignEntry) {
  2075. if (assignEntry->ResourceAssignment) {
  2076. physicalDevice = assignEntry->PhysicalDevice;
  2077. deviceNode = PP_DO_TO_DN(physicalDevice);
  2078. //
  2079. // Release the device's boot resources if desired
  2080. // (If a driver filters its res req list and removes some boot resources, after arbiter satisfies
  2081. // the new res req list, the filtered out boot resources do not get
  2082. // released by arbiters. Because they no longer passed to arbiters. )
  2083. // I am not 100% sure we should release the filtered boot resources. But that's what arbiters try
  2084. // to achieve. So, we will do it.
  2085. //
  2086. if (IopNeedToReleaseBootResources(deviceNode, assignEntry->ResourceAssignment)) {
  2087. IopReleaseResourcesInternal(deviceNode);
  2088. //
  2089. // Since we released some resources, try to satisfy devices
  2090. // with resource conflict.
  2091. //
  2092. PipRequestDeviceAction(NULL, AssignResources, FALSE, 0, NULL, NULL);
  2093. IopAllocateBootResourcesInternal(
  2094. ArbiterRequestPnpEnumerated,
  2095. physicalDevice,
  2096. assignEntry->ResourceAssignment);
  2097. deviceNode->Flags &= ~DNF_BOOT_CONFIG_RESERVED; // Keep DeviceNode->BootResources
  2098. deviceNode->ResourceList = assignEntry->ResourceAssignment;
  2099. status = IopRestoreResourcesInternal(deviceNode);
  2100. if (!NT_SUCCESS(status)) {
  2101. IopDbgPrint((
  2102. IOP_RESOURCE_WARNING_LEVEL,
  2103. "Possible boot conflict on %ws\n",
  2104. deviceNode->InstancePath.Buffer));
  2105. ASSERT(status == STATUS_SUCCESS);
  2106. assignEntry->Flags = IOP_ASSIGN_EXCLUDE;
  2107. assignEntry->Status = status;
  2108. ExFreePool(assignEntry->ResourceAssignment);
  2109. assignEntry->ResourceAssignment = NULL;
  2110. }
  2111. deviceNode->ResourceList = NULL;
  2112. }
  2113. }
  2114. }
  2115. }
  2116. NTSTATUS
  2117. IopSetupArbiterAndTranslators(
  2118. IN PREQ_DESC ReqDesc
  2119. )
  2120. /*++
  2121. Routine Description:
  2122. This routine searches the arbiter and translators which arbitrates and translate
  2123. the resources for the specified device. This routine tries to find all the
  2124. translator on the path of current device node to root device node
  2125. Parameters:
  2126. ReqDesc - supplies a pointer to REQ_DESC which contains all the required information
  2127. Return Value:
  2128. NTSTATUS value to indicate success or failure.
  2129. --*/
  2130. {
  2131. PLIST_ENTRY listHead;
  2132. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  2133. PDEVICE_OBJECT deviceObject = ReqDesc->AlternativeTable.PhysicalDeviceObject;
  2134. PDEVICE_NODE deviceNode;
  2135. PREQ_DESC reqDesc = ReqDesc, translatedReqDesc;
  2136. BOOLEAN found, arbiterFound = FALSE, restartedAlready;
  2137. BOOLEAN searchTranslator = TRUE, translatorFound = FALSE;
  2138. NTSTATUS status;
  2139. PPI_RESOURCE_TRANSLATOR_ENTRY translatorEntry;
  2140. UCHAR resourceType = ReqDesc->TranslatedReqDesc->AlternativeTable.Alternatives->Type;
  2141. PINTERFACE interface;
  2142. USHORT resourceMask;
  2143. if ((ReqDesc->AlternativeTable.RequestSource == ArbiterRequestHalReported) &&
  2144. (ReqDesc->InterfaceType == Internal)) {
  2145. // Trust hal if it says internal bus.
  2146. restartedAlready = TRUE;
  2147. } else {
  2148. restartedAlready = FALSE;
  2149. }
  2150. //
  2151. // If ReqDesc contains DeviceObject, this is for regular resources allocation
  2152. // or boot resources preallocation. Otherwise, it is for resources reservation.
  2153. //
  2154. if (deviceObject && ReqDesc->AlternativeTable.RequestSource != ArbiterRequestHalReported) {
  2155. deviceNode = PP_DO_TO_DN(deviceObject);
  2156. // We want to start with the deviceNode instead of its parent. Because the
  2157. // deviceNode may provide a translator interface.
  2158. // deviceNode = deviceNode->Parent;
  2159. } else {
  2160. //
  2161. // For resource reservation, we always need to find the arbiter and translators
  2162. // so set the device node to Root.
  2163. //
  2164. deviceNode = IopRootDeviceNode;
  2165. }
  2166. while (deviceNode) {
  2167. if ((deviceNode == IopRootDeviceNode) && (translatorFound == FALSE)) {
  2168. //
  2169. // If we reach the root and have not find any translator, the device is on the
  2170. // wrong way.
  2171. //
  2172. if (restartedAlready == FALSE) {
  2173. restartedAlready = TRUE;
  2174. deviceNode = IopFindLegacyBusDeviceNode (
  2175. ReqDesc->InterfaceType,
  2176. ReqDesc->BusNumber
  2177. );
  2178. //
  2179. // If we did not find a PDO, try again with InterfaceType == Isa. This allows
  2180. // drivers that request Internal to get resources even if there is no PDO
  2181. // that is Internal. (but if there is an Internal PDO, they get that one)
  2182. //
  2183. if ((deviceNode == IopRootDeviceNode) &&
  2184. (ReqDesc->ReqAlternative->ReqList->InterfaceType == Internal)) {
  2185. deviceNode = IopFindLegacyBusDeviceNode(
  2186. Isa,
  2187. 0
  2188. );
  2189. }
  2190. //if ((PVOID)deviceNode == deviceObject->DeviceObjectExtension->DeviceNode) {
  2191. // deviceNode = IopRootDeviceNode;
  2192. //} else {
  2193. continue;
  2194. //}
  2195. }
  2196. }
  2197. //
  2198. // Check is there an arbiter for the device node?
  2199. // if yes, set up ReqDesc->u.Arbiter and set ArbiterFound to true.
  2200. // else move up to the parent of current device node.
  2201. //
  2202. if ((arbiterFound == FALSE) && (deviceNode->PhysicalDeviceObject != deviceObject)) {
  2203. found = IopFindResourceHandlerInfo(
  2204. ResourceArbiter,
  2205. deviceNode,
  2206. resourceType,
  2207. &arbiterEntry);
  2208. if (found == FALSE) {
  2209. //
  2210. // no information found on arbiter. Try to query translator interface ...
  2211. //
  2212. if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
  2213. resourceMask = 1 << resourceType;
  2214. } else {
  2215. resourceMask = 0;
  2216. }
  2217. status = IopQueryResourceHandlerInterface(ResourceArbiter,
  2218. deviceNode->PhysicalDeviceObject,
  2219. resourceType,
  2220. &interface);
  2221. deviceNode->QueryArbiterMask |= resourceMask;
  2222. if (!NT_SUCCESS(status)) {
  2223. deviceNode->NoArbiterMask |= resourceMask;
  2224. if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
  2225. found = TRUE;
  2226. } else {
  2227. interface = NULL;
  2228. }
  2229. }
  2230. if (found == FALSE) {
  2231. arbiterEntry = (PPI_RESOURCE_ARBITER_ENTRY)ExAllocatePoolAE(
  2232. PagedPool | POOL_COLD_ALLOCATION,
  2233. sizeof(PI_RESOURCE_ARBITER_ENTRY));
  2234. if (!arbiterEntry) {
  2235. status = STATUS_INSUFFICIENT_RESOURCES;
  2236. return status;
  2237. }
  2238. IopInitializeArbiterEntryState(arbiterEntry);
  2239. InitializeListHead(&arbiterEntry->DeviceArbiterList);
  2240. arbiterEntry->ResourceType = resourceType;
  2241. arbiterEntry->Level = deviceNode->Level;
  2242. listHead = &deviceNode->DeviceArbiterList;
  2243. InsertTailList(listHead, &arbiterEntry->DeviceArbiterList);
  2244. arbiterEntry->ArbiterInterface = (PARBITER_INTERFACE)interface;
  2245. if (!interface) {
  2246. //
  2247. // if interface is NULL we really don't have translator.
  2248. //
  2249. arbiterEntry = NULL;
  2250. }
  2251. }
  2252. }
  2253. //
  2254. // If there is an desired resourcetype arbiter in the device node, make sure
  2255. // it handle this resource requriements.
  2256. //
  2257. if (arbiterEntry) {
  2258. arbiterFound = TRUE;
  2259. if (arbiterEntry->ArbiterInterface->Flags & ARBITER_PARTIAL) {
  2260. //
  2261. // If the arbiter is partial, ask if it handles the resources
  2262. // if not, goto its parent.
  2263. //
  2264. status = IopCallArbiter(
  2265. arbiterEntry,
  2266. ArbiterActionQueryArbitrate,
  2267. ReqDesc->TranslatedReqDesc,
  2268. NULL,
  2269. NULL
  2270. );
  2271. if (!NT_SUCCESS(status)) {
  2272. arbiterFound = FALSE;
  2273. }
  2274. }
  2275. }
  2276. if (arbiterFound) {
  2277. ReqDesc->u.Arbiter = arbiterEntry;
  2278. //
  2279. // Initialize the arbiter entry
  2280. //
  2281. arbiterEntry->State = 0;
  2282. arbiterEntry->ResourcesChanged = FALSE;
  2283. }
  2284. }
  2285. if (searchTranslator) {
  2286. //
  2287. // First, check if there is a translator for the device node?
  2288. // If yes, translate the req desc and link it to the front of ReqDesc->TranslatedReqDesc
  2289. // else do nothing.
  2290. //
  2291. found = IopFindResourceHandlerInfo(
  2292. ResourceTranslator,
  2293. deviceNode,
  2294. resourceType,
  2295. &translatorEntry);
  2296. if (found == FALSE) {
  2297. //
  2298. // no information found on translator. Try to query translator interface ...
  2299. //
  2300. if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
  2301. resourceMask = 1 << resourceType;
  2302. } else {
  2303. resourceMask = 0;
  2304. }
  2305. status = IopQueryResourceHandlerInterface(ResourceTranslator,
  2306. deviceNode->PhysicalDeviceObject,
  2307. resourceType,
  2308. &interface);
  2309. deviceNode->QueryTranslatorMask |= resourceMask;
  2310. if (!NT_SUCCESS(status)) {
  2311. deviceNode->NoTranslatorMask |= resourceMask;
  2312. if (resourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
  2313. found = TRUE;
  2314. } else {
  2315. interface = NULL;
  2316. }
  2317. }
  2318. if (found == FALSE) {
  2319. translatorEntry = (PPI_RESOURCE_TRANSLATOR_ENTRY)ExAllocatePoolTE(
  2320. PagedPool | POOL_COLD_ALLOCATION,
  2321. sizeof(PI_RESOURCE_TRANSLATOR_ENTRY));
  2322. if (!translatorEntry) {
  2323. status = STATUS_INSUFFICIENT_RESOURCES;
  2324. return status;
  2325. }
  2326. translatorEntry->ResourceType = resourceType;
  2327. InitializeListHead(&translatorEntry->DeviceTranslatorList);
  2328. translatorEntry->TranslatorInterface = (PTRANSLATOR_INTERFACE)interface;
  2329. translatorEntry->DeviceNode = deviceNode;
  2330. listHead = &deviceNode->DeviceTranslatorList;
  2331. InsertTailList(listHead, &translatorEntry->DeviceTranslatorList);
  2332. if (!interface) {
  2333. //
  2334. // if interface is NULL we really don't have translator.
  2335. //
  2336. translatorEntry = NULL;
  2337. }
  2338. }
  2339. }
  2340. if (translatorEntry) {
  2341. translatorFound = TRUE;
  2342. }
  2343. if ((arbiterFound == FALSE) && translatorEntry) {
  2344. //
  2345. // Find a translator to translate the req desc ... Translate it and link it to
  2346. // the front of ReqDesc->TranslatedReqDesc such that the first in the list is for
  2347. // the Arbiter to use.
  2348. //
  2349. reqDesc = ReqDesc->TranslatedReqDesc;
  2350. status = IopTranslateAndAdjustReqDesc(
  2351. reqDesc,
  2352. translatorEntry,
  2353. &translatedReqDesc);
  2354. if (NT_SUCCESS(status)) {
  2355. ASSERT(translatedReqDesc);
  2356. resourceType = translatedReqDesc->AlternativeTable.Alternatives->Type;
  2357. translatedReqDesc->TranslatedReqDesc = ReqDesc->TranslatedReqDesc;
  2358. ReqDesc->TranslatedReqDesc = translatedReqDesc;
  2359. //
  2360. // If the translator is non-hierarchial and performs a complete
  2361. // translation to root (eg ISA interrups for PCI devices) then
  2362. // don't pass translations to parent.
  2363. //
  2364. if (status == STATUS_TRANSLATION_COMPLETE) {
  2365. searchTranslator = FALSE;
  2366. }
  2367. } else {
  2368. IopDbgPrint((
  2369. IOP_RESOURCE_INFO_LEVEL,
  2370. "resreq list TranslationAndAdjusted failed\n"
  2371. ));
  2372. return status;
  2373. }
  2374. }
  2375. }
  2376. //
  2377. // Move up to current device node's parent
  2378. //
  2379. deviceNode = deviceNode->Parent;
  2380. }
  2381. if (arbiterFound) {
  2382. return STATUS_SUCCESS;
  2383. } else {
  2384. //
  2385. // We should BugCheck in this case.
  2386. //
  2387. IopDbgPrint((
  2388. IOP_RESOURCE_ERROR_LEVEL,
  2389. "can not find resource type %x arbiter\n",
  2390. resourceType));
  2391. ASSERT(arbiterFound);
  2392. return STATUS_RESOURCE_TYPE_NOT_FOUND;
  2393. }
  2394. }
  2395. VOID
  2396. IopUncacheInterfaceInformation (
  2397. IN PDEVICE_OBJECT DeviceObject
  2398. )
  2399. /*++
  2400. Routine Description:
  2401. This function removes all the cached translators and arbiters information
  2402. from the device object.
  2403. Parameters:
  2404. DeviceObject - Supplies the device object of the device being removed.
  2405. Return Value:
  2406. None.
  2407. --*/
  2408. {
  2409. PDEVICE_NODE deviceNode;
  2410. PLIST_ENTRY listHead;
  2411. PLIST_ENTRY nextEntry;
  2412. PLIST_ENTRY entry;
  2413. PPI_RESOURCE_TRANSLATOR_ENTRY translatorEntry;
  2414. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  2415. PINTERFACE interface;
  2416. deviceNode = PP_DO_TO_DN(DeviceObject);
  2417. //
  2418. // Dereference all the arbiters on this PDO.
  2419. //
  2420. listHead = &deviceNode->DeviceArbiterList;
  2421. nextEntry = listHead->Flink;
  2422. while (nextEntry != listHead) {
  2423. entry = nextEntry;
  2424. arbiterEntry = CONTAINING_RECORD(
  2425. entry,
  2426. PI_RESOURCE_ARBITER_ENTRY,
  2427. DeviceArbiterList);
  2428. interface = (PINTERFACE)arbiterEntry->ArbiterInterface;
  2429. if (interface != NULL) {
  2430. (interface->InterfaceDereference)(interface->Context);
  2431. ExFreePool(interface);
  2432. }
  2433. nextEntry = entry->Flink;
  2434. ExFreePool(entry);
  2435. }
  2436. //
  2437. // Dereference all the translators on this PDO.
  2438. //
  2439. listHead = &deviceNode->DeviceTranslatorList;
  2440. nextEntry = listHead->Flink;
  2441. while (nextEntry != listHead) {
  2442. entry = nextEntry;
  2443. translatorEntry = CONTAINING_RECORD(
  2444. entry,
  2445. PI_RESOURCE_TRANSLATOR_ENTRY,
  2446. DeviceTranslatorList);
  2447. interface = (PINTERFACE)translatorEntry->TranslatorInterface;
  2448. if (interface != NULL) {
  2449. (interface->InterfaceDereference)(interface->Context);
  2450. ExFreePool(interface);
  2451. }
  2452. nextEntry = entry->Flink;
  2453. ExFreePool(entry);
  2454. }
  2455. InitializeListHead(&deviceNode->DeviceArbiterList);
  2456. InitializeListHead(&deviceNode->DeviceTranslatorList);
  2457. deviceNode->NoArbiterMask = 0;
  2458. deviceNode->QueryArbiterMask = 0;
  2459. deviceNode->NoTranslatorMask = 0;
  2460. deviceNode->QueryTranslatorMask = 0;
  2461. }
  2462. BOOLEAN
  2463. IopFindResourceHandlerInfo (
  2464. IN RESOURCE_HANDLER_TYPE HandlerType,
  2465. IN PDEVICE_NODE DeviceNode,
  2466. IN UCHAR ResourceType,
  2467. OUT PVOID *HandlerEntry
  2468. )
  2469. /*++
  2470. Routine Description:
  2471. This routine finds the desired resource handler interface for the specified
  2472. resource type in the specified Device node.
  2473. Parameters:
  2474. HandlerType - Specifies the type of handler needed.
  2475. DeviceNode - Specifies the devicenode on which to search for handler.
  2476. ResourceType - Specifies the type of resource.
  2477. HandlerEntry - Supplies a pointer to a variable to receive the handler.
  2478. Return Value:
  2479. TRUE + non-NULL HandlerEntry : Found handler info and there is a handler
  2480. TRUE + NULL HandlerEntry : Found handler info but there is NO handler
  2481. FALSE + NULL HandlerEntry : No handler info found
  2482. --*/
  2483. {
  2484. USHORT resourceMask;
  2485. USHORT noHandlerMask;
  2486. USHORT queryHandlerMask;
  2487. PLIST_ENTRY listHead;
  2488. PLIST_ENTRY entry;
  2489. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  2490. *HandlerEntry = NULL;
  2491. switch (HandlerType) {
  2492. case ResourceArbiter:
  2493. noHandlerMask = DeviceNode->NoArbiterMask;
  2494. queryHandlerMask = DeviceNode->QueryArbiterMask;
  2495. listHead = &DeviceNode->DeviceArbiterList;
  2496. break;
  2497. case ResourceTranslator:
  2498. noHandlerMask = DeviceNode->NoTranslatorMask;
  2499. queryHandlerMask = DeviceNode->QueryTranslatorMask;
  2500. listHead = &DeviceNode->DeviceTranslatorList;
  2501. break;
  2502. default:
  2503. return FALSE;
  2504. }
  2505. resourceMask = 1 << ResourceType;
  2506. if (noHandlerMask & resourceMask) {
  2507. //
  2508. // There is no desired handler for the resource type.
  2509. //
  2510. return TRUE;
  2511. }
  2512. if ( (queryHandlerMask & resourceMask) ||
  2513. ResourceType > PI_MAXIMUM_RESOURCE_TYPE_TRACKED) {
  2514. entry = listHead->Flink;
  2515. while (entry != listHead) {
  2516. arbiterEntry = CONTAINING_RECORD(
  2517. entry,
  2518. PI_RESOURCE_ARBITER_ENTRY,
  2519. DeviceArbiterList);
  2520. if (arbiterEntry->ResourceType == ResourceType) {
  2521. if ( ResourceType <= PI_MAXIMUM_RESOURCE_TYPE_TRACKED ||
  2522. arbiterEntry->ArbiterInterface) {
  2523. *HandlerEntry = arbiterEntry;
  2524. }
  2525. return TRUE;
  2526. }
  2527. entry = entry->Flink;
  2528. }
  2529. if (queryHandlerMask & resourceMask) {
  2530. //
  2531. // There must be one.
  2532. //
  2533. ASSERT(entry != listHead);
  2534. }
  2535. }
  2536. return FALSE;
  2537. }
  2538. NTSTATUS
  2539. IopParentToRawTranslation(
  2540. IN OUT PREQ_DESC ReqDesc
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. This routine translates an CmPartialResourceDescriptors
  2545. from their translated form to their raw counterparts..
  2546. Parameters:
  2547. ReqDesc - supplies a translated ReqDesc to be translated back to its raw form
  2548. Return Value:
  2549. Status code that indicates whether or not the function was successful.
  2550. --*/
  2551. {
  2552. PTRANSLATOR_INTERFACE translator;
  2553. NTSTATUS status = STATUS_SUCCESS;
  2554. PREQ_DESC rawReqDesc;
  2555. if (ReqDesc->AlternativeTable.AlternativeCount == 0 ||
  2556. ReqDesc->Allocation.Type == CmResourceTypeMaximum) {
  2557. IopDbgPrint((
  2558. IOP_RESOURCE_ERROR_LEVEL,
  2559. "Invalid ReqDesc for parent-to-raw translation.\n"));
  2560. return STATUS_INVALID_PARAMETER;
  2561. }
  2562. //
  2563. // If this ReqDesc is the raw reqDesc then we are done.
  2564. // Else call its translator to translate the resource and leave the result
  2565. // in its raw (next level) reqdesc.
  2566. //
  2567. if (IS_TRANSLATED_REQ_DESC(ReqDesc)) {
  2568. rawReqDesc = ReqDesc->TranslatedReqDesc;
  2569. translator = ReqDesc->u.Translator->TranslatorInterface;
  2570. status = (translator->TranslateResources)(
  2571. translator->Context,
  2572. ReqDesc->AlternativeTable.Assignment,
  2573. TranslateParentToChild,
  2574. rawReqDesc->AlternativeTable.AlternativeCount,
  2575. rawReqDesc->AlternativeTable.Alternatives,
  2576. rawReqDesc->AlternativeTable.PhysicalDeviceObject,
  2577. rawReqDesc->AlternativeTable.Assignment
  2578. );
  2579. if (NT_SUCCESS(status)) {
  2580. //
  2581. // If the translator is non-hierarchial and performs a complete
  2582. // translation to root (eg ISA interrups for PCI devices) then
  2583. // don't pass translations to parent.
  2584. //
  2585. ASSERT(status != STATUS_TRANSLATION_COMPLETE);
  2586. status = IopParentToRawTranslation(rawReqDesc);
  2587. }
  2588. }
  2589. return status;
  2590. }
  2591. NTSTATUS
  2592. IopChildToRootTranslation(
  2593. IN PDEVICE_NODE DeviceNode, OPTIONAL
  2594. IN INTERFACE_TYPE InterfaceType,
  2595. IN ULONG BusNumber,
  2596. IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
  2597. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  2598. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *Target
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. This routine translates a CmPartialResourceDescriptors from
  2603. their intermediate translated form to their final translated form.
  2604. The translated CM_PARTIAL_RESOURCE_DESCRIPTOR is returned via Target variable.
  2605. The caller is responsible to release the translated descriptor.
  2606. Parameters:
  2607. DeviceNode - Specified the device object. If The DeviceNode is specified,
  2608. the InterfaceType and BusNumber are ignored and we will
  2609. use DeviceNode as a starting point to find various translators to
  2610. translate the Source descriptor. If DeviceNode is not specified,
  2611. the InterfaceType and BusNumber must be specified.
  2612. InterfaceType, BusNumber - must be supplied if DeviceNode is not specified.
  2613. Source - A pointer to the resource descriptor to be translated.
  2614. Target - Supplies an address to receive the translated resource descriptor.
  2615. Return Value:
  2616. Status code that indicates whether or not the function was successful.
  2617. --*/
  2618. {
  2619. PDEVICE_NODE deviceNode;
  2620. PLIST_ENTRY listHead, nextEntry;
  2621. PCM_PARTIAL_RESOURCE_DESCRIPTOR target, source, tmp;
  2622. PPI_RESOURCE_TRANSLATOR_ENTRY translatorEntry;
  2623. PTRANSLATOR_INTERFACE translator;
  2624. NTSTATUS status = STATUS_SUCCESS;
  2625. BOOLEAN done = FALSE, foundTranslator = FALSE, restartedAlready;
  2626. if (ArbiterRequestSource == ArbiterRequestHalReported) {
  2627. restartedAlready = TRUE;
  2628. } else {
  2629. restartedAlready = FALSE;
  2630. }
  2631. source = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ExAllocatePoolPRD(
  2632. PagedPool | POOL_COLD_ALLOCATION,
  2633. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  2634. );
  2635. if (source == NULL) {
  2636. return STATUS_INSUFFICIENT_RESOURCES;
  2637. }
  2638. target = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ExAllocatePoolPRD(
  2639. PagedPool,
  2640. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  2641. );
  2642. if (target == NULL) {
  2643. ExFreePool(source);
  2644. return STATUS_INSUFFICIENT_RESOURCES;
  2645. }
  2646. *source = *Source;
  2647. //
  2648. // Move up to current device node's parent to start translation
  2649. //
  2650. if (!ARGUMENT_PRESENT(DeviceNode)) {
  2651. deviceNode = IopFindLegacyBusDeviceNode (InterfaceType, BusNumber);
  2652. } else {
  2653. // We want to start with the deviceNode instead of its parent. Because the
  2654. // deviceNode may provide a translator interface.
  2655. deviceNode = DeviceNode;
  2656. }
  2657. while (deviceNode && !done) {
  2658. if ((deviceNode == IopRootDeviceNode) && (foundTranslator == FALSE)) {
  2659. if (restartedAlready == FALSE) {
  2660. restartedAlready = TRUE;
  2661. deviceNode = IopFindLegacyBusDeviceNode (InterfaceType, BusNumber);
  2662. //
  2663. // If we did not find a PDO, try again with InterfaceType == Isa. This allows
  2664. // drivers that request Internal to get resources even if there is no PDO
  2665. // that is Internal. (but if there is an Internal PDO, they get that one)
  2666. //
  2667. if ((deviceNode == IopRootDeviceNode) && (InterfaceType == Internal)) {
  2668. deviceNode = IopFindLegacyBusDeviceNode(Isa, 0);
  2669. }
  2670. continue;
  2671. }
  2672. }
  2673. //
  2674. // First, check if there is a translator for the device node?
  2675. // If yes, translate the req desc and link it to the front of ReqDesc->TranslatedReqDesc
  2676. // else do nothing.
  2677. //
  2678. listHead = &deviceNode->DeviceTranslatorList;
  2679. nextEntry = listHead->Flink;
  2680. for (; nextEntry != listHead; nextEntry = nextEntry->Flink) {
  2681. translatorEntry = CONTAINING_RECORD(nextEntry, PI_RESOURCE_TRANSLATOR_ENTRY, DeviceTranslatorList);
  2682. if (translatorEntry->ResourceType == Source->Type) {
  2683. translator = translatorEntry->TranslatorInterface;
  2684. if (translator != NULL) {
  2685. //
  2686. // Find a translator to translate the req desc ... Translate it and link it to
  2687. // the front of ReqDesc->TranslatedReqDesc.
  2688. //
  2689. status = (translator->TranslateResources) (
  2690. translator->Context,
  2691. source,
  2692. TranslateChildToParent,
  2693. 0,
  2694. NULL,
  2695. DeviceNode ? DeviceNode->PhysicalDeviceObject : NULL,
  2696. target
  2697. );
  2698. if (NT_SUCCESS(status)) {
  2699. tmp = source;
  2700. source = target;
  2701. target = tmp;
  2702. //
  2703. // If the translator is non-hierarchial and performs a complete
  2704. // translation to root (eg ISA interrups for PCI devices) then
  2705. // don't pass translations to parent.
  2706. //
  2707. if (status == STATUS_TRANSLATION_COMPLETE) {
  2708. done = TRUE;
  2709. }
  2710. } else {
  2711. IopDbgPrint((
  2712. IOP_RESOURCE_ERROR_LEVEL,
  2713. "Child to Root Translation failed\n"
  2714. " DeviceNode %08x (PDO %08x)\n"
  2715. " Resource Type %02x Data %08x %08x %08x\n",
  2716. DeviceNode,
  2717. DeviceNode->PhysicalDeviceObject,
  2718. source->Type,
  2719. source->u.DevicePrivate.Data[0],
  2720. source->u.DevicePrivate.Data[1],
  2721. source->u.DevicePrivate.Data[2]
  2722. ));
  2723. IopRecordTranslationFailure(DeviceNode, *source);
  2724. goto exit;
  2725. }
  2726. }
  2727. break;
  2728. }
  2729. }
  2730. //
  2731. // Move up to current device node's parent
  2732. //
  2733. deviceNode = deviceNode->Parent;
  2734. }
  2735. *Target = source;
  2736. ExFreePool(target);
  2737. return status;
  2738. exit:
  2739. ExFreePool(source);
  2740. ExFreePool(target);
  2741. return status;
  2742. }
  2743. NTSTATUS
  2744. IopTranslateAndAdjustReqDesc(
  2745. IN PREQ_DESC ReqDesc,
  2746. IN PPI_RESOURCE_TRANSLATOR_ENTRY TranslatorEntry,
  2747. OUT PREQ_DESC *TranslatedReqDesc
  2748. )
  2749. /*++
  2750. Routine Description:
  2751. This routine translates and adjusts ReqDesc IoResourceDescriptors to
  2752. their translated and adjusted form.
  2753. Parameters:
  2754. ReqDesc - supplies a pointer to the REQ_DESC to be translated.
  2755. TranslatorEntry - supplies a pointer to the translator infor structure.
  2756. TranslatedReqDesc - supplies a pointer to a variable to receive the
  2757. translated REQ_DESC.
  2758. Return Value:
  2759. Status code that indicates whether or not the function was successful.
  2760. --*/
  2761. {
  2762. ULONG i, total = 0, *targetCount;
  2763. PTRANSLATOR_INTERFACE translator = TranslatorEntry->TranslatorInterface;
  2764. PIO_RESOURCE_DESCRIPTOR ioDesc, *target, tIoDesc;
  2765. PREQ_DESC tReqDesc;
  2766. PARBITER_LIST_ENTRY arbiterEntry;
  2767. NTSTATUS status = STATUS_UNSUCCESSFUL, returnStatus = STATUS_SUCCESS;
  2768. BOOLEAN reqTranslated = FALSE;
  2769. if (ReqDesc->AlternativeTable.AlternativeCount == 0) {
  2770. return STATUS_INVALID_PARAMETER;
  2771. }
  2772. *TranslatedReqDesc = NULL;
  2773. target = (PIO_RESOURCE_DESCRIPTOR *) ExAllocatePoolIORD(
  2774. PagedPool | POOL_COLD_ALLOCATION,
  2775. sizeof(PIO_RESOURCE_DESCRIPTOR) * ReqDesc->AlternativeTable.AlternativeCount
  2776. );
  2777. if (target == NULL) {
  2778. IopDbgPrint((
  2779. IOP_RESOURCE_WARNING_LEVEL,
  2780. "Not Enough memory to perform resreqlist adjustment\n"));
  2781. return STATUS_INSUFFICIENT_RESOURCES;
  2782. }
  2783. RtlZeroMemory(target, sizeof(PIO_RESOURCE_DESCRIPTOR) * ReqDesc->AlternativeTable.AlternativeCount);
  2784. targetCount = (PULONG) ExAllocatePool(
  2785. PagedPool | POOL_COLD_ALLOCATION,
  2786. sizeof(ULONG) * ReqDesc->AlternativeTable.AlternativeCount
  2787. );
  2788. if (targetCount == NULL) {
  2789. IopDbgPrint((
  2790. IOP_RESOURCE_WARNING_LEVEL,
  2791. "Not Enough memory to perform resreqlist adjustment\n"));
  2792. ExFreePool(target);
  2793. return STATUS_INSUFFICIENT_RESOURCES;
  2794. }
  2795. RtlZeroMemory(targetCount, sizeof(ULONG) * ReqDesc->AlternativeTable.AlternativeCount);
  2796. //
  2797. // Determine the number of IO_RESOURCE_DESCRIPTORs after translation.
  2798. //
  2799. ioDesc = ReqDesc->AlternativeTable.Alternatives;
  2800. for (i = 0; i < ReqDesc->AlternativeTable.AlternativeCount; i++) {
  2801. status = (translator->TranslateResourceRequirements)(
  2802. translator->Context,
  2803. ioDesc,
  2804. ReqDesc->AlternativeTable.PhysicalDeviceObject,
  2805. &targetCount[i],
  2806. &target[i]
  2807. );
  2808. if (!NT_SUCCESS(status) || targetCount[i] == 0) {
  2809. IopDbgPrint((
  2810. IOP_RESOURCE_WARNING_LEVEL,
  2811. "Translator failed to adjust resreqlist\n"));
  2812. target[i] = ioDesc;
  2813. targetCount[i] = 0;
  2814. total++;
  2815. } else {
  2816. total += targetCount[i];
  2817. reqTranslated = TRUE;
  2818. }
  2819. ioDesc++;
  2820. if (NT_SUCCESS(status) && (returnStatus != STATUS_TRANSLATION_COMPLETE)) {
  2821. returnStatus = status;
  2822. }
  2823. }
  2824. if (!reqTranslated) {
  2825. IopDbgPrint((
  2826. IOP_RESOURCE_WARNING_LEVEL,
  2827. "Failed to translate any requirement for %ws!\n",
  2828. PP_DO_TO_DN(ReqDesc->AlternativeTable.PhysicalDeviceObject)->InstancePath.Buffer));
  2829. returnStatus = status;
  2830. }
  2831. //
  2832. // Allocate memory for the adjusted/translated resources descriptors
  2833. //
  2834. tIoDesc = (PIO_RESOURCE_DESCRIPTOR) ExAllocatePoolIORD(
  2835. PagedPool | POOL_COLD_ALLOCATION,
  2836. total * sizeof(IO_RESOURCE_DESCRIPTOR));
  2837. if (!tIoDesc) {
  2838. IopDbgPrint((
  2839. IOP_RESOURCE_WARNING_LEVEL,
  2840. "Not Enough memory to perform resreqlist adjustment\n"));
  2841. returnStatus = STATUS_INSUFFICIENT_RESOURCES;
  2842. goto exit;
  2843. }
  2844. tReqDesc = (PREQ_DESC) ExAllocatePool1RD (PagedPool | POOL_COLD_ALLOCATION, sizeof(REQ_DESC));
  2845. if (tReqDesc == NULL) {
  2846. IopDbgPrint((
  2847. IOP_RESOURCE_WARNING_LEVEL,
  2848. "Not Enough memory to perform resreqlist adjustment\n"));
  2849. ExFreePool(tIoDesc);
  2850. returnStatus = STATUS_INSUFFICIENT_RESOURCES;
  2851. goto exit;
  2852. }
  2853. //
  2854. // Create and initialize a new REQ_DESC for the translated/adjusted io resources
  2855. //
  2856. RtlCopyMemory(tReqDesc, ReqDesc, sizeof(REQ_DESC));
  2857. //
  2858. // Set the translated req desc's ReqAlternative to NULL to indicated this
  2859. // is not the original req desc.
  2860. //
  2861. tReqDesc->ReqAlternative = NULL;
  2862. tReqDesc->u.Translator = TranslatorEntry;
  2863. tReqDesc->TranslatedReqDesc = NULL;
  2864. arbiterEntry = &tReqDesc->AlternativeTable;
  2865. InitializeListHead(&arbiterEntry->ListEntry);
  2866. arbiterEntry->AlternativeCount = total;
  2867. arbiterEntry->Alternatives = tIoDesc;
  2868. arbiterEntry->Assignment = &tReqDesc->Allocation;
  2869. ioDesc = ReqDesc->AlternativeTable.Alternatives;
  2870. for (i = 0; i < ReqDesc->AlternativeTable.AlternativeCount; i++) {
  2871. if (targetCount[i] != 0) {
  2872. RtlCopyMemory(tIoDesc, target[i], targetCount[i] * sizeof(IO_RESOURCE_DESCRIPTOR));
  2873. tIoDesc += targetCount[i];
  2874. } else {
  2875. //
  2876. // Make it become impossible to satisfy.
  2877. //
  2878. RtlCopyMemory(tIoDesc, ioDesc, sizeof(IO_RESOURCE_DESCRIPTOR));
  2879. switch (tIoDesc->Type) {
  2880. case CmResourceTypePort:
  2881. case CmResourceTypeMemory:
  2882. tIoDesc->u.Port.MinimumAddress.LowPart = 2;
  2883. tIoDesc->u.Port.MinimumAddress.HighPart = 0;
  2884. tIoDesc->u.Port.MaximumAddress.LowPart = 1;
  2885. tIoDesc->u.Port.MaximumAddress.HighPart = 0;
  2886. break;
  2887. case CmResourceTypeBusNumber:
  2888. tIoDesc->u.BusNumber.MinBusNumber = 2;
  2889. tIoDesc->u.BusNumber.MaxBusNumber = 1;
  2890. break;
  2891. case CmResourceTypeInterrupt:
  2892. tIoDesc->u.Interrupt.MinimumVector = 2;
  2893. tIoDesc->u.Interrupt.MaximumVector = 1;
  2894. break;
  2895. case CmResourceTypeDma:
  2896. tIoDesc->u.Dma.MinimumChannel = 2;
  2897. tIoDesc->u.Dma.MaximumChannel = 1;
  2898. break;
  2899. default:
  2900. ASSERT(0);
  2901. break;
  2902. }
  2903. tIoDesc += 1;
  2904. }
  2905. ioDesc++;
  2906. }
  2907. #if DBG_SCOPE
  2908. //
  2909. // Verify the adjusted resource descriptors are valid
  2910. //
  2911. ioDesc = arbiterEntry->Alternatives;
  2912. ASSERT((ioDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0);
  2913. ioDesc++;
  2914. for (i = 1; i < total; i++) {
  2915. ASSERT(ioDesc->Option & IO_RESOURCE_ALTERNATIVE);
  2916. ioDesc++;
  2917. }
  2918. #endif
  2919. *TranslatedReqDesc = tReqDesc;
  2920. exit:
  2921. for (i = 0; i < ReqDesc->AlternativeTable.AlternativeCount; i++) {
  2922. if (targetCount[i] != 0) {
  2923. ASSERT(target[i]);
  2924. ExFreePool(target[i]);
  2925. }
  2926. }
  2927. ExFreePool(target);
  2928. ExFreePool(targetCount);
  2929. return returnStatus;
  2930. }
  2931. NTSTATUS
  2932. IopCallArbiter(
  2933. PPI_RESOURCE_ARBITER_ENTRY ArbiterEntry,
  2934. ARBITER_ACTION Command,
  2935. PVOID Input1,
  2936. PVOID Input2,
  2937. PVOID Input3
  2938. )
  2939. /*++
  2940. Routine Description:
  2941. This routine builds a Parameter block from Input structure and calls specified
  2942. arbiter to carry out the Command.
  2943. Parameters:
  2944. ArbiterEntry - Supplies a pointer to our PI_RESOURCE_ARBITER_ENTRY such that
  2945. we know everything about the arbiter.
  2946. Command - Supplies the Action code for the arbiter.
  2947. Input - Supplies a PVOID pointer to a structure.
  2948. Return Value:
  2949. Status code that indicates whether or not the function was successful.
  2950. --*/
  2951. {
  2952. ARBITER_PARAMETERS parameters;
  2953. PARBITER_INTERFACE arbiterInterface = ArbiterEntry->ArbiterInterface;
  2954. NTSTATUS status;
  2955. PARBITER_LIST_ENTRY arbiterListEntry;
  2956. LIST_ENTRY listHead;
  2957. PVOID *ExtParams;
  2958. switch (Command) {
  2959. case ArbiterActionTestAllocation:
  2960. case ArbiterActionRetestAllocation:
  2961. //
  2962. // For ArbiterActionTestAllocation, the Input is a pointer to the doubly
  2963. // linked list of ARBITER_LIST_ENTRY's.
  2964. //
  2965. parameters.Parameters.TestAllocation.ArbitrationList = (PLIST_ENTRY)Input1;
  2966. parameters.Parameters.TestAllocation.AllocateFromCount = (ULONG)((ULONG_PTR)Input2);
  2967. parameters.Parameters.TestAllocation.AllocateFrom =
  2968. (PCM_PARTIAL_RESOURCE_DESCRIPTOR)Input3;
  2969. status = (arbiterInterface->ArbiterHandler)(
  2970. arbiterInterface->Context,
  2971. Command,
  2972. &parameters
  2973. );
  2974. break;
  2975. case ArbiterActionBootAllocation:
  2976. //
  2977. // For ArbiterActionBootAllocation, the input is a pointer to the doubly
  2978. // linked list of ARBITER_LIST_ENTRY'S.
  2979. //
  2980. parameters.Parameters.BootAllocation.ArbitrationList = (PLIST_ENTRY)Input1;
  2981. status = (arbiterInterface->ArbiterHandler)(
  2982. arbiterInterface->Context,
  2983. Command,
  2984. &parameters
  2985. );
  2986. break;
  2987. case ArbiterActionQueryArbitrate:
  2988. //
  2989. // For QueryArbiter, the input is a pointer to REQ_DESC
  2990. //
  2991. arbiterListEntry = &((PREQ_DESC)Input1)->AlternativeTable;
  2992. ASSERT(IsListEmpty(&arbiterListEntry->ListEntry));
  2993. listHead = arbiterListEntry->ListEntry;
  2994. arbiterListEntry->ListEntry.Flink = arbiterListEntry->ListEntry.Blink = &listHead;
  2995. parameters.Parameters.QueryArbitrate.ArbitrationList = &listHead;
  2996. status = (arbiterInterface->ArbiterHandler)(
  2997. arbiterInterface->Context,
  2998. Command,
  2999. &parameters
  3000. );
  3001. arbiterListEntry->ListEntry = listHead;
  3002. break;
  3003. case ArbiterActionCommitAllocation:
  3004. case ArbiterActionWriteReservedResources:
  3005. //
  3006. // Commit, Rollback and WriteReserved do not have parmater.
  3007. //
  3008. status = (arbiterInterface->ArbiterHandler)(
  3009. arbiterInterface->Context,
  3010. Command,
  3011. NULL
  3012. );
  3013. break;
  3014. case ArbiterActionQueryAllocatedResources:
  3015. status = STATUS_NOT_IMPLEMENTED;
  3016. break;
  3017. case ArbiterActionQueryConflict:
  3018. //
  3019. // For QueryConflict
  3020. // Ex0 is PDO
  3021. // Ex1 is PIO_RESOURCE_DESCRIPTOR
  3022. // Ex2 is PULONG
  3023. // Ex3 is PARBITER_CONFLICT_INFO *
  3024. ExtParams = (PVOID*)Input1;
  3025. parameters.Parameters.QueryConflict.PhysicalDeviceObject = (PDEVICE_OBJECT)ExtParams[0];
  3026. parameters.Parameters.QueryConflict.ConflictingResource = (PIO_RESOURCE_DESCRIPTOR)ExtParams[1];
  3027. parameters.Parameters.QueryConflict.ConflictCount = (PULONG)ExtParams[2];
  3028. parameters.Parameters.QueryConflict.Conflicts = (PARBITER_CONFLICT_INFO *)ExtParams[3];
  3029. status = (arbiterInterface->ArbiterHandler)(
  3030. arbiterInterface->Context,
  3031. Command,
  3032. &parameters
  3033. );
  3034. break;
  3035. default:
  3036. status = STATUS_INVALID_PARAMETER;
  3037. break;
  3038. }
  3039. return status;
  3040. }
  3041. NTSTATUS
  3042. IopFindResourcesForArbiter (
  3043. IN PDEVICE_NODE DeviceNode,
  3044. IN UCHAR ResourceType,
  3045. OUT ULONG *Count,
  3046. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR *CmDesc
  3047. )
  3048. /*++
  3049. Routine Description:
  3050. This routine returns the resources required by the ResourceType arbiter in DeviceNode.
  3051. Parameters:
  3052. DeviceNode -specifies the device node whose ResourceType arbiter is requesting for resources
  3053. ResourceType - specifies the resource type
  3054. Count - specifies a pointer to a varaible to receive the count of Cm descriptors returned
  3055. CmDesc - specifies a pointer to a varibble to receive the returned cm descriptor.
  3056. Return Value:
  3057. Status code that indicates whether or not the function was successful.
  3058. --*/
  3059. {
  3060. PIOP_RESOURCE_REQUEST assignEntry;
  3061. PREQ_ALTERNATIVE reqAlternative;
  3062. PREQ_DESC reqDesc;
  3063. ULONG i, count = 0;
  3064. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor;
  3065. *Count = 0;
  3066. *CmDesc = NULL;
  3067. if (DeviceNode->State == DeviceNodeStarted) {
  3068. return STATUS_SUCCESS;
  3069. }
  3070. //
  3071. // Find this device node's IOP_RESOURCE_REQUEST structure first
  3072. //
  3073. for (assignEntry = PiAssignTable + PiAssignTableCount - 1;
  3074. assignEntry >= PiAssignTable;
  3075. assignEntry--) {
  3076. if (assignEntry->PhysicalDevice == DeviceNode->PhysicalDeviceObject) {
  3077. break;
  3078. }
  3079. }
  3080. if (assignEntry < PiAssignTable) {
  3081. IopDbgPrint((
  3082. IOP_RESOURCE_ERROR_LEVEL,
  3083. "Rebalance: No resreqlist for Arbiter? Can not find Arbiter assign"
  3084. " table entry\n"));
  3085. return STATUS_UNSUCCESSFUL;
  3086. }
  3087. reqAlternative = *((PREQ_LIST)assignEntry->ReqList)->SelectedAlternative;
  3088. for (i = 0; i < reqAlternative->DescCount; i++) {
  3089. reqDesc = reqAlternative->DescTable[i]->TranslatedReqDesc;
  3090. if (reqDesc->Allocation.Type == ResourceType) {
  3091. count++;
  3092. }
  3093. }
  3094. cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ExAllocatePoolPRD(
  3095. PagedPool,
  3096. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * count
  3097. );
  3098. if (!cmDescriptor) {
  3099. //
  3100. // If we can not find memory, the resources will not be committed by arbiter.
  3101. //
  3102. IopDbgPrint((
  3103. IOP_RESOURCE_WARNING_LEVEL,
  3104. "Rebalance: Not enough memory to perform rebalance\n"));
  3105. return STATUS_INSUFFICIENT_RESOURCES;
  3106. }
  3107. *Count = count;
  3108. *CmDesc = cmDescriptor;
  3109. for (i = 0; i < reqAlternative->DescCount; i++) {
  3110. reqDesc = reqAlternative->DescTable[i]->TranslatedReqDesc;
  3111. if (reqDesc->Allocation.Type == ResourceType) {
  3112. *cmDescriptor = reqDesc->Allocation;
  3113. cmDescriptor++;
  3114. }
  3115. }
  3116. return STATUS_SUCCESS;
  3117. }
  3118. NTSTATUS
  3119. IopRestoreResourcesInternal (
  3120. IN PDEVICE_NODE DeviceNode
  3121. )
  3122. /*++
  3123. Routine Description:
  3124. This routine reassigns the released resources for device specified by DeviceNode.
  3125. Parameters:
  3126. DeviceNode - specifies the device node whose resources are goint to be released.
  3127. Return Value:
  3128. Status code that indicates whether or not the function was successful.
  3129. --*/
  3130. {
  3131. IOP_RESOURCE_REQUEST requestTable;
  3132. NTSTATUS status;
  3133. LIST_ENTRY activeArbiterList;
  3134. if (DeviceNode->ResourceList == NULL) {
  3135. return STATUS_SUCCESS;
  3136. }
  3137. requestTable.ResourceRequirements =
  3138. IopCmResourcesToIoResources (0, DeviceNode->ResourceList, LCPRI_FORCECONFIG);
  3139. if (requestTable.ResourceRequirements == NULL) {
  3140. IopDbgPrint((
  3141. IOP_RESOURCE_WARNING_LEVEL,
  3142. "Not enough memory to clean up rebalance failure\n"));
  3143. return STATUS_INSUFFICIENT_RESOURCES;
  3144. }
  3145. requestTable.Priority = 0;
  3146. requestTable.Flags = 0;
  3147. requestTable.AllocationType = ArbiterRequestPnpEnumerated;
  3148. requestTable.PhysicalDevice = DeviceNode->PhysicalDeviceObject;
  3149. requestTable.ReqList = NULL;
  3150. requestTable.ResourceAssignment = NULL;
  3151. requestTable.TranslatedResourceAssignment = NULL;
  3152. requestTable.Status = 0;
  3153. //
  3154. // rebuild internal representation of the resource requirements list
  3155. //
  3156. status = IopResourceRequirementsListToReqList(
  3157. &requestTable,
  3158. &requestTable.ReqList);
  3159. if (!NT_SUCCESS(status) || requestTable.ReqList == NULL) {
  3160. IopDbgPrint((
  3161. IOP_RESOURCE_ERROR_LEVEL,
  3162. "Not enough memory to restore previous resources\n"));
  3163. ExFreePool (requestTable.ResourceRequirements);
  3164. return status;
  3165. } else {
  3166. PREQ_LIST reqList;
  3167. reqList = (PREQ_LIST)requestTable.ReqList;
  3168. //
  3169. // Sort the ReqList such that the higher priority Alternative list are
  3170. // placed in the front of the list.
  3171. //
  3172. IopRearrangeReqList(reqList);
  3173. if (reqList->BestAlternative == NULL) {
  3174. IopFreeResourceRequirementsForAssignTable(&requestTable, (&requestTable) + 1);
  3175. return STATUS_DEVICE_CONFIGURATION_ERROR;
  3176. }
  3177. }
  3178. status = IopFindBestConfiguration(&requestTable, 1, &activeArbiterList);
  3179. IopFreeResourceRequirementsForAssignTable(&requestTable, (&requestTable) + 1);
  3180. if (NT_SUCCESS(status)) {
  3181. //
  3182. // Ask the arbiters to commit this configuration.
  3183. //
  3184. status = IopCommitConfiguration(&activeArbiterList);
  3185. }
  3186. if (!NT_SUCCESS(status)) {
  3187. IopDbgPrint((
  3188. IOP_RESOURCE_ERROR_LEVEL,
  3189. "IopRestoreResourcesInternal: BOOT conflict for %ws\n",
  3190. DeviceNode->InstancePath.Buffer));
  3191. }
  3192. if (requestTable.ResourceAssignment) {
  3193. ExFreePool(requestTable.ResourceAssignment);
  3194. }
  3195. if (requestTable.TranslatedResourceAssignment) {
  3196. ExFreePool(requestTable.TranslatedResourceAssignment);
  3197. }
  3198. IopWriteAllocatedResourcesToRegistry (
  3199. DeviceNode,
  3200. DeviceNode->ResourceList,
  3201. IopDetermineResourceListSize(DeviceNode->ResourceList)
  3202. );
  3203. return status;
  3204. }
  3205. VOID
  3206. IopReleaseResourcesInternal (
  3207. IN PDEVICE_NODE DeviceNode
  3208. )
  3209. /*++
  3210. Routine Description:
  3211. This routine releases the assigned resources for device specified by DeviceNode.
  3212. Note, this routine does not reset the resource related fields in DeviceNode structure.
  3213. Parameters:
  3214. DeviceNode - specifies the device node whose resources are goint to be released.
  3215. Return Value:
  3216. Status code that indicates whether or not the function was successful.
  3217. --*/
  3218. {
  3219. PDEVICE_NODE device;
  3220. PLIST_ENTRY listHead, listEntry;
  3221. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  3222. ARBITER_LIST_ENTRY arbiterListEntry;
  3223. INTERFACE_TYPE interfaceType;
  3224. ULONG busNumber, listCount, i, j, size;
  3225. PCM_RESOURCE_LIST resourceList;
  3226. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  3227. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
  3228. BOOLEAN search = TRUE;
  3229. #if DBG_SCOPE
  3230. NTSTATUS status;
  3231. #endif
  3232. InitializeListHead(&arbiterListEntry.ListEntry);
  3233. arbiterListEntry.AlternativeCount = 0;
  3234. arbiterListEntry.Alternatives = NULL;
  3235. arbiterListEntry.PhysicalDeviceObject = DeviceNode->PhysicalDeviceObject;
  3236. arbiterListEntry.Flags = 0;
  3237. arbiterListEntry.WorkSpace = 0;
  3238. arbiterListEntry.Assignment = NULL;
  3239. arbiterListEntry.RequestSource = ArbiterRequestPnpEnumerated;
  3240. resourceList = DeviceNode->ResourceList;
  3241. if (resourceList == NULL) {
  3242. resourceList = DeviceNode->BootResources;
  3243. }
  3244. if (resourceList && resourceList->Count > 0) {
  3245. listCount = resourceList->Count;
  3246. cmFullDesc = &resourceList->List[0];
  3247. } else {
  3248. listCount = 1;
  3249. resourceList = NULL;
  3250. }
  3251. for (i = 0; i < listCount; i++) {
  3252. if (resourceList) {
  3253. interfaceType = cmFullDesc->InterfaceType;
  3254. busNumber = cmFullDesc->BusNumber;
  3255. if (interfaceType == InterfaceTypeUndefined) {
  3256. interfaceType = PnpDefaultInterfaceType;
  3257. }
  3258. } else {
  3259. interfaceType = PnpDefaultInterfaceType;
  3260. busNumber = 0;
  3261. }
  3262. device = DeviceNode->Parent;
  3263. while (device) {
  3264. if ((device == IopRootDeviceNode) && search) {
  3265. device = IopFindLegacyBusDeviceNode (
  3266. interfaceType,
  3267. busNumber
  3268. );
  3269. //
  3270. // If we did not find a PDO, try again with InterfaceType == Isa. This allows
  3271. // drivers that request Internal to get resources even if there is no PDO
  3272. // that is Internal. (but if there is an Internal PDO, they get that one)
  3273. //
  3274. if ((device == IopRootDeviceNode) && (interfaceType == Internal)) {
  3275. device = IopFindLegacyBusDeviceNode(Isa, 0);
  3276. }
  3277. search = FALSE;
  3278. }
  3279. listHead = &device->DeviceArbiterList;
  3280. listEntry = listHead->Flink;
  3281. while (listEntry != listHead) {
  3282. arbiterEntry = CONTAINING_RECORD(listEntry, PI_RESOURCE_ARBITER_ENTRY, DeviceArbiterList);
  3283. if (arbiterEntry->ArbiterInterface != NULL) {
  3284. search = FALSE;
  3285. ASSERT(IsListEmpty(&arbiterEntry->ResourceList));
  3286. InitializeListHead(&arbiterEntry->ResourceList); // Recover from assert
  3287. InsertTailList(&arbiterEntry->ResourceList, &arbiterListEntry.ListEntry);
  3288. #if DBG_SCOPE
  3289. status =
  3290. #endif
  3291. IopCallArbiter(arbiterEntry,
  3292. ArbiterActionTestAllocation,
  3293. &arbiterEntry->ResourceList,
  3294. NULL,
  3295. NULL
  3296. );
  3297. #if DBG_SCOPE
  3298. ASSERT(status == STATUS_SUCCESS);
  3299. status =
  3300. #endif
  3301. IopCallArbiter(arbiterEntry,
  3302. ArbiterActionCommitAllocation,
  3303. NULL,
  3304. NULL,
  3305. NULL
  3306. );
  3307. #if DBG_SCOPE
  3308. ASSERT(status == STATUS_SUCCESS);
  3309. #endif
  3310. RemoveEntryList(&arbiterListEntry.ListEntry);
  3311. InitializeListHead(&arbiterListEntry.ListEntry);
  3312. }
  3313. listEntry = listEntry->Flink;
  3314. }
  3315. device = device->Parent;
  3316. }
  3317. //
  3318. // If there are more than 1 list, move to next list
  3319. //
  3320. if (listCount > 1) {
  3321. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  3322. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  3323. size = 0;
  3324. switch (cmPartDesc->Type) {
  3325. case CmResourceTypeDeviceSpecific:
  3326. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  3327. break;
  3328. }
  3329. cmPartDesc++;
  3330. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  3331. }
  3332. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  3333. }
  3334. }
  3335. IopWriteAllocatedResourcesToRegistry(DeviceNode, NULL, 0);
  3336. }
  3337. NTSTATUS
  3338. IopFindLegacyDeviceNode (
  3339. IN PDRIVER_OBJECT DriverObject,
  3340. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  3341. OUT PDEVICE_NODE *LegacyDeviceNode,
  3342. OUT PDEVICE_OBJECT *LegacyPDO
  3343. )
  3344. /*++
  3345. Routine Description:
  3346. This routine searches for the device node and device object created for legacy resource
  3347. allocation for the DriverObject and DeviceObject.
  3348. Parameters:
  3349. DriverObject - specifies the driver object doing the legacy allocation.
  3350. DeviceObject - specifies the device object.
  3351. LegacyDeviceNode - receives the pointer to the legacy device node if found.
  3352. LegacyDeviceObject - receives the pointer to the legacy device object if found.
  3353. Return Value:
  3354. Status code that indicates whether or not the function was successful.
  3355. --*/
  3356. {
  3357. NTSTATUS status = STATUS_UNSUCCESSFUL;
  3358. PDEVICE_NODE deviceNode;
  3359. ASSERT(LegacyDeviceNode && LegacyPDO);
  3360. //
  3361. // Use the device object if it exists.
  3362. //
  3363. if (DeviceObject) {
  3364. deviceNode = PP_DO_TO_DN(DeviceObject);
  3365. if (deviceNode) {
  3366. *LegacyPDO = DeviceObject;
  3367. *LegacyDeviceNode = deviceNode;
  3368. status = STATUS_SUCCESS;
  3369. } else if (!(DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE)) {
  3370. status = PipAllocateDeviceNode(DeviceObject, &deviceNode);
  3371. if (deviceNode) {
  3372. if (status == STATUS_SYSTEM_HIVE_TOO_LARGE) {
  3373. IopDestroyDeviceNode(deviceNode);
  3374. } else {
  3375. deviceNode->Flags |= DNF_LEGACY_RESOURCE_DEVICENODE;
  3376. IopSetLegacyDeviceInstance (DriverObject, deviceNode);
  3377. *LegacyPDO = DeviceObject;
  3378. *LegacyDeviceNode = deviceNode;
  3379. status = STATUS_SUCCESS;
  3380. }
  3381. } else {
  3382. IopDbgPrint((
  3383. IOP_RESOURCE_ERROR_LEVEL,
  3384. "Failed to allocate device node for PDO %08X\n",
  3385. DeviceObject));
  3386. status = STATUS_INSUFFICIENT_RESOURCES;
  3387. }
  3388. } else {
  3389. IopDbgPrint((
  3390. IOP_RESOURCE_ERROR_LEVEL,
  3391. "%08X PDO without a device node!\n",
  3392. DeviceObject));
  3393. ASSERT(PP_DO_TO_DN(DeviceObject));
  3394. }
  3395. } else {
  3396. //
  3397. // Search our list of legacy device nodes.
  3398. //
  3399. for ( deviceNode = IopLegacyDeviceNode;
  3400. deviceNode && deviceNode->DuplicatePDO != (PDEVICE_OBJECT)DriverObject;
  3401. deviceNode = deviceNode->NextDeviceNode);
  3402. if (deviceNode) {
  3403. *LegacyPDO = deviceNode->PhysicalDeviceObject;
  3404. *LegacyDeviceNode = deviceNode;
  3405. status = STATUS_SUCCESS;
  3406. } else {
  3407. PDEVICE_OBJECT pdo;
  3408. //
  3409. // We are seeing this for the first time.
  3410. // Create a madeup device node.
  3411. //
  3412. status = IoCreateDevice( IoPnpDriverObject,
  3413. sizeof(IOPNP_DEVICE_EXTENSION),
  3414. NULL,
  3415. FILE_DEVICE_CONTROLLER,
  3416. FILE_AUTOGENERATED_DEVICE_NAME,
  3417. FALSE,
  3418. &pdo);
  3419. if (NT_SUCCESS(status)) {
  3420. pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
  3421. PipAllocateDeviceNode(pdo, &deviceNode);
  3422. if (status != STATUS_SYSTEM_HIVE_TOO_LARGE && deviceNode) {
  3423. //
  3424. // Change driver object to the caller even though the owner
  3425. // of the pdo is IoPnpDriverObject. This is to support
  3426. // DriverExclusive for legacy interface.
  3427. //
  3428. pdo->DriverObject = DriverObject;
  3429. deviceNode->Flags = DNF_MADEUP | DNF_LEGACY_RESOURCE_DEVICENODE;
  3430. PipSetDevNodeState(deviceNode, DeviceNodeInitialized, NULL);
  3431. deviceNode->DuplicatePDO = (PDEVICE_OBJECT)DriverObject;
  3432. IopSetLegacyDeviceInstance (DriverObject, deviceNode);
  3433. //
  3434. // Add it to our list of legacy device nodes rather than adding it to the HW tree.
  3435. //
  3436. deviceNode->NextDeviceNode = IopLegacyDeviceNode;
  3437. if (IopLegacyDeviceNode) {
  3438. IopLegacyDeviceNode->PreviousDeviceNode = deviceNode;
  3439. }
  3440. IopLegacyDeviceNode = deviceNode;
  3441. *LegacyPDO = pdo;
  3442. *LegacyDeviceNode = deviceNode;
  3443. } else {
  3444. IopDbgPrint((
  3445. IOP_RESOURCE_ERROR_LEVEL,
  3446. "Failed to allocate device node for PDO %08X\n",
  3447. pdo));
  3448. IoDeleteDevice(pdo);
  3449. status = STATUS_INSUFFICIENT_RESOURCES;
  3450. }
  3451. } else {
  3452. IopDbgPrint((
  3453. IOP_RESOURCE_ERROR_LEVEL,
  3454. "IoCreateDevice failed with status %08X\n",
  3455. status));
  3456. }
  3457. }
  3458. }
  3459. return status;
  3460. }
  3461. VOID
  3462. IopRemoveLegacyDeviceNode (
  3463. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  3464. IN PDEVICE_NODE LegacyDeviceNode
  3465. )
  3466. /*++
  3467. Routine Description:
  3468. This routine removes the device node and device object created for legacy resource
  3469. allocation for the DeviceObject.
  3470. Parameters:
  3471. DeviceObject - specifies the device object.
  3472. LegacyDeviceNode - receives the pointer to the legacy device node if found.
  3473. Return Value:
  3474. Status code that indicates whether or not the function was successful.
  3475. --*/
  3476. {
  3477. ASSERT(LegacyDeviceNode);
  3478. if (!DeviceObject) {
  3479. if (LegacyDeviceNode->DuplicatePDO) {
  3480. LegacyDeviceNode->DuplicatePDO = NULL;
  3481. if (LegacyDeviceNode->PreviousDeviceNode) {
  3482. LegacyDeviceNode->PreviousDeviceNode->NextDeviceNode = LegacyDeviceNode->NextDeviceNode;
  3483. }
  3484. if (LegacyDeviceNode->NextDeviceNode) {
  3485. LegacyDeviceNode->NextDeviceNode->PreviousDeviceNode = LegacyDeviceNode->PreviousDeviceNode;
  3486. }
  3487. if (IopLegacyDeviceNode == LegacyDeviceNode) {
  3488. IopLegacyDeviceNode = LegacyDeviceNode->NextDeviceNode;
  3489. }
  3490. } else {
  3491. IopDbgPrint((
  3492. IOP_RESOURCE_ERROR_LEVEL,
  3493. "%ws does not have a duplicate PDO\n",
  3494. LegacyDeviceNode->InstancePath.Buffer));
  3495. ASSERT(LegacyDeviceNode->DuplicatePDO);
  3496. return;
  3497. }
  3498. }
  3499. if (!(DeviceObject && (DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE))) {
  3500. PDEVICE_NODE resourceDeviceNode;
  3501. PDEVICE_OBJECT pdo;
  3502. for ( resourceDeviceNode = (PDEVICE_NODE)LegacyDeviceNode->OverUsed1.LegacyDeviceNode;
  3503. resourceDeviceNode;
  3504. resourceDeviceNode = resourceDeviceNode->OverUsed2.NextResourceDeviceNode) {
  3505. if (resourceDeviceNode->OverUsed2.NextResourceDeviceNode == LegacyDeviceNode) {
  3506. resourceDeviceNode->OverUsed2.NextResourceDeviceNode = LegacyDeviceNode->OverUsed2.NextResourceDeviceNode;
  3507. break;
  3508. }
  3509. }
  3510. LegacyDeviceNode->Parent = LegacyDeviceNode->Sibling =
  3511. LegacyDeviceNode->Child = LegacyDeviceNode->LastChild = NULL;
  3512. //
  3513. // Delete the dummy PDO and device node.
  3514. //
  3515. pdo = LegacyDeviceNode->PhysicalDeviceObject;
  3516. LegacyDeviceNode->Flags &= ~DNF_LEGACY_RESOURCE_DEVICENODE;
  3517. IopDestroyDeviceNode(LegacyDeviceNode);
  3518. if (!DeviceObject) {
  3519. pdo->DriverObject = IoPnpDriverObject;
  3520. IoDeleteDevice(pdo);
  3521. }
  3522. }
  3523. }
  3524. VOID
  3525. IopSetLegacyResourcesFlag(
  3526. IN PDRIVER_OBJECT DriverObject
  3527. )
  3528. {
  3529. KIRQL irql;
  3530. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  3531. //
  3532. // Once tainted, a driver can never lose it's legacy history
  3533. // (unless unloaded). This is because the device object
  3534. // field is optional, and we don't bother counting here...
  3535. //
  3536. DriverObject->Flags |= DRVO_LEGACY_RESOURCES;
  3537. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  3538. }
  3539. NTSTATUS
  3540. IopLegacyResourceAllocation (
  3541. IN ARBITER_REQUEST_SOURCE AllocationType,
  3542. IN PDRIVER_OBJECT DriverObject,
  3543. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  3544. IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements,
  3545. IN OUT PCM_RESOURCE_LIST *AllocatedResources OPTIONAL
  3546. )
  3547. /*++
  3548. Routine Description:
  3549. This routine handles legacy interface IoAssignResources and IoReportResourcesUsage,
  3550. It converts the request to call IopAllocateResources.
  3551. Parameters:
  3552. AllocationType - Allocation type for the legacy request.
  3553. DriverObject - Driver object doing the legacy allocation.
  3554. DeviceObject - Device object.
  3555. ResourceRequirements - Legacy resource requirements. If NULL, caller want to free resources.
  3556. AllocatedResources - Pointer to a variable that receives pointer to allocated resources.
  3557. Return Value:
  3558. Status code that indicates whether or not the function was successful.
  3559. --*/
  3560. {
  3561. PDEVICE_OBJECT pdo;
  3562. PDEVICE_NODE deviceNode;
  3563. PDEVICE_NODE legacyDeviceNode;
  3564. NTSTATUS status;
  3565. PCM_RESOURCE_LIST combinedResources;
  3566. ASSERT(DriverObject);
  3567. //
  3568. // Grab the IO registry semaphore to make sure no other device is
  3569. // reporting it's resource usage while we are searching for conflicts.
  3570. //
  3571. IopLockResourceManager();
  3572. status = IopFindLegacyDeviceNode(DriverObject, DeviceObject, &deviceNode, &pdo);
  3573. if (NT_SUCCESS(status)) {
  3574. legacyDeviceNode = NULL;
  3575. if (!deviceNode->Parent && ResourceRequirements) {
  3576. //
  3577. // Make IopRootDeviceNode the bus pdo so we will search the right bus pdo
  3578. // on resource descriptor level.
  3579. //
  3580. if (ResourceRequirements->InterfaceType == InterfaceTypeUndefined) {
  3581. ResourceRequirements->InterfaceType = PnpDefaultInterfaceType;
  3582. }
  3583. deviceNode->Parent = IopRootDeviceNode;
  3584. }
  3585. //
  3586. // Release resources for this device node.
  3587. //
  3588. if ( (!ResourceRequirements && deviceNode->Parent) ||
  3589. deviceNode->ResourceList ||
  3590. deviceNode->BootResources) {
  3591. IopReleaseResources(deviceNode);
  3592. }
  3593. if (ResourceRequirements) {
  3594. IOP_RESOURCE_REQUEST requestTable;
  3595. IOP_RESOURCE_REQUEST *requestTablep;
  3596. ULONG count;
  3597. //
  3598. // Try to allocate these resource requirements.
  3599. //
  3600. count = 1;
  3601. RtlZeroMemory(&requestTable, sizeof(IOP_RESOURCE_REQUEST));
  3602. requestTable.ResourceRequirements = ResourceRequirements;
  3603. requestTable.PhysicalDevice = pdo;
  3604. requestTable.Flags = IOP_ASSIGN_NO_REBALANCE;
  3605. requestTable.AllocationType = AllocationType;
  3606. requestTablep = &requestTable;
  3607. IopAllocateResources(&count, &requestTablep, TRUE, TRUE, NULL);
  3608. status = requestTable.Status;
  3609. if (NT_SUCCESS(status)) {
  3610. deviceNode->ResourceListTranslated = requestTable.TranslatedResourceAssignment;
  3611. count = IopDetermineResourceListSize((*AllocatedResources) ? *AllocatedResources : requestTable.ResourceAssignment);
  3612. deviceNode->ResourceList = ExAllocatePoolIORL(PagedPool, count);
  3613. if (deviceNode->ResourceList) {
  3614. if (*AllocatedResources) {
  3615. //
  3616. // We got called from IoReportResourceUsage.
  3617. //
  3618. ASSERT(requestTable.ResourceAssignment);
  3619. ExFreePool(requestTable.ResourceAssignment);
  3620. } else {
  3621. //
  3622. // We got called from IoAssignResources.
  3623. //
  3624. *AllocatedResources = requestTable.ResourceAssignment;
  3625. }
  3626. RtlCopyMemory(deviceNode->ResourceList, *AllocatedResources, count);
  3627. legacyDeviceNode = (PDEVICE_NODE)deviceNode->OverUsed1.LegacyDeviceNode;
  3628. } else {
  3629. deviceNode->ResourceList = requestTable.ResourceAssignment;
  3630. IopReleaseResources(deviceNode);
  3631. status = STATUS_INSUFFICIENT_RESOURCES;
  3632. }
  3633. }
  3634. //
  3635. // Remove the madeup PDO and device node if there was some error.
  3636. //
  3637. if (!NT_SUCCESS(status)) {
  3638. IopRemoveLegacyDeviceNode(DeviceObject, deviceNode);
  3639. }
  3640. } else {
  3641. //
  3642. // Caller wants to release resources.
  3643. //
  3644. legacyDeviceNode = (PDEVICE_NODE)deviceNode->OverUsed1.LegacyDeviceNode;
  3645. IopRemoveLegacyDeviceNode(DeviceObject, deviceNode);
  3646. }
  3647. if (NT_SUCCESS(status)) {
  3648. if (legacyDeviceNode) {
  3649. //
  3650. // After the resource is modified, update the allocated resource list
  3651. // for the Root\Legacy_xxxx\0000 device instance.
  3652. //
  3653. combinedResources = IopCombineLegacyResources(legacyDeviceNode);
  3654. if (combinedResources) {
  3655. IopWriteAllocatedResourcesToRegistry( legacyDeviceNode,
  3656. combinedResources,
  3657. IopDetermineResourceListSize(combinedResources));
  3658. ExFreePool(combinedResources);
  3659. }
  3660. }
  3661. if (AllocationType != ArbiterRequestPnpDetected) {
  3662. //
  3663. // Modify the DRVOBJ flags.
  3664. //
  3665. if (ResourceRequirements) {
  3666. IopSetLegacyResourcesFlag(DriverObject);
  3667. }
  3668. }
  3669. }
  3670. }
  3671. IopUnlockResourceManager();
  3672. return status;
  3673. }
  3674. NTSTATUS
  3675. IopDuplicateDetection (
  3676. IN INTERFACE_TYPE LegacyBusType,
  3677. IN ULONG BusNumber,
  3678. IN ULONG SlotNumber,
  3679. OUT PDEVICE_NODE *DeviceNode
  3680. )
  3681. /*++
  3682. Routine Description:
  3683. This routine searches for the bus device driver for a given legacy device,
  3684. sends a query interface IRP for legacy device detection, and if the driver
  3685. implements this interface, requests the PDO for the given legacy device.
  3686. Parameters:
  3687. LegacyBusType - The legacy device's interface type.
  3688. BusNumber - The legacy device's bus number.
  3689. SlotNumber - The legacy device's slot number.
  3690. DeviceNode - specifies a pointer to a variable to receive the duplicated device node
  3691. Return Value:
  3692. NTSTATUS code.
  3693. --*/
  3694. {
  3695. PDEVICE_NODE deviceNode;
  3696. PDEVICE_OBJECT busDeviceObject;
  3697. PLEGACY_DEVICE_DETECTION_INTERFACE interface;
  3698. NTSTATUS status;
  3699. PDEVICE_OBJECT deviceObject;
  3700. UNREFERENCED_PARAMETER(SlotNumber);
  3701. //
  3702. // Initialize return parameter to "not found".
  3703. //
  3704. *DeviceNode = NULL;
  3705. //
  3706. // Search the device tree for the bus of the legacy device.
  3707. //
  3708. deviceNode = IopFindLegacyBusDeviceNode(
  3709. LegacyBusType,
  3710. BusNumber);
  3711. //
  3712. // Either a bus driver does not exist (or more likely, the legacy bus
  3713. // type and bus number were unspecified). Either way, we can't make
  3714. // any further progress.
  3715. //
  3716. if (deviceNode == NULL) {
  3717. return STATUS_INVALID_DEVICE_REQUEST;
  3718. }
  3719. //
  3720. // We found the legacy device's bus driver. Query it to determine
  3721. // whether it implements the LEGACY_DEVICE_DETECTION interface.
  3722. //
  3723. busDeviceObject = deviceNode->PhysicalDeviceObject;
  3724. status = IopQueryResourceHandlerInterface(
  3725. ResourceLegacyDeviceDetection,
  3726. busDeviceObject,
  3727. 0,
  3728. (PINTERFACE *)&interface);
  3729. //
  3730. // If it doesn't, we're stuck.
  3731. //
  3732. if (!NT_SUCCESS(status) || interface == NULL) {
  3733. return STATUS_INVALID_DEVICE_REQUEST;
  3734. }
  3735. //
  3736. // Invoke the bus driver's legacy device detection method.
  3737. //
  3738. status = (*interface->LegacyDeviceDetection)(
  3739. interface->Context,
  3740. LegacyBusType,
  3741. BusNumber,
  3742. SlotNumber,
  3743. &deviceObject);
  3744. //
  3745. // If it found a legacy device, update the return parameter.
  3746. //
  3747. if (NT_SUCCESS(status) && deviceObject != NULL) {
  3748. *DeviceNode = PP_DO_TO_DN(deviceObject);
  3749. status = STATUS_SUCCESS;
  3750. } else {
  3751. status = STATUS_INVALID_DEVICE_REQUEST;
  3752. }
  3753. //
  3754. // Free the interface.
  3755. //
  3756. (*interface->InterfaceDereference)(interface->Context);
  3757. ExFreePool(interface);
  3758. return status;
  3759. }
  3760. VOID
  3761. IopSetLegacyDeviceInstance (
  3762. IN PDRIVER_OBJECT DriverObject,
  3763. IN PDEVICE_NODE DeviceNode
  3764. )
  3765. /*++
  3766. Routine Description:
  3767. This routine sets the Root\Legacy_xxxx\0000 device instance path to the
  3768. madeup PDO (i.e. DeviceNode) which is created only for legacy resource allocation.
  3769. This routine also links the madeup PDO to the Root\Legacy_xxxx\0000 device node
  3770. to keep track what resources are assigned to the driver which services the
  3771. root\legacy_xxxx\0000 device.
  3772. Parameters:
  3773. P1 -
  3774. Return Value:
  3775. Status code that indicates whether or not the function was successful.
  3776. --*/
  3777. {
  3778. NTSTATUS status;
  3779. UNICODE_STRING instancePath, rootString;
  3780. HANDLE handle;
  3781. PDEVICE_NODE legacyDeviceNode;
  3782. PDEVICE_OBJECT legacyPdo;
  3783. PAGED_CODE();
  3784. DeviceNode->OverUsed1.LegacyDeviceNode = 0;
  3785. instancePath.Length = 0;
  3786. instancePath.Buffer = NULL;
  3787. status = PipServiceInstanceToDeviceInstance (
  3788. NULL,
  3789. &DriverObject->DriverExtension->ServiceKeyName,
  3790. 0,
  3791. &instancePath,
  3792. &handle,
  3793. KEY_READ
  3794. );
  3795. if (NT_SUCCESS(status) && (instancePath.Length != 0)) {
  3796. PiWstrToUnicodeString(&rootString, L"ROOT\\LEGACY");
  3797. if (RtlPrefixUnicodeString(&rootString, &instancePath, TRUE) == FALSE) {
  3798. RtlFreeUnicodeString(&instancePath);
  3799. } else {
  3800. DeviceNode->InstancePath = instancePath;
  3801. legacyPdo = IopDeviceObjectFromDeviceInstance (&instancePath);
  3802. if (legacyPdo) {
  3803. legacyDeviceNode = PP_DO_TO_DN(legacyPdo);
  3804. DeviceNode->OverUsed2.NextResourceDeviceNode =
  3805. legacyDeviceNode->OverUsed2.NextResourceDeviceNode;
  3806. legacyDeviceNode->OverUsed2.NextResourceDeviceNode = DeviceNode;
  3807. DeviceNode->OverUsed1.LegacyDeviceNode = legacyDeviceNode;
  3808. }
  3809. }
  3810. ZwClose(handle);
  3811. }
  3812. }
  3813. PCM_RESOURCE_LIST
  3814. IopCombineLegacyResources (
  3815. IN PDEVICE_NODE DeviceNode
  3816. )
  3817. /*++
  3818. Routine Description:
  3819. This routine sets the Root\Legacy_xxxx\0000 device instance path to the
  3820. madeup PDO (i.e. DeviceNode) which is created only for legacy resource allocation.
  3821. This routine also links the madeup PDO to the Root\Legacy_xxxx\0000 device node
  3822. to keep track what resources are assigned to the driver which services the
  3823. root\legacy_xxxx\0000 device.
  3824. Parameters:
  3825. DeviceNode - The legacy device node whose resources need to be combined.
  3826. Return Value:
  3827. Return the combined resource list.
  3828. --*/
  3829. {
  3830. PCM_RESOURCE_LIST combinedList = NULL;
  3831. PDEVICE_NODE devNode = DeviceNode;
  3832. ULONG size = 0;
  3833. PUCHAR p;
  3834. PAGED_CODE();
  3835. if (DeviceNode) {
  3836. //
  3837. // First determine how much memory is needed for the new combined list.
  3838. //
  3839. while (devNode) {
  3840. if (devNode->ResourceList) {
  3841. size += IopDetermineResourceListSize(devNode->ResourceList);
  3842. }
  3843. devNode = (PDEVICE_NODE)devNode->OverUsed2.NextResourceDeviceNode;
  3844. }
  3845. if (size != 0) {
  3846. combinedList = (PCM_RESOURCE_LIST) ExAllocatePoolCMRL(PagedPool, size);
  3847. devNode = DeviceNode;
  3848. if (combinedList) {
  3849. combinedList->Count = 0;
  3850. p = (PUCHAR)combinedList;
  3851. p += sizeof(ULONG); // Skip Count
  3852. while (devNode) {
  3853. if (devNode->ResourceList) {
  3854. size = IopDetermineResourceListSize(devNode->ResourceList);
  3855. if (size != 0) {
  3856. size -= sizeof(ULONG);
  3857. RtlCopyMemory(
  3858. p,
  3859. devNode->ResourceList->List,
  3860. size
  3861. );
  3862. p += size;
  3863. combinedList->Count += devNode->ResourceList->Count;
  3864. }
  3865. }
  3866. devNode = (PDEVICE_NODE)devNode->OverUsed2.NextResourceDeviceNode;
  3867. }
  3868. }
  3869. }
  3870. }
  3871. return combinedList;
  3872. }
  3873. VOID
  3874. IopReleaseResources (
  3875. IN PDEVICE_NODE DeviceNode
  3876. )
  3877. /*++
  3878. Routine Description:
  3879. IopReleaseResources releases resources owned by the device and release
  3880. the memory pool. We also release the cached resource requirements list.
  3881. If the device is a root enumerated device with BOOT config, we will preallocate
  3882. boot config resources for this device.
  3883. NOTE, this is a routine INTERNAL to this file. NO one should call this function
  3884. outside of this file. Outside of this file, IopReleaseDeviceResources should be
  3885. used.
  3886. Arguments:
  3887. DeviceNode - Supplies a pointer to the device node.object. If present, caller wants to
  3888. Return Value:
  3889. None.
  3890. --*/
  3891. {
  3892. //
  3893. // Release the resources owned by the device
  3894. //
  3895. IopReleaseResourcesInternal(DeviceNode);
  3896. #if DBG_SCOPE
  3897. if (DeviceNode->PreviousResourceList) {
  3898. ExFreePool(DeviceNode->PreviousResourceList);
  3899. DeviceNode->PreviousResourceList = NULL;
  3900. }
  3901. if (DeviceNode->PreviousResourceRequirements) {
  3902. ExFreePool(DeviceNode->PreviousResourceRequirements);
  3903. DeviceNode->PreviousResourceRequirements = NULL;
  3904. }
  3905. #endif
  3906. if (DeviceNode->ResourceList) {
  3907. #if DBG_SCOPE
  3908. if (!NT_SUCCESS(DeviceNode->FailureStatus)) {
  3909. DeviceNode->PreviousResourceList = DeviceNode->ResourceList;
  3910. } else {
  3911. ExFreePool(DeviceNode->ResourceList);
  3912. }
  3913. #else
  3914. ExFreePool(DeviceNode->ResourceList);
  3915. #endif
  3916. DeviceNode->ResourceList = NULL;
  3917. }
  3918. if (DeviceNode->ResourceListTranslated) {
  3919. ExFreePool(DeviceNode->ResourceListTranslated);
  3920. DeviceNode->ResourceListTranslated = NULL;
  3921. }
  3922. //
  3923. // If this device is a root enumerated device, preallocate its BOOT resources
  3924. //
  3925. if ((DeviceNode->Flags & (DNF_MADEUP | DNF_DEVICE_GONE)) == DNF_MADEUP) {
  3926. if (DeviceNode->Flags & DNF_HAS_BOOT_CONFIG && DeviceNode->BootResources) {
  3927. IopAllocateBootResourcesInternal(ArbiterRequestPnpEnumerated,
  3928. DeviceNode->PhysicalDeviceObject,
  3929. DeviceNode->BootResources);
  3930. }
  3931. } else {
  3932. DeviceNode->Flags &= ~(DNF_HAS_BOOT_CONFIG | DNF_BOOT_CONFIG_RESERVED);
  3933. if (DeviceNode->BootResources) {
  3934. ExFreePool(DeviceNode->BootResources);
  3935. DeviceNode->BootResources = NULL;
  3936. }
  3937. }
  3938. }
  3939. VOID
  3940. IopReallocateResources(
  3941. IN PDEVICE_NODE DeviceNode
  3942. )
  3943. /*++
  3944. Routine Description:
  3945. This routine performs the real work for IoInvalidateDeviceState - ResourceRequirementsChanged.
  3946. Arguments:
  3947. DeviceNode - Supplies a pointer to the device node.
  3948. Return Value:
  3949. None.
  3950. --*/
  3951. {
  3952. IOP_RESOURCE_REQUEST requestTable, *requestTablep;
  3953. ULONG deviceCount, oldFlags;
  3954. NTSTATUS status;
  3955. LIST_ENTRY activeArbiterList;
  3956. PAGED_CODE();
  3957. //
  3958. // Grab the IO registry semaphore to make sure no other device is
  3959. // reporting it's resource usage while we are searching for conflicts.
  3960. //
  3961. IopLockResourceManager();
  3962. //
  3963. // Check the flags after acquiring the semaphore.
  3964. //
  3965. if (DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) {
  3966. //
  3967. // Save the flags which we may have to restore in case of failure.
  3968. //
  3969. oldFlags = DeviceNode->Flags & DNF_NO_RESOURCE_REQUIRED;
  3970. DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
  3971. if (DeviceNode->Flags & DNF_NON_STOPPED_REBALANCE) {
  3972. //
  3973. // Set up parameters to call real routine
  3974. //
  3975. RtlZeroMemory(&requestTable, sizeof(IOP_RESOURCE_REQUEST));
  3976. requestTable.PhysicalDevice = DeviceNode->PhysicalDeviceObject;
  3977. requestTablep = &requestTable;
  3978. requestTable.Flags |= IOP_ASSIGN_NO_REBALANCE + IOP_ASSIGN_KEEP_CURRENT_CONFIG;
  3979. status = IopGetResourceRequirementsForAssignTable( requestTablep,
  3980. requestTablep + 1,
  3981. &deviceCount);
  3982. if (deviceCount) {
  3983. //
  3984. // Release the current resources to the arbiters.
  3985. // Memory for ResourceList is not released.
  3986. //
  3987. if (DeviceNode->ResourceList) {
  3988. IopReleaseResourcesInternal(DeviceNode);
  3989. }
  3990. //
  3991. // Try to do the assignment.
  3992. //
  3993. status = IopFindBestConfiguration(
  3994. requestTablep,
  3995. deviceCount,
  3996. &activeArbiterList);
  3997. if (NT_SUCCESS(status)) {
  3998. //
  3999. // Ask the arbiters to commit this configuration.
  4000. //
  4001. status = IopCommitConfiguration(&activeArbiterList);
  4002. }
  4003. if (NT_SUCCESS(status)) {
  4004. DeviceNode->Flags &= ~(DNF_RESOURCE_REQUIREMENTS_CHANGED | DNF_NON_STOPPED_REBALANCE);
  4005. IopBuildCmResourceLists(requestTablep, requestTablep + 1);
  4006. //
  4007. // We need to release the pool space for ResourceList and ResourceListTranslated.
  4008. // Because the earlier IopReleaseResourcesInternal does not release the pool.
  4009. //
  4010. if (DeviceNode->ResourceList) {
  4011. ExFreePool(DeviceNode->ResourceList);
  4012. }
  4013. if (DeviceNode->ResourceListTranslated) {
  4014. ExFreePool(DeviceNode->ResourceListTranslated);
  4015. }
  4016. DeviceNode->ResourceList = requestTablep->ResourceAssignment;
  4017. DeviceNode->ResourceListTranslated = requestTablep->TranslatedResourceAssignment;
  4018. ASSERT(DeviceNode->State == DeviceNodeStarted);
  4019. status = IopStartDevice(DeviceNode->PhysicalDeviceObject);
  4020. if (!NT_SUCCESS(status)) {
  4021. PipRequestDeviceRemoval(DeviceNode, FALSE, CM_PROB_NORMAL_CONFLICT);
  4022. }
  4023. } else {
  4024. NTSTATUS restoreResourcesStatus;
  4025. restoreResourcesStatus = IopRestoreResourcesInternal(DeviceNode);
  4026. if (!NT_SUCCESS(restoreResourcesStatus)) {
  4027. ASSERT(NT_SUCCESS(restoreResourcesStatus));
  4028. PipRequestDeviceRemoval(DeviceNode, FALSE, CM_PROB_NEED_RESTART);
  4029. }
  4030. }
  4031. IopFreeResourceRequirementsForAssignTable(requestTablep, requestTablep + 1);
  4032. }
  4033. } else {
  4034. //
  4035. // The device needs to be stopped to change resources.
  4036. //
  4037. status = IopRebalance(0, NULL);
  4038. }
  4039. //
  4040. // Restore the flags in case of failure.
  4041. //
  4042. if (!NT_SUCCESS(status)) {
  4043. DeviceNode->Flags &= ~DNF_NO_RESOURCE_REQUIRED;
  4044. DeviceNode->Flags |= oldFlags;
  4045. }
  4046. } else {
  4047. IopDbgPrint((
  4048. IOP_RESOURCE_ERROR_LEVEL,
  4049. "Resource requirements not changed in "
  4050. "IopReallocateResources, returning error!\n"));
  4051. }
  4052. IopUnlockResourceManager();
  4053. }
  4054. NTSTATUS
  4055. IopQueryConflictList(
  4056. PDEVICE_OBJECT PhysicalDeviceObject,
  4057. IN PCM_RESOURCE_LIST ResourceList,
  4058. IN ULONG ResourceListSize,
  4059. OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
  4060. IN ULONG ConflictListSize,
  4061. IN ULONG Flags
  4062. )
  4063. /*++
  4064. Routine Description:
  4065. This routine performs the querying of device conflicts
  4066. returning data in ConflictList
  4067. Arguments:
  4068. PhysicalDeviceObject PDO of device to Query
  4069. ResourceList CM resource list containing single resource to query
  4070. ResourceListSize Size of ResourceList
  4071. ConflictList Conflict list to fill query details in
  4072. ConflictListSize Size of buffer that we can fill with Conflict information
  4073. Flags Currently unused (zero) for future passing of flags
  4074. Return Value:
  4075. Should be success in most cases
  4076. --*/
  4077. {
  4078. NTSTATUS status;
  4079. PAGED_CODE();
  4080. IopLockResourceManager();
  4081. status = IopQueryConflictListInternal(PhysicalDeviceObject, ResourceList, ResourceListSize, ConflictList, ConflictListSize, Flags);
  4082. IopUnlockResourceManager();
  4083. return status;
  4084. }
  4085. BOOLEAN
  4086. IopEliminateBogusConflict(
  4087. IN PDEVICE_OBJECT PhysicalDeviceObject,
  4088. IN PDEVICE_OBJECT ConflictDeviceObject
  4089. )
  4090. /*++
  4091. Routine Description:
  4092. Determine if we're really conflicting with ourselves
  4093. if this is the case, we ignore it
  4094. Arguments:
  4095. PhysicalDeviceObject PDO we're performing the test for
  4096. ConflictDeviceObject The object we've determined is conflicting
  4097. Return Value:
  4098. TRUE to eliminate the conflict
  4099. --*/
  4100. {
  4101. PDEVICE_NODE deviceNode;
  4102. PDRIVER_OBJECT driverObject;
  4103. KIRQL irql;
  4104. PDEVICE_OBJECT attachedDevice;
  4105. //
  4106. // simple cases
  4107. //
  4108. if (PhysicalDeviceObject == NULL || ConflictDeviceObject == NULL) {
  4109. return FALSE;
  4110. }
  4111. //
  4112. // if ConflictDeviceObject is on PDO's stack, this is a non-conflict
  4113. // nb at least PDO has to be checked
  4114. //
  4115. irql = KeAcquireQueuedSpinLock( LockQueueIoDatabaseLock );
  4116. for (attachedDevice = PhysicalDeviceObject;
  4117. attachedDevice;
  4118. attachedDevice = attachedDevice->AttachedDevice) {
  4119. if (attachedDevice == ConflictDeviceObject) {
  4120. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  4121. return TRUE;
  4122. }
  4123. }
  4124. KeReleaseQueuedSpinLock( LockQueueIoDatabaseLock, irql );
  4125. //
  4126. // legacy case
  4127. //
  4128. deviceNode = PP_DO_TO_DN(PhysicalDeviceObject);
  4129. ASSERT(deviceNode);
  4130. if (deviceNode->Flags & DNF_LEGACY_DRIVER) {
  4131. //
  4132. // hmmm, let's see if our ConflictDeviceObject is resources associated with a legacy device
  4133. //
  4134. if (ConflictDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) {
  4135. //
  4136. // if not, we have a legacy conflicting with non-legacy, we're interested!
  4137. //
  4138. return FALSE;
  4139. }
  4140. //
  4141. // FDO, report driver name
  4142. //
  4143. driverObject = ConflictDeviceObject->DriverObject;
  4144. if(driverObject == NULL) {
  4145. //
  4146. // should not be NULL
  4147. //
  4148. ASSERT(driverObject);
  4149. return FALSE;
  4150. }
  4151. //
  4152. // compare deviceNode->Service with driverObject->Service
  4153. //
  4154. if (deviceNode->ServiceName.Length != 0 &&
  4155. deviceNode->ServiceName.Length == driverObject->DriverExtension->ServiceKeyName.Length &&
  4156. RtlCompareUnicodeString(&deviceNode->ServiceName,&driverObject->DriverExtension->ServiceKeyName,TRUE)==0) {
  4157. //
  4158. // the driver's service name is the same that this PDO is associated with
  4159. // by ignoring it we could end up ignoring conflicts of simular types of legacy devices
  4160. // but since these have to be hand-config'd anyhow, it's prob better than having false conflicts
  4161. //
  4162. return TRUE;
  4163. }
  4164. }
  4165. return FALSE;
  4166. }
  4167. NTSTATUS
  4168. IopQueryConflictFillString(
  4169. IN PDEVICE_OBJECT DeviceObject,
  4170. IN PWSTR Buffer,
  4171. IN OUT PULONG Length,
  4172. IN OUT PULONG Flags
  4173. )
  4174. /*++
  4175. Routine Description:
  4176. Obtain string or string-length for details of conflicting device
  4177. Arguments:
  4178. DeviceObject Device object we want Device-Instance-String or Service Name
  4179. Buffer Buffer to Fill, NULL if we just want length
  4180. Length Filled with length of Buffer, including terminated NULL (Words)
  4181. Flags Apropriate flags set describing what the string represents
  4182. Return Value:
  4183. Should be success in most cases
  4184. --*/
  4185. {
  4186. NTSTATUS status = STATUS_SUCCESS;
  4187. PDEVICE_NODE deviceNode;
  4188. PDRIVER_OBJECT driverObject;
  4189. PUNICODE_STRING infoString = NULL;
  4190. ULONG MaxLength = 0; // words
  4191. ULONG ReqLength = 0; // words
  4192. ULONG flags = 0;
  4193. PAGED_CODE();
  4194. if (Length != NULL) {
  4195. MaxLength = *Length;
  4196. }
  4197. if (Flags != NULL) {
  4198. flags = *Flags;
  4199. }
  4200. if (DeviceObject == NULL) {
  4201. //
  4202. // unknown
  4203. //
  4204. goto final;
  4205. }
  4206. if ((DeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) == 0 ) {
  4207. //
  4208. // FDO, report driver name
  4209. //
  4210. driverObject = DeviceObject->DriverObject;
  4211. if(driverObject == NULL) {
  4212. //
  4213. // should not be NULL
  4214. //
  4215. ASSERT(driverObject);
  4216. goto final;
  4217. }
  4218. infoString = & (driverObject->DriverName);
  4219. flags |= PNP_CE_LEGACY_DRIVER;
  4220. goto final;
  4221. }
  4222. //
  4223. // we should in actual fact have a PDO
  4224. //
  4225. if (DeviceObject->DeviceObjectExtension == NULL) {
  4226. //
  4227. // should not be NULL
  4228. //
  4229. ASSERT(DeviceObject->DeviceObjectExtension);
  4230. goto final;
  4231. }
  4232. deviceNode = PP_DO_TO_DN(DeviceObject);
  4233. if (deviceNode == NULL) {
  4234. //
  4235. // should not be NULL
  4236. //
  4237. ASSERT(deviceNode);
  4238. goto final;
  4239. }
  4240. if (deviceNode == IopRootDeviceNode) {
  4241. //
  4242. // owned by root device
  4243. //
  4244. flags |= PNP_CE_ROOT_OWNED;
  4245. } else if (deviceNode -> Parent == NULL) {
  4246. //
  4247. // faked out PDO - must be legacy device
  4248. //
  4249. driverObject = (PDRIVER_OBJECT)(deviceNode->DuplicatePDO);
  4250. if(driverObject == NULL) {
  4251. //
  4252. // should not be NULL
  4253. //
  4254. ASSERT(driverObject);
  4255. goto final;
  4256. }
  4257. infoString = & (driverObject->DriverName);
  4258. flags |= PNP_CE_LEGACY_DRIVER;
  4259. goto final;
  4260. }
  4261. //
  4262. // we should be happy with what we have
  4263. //
  4264. infoString = &deviceNode->InstancePath;
  4265. final:
  4266. if (infoString != NULL) {
  4267. //
  4268. // we have a string to copy
  4269. //
  4270. if ((Buffer != NULL) && (MaxLength*sizeof(WCHAR) > infoString->Length)) {
  4271. RtlCopyMemory(Buffer, infoString->Buffer, infoString->Length);
  4272. }
  4273. ReqLength += infoString->Length / sizeof(WCHAR);
  4274. }
  4275. if ((Buffer != NULL) && (MaxLength > ReqLength)) {
  4276. Buffer[ReqLength] = 0;
  4277. }
  4278. ReqLength++;
  4279. if (Length != NULL) {
  4280. *Length = ReqLength;
  4281. }
  4282. if (Flags != NULL) {
  4283. *Flags = flags;
  4284. }
  4285. return status;
  4286. }
  4287. NTSTATUS
  4288. IopQueryConflictFillConflicts(
  4289. PDEVICE_OBJECT PhysicalDeviceObject,
  4290. IN ULONG ConflictCount,
  4291. IN PARBITER_CONFLICT_INFO ConflictInfoList,
  4292. OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
  4293. IN ULONG ConflictListSize,
  4294. IN ULONG Flags
  4295. )
  4296. /*++
  4297. Routine Description:
  4298. Fill ConflictList with information on as many conflicts as possible
  4299. Arguments:
  4300. PhysicalDeviceObject The PDO we're performing the test on
  4301. ConflictCount Number of Conflicts.
  4302. ConflictInfoList List of conflicting device info, can be NULL if ConflictCount is 0
  4303. ConflictList Structure to fill in with conflicts
  4304. ConflictListSize Size of Conflict List
  4305. Flags if non-zero, dummy conflict is created
  4306. Return Value:
  4307. Should be success in most cases
  4308. --*/
  4309. {
  4310. NTSTATUS status = STATUS_SUCCESS;
  4311. ULONG ConflictListIdealSize;
  4312. ULONG ConflictListCount;
  4313. ULONG Index;
  4314. ULONG ConflictIndex;
  4315. ULONG EntrySize;
  4316. ULONG ConflictStringsOffset;
  4317. ULONG stringSize;
  4318. ULONG stringTotalSize;
  4319. ULONG DummyCount;
  4320. PPLUGPLAY_CONTROL_CONFLICT_STRINGS ConfStrings;
  4321. PAGED_CODE();
  4322. //
  4323. // determine how many conflicts we can
  4324. //
  4325. // for each conflict
  4326. // translate to bus/resource/address in respect to conflicting device
  4327. // add to conflict list
  4328. //
  4329. //
  4330. //
  4331. // preprocessing - given our ConflictInfoList and ConflictCount
  4332. // remove any that appear to be bogus - ie, that are the same device that we are testing against
  4333. // this stops mostly legacy issues
  4334. //
  4335. for(Index = 0;Index < ConflictCount; Index++) {
  4336. if (IopEliminateBogusConflict(PhysicalDeviceObject,ConflictInfoList[Index].OwningObject)) {
  4337. IopDbgPrint((
  4338. IOP_RESOURCE_VERBOSE_LEVEL,
  4339. "IopQueryConflictFillConflicts: eliminating \"identical\" PDO"
  4340. " %08x conflicting with self (%08x)\n",
  4341. ConflictInfoList[Index].OwningObject,
  4342. PhysicalDeviceObject));
  4343. //
  4344. // move the last listed conflict into this space
  4345. //
  4346. if (Index+1 < ConflictCount) {
  4347. RtlCopyMemory(&ConflictInfoList[Index],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
  4348. }
  4349. //
  4350. // account for deleting this item
  4351. //
  4352. ConflictCount--;
  4353. Index--;
  4354. }
  4355. }
  4356. //
  4357. // preprocessing - in our conflict list, we may have PDO's for legacy devices, and resource nodes for the same
  4358. // or other duplicate entities (we only ever want to report a conflict once, even if there's multiple conflicting ranges)
  4359. //
  4360. RestartScan:
  4361. for(Index = 0;Index < ConflictCount; Index++) {
  4362. if (ConflictInfoList[Index].OwningObject != NULL) {
  4363. ULONG Index2;
  4364. for (Index2 = Index+1; Index2 < ConflictCount; Index2++) {
  4365. if (IopEliminateBogusConflict(ConflictInfoList[Index].OwningObject,ConflictInfoList[Index2].OwningObject)) {
  4366. //
  4367. // Index2 is considered a dup of Index
  4368. //
  4369. IopDbgPrint((
  4370. IOP_RESOURCE_VERBOSE_LEVEL,
  4371. "IopQueryConflictFillConflicts: eliminating \"identical\" PDO"
  4372. " %08x conflicting with PDO %08x\n",
  4373. ConflictInfoList[Index2].OwningObject,
  4374. ConflictInfoList[Index].OwningObject));
  4375. //
  4376. // move the last listed conflict into this space
  4377. //
  4378. if (Index2+1 < ConflictCount) {
  4379. RtlCopyMemory(&ConflictInfoList[Index2],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
  4380. }
  4381. //
  4382. // account for deleting this item
  4383. //
  4384. ConflictCount--;
  4385. Index2--;
  4386. } else if (IopEliminateBogusConflict(ConflictInfoList[Index2].OwningObject,ConflictInfoList[Index].OwningObject)) {
  4387. //
  4388. // Index is considered a dup of Index2 (some legacy case)
  4389. //
  4390. IopDbgPrint((
  4391. IOP_RESOURCE_VERBOSE_LEVEL,
  4392. "IopQueryConflictFillConflicts: eliminating \"identical\" PDO"
  4393. " %08x conflicting with PDO %08x\n",
  4394. ConflictInfoList[Index2].OwningObject,
  4395. ConflictInfoList[Index].OwningObject));
  4396. //
  4397. // move the one we want (Index2) into the space occupied by Index
  4398. //
  4399. RtlCopyMemory(&ConflictInfoList[Index],&ConflictInfoList[Index2],sizeof(ARBITER_CONFLICT_INFO));
  4400. //
  4401. // move the last listed conflict into the space we just created
  4402. //
  4403. if (Index2+1 < ConflictCount) {
  4404. RtlCopyMemory(&ConflictInfoList[Index2],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
  4405. }
  4406. //
  4407. // account for deleting this item
  4408. //
  4409. ConflictCount--;
  4410. //
  4411. // but as this is quirky, restart the scan
  4412. //
  4413. goto RestartScan;
  4414. }
  4415. }
  4416. }
  4417. }
  4418. //
  4419. // preprocessing - if we have any known reported conflicts, don't report back any unknown
  4420. //
  4421. for(Index = 0;Index < ConflictCount; Index++) {
  4422. //
  4423. // find first unknown
  4424. //
  4425. if (ConflictInfoList[Index].OwningObject == NULL) {
  4426. //
  4427. // eliminate all other unknowns
  4428. //
  4429. ULONG Index2;
  4430. for (Index2 = Index+1; Index2 < ConflictCount; Index2++) {
  4431. if (ConflictInfoList[Index2].OwningObject == NULL) {
  4432. IopDbgPrint((
  4433. IOP_RESOURCE_VERBOSE_LEVEL,
  4434. "IopQueryConflictFillConflicts: eliminating extra"
  4435. " unknown\n"));
  4436. //
  4437. // move the last listed conflict into this space
  4438. //
  4439. if (Index2+1 < ConflictCount) {
  4440. RtlCopyMemory(&ConflictInfoList[Index2],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
  4441. }
  4442. //
  4443. // account for deleting this item
  4444. //
  4445. ConflictCount--;
  4446. Index2--;
  4447. }
  4448. }
  4449. if(ConflictCount != 1) {
  4450. IopDbgPrint((
  4451. IOP_RESOURCE_VERBOSE_LEVEL,
  4452. "IopQueryConflictFillConflicts: eliminating first unknown\n"
  4453. ));
  4454. //
  4455. // there were others, so ignore the unknown
  4456. //
  4457. if (Index+1 < ConflictCount) {
  4458. RtlCopyMemory(&ConflictInfoList[Index],&ConflictInfoList[ConflictCount-1],sizeof(ARBITER_CONFLICT_INFO));
  4459. }
  4460. ConflictCount --;
  4461. }
  4462. break;
  4463. }
  4464. }
  4465. //
  4466. // set number of actual and listed conflicts
  4467. //
  4468. ConflictListIdealSize = (sizeof(PLUGPLAY_CONTROL_CONFLICT_LIST) - sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY)) + sizeof(PLUGPLAY_CONTROL_CONFLICT_STRINGS);
  4469. ConflictListCount = 0;
  4470. stringTotalSize = 0;
  4471. DummyCount = 0;
  4472. ASSERT(ConflictListSize >= ConflictListIdealSize); // we should have checked to see if buffer is at least this big
  4473. IopDbgPrint((
  4474. IOP_RESOURCE_VERBOSE_LEVEL,
  4475. "IopQueryConflictFillConflicts: Detected %d conflicts\n",
  4476. ConflictCount));
  4477. //
  4478. // estimate sizes
  4479. //
  4480. if (Flags) {
  4481. //
  4482. // flags entry required (ie resource not available for some specified reason)
  4483. //
  4484. stringSize = 1; // null-length string
  4485. DummyCount ++;
  4486. EntrySize = sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY);
  4487. EntrySize += sizeof(WCHAR) * stringSize;
  4488. if((ConflictListIdealSize+EntrySize) <= ConflictListSize) {
  4489. //
  4490. // we can fit this one in
  4491. //
  4492. ConflictListCount++;
  4493. stringTotalSize += stringSize;
  4494. }
  4495. ConflictListIdealSize += EntrySize;
  4496. }
  4497. //
  4498. // report conflicts
  4499. //
  4500. for(Index = 0; Index < ConflictCount; Index ++) {
  4501. stringSize = 0;
  4502. IopQueryConflictFillString(ConflictInfoList[Index].OwningObject,NULL,&stringSize,NULL);
  4503. //
  4504. // account for entry
  4505. //
  4506. EntrySize = sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY);
  4507. EntrySize += sizeof(WCHAR) * stringSize;
  4508. if((ConflictListIdealSize+EntrySize) <= ConflictListSize) {
  4509. //
  4510. // we can fit this one in
  4511. //
  4512. ConflictListCount++;
  4513. stringTotalSize += stringSize;
  4514. }
  4515. ConflictListIdealSize += EntrySize;
  4516. }
  4517. ConflictList->ConflictsCounted = ConflictCount+DummyCount; // number of conflicts detected including any dummy conflict
  4518. ConflictList->ConflictsListed = ConflictListCount; // how many we could fit in
  4519. ConflictList->RequiredBufferSize = ConflictListIdealSize; // how much buffer space to supply on next call
  4520. IopDbgPrint((
  4521. IOP_RESOURCE_VERBOSE_LEVEL,
  4522. "IopQueryConflictFillConflicts: Listing %d conflicts\n",
  4523. ConflictListCount));
  4524. IopDbgPrint((
  4525. IOP_RESOURCE_VERBOSE_LEVEL,
  4526. "IopQueryConflictFillConflicts: Need %08x bytes to list all conflicts\n",
  4527. ConflictListIdealSize));
  4528. ConfStrings = (PPLUGPLAY_CONTROL_CONFLICT_STRINGS)&(ConflictList->ConflictEntry[ConflictListCount]);
  4529. ConfStrings->NullDeviceInstance = (ULONG)(-1);
  4530. ConflictStringsOffset = 0;
  4531. for(ConflictIndex = 0; ConflictIndex < DummyCount; ConflictIndex++) {
  4532. //
  4533. // flags entry required (ie resource not available for some specified reason)
  4534. //
  4535. if (Flags && ConflictIndex == 0) {
  4536. ConflictList->ConflictEntry[ConflictIndex].DeviceInstance = ConflictStringsOffset;
  4537. ConflictList->ConflictEntry[ConflictIndex].DeviceFlags = Flags;
  4538. ConflictList->ConflictEntry[ConflictIndex].ResourceType = 0;
  4539. ConflictList->ConflictEntry[ConflictIndex].ResourceStart = 0;
  4540. ConflictList->ConflictEntry[ConflictIndex].ResourceEnd = 0;
  4541. ConflictList->ConflictEntry[ConflictIndex].ResourceFlags = 0;
  4542. ConfStrings->DeviceInstanceStrings[ConflictStringsOffset] = 0; // null string
  4543. stringTotalSize --;
  4544. ConflictStringsOffset ++;
  4545. IopDbgPrint((
  4546. IOP_RESOURCE_VERBOSE_LEVEL,
  4547. "IopQueryConflictFillConflicts: Listing flags %08x\n",
  4548. Flags));
  4549. }
  4550. }
  4551. //
  4552. // get/fill in details for all those we can fit into the buffer
  4553. //
  4554. for(Index = 0; ConflictIndex < ConflictListCount ; Index ++, ConflictIndex++) {
  4555. ASSERT(Index < ConflictCount);
  4556. //
  4557. // assign conflict information
  4558. //
  4559. ConflictList->ConflictEntry[ConflictIndex].DeviceInstance = ConflictStringsOffset;
  4560. ConflictList->ConflictEntry[ConflictIndex].DeviceFlags = 0;
  4561. ConflictList->ConflictEntry[ConflictIndex].ResourceType = 0; // NYI
  4562. ConflictList->ConflictEntry[ConflictIndex].ResourceStart = (ULONGLONG)(1); // for now, return totally invalid range (1-0)
  4563. ConflictList->ConflictEntry[ConflictIndex].ResourceEnd = 0;
  4564. ConflictList->ConflictEntry[ConflictIndex].ResourceFlags = 0;
  4565. //
  4566. // fill string details
  4567. //
  4568. stringSize = stringTotalSize;
  4569. IopQueryConflictFillString(ConflictInfoList[Index].OwningObject,
  4570. &(ConfStrings->DeviceInstanceStrings[ConflictStringsOffset]),
  4571. &stringSize,
  4572. &(ConflictList->ConflictEntry[ConflictIndex].DeviceFlags));
  4573. stringTotalSize -= stringSize;
  4574. IopDbgPrint((
  4575. IOP_RESOURCE_VERBOSE_LEVEL,
  4576. "IopQueryConflictFillConflicts: Listing \"%S\"\n",
  4577. &(ConfStrings->DeviceInstanceStrings[ConflictStringsOffset])));
  4578. ConflictStringsOffset += stringSize;
  4579. }
  4580. //
  4581. // another NULL at end of strings (this is accounted for in the PPLUGPLAY_CONTROL_CONFLICT_STRINGS structure)
  4582. //
  4583. ConfStrings->DeviceInstanceStrings[ConflictStringsOffset] = 0;
  4584. //Clean0:
  4585. ;
  4586. return status;
  4587. }
  4588. NTSTATUS
  4589. IopQueryConflictListInternal(
  4590. PDEVICE_OBJECT PhysicalDeviceObject,
  4591. IN PCM_RESOURCE_LIST ResourceList,
  4592. IN ULONG ResourceListSize,
  4593. OUT PPLUGPLAY_CONTROL_CONFLICT_LIST ConflictList,
  4594. IN ULONG ConflictListSize,
  4595. IN ULONG Flags
  4596. )
  4597. /*++
  4598. Routine Description:
  4599. Version of IopQueryConflictList without the locking
  4600. --*/
  4601. {
  4602. NTSTATUS status = STATUS_SUCCESS;
  4603. PDEVICE_NODE deviceNode = NULL;
  4604. PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
  4605. PREQ_LIST reqList;
  4606. PREQ_DESC reqDesc, reqDescTranslated;
  4607. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  4608. PREQ_ALTERNATIVE RA;
  4609. PPREQ_ALTERNATIVE reqAlternative;
  4610. ULONG ConflictCount = 0;
  4611. PARBITER_CONFLICT_INFO ConflictInfoList = NULL;
  4612. PIO_RESOURCE_DESCRIPTOR ConflictDesc = NULL;
  4613. ULONG ReqDescCount = 0;
  4614. PREQ_DESC *ReqDescTable = NULL;
  4615. PIO_RESOURCE_REQUIREMENTS_LIST pIoReqList = NULL;
  4616. PVOID ExtParams[4];
  4617. IOP_RESOURCE_REQUEST request;
  4618. UNREFERENCED_PARAMETER( Flags );
  4619. PAGED_CODE();
  4620. ASSERT(PhysicalDeviceObject);
  4621. ASSERT(ResourceList);
  4622. ASSERT(ResourceListSize);
  4623. //
  4624. // these parameters were generated by umpnpmgr
  4625. // so should be correct - one resource, and one resource only
  4626. //
  4627. ASSERT(ResourceList->Count == 1);
  4628. ASSERT(ResourceList->List[0].PartialResourceList.Count == 1);
  4629. if (ConflictList == NULL || (ConflictListSize < (sizeof(PLUGPLAY_CONTROL_CONFLICT_LIST) - sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY)) + sizeof(PLUGPLAY_CONTROL_CONFLICT_STRINGS))) {
  4630. //
  4631. // sanity check
  4632. //
  4633. status = STATUS_BUFFER_TOO_SMALL;
  4634. goto Clean0;
  4635. }
  4636. //
  4637. // whatever other error we return, ensure that ConflictList is interpretable
  4638. //
  4639. ConflictList->ConflictsCounted = 0;
  4640. ConflictList->ConflictsListed = 0;
  4641. ConflictList->RequiredBufferSize = (sizeof(PLUGPLAY_CONTROL_CONFLICT_LIST) - sizeof(PLUGPLAY_CONTROL_CONFLICT_ENTRY)) + sizeof(PLUGPLAY_CONTROL_CONFLICT_STRINGS);
  4642. //
  4643. // Retrieve the devnode from the PDO
  4644. //
  4645. deviceNode = PP_DO_TO_DN(PhysicalDeviceObject);
  4646. if (!deviceNode) {
  4647. status = STATUS_NO_SUCH_DEVICE;
  4648. goto Clean0;
  4649. }
  4650. //
  4651. // type-specific validation
  4652. //
  4653. switch(ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type) {
  4654. case CmResourceTypePort:
  4655. case CmResourceTypeMemory:
  4656. if(ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Generic.Length == 0) {
  4657. //
  4658. // zero-range resource can never conflict
  4659. //
  4660. status = STATUS_SUCCESS;
  4661. goto Clean0;
  4662. }
  4663. break;
  4664. case CmResourceTypeInterrupt:
  4665. case CmResourceTypeDma:
  4666. break;
  4667. default:
  4668. ASSERT(0);
  4669. status = STATUS_INVALID_PARAMETER;
  4670. goto Clean0;
  4671. }
  4672. //
  4673. // apply bus details from node
  4674. //
  4675. if (deviceNode->ChildInterfaceType == InterfaceTypeUndefined) {
  4676. //
  4677. // we have to grovel around to find real Interface Type
  4678. //
  4679. pIoReqList = deviceNode->ResourceRequirements;
  4680. if (pIoReqList != NULL && pIoReqList->InterfaceType != InterfaceTypeUndefined) {
  4681. ResourceList->List[0].InterfaceType = pIoReqList->InterfaceType;
  4682. } else {
  4683. //
  4684. // we should never get here
  4685. // if we do, I need to look at this more
  4686. //
  4687. #if MAXDBG
  4688. ASSERT(0);
  4689. #endif
  4690. ResourceList->List[0].InterfaceType = PnpDefaultInterfaceType;
  4691. }
  4692. } else {
  4693. //
  4694. // we trust the deviceNode to tell us Interface Type
  4695. //
  4696. ResourceList->List[0].InterfaceType = deviceNode->ChildInterfaceType;
  4697. }
  4698. //
  4699. // Some bus-types we are better off considered as default
  4700. //
  4701. switch(ResourceList->List[0].InterfaceType) {
  4702. case InterfaceTypeUndefined:
  4703. case PCMCIABus:
  4704. ResourceList->List[0].InterfaceType = PnpDefaultInterfaceType;
  4705. }
  4706. if ((deviceNode->ChildBusNumber & 0x80000000) == 0x80000000) {
  4707. //
  4708. // we have to grovel around to find real Bus Number
  4709. //
  4710. pIoReqList = deviceNode->ResourceRequirements;
  4711. if (pIoReqList != NULL && (pIoReqList->BusNumber & 0x80000000) != 0x80000000) {
  4712. ResourceList->List[0].BusNumber = pIoReqList->BusNumber;
  4713. } else {
  4714. //
  4715. // a resonable default, but assert is here so I remember to look at this more
  4716. //
  4717. #if MAXDBG
  4718. ASSERT(0);
  4719. #endif
  4720. ResourceList->List[0].BusNumber = 0;
  4721. }
  4722. } else {
  4723. //
  4724. // we trust the deviceNode to tell us Bus Number
  4725. //
  4726. ResourceList->List[0].BusNumber = deviceNode->ChildBusNumber;
  4727. }
  4728. //
  4729. // from our CM Resource List, obtain an IO Resource Requirements List
  4730. //
  4731. ioResources = IopCmResourcesToIoResources(0, ResourceList, LCPRI_FORCECONFIG);
  4732. if (!ioResources) {
  4733. status = STATUS_INVALID_PARAMETER;
  4734. goto Clean0;
  4735. }
  4736. //
  4737. // Convert ioResources to a Request list
  4738. // and in the processess, determine any Arbiters/Translators to use
  4739. //
  4740. request.AllocationType = ArbiterRequestUndefined;
  4741. request.ResourceRequirements = ioResources;
  4742. request.PhysicalDevice = PhysicalDeviceObject;
  4743. status = IopResourceRequirementsListToReqList(
  4744. &request,
  4745. &reqList);
  4746. //
  4747. // get arbitrator/translator for current device/bus
  4748. //
  4749. if (NT_SUCCESS(status) && reqList) {
  4750. reqAlternative = reqList->AlternativeTable;
  4751. RA = *reqAlternative;
  4752. reqList->SelectedAlternative = reqAlternative;
  4753. ReqDescCount = RA->DescCount;
  4754. ReqDescTable = RA->DescTable;
  4755. //
  4756. // we should have got only one descriptor, use only the first one
  4757. //
  4758. if (ReqDescCount>0) {
  4759. //
  4760. // get first descriptor & it's arbitor
  4761. //
  4762. reqDesc = *ReqDescTable;
  4763. if (reqDesc->ArbitrationRequired) {
  4764. reqDescTranslated = reqDesc->TranslatedReqDesc; // Could be reqDesc itself
  4765. arbiterEntry = reqDesc->u.Arbiter;
  4766. ASSERT(arbiterEntry);
  4767. //
  4768. // the descriptor of interest - translated, first alternative in the table
  4769. //
  4770. ConflictDesc = reqDescTranslated->AlternativeTable.Alternatives;
  4771. //
  4772. // skip special descriptor
  4773. // to get to the actual descriptor
  4774. //
  4775. if(ConflictDesc->Type == CmResourceTypeConfigData || ConflictDesc->Type == CmResourceTypeReserved)
  4776. ConflictDesc++;
  4777. //
  4778. // finally we can call the arbiter to get a conflict list (returning PDO's and Global Address Ranges)
  4779. //
  4780. ExtParams[0] = PhysicalDeviceObject;
  4781. ExtParams[1] = ConflictDesc;
  4782. ExtParams[2] = &ConflictCount;
  4783. ExtParams[3] = &ConflictInfoList;
  4784. status = IopCallArbiter(arbiterEntry, ArbiterActionQueryConflict , ExtParams, NULL , NULL);
  4785. if (NT_SUCCESS(status)) {
  4786. //
  4787. // fill in user-memory buffer with conflict
  4788. //
  4789. status = IopQueryConflictFillConflicts(PhysicalDeviceObject,ConflictCount,ConflictInfoList,ConflictList,ConflictListSize,0);
  4790. if(ConflictInfoList != NULL) {
  4791. ExFreePool(ConflictInfoList);
  4792. }
  4793. }
  4794. else if(status == STATUS_RANGE_NOT_FOUND) {
  4795. //
  4796. // fill in with flag indicating bad range (this means range is not available)
  4797. // ConflictInfoList should not be allocated
  4798. //
  4799. status = IopQueryConflictFillConflicts(NULL,0,NULL,ConflictList,ConflictListSize,PNP_CE_TRANSLATE_FAILED);
  4800. }
  4801. } else {
  4802. #if MAXDBG
  4803. ASSERT(0); // For now
  4804. #endif
  4805. status = STATUS_INVALID_PARAMETER; // if we failed, it's prob because ResourceList was invalid
  4806. }
  4807. } else {
  4808. #if MAXDBG
  4809. ASSERT(0); // For now
  4810. #endif
  4811. status = STATUS_INVALID_PARAMETER; // if we failed, it's prob because ResourceList was invalid
  4812. }
  4813. IopCheckDataStructures(IopRootDeviceNode);
  4814. IopFreeReqList(reqList);
  4815. } else {
  4816. #if MAXDBG
  4817. ASSERT(0); // For now
  4818. #endif
  4819. if(NT_SUCCESS(status)) {
  4820. //
  4821. // it was NULL because we had a zero resource count, must be invalid parameter
  4822. //
  4823. status = STATUS_INVALID_PARAMETER;
  4824. }
  4825. }
  4826. ExFreePool(ioResources);
  4827. Clean0:
  4828. ;
  4829. return status;
  4830. }
  4831. /*++
  4832. SECTION = REBALANCE.
  4833. Description:
  4834. This section contains code that implements functions to performa
  4835. resource rebalance.
  4836. --*/
  4837. VOID
  4838. IopQueryRebalance (
  4839. IN PDEVICE_NODE DeviceNode,
  4840. IN ULONG Phase,
  4841. IN PULONG RebalanceCount,
  4842. IN PDEVICE_OBJECT **DeviceTable
  4843. )
  4844. /*++
  4845. Routine Description:
  4846. This routine walks hardware tree depth first. For each device node it visits,
  4847. it call IopQueryReconfigureDevice to query-stop device for resource
  4848. reconfiguration.
  4849. Note, Under rebalancing situation, all the participated devices will be asked to
  4850. stop. Even they support non-stopped rebalancing.
  4851. Parameters:
  4852. DeviceNode - supplies a pionter a device node which is the root of the tree to
  4853. be tested.
  4854. Phase - Supplies a value to specify the phase of the rebalance.
  4855. RebalanceCount - supplies a pointer to a variable to receive the number of devices
  4856. participating the rebalance.
  4857. Return Value:
  4858. None.
  4859. --*/
  4860. {
  4861. PDEVICE_OBJECT *deviceList, *deviceTable, *device;
  4862. ULONG count;
  4863. PDEVICE_NODE deviceNode;
  4864. //
  4865. // Call worker routine to get a list of devices to be rebalanced.
  4866. //
  4867. deviceTable = *DeviceTable;
  4868. IopQueryRebalanceWorker (DeviceNode, Phase, RebalanceCount, DeviceTable);
  4869. count = *RebalanceCount;
  4870. if (count != 0 && Phase == 0) {
  4871. //
  4872. // At phase 0, we did not actually query-stop the device.
  4873. // We need to do it now.
  4874. //
  4875. deviceList = (PDEVICE_OBJECT *)ExAllocatePoolPDO(PagedPool, count * sizeof(PDEVICE_OBJECT));
  4876. if (deviceList == NULL) {
  4877. *RebalanceCount = 0;
  4878. return;
  4879. }
  4880. RtlCopyMemory(deviceList, deviceTable, sizeof(PDEVICE_OBJECT) * count);
  4881. //
  4882. // Rebuild the returned device list
  4883. //
  4884. *RebalanceCount = 0;
  4885. *DeviceTable = deviceTable;
  4886. for (device = deviceList; device < (deviceList + count); device++) {
  4887. deviceNode = PP_DO_TO_DN(*device);
  4888. IopQueryRebalanceWorker (deviceNode, 1, RebalanceCount, DeviceTable);
  4889. }
  4890. ExFreePool(deviceList);
  4891. }
  4892. return;
  4893. }
  4894. VOID
  4895. IopQueryRebalanceWorker (
  4896. IN PDEVICE_NODE DeviceNode,
  4897. IN ULONG Phase,
  4898. IN PULONG RebalanceCount,
  4899. IN PDEVICE_OBJECT **DeviceTable
  4900. )
  4901. /*++
  4902. Routine Description:
  4903. This routine walks hardware tree depth first. For each device node it visits,
  4904. it call IopQueryReconfigureDevice to query-stop and stop device for resource
  4905. reconfiguration.
  4906. Parameters:
  4907. DeviceNode - supplies a pionter a device node which is the root of the tree to
  4908. be tested.
  4909. Phase - Supplies a value to specify the phase of the rebalance.
  4910. RebalanceCount - supplies a pointer to a variable to receive the number of devices
  4911. participating the rebalance.
  4912. Return Value:
  4913. None.
  4914. --*/
  4915. {
  4916. PDEVICE_NODE node;
  4917. ASSERT(DeviceNode);
  4918. //
  4919. // We dont include following in rebalance
  4920. // a. non-started devices
  4921. // b. devices with problem
  4922. // c. devices with legacy driver
  4923. //
  4924. if ( DeviceNode == NULL ||
  4925. DeviceNode->State != DeviceNodeStarted ||
  4926. PipDoesDevNodeHaveProblem(DeviceNode) ||
  4927. (DeviceNode->Flags & DNF_LEGACY_DRIVER)) {
  4928. return;
  4929. }
  4930. //
  4931. // Recursively test the entire subtree.
  4932. //
  4933. for (node = DeviceNode->Child; node; node = node->Sibling) {
  4934. IopQueryRebalanceWorker(node, Phase, RebalanceCount, DeviceTable);
  4935. }
  4936. //
  4937. // Test the root of the subtree.
  4938. //
  4939. IopTestForReconfiguration(DeviceNode, Phase, RebalanceCount, DeviceTable);
  4940. }
  4941. VOID
  4942. IopTestForReconfiguration (
  4943. IN PDEVICE_NODE DeviceNode,
  4944. IN ULONG Phase,
  4945. IN PULONG RebalanceCount,
  4946. IN PDEVICE_OBJECT **DeviceTable
  4947. )
  4948. /*++
  4949. Routine Description:
  4950. This routine query-stops a device which is started and owns resources.
  4951. Note the resources for the device are not released at this point.
  4952. Parameters:
  4953. DeviceNode - supplies a pointer to the device node to be tested for reconfiguration.
  4954. Phase - Supplies a value to specify the phase of the rebalance.
  4955. RebalanceCount - supplies a pointer to a variable to receive the number of devices
  4956. participating the rebalance.
  4957. Return Value:
  4958. Status code that indicates whether or not the function was successful.
  4959. --*/
  4960. {
  4961. PDEVICE_NODE nodex;
  4962. NTSTATUS status;
  4963. BOOLEAN addToList = FALSE;
  4964. if (Phase == 0) {
  4965. //
  4966. // At phase zero, this routine only wants to find out which devices's resource
  4967. // requirements lists chagned. No one actually gets stopped.
  4968. //
  4969. if ((DeviceNode->Flags & DNF_RESOURCE_REQUIREMENTS_CHANGED) &&
  4970. !(DeviceNode->Flags & DNF_NON_STOPPED_REBALANCE) ) {
  4971. //
  4972. // It's too hard to handle non-stop rebalancing devices during rebalance.
  4973. // So, We will skip it.
  4974. //
  4975. addToList = TRUE;
  4976. } else {
  4977. if (DeviceNode->State == DeviceNodeStarted) {
  4978. status = IopQueryReconfiguration (IRP_MN_QUERY_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
  4979. if (NT_SUCCESS(status)) {
  4980. if (status == STATUS_RESOURCE_REQUIREMENTS_CHANGED) {
  4981. //
  4982. // If we find out a device's resource requirements changed this way,
  4983. // it will be stopped and reassigned resources even if it supports
  4984. // non-stopped rebalance.
  4985. //
  4986. DeviceNode->Flags |= DNF_RESOURCE_REQUIREMENTS_CHANGED;
  4987. addToList = TRUE;
  4988. }
  4989. }
  4990. IopQueryReconfiguration (IRP_MN_CANCEL_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
  4991. }
  4992. }
  4993. if (addToList) {
  4994. *RebalanceCount = *RebalanceCount + 1;
  4995. **DeviceTable = DeviceNode->PhysicalDeviceObject;
  4996. *DeviceTable = *DeviceTable + 1;
  4997. }
  4998. } else {
  4999. //
  5000. // Phase 1
  5001. //
  5002. if (DeviceNode->State == DeviceNodeStarted) {
  5003. //
  5004. // Make sure all the resources required children of the DeviceNode are stopped.
  5005. //
  5006. nodex = DeviceNode->Child;
  5007. while (nodex) {
  5008. if (nodex->State == DeviceNodeUninitialized ||
  5009. nodex->State == DeviceNodeInitialized ||
  5010. nodex->State == DeviceNodeDriversAdded ||
  5011. nodex->State == DeviceNodeQueryStopped ||
  5012. nodex->State == DeviceNodeRemovePendingCloses ||
  5013. nodex->State == DeviceNodeRemoved ||
  5014. (nodex->Flags & DNF_NEEDS_REBALANCE)) {
  5015. nodex = nodex->Sibling;
  5016. } else {
  5017. break;
  5018. }
  5019. }
  5020. if (nodex) {
  5021. //
  5022. // If any resource required child of the DeviceNode is not stopped,
  5023. // we won't ask the DeviceNode to stop.
  5024. //
  5025. IopDbgPrint((
  5026. IOP_RESOURCE_INFO_LEVEL,
  5027. "Rebalance: Child %ws not stopped for %ws\n",
  5028. nodex->InstancePath.Buffer,
  5029. DeviceNode->InstancePath.Buffer));
  5030. return;
  5031. }
  5032. } else if (DeviceNode->State != DeviceNodeDriversAdded ||
  5033. !(DeviceNode->Flags & DNF_HAS_BOOT_CONFIG) ||
  5034. (DeviceNode->Flags & DNF_MADEUP)) {
  5035. //
  5036. // The device is not started and has no boot config. There is no need to query-stop it.
  5037. // Or if the device has BOOT config but there is no driver installed for it. We don't query
  5038. // stop it. (There may be legacy drivers are using the resources.)
  5039. // We also don't want to query stop root enumerated devices (for performance reason.)
  5040. //
  5041. return;
  5042. }
  5043. status = IopQueryReconfiguration (IRP_MN_QUERY_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
  5044. if (NT_SUCCESS(status)) {
  5045. IopDbgPrint((
  5046. IOP_RESOURCE_INFO_LEVEL,
  5047. "Rebalance: %ws succeeded QueryStop\n",
  5048. DeviceNode->InstancePath.Buffer));
  5049. if (DeviceNode->State == DeviceNodeStarted) {
  5050. PipSetDevNodeState(DeviceNode, DeviceNodeQueryStopped, NULL);
  5051. *RebalanceCount = *RebalanceCount + 1;
  5052. **DeviceTable = DeviceNode->PhysicalDeviceObject;
  5053. //
  5054. // Add a reference to the device object such that it won't disapear during rebalance.
  5055. //
  5056. ObReferenceObject(DeviceNode->PhysicalDeviceObject);
  5057. *DeviceTable = *DeviceTable + 1;
  5058. } else {
  5059. //
  5060. // We need to release the device's prealloc boot config. This device will NOT
  5061. // participate in resource rebalancing.
  5062. //
  5063. ASSERT(DeviceNode->Flags & DNF_HAS_BOOT_CONFIG);
  5064. status = IopQueryReconfiguration (IRP_MN_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
  5065. ASSERT(NT_SUCCESS(status));
  5066. IopReleaseBootResources(DeviceNode);
  5067. //
  5068. // Reset BOOT CONFIG flags.
  5069. //
  5070. DeviceNode->Flags &= ~(DNF_HAS_BOOT_CONFIG + DNF_BOOT_CONFIG_RESERVED);
  5071. }
  5072. } else {
  5073. IopQueryReconfiguration (IRP_MN_CANCEL_STOP_DEVICE, DeviceNode->PhysicalDeviceObject);
  5074. }
  5075. }
  5076. }
  5077. NTSTATUS
  5078. IopRebalance(
  5079. IN ULONG AssignTableCount,
  5080. IN PIOP_RESOURCE_REQUEST AssignTable
  5081. )
  5082. /*++
  5083. Routine Description:
  5084. This routine performs rebalancing operation. There are two rebalance phases:
  5085. In the phase 0, we only consider the devices whoes resource requirements changed
  5086. and their children; in phase 1, we consider anyone who succeeds the query-stop.
  5087. Parameters:
  5088. AssignTableCount,
  5089. AssignTable - Supplies the number of origianl AssignTableCout and AssignTable which
  5090. triggers the rebalance operation.
  5091. (if AssignTableCount == 0, we are processing device state change.)
  5092. Return Value:
  5093. Status code that indicates whether or not the function was successful.
  5094. --*/
  5095. {
  5096. ULONG i;
  5097. PIOP_RESOURCE_REQUEST table = NULL, tableEnd, newEntry;
  5098. PIOP_RESOURCE_REQUEST requestTable = NULL, requestTableEnd, entry1, entry2;
  5099. ULONG phase0RebalanceCount = 0, rebalanceCount = 0, deviceCount;
  5100. NTSTATUS status;
  5101. PDEVICE_OBJECT *deviceTable, *deviceTablex;
  5102. PDEVICE_NODE deviceNode;
  5103. ULONG rebalancePhase = 0;
  5104. LIST_ENTRY activeArbiterList;
  5105. //
  5106. // Query all the device nodes to see who are willing to participate the rebalance
  5107. // process.
  5108. //
  5109. deviceTable = (PDEVICE_OBJECT *) ExAllocatePoolPDO(
  5110. PagedPool,
  5111. sizeof(PDEVICE_OBJECT) * IopNumberDeviceNodes);
  5112. if (deviceTable == NULL) {
  5113. IopDbgPrint((
  5114. IOP_RESOURCE_WARNING_LEVEL,
  5115. "Rebalance: Not enough memory to perform rebalance\n"));
  5116. return STATUS_INSUFFICIENT_RESOURCES;
  5117. }
  5118. tryAgain:
  5119. deviceTablex = deviceTable + phase0RebalanceCount;
  5120. //
  5121. // Walk device node tree depth-first to query-stop and stop devices.
  5122. // At this point the resources of the stopped devices are not released yet.
  5123. // Also, the leaf nodes are in the front of the device table and non leaf nodes
  5124. // are at the end of the table.
  5125. //
  5126. IopQueryRebalance (IopRootDeviceNode, rebalancePhase, &rebalanceCount, &deviceTablex);
  5127. if (rebalanceCount == 0) {
  5128. //
  5129. // If no one is interested and we are not processing resources req change,
  5130. // move to next phase.
  5131. //
  5132. if (rebalancePhase == 0 && AssignTableCount != 0) {
  5133. rebalancePhase = 1;
  5134. goto tryAgain;
  5135. }
  5136. IopDbgPrint((
  5137. IOP_RESOURCE_INFO_LEVEL,
  5138. "Rebalance: No device participates in rebalance phase %x\n",
  5139. rebalancePhase));
  5140. ExFreePool(deviceTable);
  5141. deviceTable = NULL;
  5142. status = STATUS_UNSUCCESSFUL;
  5143. goto exit;
  5144. }
  5145. if (rebalanceCount == phase0RebalanceCount) {
  5146. //
  5147. // Phase 0 failed and no new device participates. failed the rebalance.
  5148. //
  5149. status = STATUS_UNSUCCESSFUL;
  5150. goto exit;
  5151. }
  5152. if (rebalancePhase == 0) {
  5153. phase0RebalanceCount = rebalanceCount;
  5154. }
  5155. //
  5156. // Allocate pool for the new reconfiguration requests and the original requests.
  5157. //
  5158. table = (PIOP_RESOURCE_REQUEST) ExAllocatePoolIORR(
  5159. PagedPool,
  5160. sizeof(IOP_RESOURCE_REQUEST) * (AssignTableCount + rebalanceCount)
  5161. );
  5162. if (table == NULL) {
  5163. IopDbgPrint((
  5164. IOP_RESOURCE_WARNING_LEVEL,
  5165. "Rebalance: Not enough memory to perform rebalance\n"));
  5166. status = STATUS_INSUFFICIENT_RESOURCES;
  5167. goto exit;
  5168. }
  5169. tableEnd = table + AssignTableCount + rebalanceCount;
  5170. //
  5171. // Build a new resource request table. The original requests will be at the beginning
  5172. // of the table and new requests (reconfigured devices) are at the end.
  5173. // After the new request table is built, the leaf nodes will be in front of the table,
  5174. // and non leaf nodes will be close to the end of the table. This is for optimization.
  5175. //
  5176. //
  5177. // Copy the original request to the front of our new request table.
  5178. //
  5179. if (AssignTableCount != 0) {
  5180. RtlCopyMemory(table, AssignTable, sizeof(IOP_RESOURCE_REQUEST) * AssignTableCount);
  5181. }
  5182. //
  5183. // Initialize all the new entries of our new request table,
  5184. //
  5185. newEntry = table + AssignTableCount;
  5186. RtlZeroMemory(newEntry, sizeof(IOP_RESOURCE_REQUEST) * rebalanceCount);
  5187. for (i = 0, deviceTablex = deviceTable; i < rebalanceCount; i++, deviceTablex++) {
  5188. newEntry[i].AllocationType = ArbiterRequestPnpEnumerated;
  5189. newEntry[i].PhysicalDevice = *deviceTablex;
  5190. }
  5191. status = IopGetResourceRequirementsForAssignTable(
  5192. newEntry,
  5193. tableEnd ,
  5194. &deviceCount);
  5195. if (deviceCount == 0) {
  5196. IopDbgPrint((
  5197. IOP_RESOURCE_WARNING_LEVEL,
  5198. "Rebalance: GetResourceRequirementsForAssignTable failed\n"));
  5199. goto exit;
  5200. }
  5201. //
  5202. // Process the AssignTable to remove any entry which is marked as IOP_ASSIGN_IGNORE
  5203. //
  5204. if (deviceCount != rebalanceCount) {
  5205. deviceCount += AssignTableCount;
  5206. requestTable = (PIOP_RESOURCE_REQUEST) ExAllocatePoolIORR(
  5207. PagedPool,
  5208. sizeof(IOP_RESOURCE_REQUEST) * deviceCount
  5209. );
  5210. if (requestTable == NULL) {
  5211. IopFreeResourceRequirementsForAssignTable(newEntry, tableEnd);
  5212. status = STATUS_INSUFFICIENT_RESOURCES;
  5213. goto exit;
  5214. }
  5215. for (entry1 = table, entry2 = requestTable; entry1 < tableEnd; entry1++) {
  5216. if (!(entry1->Flags & IOP_ASSIGN_IGNORE)) {
  5217. *entry2 = *entry1;
  5218. entry2++;
  5219. } else {
  5220. ASSERT(entry1 >= newEntry);
  5221. }
  5222. }
  5223. requestTableEnd = requestTable + deviceCount;
  5224. } else {
  5225. requestTable = table;
  5226. requestTableEnd = tableEnd;
  5227. deviceCount += AssignTableCount;
  5228. }
  5229. //
  5230. // DO NOT Sort the AssignTable
  5231. //
  5232. //IopRearrangeAssignTable(requestTable, deviceCount);
  5233. #if 0
  5234. //
  5235. // We are about to perform rebalance. Release the resources of the reconfiguration devices
  5236. //
  5237. for (entry1 = newEntry; entry1 < tableEnd; entry1++) {
  5238. if (!(entry1->Flags & IOP_ASSIGN_IGNORE) &&
  5239. !(entry1->Flags & IOP_ASSIGN_RESOURCES_RELEASED)) {
  5240. deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
  5241. if (deviceNode->ResourceList) {
  5242. //
  5243. // Call IopReleaseResourcesInternal instead of IopReleaseResources such that
  5244. // the pool for devicenode->ResourceList is not freed. We need it to restart
  5245. // the reconfigured devices in case rebalance failed.
  5246. //
  5247. IopReleaseResourcesInternal(deviceNode);
  5248. entry1->Flags |= IOP_ASSIGN_RESOURCES_RELEASED;
  5249. }
  5250. }
  5251. }
  5252. #endif
  5253. //
  5254. // Assign the resources. If we succeed, or if
  5255. // there is a memory shortage return immediately.
  5256. //
  5257. status = IopFindBestConfiguration(
  5258. requestTable,
  5259. deviceCount,
  5260. &activeArbiterList);
  5261. if (NT_SUCCESS(status)) {
  5262. //
  5263. // If the rebalance succeeded, we need to restart all the reconfigured devices.
  5264. // For the original devices, we will return and let IopAllocateResources to deal
  5265. // with them.
  5266. //
  5267. IopBuildCmResourceLists(requestTable, requestTableEnd);
  5268. //
  5269. // Copy the new status back to the original AssignTable.
  5270. //
  5271. if (AssignTableCount != 0) {
  5272. RtlCopyMemory(AssignTable, requestTable, sizeof(IOP_RESOURCE_REQUEST) * AssignTableCount);
  5273. }
  5274. //
  5275. // free resource requirements we allocated while here
  5276. //
  5277. IopFreeResourceRequirementsForAssignTable(requestTable+AssignTableCount, requestTableEnd);
  5278. if (table != requestTable) {
  5279. //
  5280. // If we switched request table ... copy the contents of new table back to
  5281. // the old table.
  5282. //
  5283. for (entry1 = table, entry2 = requestTable; entry2 < requestTableEnd;) {
  5284. if (entry1->Flags & IOP_ASSIGN_IGNORE) {
  5285. entry1++;
  5286. continue;
  5287. }
  5288. *entry1 = *entry2;
  5289. if (entry2->Flags & IOP_ASSIGN_EXCLUDE) {
  5290. entry1->Status = STATUS_CONFLICTING_ADDRESSES;
  5291. }
  5292. entry2++;
  5293. entry1++;
  5294. }
  5295. }
  5296. //
  5297. // Go thru the origianl request table to stop each query-stopped/reconfigured device.
  5298. //
  5299. for (entry1 = newEntry; entry1 < tableEnd; entry1++) {
  5300. deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
  5301. if (NT_SUCCESS(entry1->Status)) {
  5302. IopDbgPrint((
  5303. IOP_RESOURCE_INFO_LEVEL,
  5304. "STOPPING %wZ during REBALANCE\n",
  5305. &deviceNode->InstancePath));
  5306. IopQueryReconfiguration(
  5307. IRP_MN_STOP_DEVICE,
  5308. entry1->PhysicalDevice);
  5309. PipSetDevNodeState(deviceNode, DeviceNodeStopped, NULL);
  5310. } else {
  5311. IopQueryReconfiguration(
  5312. IRP_MN_CANCEL_STOP_DEVICE,
  5313. entry1->PhysicalDevice);
  5314. PipRestoreDevNodeState(deviceNode);
  5315. }
  5316. }
  5317. //
  5318. // Ask the arbiters to commit this configuration.
  5319. //
  5320. status = IopCommitConfiguration(&activeArbiterList);
  5321. //
  5322. // Go thru the origianl request table to start each stopped/reconfigured device.
  5323. //
  5324. for (entry1 = tableEnd - 1; entry1 >= newEntry; entry1--) {
  5325. deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
  5326. if (NT_SUCCESS(entry1->Status)) {
  5327. //
  5328. // We need to release the pool space for ResourceList and ResourceListTranslated.
  5329. // Because the earlier IopReleaseResourcesInternal does not release the pool.
  5330. //
  5331. if (deviceNode->ResourceList) {
  5332. ExFreePool(deviceNode->ResourceList);
  5333. }
  5334. deviceNode->ResourceList = entry1->ResourceAssignment;
  5335. if (deviceNode->ResourceListTranslated) {
  5336. ExFreePool(deviceNode->ResourceListTranslated);
  5337. }
  5338. deviceNode->ResourceListTranslated = entry1->TranslatedResourceAssignment;
  5339. if (deviceNode->ResourceList == NULL) {
  5340. deviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
  5341. }
  5342. if (entry1->Flags & IOP_ASSIGN_CLEAR_RESOURCE_REQUIREMENTS_CHANGE_FLAG) {
  5343. //
  5344. // If we are processing the resource requirements change request,
  5345. // clear its related flags.
  5346. //
  5347. deviceNode->Flags &= ~(DNF_RESOURCE_REQUIREMENTS_CHANGED | DNF_NON_STOPPED_REBALANCE);
  5348. }
  5349. }
  5350. }
  5351. status = STATUS_SUCCESS;
  5352. } else {
  5353. //
  5354. // Rebalance failed. Free our internal representation of the rebalance
  5355. // candidates' resource requirements lists.
  5356. //
  5357. IopFreeResourceRequirementsForAssignTable(requestTable + AssignTableCount, requestTableEnd);
  5358. if (rebalancePhase == 0) {
  5359. rebalancePhase++;
  5360. if (requestTable) {
  5361. ExFreePool(requestTable);
  5362. }
  5363. if (table && (table != requestTable)) {
  5364. ExFreePool(table);
  5365. }
  5366. table = requestTable = NULL;
  5367. goto tryAgain;
  5368. }
  5369. for (entry1 = newEntry; entry1 < tableEnd; entry1++) {
  5370. IopQueryReconfiguration (
  5371. IRP_MN_CANCEL_STOP_DEVICE,
  5372. entry1->PhysicalDevice);
  5373. deviceNode = PP_DO_TO_DN(entry1->PhysicalDevice);
  5374. PipRestoreDevNodeState(deviceNode);
  5375. }
  5376. }
  5377. //
  5378. // Finally release the references of the reconfigured device objects
  5379. //
  5380. for (deviceTablex = (deviceTable + rebalanceCount - 1);
  5381. deviceTablex >= deviceTable;
  5382. deviceTablex--) {
  5383. ObDereferenceObject(*deviceTablex);
  5384. }
  5385. ExFreePool(deviceTable);
  5386. deviceTable = NULL;
  5387. exit:
  5388. if (!NT_SUCCESS(status) && deviceTable) {
  5389. //
  5390. // If we failed before trying to perform resource assignment,
  5391. // we will end up here.
  5392. //
  5393. IopDbgPrint((
  5394. IOP_RESOURCE_INFO_LEVEL,
  5395. "Rebalance: Rebalance failed\n"));
  5396. //
  5397. // Somehow we failed to start the rebalance operation.
  5398. // We will cancel the query-stop request for the query-stopped devices bredth first.
  5399. //
  5400. for (deviceTablex = (deviceTable + rebalanceCount - 1);
  5401. deviceTablex >= deviceTable;
  5402. deviceTablex--) {
  5403. deviceNode = PP_DO_TO_DN(*deviceTablex);
  5404. IopQueryReconfiguration (IRP_MN_CANCEL_STOP_DEVICE, *deviceTablex);
  5405. PipRestoreDevNodeState(deviceNode);
  5406. ObDereferenceObject(*deviceTablex);
  5407. }
  5408. }
  5409. if (deviceTable) {
  5410. ExFreePool(deviceTable);
  5411. }
  5412. if (requestTable) {
  5413. ExFreePool(requestTable);
  5414. }
  5415. if (table && (table != requestTable)) {
  5416. ExFreePool(table);
  5417. }
  5418. return status;
  5419. }
  5420. /*++
  5421. SECTION = OUTER ARBITRATION LOOP.
  5422. Description:
  5423. This section contains code that implements functions to call arbiters
  5424. and come up with the best possible configuration.
  5425. --*/
  5426. NTSTATUS
  5427. IopTestConfiguration (
  5428. IN OUT PLIST_ENTRY ArbiterList
  5429. )
  5430. /*++
  5431. Routine Description:
  5432. This routine calls the arbiters in the specified list for TestAllocation.
  5433. Parameters:
  5434. ArbiterList - Head of list of arbiters to be called.
  5435. Return Value:
  5436. STATUS_SUCCESS if all arbiters succeed, else first failure code.
  5437. --*/
  5438. {
  5439. NTSTATUS status;
  5440. PLIST_ENTRY listEntry;
  5441. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  5442. ARBITER_PARAMETERS p;
  5443. PARBITER_INTERFACE arbiterInterface;
  5444. PAGED_CODE();
  5445. status = STATUS_SUCCESS;
  5446. for ( listEntry = ArbiterList->Flink;
  5447. listEntry != ArbiterList;
  5448. listEntry = listEntry->Flink) {
  5449. arbiterEntry = CONTAINING_RECORD(
  5450. listEntry,
  5451. PI_RESOURCE_ARBITER_ENTRY,
  5452. ActiveArbiterList);
  5453. ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
  5454. if (arbiterEntry->ResourcesChanged == FALSE) {
  5455. if (arbiterEntry->State & PI_ARBITER_TEST_FAILED) {
  5456. //
  5457. // If the resource requirements are the same and
  5458. // it failed before, return failure.
  5459. //
  5460. status = STATUS_UNSUCCESSFUL;
  5461. break;
  5462. }
  5463. } else {
  5464. arbiterInterface = arbiterEntry->ArbiterInterface;
  5465. //
  5466. // Call the arbiter to test the new configuration.
  5467. //
  5468. p.Parameters.TestAllocation.ArbitrationList =
  5469. &arbiterEntry->ResourceList;
  5470. p.Parameters.TestAllocation.AllocateFromCount = 0;
  5471. p.Parameters.TestAllocation.AllocateFrom = NULL;
  5472. status = arbiterInterface->ArbiterHandler(
  5473. arbiterInterface->Context,
  5474. ArbiterActionTestAllocation,
  5475. &p);
  5476. if (NT_SUCCESS(status)) {
  5477. arbiterEntry->State &= ~PI_ARBITER_TEST_FAILED;
  5478. arbiterEntry->State |= PI_ARBITER_HAS_SOMETHING;
  5479. arbiterEntry->ResourcesChanged = FALSE;
  5480. } else {
  5481. //
  5482. // This configuration does not work
  5483. // (no need to try other arbiters).
  5484. //
  5485. arbiterEntry->State |= PI_ARBITER_TEST_FAILED;
  5486. break;
  5487. }
  5488. }
  5489. }
  5490. return status;
  5491. }
  5492. NTSTATUS
  5493. IopRetestConfiguration (
  5494. IN OUT PLIST_ENTRY ArbiterList
  5495. )
  5496. /*++
  5497. Routine Description:
  5498. This routine calls the arbiters in the specified list for RetestAllocation.
  5499. Parameters:
  5500. ArbiterList - Head of list of arbiters to be called.
  5501. Return Value:
  5502. STATUS_SUCCESS if all arbiters succeed, else first failure code.
  5503. --*/
  5504. {
  5505. NTSTATUS retestStatus;
  5506. PLIST_ENTRY listEntry;
  5507. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  5508. ARBITER_PARAMETERS p;
  5509. PARBITER_INTERFACE arbiterInterface;
  5510. PAGED_CODE();
  5511. retestStatus = STATUS_UNSUCCESSFUL;
  5512. listEntry = ArbiterList->Flink;
  5513. while (listEntry != ArbiterList) {
  5514. arbiterEntry = CONTAINING_RECORD(
  5515. listEntry,
  5516. PI_RESOURCE_ARBITER_ENTRY,
  5517. ActiveArbiterList);
  5518. listEntry = listEntry->Flink;
  5519. if (arbiterEntry->ResourcesChanged == FALSE) {
  5520. continue;
  5521. }
  5522. ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
  5523. arbiterInterface = arbiterEntry->ArbiterInterface;
  5524. //
  5525. // Call the arbiter to retest the configuration.
  5526. //
  5527. p.Parameters.RetestAllocation.ArbitrationList =
  5528. &arbiterEntry->ResourceList;
  5529. p.Parameters.RetestAllocation.AllocateFromCount = 0;
  5530. p.Parameters.RetestAllocation.AllocateFrom = NULL;
  5531. retestStatus = arbiterInterface->ArbiterHandler(
  5532. arbiterInterface->Context,
  5533. ArbiterActionRetestAllocation,
  5534. &p);
  5535. if (!NT_SUCCESS(retestStatus)) {
  5536. break;
  5537. }
  5538. }
  5539. ASSERT(NT_SUCCESS(retestStatus));
  5540. return retestStatus;
  5541. }
  5542. NTSTATUS
  5543. IopCommitConfiguration (
  5544. IN OUT PLIST_ENTRY ArbiterList
  5545. )
  5546. /*++
  5547. Routine Description:
  5548. This routine calls the arbiters in the specified list for CommitAllocation.
  5549. Parameters:
  5550. ArbiterList - Head of list of arbiters to be called.
  5551. Return Value:
  5552. STATUS_SUCCESS if all arbiters succeed, else first failure code.
  5553. --*/
  5554. {
  5555. NTSTATUS commitStatus;
  5556. PLIST_ENTRY listEntry;
  5557. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  5558. PARBITER_INTERFACE arbiterInterface;
  5559. PAGED_CODE();
  5560. commitStatus = STATUS_SUCCESS;
  5561. listEntry = ArbiterList->Flink;
  5562. while (listEntry != ArbiterList) {
  5563. arbiterEntry = CONTAINING_RECORD(
  5564. listEntry,
  5565. PI_RESOURCE_ARBITER_ENTRY,
  5566. ActiveArbiterList);
  5567. listEntry = listEntry->Flink;
  5568. ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
  5569. arbiterInterface = arbiterEntry->ArbiterInterface;
  5570. //
  5571. // Call the arbiter to commit the configuration.
  5572. //
  5573. commitStatus = arbiterInterface->ArbiterHandler(
  5574. arbiterInterface->Context,
  5575. ArbiterActionCommitAllocation,
  5576. NULL);
  5577. IopInitializeArbiterEntryState(arbiterEntry);
  5578. if (!NT_SUCCESS(commitStatus)) {
  5579. break;
  5580. }
  5581. }
  5582. ASSERT(NT_SUCCESS(commitStatus));
  5583. IopCheckDataStructures(IopRootDeviceNode);
  5584. return commitStatus;
  5585. }
  5586. VOID
  5587. IopSelectFirstConfiguration (
  5588. IN PIOP_RESOURCE_REQUEST RequestTable,
  5589. IN ULONG RequestTableCount,
  5590. IN OUT PLIST_ENTRY ActiveArbiterList
  5591. )
  5592. /*++
  5593. Routine Description:
  5594. This routine selects the first possible configuration and adds the
  5595. descriptors to their corresponding arbiter lists. The arbiters used are
  5596. linked into the list of active arbiters.
  5597. Parameters:
  5598. RequestTable - Table of resource requests.
  5599. RequestTableCount - Number of requests in the request table.
  5600. ActiveArbiterList - Head of list which contains arbiters used for the
  5601. first selected configuration.
  5602. Return Value:
  5603. None.
  5604. --*/
  5605. {
  5606. ULONG tableIndex;
  5607. PREQ_ALTERNATIVE reqAlternative;
  5608. PREQ_LIST reqList;
  5609. PAGED_CODE();
  5610. //
  5611. // For each entry in the request table, set the first configuration
  5612. // as the selected configuration.
  5613. // Update the arbiters with all the descriptors in the selected
  5614. // configuration.
  5615. //
  5616. for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
  5617. reqList = RequestTable[tableIndex].ReqList;
  5618. reqList->SelectedAlternative = &reqList->AlternativeTable[0];
  5619. reqAlternative = *(reqList->SelectedAlternative);
  5620. IopAddRemoveReqDescs(
  5621. reqAlternative->DescTable,
  5622. reqAlternative->DescCount,
  5623. ActiveArbiterList,
  5624. TRUE);
  5625. }
  5626. }
  5627. BOOLEAN
  5628. IopSelectNextConfiguration (
  5629. IN PIOP_RESOURCE_REQUEST RequestTable,
  5630. IN ULONG RequestTableCount,
  5631. IN OUT PLIST_ENTRY ActiveArbiterList
  5632. )
  5633. /*++
  5634. Routine Description:
  5635. This routine selects the next possible configuration and adds the
  5636. descriptors to their corresponding arbiter lists. The arbiters used are
  5637. linked into the list of active arbiters.
  5638. Parameters:
  5639. RequestTable - Table of resource requests.
  5640. RequestTableCount - Number of requests in the request table.
  5641. ActiveArbiterList - Head of list which contains arbiters used for the
  5642. currently selected configuration.
  5643. Return Value:
  5644. FALSE if this the currently selected configuration is the last possible,
  5645. else TRUE.
  5646. --*/
  5647. {
  5648. ULONG tableIndex;
  5649. PREQ_ALTERNATIVE reqAlternative;
  5650. PREQ_LIST reqList;
  5651. PAGED_CODE();
  5652. //
  5653. // Remove all the descriptors from the currently selected alternative
  5654. // for the first entry in the request table.
  5655. // Update the selected configuration to the next possible.
  5656. // Reset the selected configuration to the first possible one if
  5657. // all configurations have been tried and go to the next entry
  5658. // in the request table.
  5659. //
  5660. for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
  5661. reqList = RequestTable[tableIndex].ReqList;
  5662. reqAlternative = *(reqList->SelectedAlternative);
  5663. IopAddRemoveReqDescs(
  5664. reqAlternative->DescTable,
  5665. reqAlternative->DescCount,
  5666. NULL,
  5667. FALSE);
  5668. if (++reqList->SelectedAlternative < reqList->BestAlternative) {
  5669. break;
  5670. }
  5671. reqList->SelectedAlternative = &reqList->AlternativeTable[0];
  5672. }
  5673. //
  5674. // We are done if there is no next possible configuration.
  5675. //
  5676. if (tableIndex == RequestTableCount) {
  5677. return FALSE;
  5678. }
  5679. //
  5680. // For each entry in the request table, add all the descriptors in
  5681. // the currently selected alternative.
  5682. //
  5683. for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
  5684. reqList = RequestTable[tableIndex].ReqList;
  5685. reqAlternative = *(reqList->SelectedAlternative);
  5686. IopAddRemoveReqDescs(
  5687. reqAlternative->DescTable,
  5688. reqAlternative->DescCount,
  5689. ActiveArbiterList,
  5690. TRUE);
  5691. if (reqList->SelectedAlternative != &reqList->AlternativeTable[0]) {
  5692. break;
  5693. }
  5694. }
  5695. return TRUE;
  5696. }
  5697. VOID
  5698. IopCleanupSelectedConfiguration (
  5699. IN PIOP_RESOURCE_REQUEST RequestTable,
  5700. IN ULONG RequestTableCount
  5701. )
  5702. /*++
  5703. Routine Description:
  5704. This routine removes the descriptors from their corresponding arbiter
  5705. lists.
  5706. Parameters:
  5707. RequestTable - Table of resource requests.
  5708. RequestTableCount - Number of requests in the request table.
  5709. Return Value:
  5710. None.
  5711. --*/
  5712. {
  5713. ULONG tableIndex;
  5714. PREQ_ALTERNATIVE reqAlternative;
  5715. PREQ_LIST reqList;
  5716. PAGED_CODE();
  5717. //
  5718. // For each entry in the request table, remove all the descriptors
  5719. // from the currently selected alternative.
  5720. //
  5721. for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
  5722. reqList = RequestTable[tableIndex].ReqList;
  5723. reqAlternative = *(reqList->SelectedAlternative);
  5724. IopAddRemoveReqDescs(
  5725. reqAlternative->DescTable,
  5726. reqAlternative->DescCount,
  5727. NULL,
  5728. FALSE);
  5729. }
  5730. }
  5731. ULONG
  5732. IopComputeConfigurationPriority (
  5733. IN PIOP_RESOURCE_REQUEST RequestTable,
  5734. IN ULONG RequestTableCount
  5735. )
  5736. /*++
  5737. Routine Description:
  5738. This routine computes the overall priority of the set of selected
  5739. configurations for all requests in the request table.
  5740. Parameters:
  5741. RequestTable - Table of resource requests.
  5742. RequestTableCount - Number of requests in the request table.
  5743. Return Value:
  5744. Computed priority for this configuration.
  5745. --*/
  5746. {
  5747. ULONG tableIndex;
  5748. ULONG priority;
  5749. PREQ_ALTERNATIVE reqAlternative;
  5750. PREQ_LIST reqList;
  5751. PAGED_CODE();
  5752. //
  5753. // Compute the current configurations overall priority
  5754. // as the sum of the priorities of currently selected
  5755. // configuration in the request table.
  5756. //
  5757. priority = 0;
  5758. for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
  5759. reqList = RequestTable[tableIndex].ReqList;
  5760. reqAlternative = *(reqList->SelectedAlternative);
  5761. priority += reqAlternative->Priority;
  5762. }
  5763. return priority;
  5764. }
  5765. VOID
  5766. IopSaveRestoreConfiguration (
  5767. IN PIOP_RESOURCE_REQUEST RequestTable,
  5768. IN ULONG RequestTableCount,
  5769. IN OUT PLIST_ENTRY ArbiterList,
  5770. IN BOOLEAN Save
  5771. )
  5772. /*++
  5773. Routine Description:
  5774. This routine saves\restores the currently selected configuration.
  5775. Parameters:
  5776. RequestTable - Table of resource requests.
  5777. RequestTableCount - Number of requests in the request table.
  5778. ArbiterList - Head of list which contains arbiters used for the
  5779. currently selected configuration.
  5780. Save - Specifies if the configuration is to be saved or
  5781. restored.
  5782. Return Value:
  5783. None.
  5784. --*/
  5785. {
  5786. ULONG tableIndex;
  5787. PREQ_ALTERNATIVE reqAlternative;
  5788. PREQ_DESC reqDesc;
  5789. PREQ_DESC *reqDescpp;
  5790. PREQ_DESC *reqDescTableEnd;
  5791. PLIST_ENTRY listEntry;
  5792. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  5793. PREQ_LIST reqList;
  5794. PAGED_CODE();
  5795. IopDbgPrint((
  5796. IOP_RESOURCE_TRACE_LEVEL,
  5797. "%s configuration\n",
  5798. (Save)? "Saving" : "Restoring"));
  5799. //
  5800. // For each entry in the request table, save information for
  5801. // following RETEST.
  5802. //
  5803. for (tableIndex = 0; tableIndex < RequestTableCount; tableIndex++) {
  5804. reqList = RequestTable[tableIndex].ReqList;
  5805. if (Save) {
  5806. reqList->BestAlternative = reqList->SelectedAlternative;
  5807. } else {
  5808. reqList->SelectedAlternative = reqList->BestAlternative;
  5809. }
  5810. reqAlternative = *(reqList->BestAlternative);
  5811. reqDescTableEnd = reqAlternative->DescTable +
  5812. reqAlternative->DescCount;
  5813. for ( reqDescpp = reqAlternative->DescTable;
  5814. reqDescpp < reqDescTableEnd;
  5815. reqDescpp++) {
  5816. if ((*reqDescpp)->ArbitrationRequired == FALSE) {
  5817. continue;
  5818. }
  5819. //
  5820. // Save\restore information for the descriptor.
  5821. //
  5822. reqDesc = (*reqDescpp)->TranslatedReqDesc;
  5823. if (Save == TRUE) {
  5824. reqDesc->BestAlternativeTable = reqDesc->AlternativeTable;
  5825. reqDesc->BestAllocation = reqDesc->Allocation;
  5826. } else {
  5827. reqDesc->AlternativeTable = reqDesc->BestAlternativeTable;
  5828. reqDesc->Allocation = reqDesc->BestAllocation;
  5829. }
  5830. }
  5831. }
  5832. //
  5833. // For each entry in the currently active arbiter list,
  5834. // save information for following RETEST.
  5835. //
  5836. listEntry = ArbiterList->Flink;
  5837. while (listEntry != ArbiterList) {
  5838. arbiterEntry = CONTAINING_RECORD(
  5839. listEntry,
  5840. PI_RESOURCE_ARBITER_ENTRY,
  5841. ActiveArbiterList);
  5842. if (Save == TRUE) {
  5843. arbiterEntry->BestResourceList = arbiterEntry->ResourceList;
  5844. arbiterEntry->BestConfig = arbiterEntry->ActiveArbiterList;
  5845. } else {
  5846. arbiterEntry->ResourceList = arbiterEntry->BestResourceList;
  5847. arbiterEntry->ActiveArbiterList = arbiterEntry->BestConfig;
  5848. }
  5849. listEntry = listEntry->Flink;
  5850. }
  5851. }
  5852. VOID
  5853. IopAddRemoveReqDescs (
  5854. IN PREQ_DESC *ReqDescTable,
  5855. IN ULONG ReqDescCount,
  5856. IN OUT PLIST_ENTRY ActiveArbiterList,
  5857. IN BOOLEAN Add
  5858. )
  5859. /*++
  5860. Routine Description:
  5861. This routine adds\removes the descriptors to\from the arbiter lists. It
  5862. also updates the list of arbiters involved.
  5863. Parameters:
  5864. RequestTable - Table of resource requests.
  5865. RequestTableCount - Number of requests in the request table.
  5866. ActiveArbiterList - Head of list which contains arbiters used for the
  5867. currently selected configuration.
  5868. Add - Specifies if the descriptors are to be added or
  5869. removed.
  5870. Return Value:
  5871. None.
  5872. --*/
  5873. {
  5874. ULONG tableIndex;
  5875. PREQ_DESC reqDesc;
  5876. PREQ_DESC reqDescTranslated;
  5877. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  5878. PREQ_ALTERNATIVE reqAlternative;
  5879. PREQ_LIST reqList;
  5880. PDEVICE_NODE deviceNode;
  5881. PAGED_CODE();
  5882. if (ReqDescCount == 0) {
  5883. return;
  5884. }
  5885. reqList = ReqDescTable[0]->ReqAlternative->ReqList;
  5886. reqAlternative = *reqList->SelectedAlternative;
  5887. deviceNode = PP_DO_TO_DN(reqList->Request->PhysicalDevice);
  5888. IopDbgPrint((
  5889. IOP_RESOURCE_VERBOSE_LEVEL,
  5890. "%s %d/%d req alt %s the arbiters for %wZ\n",
  5891. (Add)? "Adding" : "Removing",
  5892. reqAlternative->ReqAlternativeIndex + 1,
  5893. reqList->AlternativeCount,
  5894. (Add)? "to" : "from",
  5895. &deviceNode->InstancePath));
  5896. for (tableIndex = 0; tableIndex < ReqDescCount; tableIndex++) {
  5897. reqDesc = ReqDescTable[tableIndex];
  5898. if (reqDesc->ArbitrationRequired == FALSE) {
  5899. continue;
  5900. }
  5901. arbiterEntry = reqDesc->u.Arbiter;
  5902. ASSERT(arbiterEntry);
  5903. if (arbiterEntry->State & PI_ARBITER_HAS_SOMETHING) {
  5904. arbiterEntry->State &= ~PI_ARBITER_HAS_SOMETHING;
  5905. arbiterEntry->ArbiterInterface->ArbiterHandler(
  5906. arbiterEntry->ArbiterInterface->Context,
  5907. ArbiterActionRollbackAllocation,
  5908. NULL);
  5909. }
  5910. arbiterEntry->ResourcesChanged = TRUE;
  5911. reqDescTranslated = reqDesc->TranslatedReqDesc;
  5912. if (Add == TRUE) {
  5913. InitializeListHead(&reqDescTranslated->AlternativeTable.ListEntry);
  5914. InsertTailList(
  5915. &arbiterEntry->ResourceList,
  5916. &reqDescTranslated->AlternativeTable.ListEntry);
  5917. if (IsListEmpty(&arbiterEntry->ActiveArbiterList)) {
  5918. PLIST_ENTRY listEntry;
  5919. PPI_RESOURCE_ARBITER_ENTRY entry;
  5920. //
  5921. // Insert the entry into the sorted list
  5922. // (sorted by depth in the tree).
  5923. //
  5924. for ( listEntry = ActiveArbiterList->Flink;
  5925. listEntry != ActiveArbiterList;
  5926. listEntry = listEntry->Flink) {
  5927. entry = CONTAINING_RECORD(
  5928. listEntry,
  5929. PI_RESOURCE_ARBITER_ENTRY,
  5930. ActiveArbiterList);
  5931. if (entry->Level >= arbiterEntry->Level) {
  5932. break;
  5933. }
  5934. }
  5935. arbiterEntry->ActiveArbiterList.Flink = listEntry;
  5936. arbiterEntry->ActiveArbiterList.Blink = listEntry->Blink;
  5937. listEntry->Blink->Flink = &arbiterEntry->ActiveArbiterList;
  5938. listEntry->Blink = &arbiterEntry->ActiveArbiterList;
  5939. }
  5940. } else {
  5941. ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
  5942. RemoveEntryList(&reqDescTranslated->AlternativeTable.ListEntry);
  5943. InitializeListHead(&reqDescTranslated->AlternativeTable.ListEntry);
  5944. if (IsListEmpty(&arbiterEntry->ResourceList)) {
  5945. RemoveEntryList(&arbiterEntry->ActiveArbiterList);
  5946. InitializeListHead(&arbiterEntry->ActiveArbiterList);
  5947. }
  5948. }
  5949. }
  5950. }
  5951. NTSTATUS
  5952. IopFindBestConfiguration (
  5953. IN PIOP_RESOURCE_REQUEST RequestTable,
  5954. IN ULONG RequestTableCount,
  5955. IN OUT PLIST_ENTRY ActiveArbiterList
  5956. )
  5957. /*++
  5958. Routine Description:
  5959. This routine attempts to satisfy the resource requests for all the entries
  5960. in the request table. It also attempts to find the best possible overall
  5961. solution.
  5962. Parameters:
  5963. RequestTable - Table of resource requests.
  5964. RequestTableCount - Number of requests in the request table.
  5965. Return Value:
  5966. Final status.
  5967. --*/
  5968. {
  5969. LIST_ENTRY bestArbiterList;
  5970. LARGE_INTEGER startTime;
  5971. LARGE_INTEGER currentTime;
  5972. ULONG timeDiff;
  5973. NTSTATUS status;
  5974. ULONG priority;
  5975. ULONG bestPriority;
  5976. PAGED_CODE();
  5977. //
  5978. // Initialize the arbiter lists used during the search for the best
  5979. // configuration.
  5980. //
  5981. InitializeListHead(ActiveArbiterList);
  5982. InitializeListHead(&bestArbiterList);
  5983. //
  5984. // Start the search from the first possible configuration.
  5985. // Possible configurations are already sorted by priority.
  5986. //
  5987. IopSelectFirstConfiguration(
  5988. RequestTable,
  5989. RequestTableCount,
  5990. ActiveArbiterList);
  5991. //
  5992. // Search for all configurations that work, updating
  5993. // the best configuration until we have tried all
  5994. // possible configurations or timeout has expired.
  5995. //
  5996. KeQuerySystemTime(&startTime);
  5997. bestPriority = (ULONG)-1;
  5998. do {
  5999. //
  6000. // Test the arbiters for this combination.
  6001. //
  6002. status = IopTestConfiguration(ActiveArbiterList);
  6003. if (NT_SUCCESS(status)) {
  6004. //
  6005. // Since the configurations are sorted, we dont need to try others
  6006. // if there is only one entry in the request table.
  6007. //
  6008. bestArbiterList = *ActiveArbiterList;
  6009. if (RequestTableCount == 1) {
  6010. break;
  6011. }
  6012. //
  6013. // Save this configuration if it is better than the best one found
  6014. // so far.
  6015. //
  6016. priority = IopComputeConfigurationPriority(
  6017. RequestTable,
  6018. RequestTableCount);
  6019. if (priority < bestPriority) {
  6020. bestPriority = priority;
  6021. IopSaveRestoreConfiguration(
  6022. RequestTable,
  6023. RequestTableCount,
  6024. ActiveArbiterList,
  6025. TRUE);
  6026. }
  6027. }
  6028. //
  6029. // Check if timeout has expired.
  6030. //
  6031. KeQuerySystemTime(&currentTime);
  6032. timeDiff = (ULONG)((currentTime.QuadPart - startTime.QuadPart) / 10000);
  6033. if (timeDiff >= FIND_BEST_CONFIGURATION_TIMEOUT) {
  6034. IopDbgPrint((
  6035. IOP_RESOURCE_WARNING_LEVEL,
  6036. "IopFindBestConfiguration: Timeout expired"));
  6037. if (IopStopOnTimeout()) {
  6038. IopDbgPrint((
  6039. IOP_RESOURCE_WARNING_LEVEL,
  6040. ", terminating search!\n"));
  6041. IopCleanupSelectedConfiguration(
  6042. RequestTable,
  6043. RequestTableCount);
  6044. break;
  6045. } else {
  6046. //
  6047. // Re-initialize start time so we spew only every timeout
  6048. // interval.
  6049. //
  6050. startTime = currentTime;
  6051. IopDbgPrint((IOP_RESOURCE_WARNING_LEVEL, "\n"));
  6052. }
  6053. }
  6054. //
  6055. // Select the next possible combination of configurations.
  6056. //
  6057. } while (IopSelectNextConfiguration(
  6058. RequestTable,
  6059. RequestTableCount,
  6060. ActiveArbiterList) == TRUE);
  6061. //
  6062. // Check if we found any working configuration.
  6063. //
  6064. if (IsListEmpty(&bestArbiterList)) {
  6065. status = STATUS_UNSUCCESSFUL;
  6066. } else {
  6067. status = STATUS_SUCCESS;
  6068. //
  6069. // Restore the saved configuration.
  6070. //
  6071. if (RequestTableCount != 1) {
  6072. *ActiveArbiterList = bestArbiterList;
  6073. IopSaveRestoreConfiguration(
  6074. RequestTable,
  6075. RequestTableCount,
  6076. ActiveArbiterList,
  6077. FALSE);
  6078. //
  6079. // Retest this configuration since this may not be the
  6080. // last one tested.
  6081. //
  6082. status = IopRetestConfiguration(ActiveArbiterList);
  6083. }
  6084. }
  6085. return status;
  6086. }
  6087. /*++
  6088. SECTION = LEGACY BUS INFORMATION TABLE.
  6089. Description:
  6090. This section contains code that implements functions to maintain and
  6091. access the table of Legacy Bus Information.
  6092. --*/
  6093. VOID
  6094. IopInsertLegacyBusDeviceNode (
  6095. IN PDEVICE_NODE BusDeviceNode,
  6096. IN INTERFACE_TYPE InterfaceType,
  6097. IN ULONG BusNumber
  6098. )
  6099. /*++
  6100. Routine Description:
  6101. This routine inserts the specified BusDeviceNode in the table according to
  6102. its InterfaceType and BusNumber.
  6103. Parameters:
  6104. BusDeviceNode - Device with the specified InterfaceType and BusNumber.
  6105. InterfaceType - Specifies the bus devicenode's interface type.
  6106. BusNumber - Specifies the bus devicenode's bus number.
  6107. Return Value:
  6108. None.
  6109. --*/
  6110. {
  6111. PAGED_CODE();
  6112. ASSERT(InterfaceType < MaximumInterfaceType && InterfaceType > InterfaceTypeUndefined);
  6113. if ( InterfaceType < MaximumInterfaceType &&
  6114. InterfaceType > InterfaceTypeUndefined &&
  6115. InterfaceType != PNPBus) {
  6116. PLIST_ENTRY listEntry;
  6117. //
  6118. // Eisa == Isa.
  6119. //
  6120. if (InterfaceType == Eisa) {
  6121. InterfaceType = Isa;
  6122. }
  6123. IopLockResourceManager();
  6124. listEntry = IopLegacyBusInformationTable[InterfaceType].Flink;
  6125. while (listEntry != &IopLegacyBusInformationTable[InterfaceType]) {
  6126. PDEVICE_NODE deviceNode = CONTAINING_RECORD(
  6127. listEntry,
  6128. DEVICE_NODE,
  6129. LegacyBusListEntry);
  6130. if (deviceNode->BusNumber == BusNumber) {
  6131. if (deviceNode != BusDeviceNode) {
  6132. //
  6133. // There better not be two bus devicenodes with same
  6134. // interface and bus number.
  6135. //
  6136. IopDbgPrint((
  6137. IOP_RESOURCE_ERROR_LEVEL,
  6138. "Identical legacy bus devicenodes with "
  6139. "interface=%08X & bus=%08X...\n"
  6140. "\t%wZ\n"
  6141. "\t%wZ\n",
  6142. InterfaceType,
  6143. BusNumber,
  6144. &deviceNode->InstancePath,
  6145. &BusDeviceNode->InstancePath));
  6146. }
  6147. IopUnlockResourceManager();
  6148. return;
  6149. } else if (deviceNode->BusNumber > BusNumber) {
  6150. break;
  6151. }
  6152. listEntry = listEntry->Flink;
  6153. }
  6154. //
  6155. // Insert the new devicenode before the one with the higher bus number.
  6156. //
  6157. IopDbgPrint((
  6158. IOP_RESOURCE_VERBOSE_LEVEL,
  6159. "IopInsertLegacyBusDeviceNode: Inserting %wZ with "
  6160. "interface=%08X & bus=%08X into the legacy bus information table\n",
  6161. &BusDeviceNode->InstancePath,
  6162. InterfaceType, BusNumber));
  6163. BusDeviceNode->LegacyBusListEntry.Blink = listEntry->Blink;
  6164. BusDeviceNode->LegacyBusListEntry.Flink = listEntry;
  6165. listEntry->Blink->Flink = &BusDeviceNode->LegacyBusListEntry;
  6166. listEntry->Blink = &BusDeviceNode->LegacyBusListEntry;
  6167. IopUnlockResourceManager();
  6168. }
  6169. }
  6170. PDEVICE_NODE
  6171. IopFindLegacyBusDeviceNode (
  6172. IN INTERFACE_TYPE InterfaceType,
  6173. IN ULONG BusNumber
  6174. )
  6175. /*++
  6176. Routine Description:
  6177. This routine finds the bus devicenode with the specified InterfaceType
  6178. and BusNumber.
  6179. Parameters:
  6180. InterfaceType - Specifies the bus devicenode's interface type.
  6181. BusNumber - Specifies the bus devicenode's bus number.
  6182. Return Value:
  6183. A pointer to the bus devicenode.
  6184. --*/
  6185. {
  6186. PDEVICE_NODE busDeviceNode;
  6187. PAGED_CODE();
  6188. busDeviceNode = IopRootDeviceNode;
  6189. if ( InterfaceType < MaximumInterfaceType &&
  6190. InterfaceType > InterfaceTypeUndefined &&
  6191. InterfaceType != PNPBus) {
  6192. PLIST_ENTRY listEntry;
  6193. //
  6194. // Eisa == Isa.
  6195. //
  6196. if (InterfaceType == Eisa) {
  6197. InterfaceType = Isa;
  6198. }
  6199. //
  6200. // Search our table...
  6201. //
  6202. listEntry = IopLegacyBusInformationTable[InterfaceType].Flink;
  6203. while (listEntry != &IopLegacyBusInformationTable[InterfaceType]) {
  6204. PDEVICE_NODE deviceNode = CONTAINING_RECORD(
  6205. listEntry,
  6206. DEVICE_NODE,
  6207. LegacyBusListEntry);
  6208. if (deviceNode->BusNumber == BusNumber) {
  6209. //
  6210. // Return the bus devicenode matching the bus number and
  6211. // interface.
  6212. //
  6213. busDeviceNode = deviceNode;
  6214. break;
  6215. } else if (deviceNode->BusNumber > BusNumber) {
  6216. //
  6217. // We are done since our list of bus numbers is sorted.
  6218. //
  6219. break;
  6220. }
  6221. listEntry = listEntry->Flink;
  6222. }
  6223. }
  6224. IopDbgPrint((
  6225. IOP_RESOURCE_VERBOSE_LEVEL,
  6226. "IopFindLegacyBusDeviceNode() Found %wZ with "
  6227. "interface=%08X & bus=%08X\n",
  6228. &busDeviceNode->InstancePath,
  6229. InterfaceType,
  6230. BusNumber));
  6231. return busDeviceNode;
  6232. }
  6233. /*++
  6234. SECTION = BOOT CONFIG.
  6235. Description:
  6236. This section contains code that implements BOOT config allocation and
  6237. release.
  6238. --*/
  6239. NTSTATUS
  6240. IopAllocateBootResources (
  6241. IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
  6242. IN PDEVICE_OBJECT DeviceObject,
  6243. IN PCM_RESOURCE_LIST BootResources
  6244. )
  6245. /*++
  6246. Routine Description:
  6247. This routine allocates boot resources.
  6248. Before all Boot Bux Extenders are processed, this routine is called only
  6249. for non-madeup devices since arbiters for their boot resources should
  6250. already be initialized by the time the time they got enumerated.
  6251. After all Boot Bus Extenders are processed, this routine is used for all
  6252. boot allocations.
  6253. Parameters:
  6254. ArbiterRequestSource - Source of this resource request.
  6255. DeviceObject - If non-NULL, the boot resources are
  6256. pre-allocated. These resources will not be given out until they are
  6257. released to the arbiters. If NULL, the boot resources get reserved and
  6258. may be given out if there is no other choice.
  6259. BootResources - Supplies a pointer to the BOOT resources. If
  6260. DeviceObject is NULL, caller should release this pool.
  6261. Return Value:
  6262. The status returned is the final completion status of the operation.
  6263. --*/
  6264. {
  6265. NTSTATUS status;
  6266. PAGED_CODE();
  6267. IopDbgPrint((
  6268. IOP_RESOURCE_INFO_LEVEL,
  6269. "Allocating boot resources...\n"));
  6270. //
  6271. // Claim the lock so no other resource allocations\releases can take place.
  6272. //
  6273. IopLockResourceManager();
  6274. //
  6275. // Call the function that does the real work.
  6276. //
  6277. status = IopAllocateBootResourcesInternal(
  6278. ArbiterRequestSource,
  6279. DeviceObject,
  6280. BootResources);
  6281. //
  6282. // Unblock other resource allocations\releases.
  6283. //
  6284. IopUnlockResourceManager();
  6285. return status;
  6286. }
  6287. NTSTATUS
  6288. IopReportBootResources (
  6289. IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
  6290. IN PDEVICE_OBJECT DeviceObject,
  6291. IN PCM_RESOURCE_LIST BootResources
  6292. )
  6293. /*++
  6294. Routine Description:
  6295. This routine is used to report boot resources.
  6296. This routine gets called before all Boot Bus Extenders are processed. It
  6297. calls the actual allocation function for non-madeup devices. For others,
  6298. it delays the allocation. The postponed allocations take place when the
  6299. arbiters come online by calling IopAllocateLegacyBootResources. Once all
  6300. Boot Bus Extenders are processed, the calls get routed to
  6301. IopAllocateBootResources directly.
  6302. Parameters:
  6303. ArbiterRequestSource - Source of this resource request.
  6304. DeviceObject - If non-NULL, the boot resources are
  6305. pre-allocated. These resources will not be given out until they are
  6306. released to the arbiters. If NULL, the boot resources get reserved and
  6307. may be given out if there is no other choice.
  6308. BootResources - Supplies a pointer to the BOOT resources. If
  6309. DeviceObject is NULL, caller should release this pool.
  6310. Return Value:
  6311. The status returned is the final completion status of the operation.
  6312. --*/
  6313. {
  6314. ULONG size;
  6315. PDEVICE_NODE deviceNode;
  6316. PIOP_RESERVED_RESOURCES_RECORD resourceRecord;
  6317. IopDbgPrint((
  6318. IOP_RESOURCE_INFO_LEVEL,
  6319. "Reporting boot resources...\n"));
  6320. if ((size = IopDetermineResourceListSize(BootResources)) == 0) {
  6321. return STATUS_SUCCESS;
  6322. }
  6323. if (DeviceObject) {
  6324. deviceNode = PP_DO_TO_DN(DeviceObject);
  6325. ASSERT(deviceNode);
  6326. if (!(deviceNode->Flags & DNF_MADEUP)) {
  6327. //
  6328. // Allocate BOOT configs for non-madeup devices right away.
  6329. //
  6330. return IopAllocateBootResources(
  6331. ArbiterRequestSource,
  6332. DeviceObject,
  6333. BootResources);
  6334. }
  6335. if (!deviceNode->BootResources) {
  6336. deviceNode->BootResources = ExAllocatePoolIORL(PagedPool, size);
  6337. if (!deviceNode->BootResources) {
  6338. return STATUS_INSUFFICIENT_RESOURCES;
  6339. }
  6340. RtlCopyMemory(deviceNode->BootResources, BootResources, size);
  6341. }
  6342. } else {
  6343. deviceNode = NULL;
  6344. }
  6345. //
  6346. // Delay BOOT allocation since arbiters may not be around.
  6347. //
  6348. resourceRecord = (PIOP_RESERVED_RESOURCES_RECORD) ExAllocatePoolIORRR(
  6349. PagedPool,
  6350. sizeof(IOP_RESERVED_RESOURCES_RECORD));
  6351. if (!resourceRecord) {
  6352. //
  6353. // Free memory we allocated and return failure.
  6354. //
  6355. if (deviceNode && deviceNode->BootResources) {
  6356. ExFreePool(deviceNode->BootResources);
  6357. deviceNode->BootResources = NULL;
  6358. }
  6359. return STATUS_INSUFFICIENT_RESOURCES;
  6360. }
  6361. if (deviceNode) {
  6362. resourceRecord->ReservedResources = deviceNode->BootResources;
  6363. } else {
  6364. resourceRecord->ReservedResources = BootResources;
  6365. }
  6366. resourceRecord->DeviceObject = DeviceObject;
  6367. //
  6368. // Link this record into our list.
  6369. //
  6370. resourceRecord->Next = IopInitReservedResourceList;
  6371. IopInitReservedResourceList = resourceRecord;
  6372. return STATUS_SUCCESS;
  6373. }
  6374. NTSTATUS
  6375. IopAllocateLegacyBootResources (
  6376. IN INTERFACE_TYPE InterfaceType,
  6377. IN ULONG BusNumber
  6378. )
  6379. /*++
  6380. Routine Description:
  6381. This routine is called to reserve legacy BOOT resources for the specified
  6382. InterfaceType and BusNumber. This is done everytime a new bus with a legacy
  6383. InterfaceType gets enumerated.
  6384. Parameters:
  6385. InterfaceType - Legacy InterfaceType.
  6386. BusNumber - Legacy BusNumber.
  6387. Return Value:
  6388. The status returned is the final completion status of the operation.
  6389. --*/
  6390. {
  6391. NTSTATUS status;
  6392. PIOP_RESERVED_RESOURCES_RECORD resourceRecord;
  6393. PIOP_RESERVED_RESOURCES_RECORD prevRecord;
  6394. PCM_RESOURCE_LIST newList;
  6395. PCM_RESOURCE_LIST remainingList;
  6396. PCM_RESOURCE_LIST resourceList;
  6397. if (IopInitHalDeviceNode && IopInitHalResources) {
  6398. remainingList = NULL;
  6399. newList = IopCreateCmResourceList(
  6400. IopInitHalResources,
  6401. InterfaceType,
  6402. BusNumber,
  6403. &remainingList);
  6404. if (newList) {
  6405. //
  6406. // Sanity check that there was no error.
  6407. //
  6408. if (remainingList == NULL) {
  6409. //
  6410. // Full match.
  6411. //
  6412. ASSERT(newList == IopInitHalResources);
  6413. } else {
  6414. //
  6415. // Partial match.
  6416. //
  6417. ASSERT(IopInitHalResources != newList);
  6418. ASSERT(IopInitHalResources != remainingList);
  6419. }
  6420. if (remainingList) {
  6421. ExFreePool(IopInitHalResources);
  6422. }
  6423. IopInitHalResources = remainingList;
  6424. remainingList = IopInitHalDeviceNode->BootResources;
  6425. IopInitHalDeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
  6426. IopDbgPrint((
  6427. IOP_RESOURCE_INFO_LEVEL,
  6428. "Allocating HAL reported resources on interface=%x and "
  6429. "bus number=%x...\n", InterfaceType, BusNumber));
  6430. status = IopAllocateBootResources(
  6431. ArbiterRequestHalReported,
  6432. IopInitHalDeviceNode->PhysicalDeviceObject,
  6433. newList);
  6434. IopInitHalDeviceNode->BootResources = IopCombineCmResourceList(
  6435. remainingList,
  6436. newList);
  6437. ASSERT(IopInitHalDeviceNode->BootResources);
  6438. //
  6439. // Free previous BOOT config if any.
  6440. //
  6441. if (remainingList) {
  6442. ExFreePool(remainingList);
  6443. }
  6444. } else {
  6445. //
  6446. // No match. Sanity check that there was no error.
  6447. //
  6448. ASSERT(remainingList && remainingList == IopInitHalResources);
  6449. }
  6450. }
  6451. prevRecord = NULL;
  6452. resourceRecord = IopInitReservedResourceList;
  6453. while (resourceRecord) {
  6454. resourceList = resourceRecord->ReservedResources;
  6455. if ( resourceList->List[0].InterfaceType == InterfaceType &&
  6456. resourceList->List[0].BusNumber == BusNumber) {
  6457. IopDbgPrint((
  6458. IOP_RESOURCE_INFO_LEVEL,
  6459. "Allocating boot config for made-up device on interface=%x and"
  6460. " bus number=%x...\n", InterfaceType, BusNumber));
  6461. status = IopAllocateBootResources(
  6462. ArbiterRequestPnpEnumerated,
  6463. resourceRecord->DeviceObject,
  6464. resourceList);
  6465. if (resourceRecord->DeviceObject == NULL) {
  6466. ExFreePool(resourceList);
  6467. }
  6468. if (prevRecord) {
  6469. prevRecord->Next = resourceRecord->Next;
  6470. } else {
  6471. IopInitReservedResourceList = resourceRecord->Next;
  6472. }
  6473. ExFreePool(resourceRecord);
  6474. if (prevRecord) {
  6475. resourceRecord = prevRecord->Next;
  6476. } else {
  6477. resourceRecord = IopInitReservedResourceList;
  6478. }
  6479. } else {
  6480. prevRecord = resourceRecord;
  6481. resourceRecord = resourceRecord->Next;
  6482. }
  6483. }
  6484. return STATUS_SUCCESS;
  6485. }
  6486. NTSTATUS
  6487. IopAllocateBootResourcesInternal (
  6488. IN ARBITER_REQUEST_SOURCE ArbiterRequestSource,
  6489. IN PDEVICE_OBJECT DeviceObject,
  6490. IN PCM_RESOURCE_LIST BootResources
  6491. )
  6492. /*++
  6493. Routine Description:
  6494. This routine reports boot resources for the specified device to
  6495. arbiters.
  6496. Parameters:
  6497. ArbiterRequestSource - Source of this resource request.
  6498. DeviceObject - If non-NULL, the boot resources are
  6499. pre-allocated. These resources will not be given out until they are
  6500. released to the arbiters. If NULL, the boot resources get reserved and
  6501. may be given out if there is no other choice.
  6502. BootResources - Supplies a pointer to the BOOT resources. If
  6503. DeviceObject is NULL, caller should release this pool.
  6504. Return Value:
  6505. The status returned is the final completion status of the operation.
  6506. --*/
  6507. {
  6508. NTSTATUS status;
  6509. PDEVICE_NODE deviceNode;
  6510. PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
  6511. PREQ_LIST reqList;
  6512. IOP_RESOURCE_REQUEST request;
  6513. PAGED_CODE();
  6514. ioResources = IopCmResourcesToIoResources(
  6515. 0,
  6516. BootResources,
  6517. LCPRI_BOOTCONFIG);
  6518. if (ioResources) {
  6519. deviceNode = PP_DO_TO_DN(DeviceObject);
  6520. IopDbgPrint((
  6521. IOP_RESOURCE_VERBOSE_LEVEL,
  6522. "\n===================================\n"
  6523. ));
  6524. IopDbgPrint((
  6525. IOP_RESOURCE_VERBOSE_LEVEL,
  6526. "Boot Resource List:: "));
  6527. IopDumpResourceRequirementsList(ioResources);
  6528. IopDbgPrint((
  6529. IOP_RESOURCE_VERBOSE_LEVEL,
  6530. " ++++++++++++++++++++++++++++++\n"));
  6531. request.AllocationType = ArbiterRequestSource;
  6532. request.ResourceRequirements = ioResources;
  6533. request.PhysicalDevice = DeviceObject;
  6534. status = IopResourceRequirementsListToReqList(
  6535. &request,
  6536. &reqList);
  6537. if (NT_SUCCESS(status)) {
  6538. if (reqList) {
  6539. status = IopBootAllocation(reqList);
  6540. if (NT_SUCCESS(status)) {
  6541. if (deviceNode) {
  6542. deviceNode->Flags |= DNF_BOOT_CONFIG_RESERVED;
  6543. if (!deviceNode->BootResources) {
  6544. ULONG size;
  6545. size = IopDetermineResourceListSize(BootResources);
  6546. deviceNode->BootResources = ExAllocatePoolIORL(
  6547. PagedPool,
  6548. size);
  6549. if (!deviceNode->BootResources) {
  6550. return STATUS_INSUFFICIENT_RESOURCES;
  6551. }
  6552. RtlCopyMemory(
  6553. deviceNode->BootResources,
  6554. BootResources,
  6555. size);
  6556. }
  6557. }
  6558. }
  6559. IopFreeReqList(reqList);
  6560. } else {
  6561. status = STATUS_UNSUCCESSFUL;
  6562. }
  6563. }
  6564. ExFreePool(ioResources);
  6565. } else {
  6566. status = STATUS_UNSUCCESSFUL;
  6567. }
  6568. if (!NT_SUCCESS(status)) {
  6569. IopDbgPrint((
  6570. IOP_RESOURCE_ERROR_LEVEL,
  6571. "IopAllocateBootResourcesInternal: Failed with status = %08X\n",
  6572. status));
  6573. }
  6574. return status;
  6575. }
  6576. NTSTATUS
  6577. IopBootAllocation (
  6578. IN PREQ_LIST ReqList
  6579. )
  6580. /*++
  6581. Routine Description:
  6582. This routine calls the arbiters for the ReqList to do BootAllocation.
  6583. Parameters:
  6584. ReqList - List of BOOT resources in internal format.
  6585. Return Value:
  6586. The status returned is the final completion status of the operation.
  6587. --*/
  6588. {
  6589. NTSTATUS status;
  6590. NTSTATUS returnStatus;
  6591. LIST_ENTRY activeArbiterList;
  6592. PLIST_ENTRY listEntry;
  6593. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  6594. ARBITER_PARAMETERS p;
  6595. PAGED_CODE();
  6596. returnStatus = STATUS_SUCCESS;
  6597. InitializeListHead(&activeArbiterList);
  6598. ReqList->SelectedAlternative = ReqList->AlternativeTable;
  6599. IopAddRemoveReqDescs( (*ReqList->SelectedAlternative)->DescTable,
  6600. (*ReqList->SelectedAlternative)->DescCount,
  6601. &activeArbiterList,
  6602. TRUE);
  6603. listEntry = activeArbiterList.Flink;
  6604. while (listEntry != &activeArbiterList){
  6605. arbiterEntry = CONTAINING_RECORD(
  6606. listEntry,
  6607. PI_RESOURCE_ARBITER_ENTRY,
  6608. ActiveArbiterList);
  6609. listEntry = listEntry->Flink;
  6610. if (arbiterEntry->ResourcesChanged == FALSE) {
  6611. continue;
  6612. }
  6613. ASSERT(IsListEmpty(&arbiterEntry->ResourceList) == FALSE);
  6614. p.Parameters.BootAllocation.ArbitrationList =
  6615. &arbiterEntry->ResourceList;
  6616. status = arbiterEntry->ArbiterInterface->ArbiterHandler(
  6617. arbiterEntry->ArbiterInterface->Context,
  6618. ArbiterActionBootAllocation,
  6619. &p);
  6620. if (!NT_SUCCESS(status)) {
  6621. PARBITER_LIST_ENTRY arbiterListEntry;
  6622. arbiterListEntry = (PARBITER_LIST_ENTRY)
  6623. arbiterEntry->ResourceList.Flink;
  6624. IopDbgPrint((
  6625. IOP_RESOURCE_ERROR_LEVEL,
  6626. "Allocate Boot Resources Failed ::\n\tCount = %x, PDO = %x\n",
  6627. arbiterListEntry->AlternativeCount,
  6628. arbiterListEntry->PhysicalDeviceObject));
  6629. IopDumpResourceDescriptor("\t", arbiterListEntry->Alternatives);
  6630. returnStatus = status;
  6631. }
  6632. IopInitializeArbiterEntryState(arbiterEntry);
  6633. }
  6634. IopCheckDataStructures(IopRootDeviceNode);
  6635. return returnStatus;
  6636. }
  6637. PCM_RESOURCE_LIST
  6638. IopCreateCmResourceList (
  6639. IN PCM_RESOURCE_LIST ResourceList,
  6640. IN INTERFACE_TYPE InterfaceType,
  6641. IN ULONG BusNumber,
  6642. OUT PCM_RESOURCE_LIST *RemainingList
  6643. )
  6644. /*++
  6645. Routine Description:
  6646. This routine returns the CM_RESOURCE_LIST portion out of the specified list
  6647. that matches the specified BusNumber and InterfaceType.
  6648. Parameters:
  6649. ResourceList - Input resource list.
  6650. InterfaceType - Interface type.
  6651. BusNumber - Bus number.
  6652. RemainingList - Portion not matching BusNumber and InterfaceType.
  6653. Return Value:
  6654. Returns the matching CM_RESOURCE_LIST if successful, else NULL.
  6655. --*/
  6656. {
  6657. ULONG i;
  6658. ULONG j;
  6659. ULONG totalSize;
  6660. ULONG matchSize;
  6661. ULONG listSize;
  6662. PCM_RESOURCE_LIST newList;
  6663. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  6664. PCM_FULL_RESOURCE_DESCRIPTOR newFullResourceDesc;
  6665. PCM_FULL_RESOURCE_DESCRIPTOR remainingFullResourceDesc;
  6666. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  6667. PAGED_CODE();
  6668. fullResourceDesc = &ResourceList->List[0];
  6669. totalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
  6670. matchSize = 0;
  6671. //
  6672. // Determine the size of memory to be allocated for the matching resource
  6673. // list.
  6674. //
  6675. for (i = 0; i < ResourceList->Count; i++) {
  6676. //
  6677. // Add the size of this descriptor.
  6678. //
  6679. listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  6680. PartialResourceList) +
  6681. FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
  6682. PartialDescriptors);
  6683. partialDescriptor =
  6684. &fullResourceDesc->PartialResourceList.PartialDescriptors[0];
  6685. for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) {
  6686. ULONG descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  6687. if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) {
  6688. descriptorSize +=
  6689. partialDescriptor->u.DeviceSpecificData.DataSize;
  6690. }
  6691. listSize += descriptorSize;
  6692. partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  6693. ((PUCHAR)partialDescriptor +
  6694. descriptorSize);
  6695. }
  6696. if ( fullResourceDesc->InterfaceType == InterfaceType &&
  6697. fullResourceDesc->BusNumber == BusNumber) {
  6698. matchSize += listSize;
  6699. }
  6700. totalSize += listSize;
  6701. fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
  6702. ((PUCHAR)fullResourceDesc + listSize);
  6703. }
  6704. if (!matchSize) {
  6705. *RemainingList = ResourceList;
  6706. return NULL;
  6707. }
  6708. matchSize += FIELD_OFFSET(CM_RESOURCE_LIST, List);
  6709. if (matchSize == totalSize) {
  6710. *RemainingList = NULL;
  6711. return ResourceList;
  6712. }
  6713. //
  6714. // Allocate memory for both lists.
  6715. //
  6716. newList = (PCM_RESOURCE_LIST)ExAllocatePoolIORRR(PagedPool, matchSize);
  6717. if (newList == NULL) {
  6718. *RemainingList = NULL;
  6719. return NULL;
  6720. }
  6721. *RemainingList = (PCM_RESOURCE_LIST)
  6722. ExAllocatePoolIORRR(
  6723. PagedPool,
  6724. totalSize - matchSize +
  6725. FIELD_OFFSET(CM_RESOURCE_LIST, List));
  6726. if (*RemainingList == NULL) {
  6727. ExFreePool(newList);
  6728. return NULL;
  6729. }
  6730. newList->Count = 0;
  6731. (*RemainingList)->Count = 0;
  6732. newFullResourceDesc = &newList->List[0];
  6733. remainingFullResourceDesc = &(*RemainingList)->List[0];
  6734. fullResourceDesc = &ResourceList->List[0];
  6735. for (i = 0; i < ResourceList->Count; i++) {
  6736. listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
  6737. PartialResourceList) +
  6738. FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
  6739. PartialDescriptors);
  6740. partialDescriptor =
  6741. &fullResourceDesc->PartialResourceList.PartialDescriptors[0];
  6742. for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) {
  6743. ULONG descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  6744. if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) {
  6745. descriptorSize +=
  6746. partialDescriptor->u.DeviceSpecificData.DataSize;
  6747. }
  6748. listSize += descriptorSize;
  6749. partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  6750. ((PUCHAR)partialDescriptor +
  6751. descriptorSize);
  6752. }
  6753. if ( fullResourceDesc->InterfaceType == InterfaceType &&
  6754. fullResourceDesc->BusNumber == BusNumber) {
  6755. newList->Count++;
  6756. RtlCopyMemory(newFullResourceDesc, fullResourceDesc, listSize);
  6757. newFullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
  6758. ((PUCHAR)newFullResourceDesc +
  6759. listSize);
  6760. } else {
  6761. (*RemainingList)->Count++;
  6762. RtlCopyMemory(
  6763. remainingFullResourceDesc,
  6764. fullResourceDesc,
  6765. listSize);
  6766. remainingFullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
  6767. ((PUCHAR)remainingFullResourceDesc +
  6768. listSize);
  6769. }
  6770. fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
  6771. ((PUCHAR)fullResourceDesc +
  6772. listSize);
  6773. }
  6774. return newList;
  6775. }
  6776. PCM_RESOURCE_LIST
  6777. IopCombineCmResourceList (
  6778. IN PCM_RESOURCE_LIST ResourceListA,
  6779. IN PCM_RESOURCE_LIST ResourceListB
  6780. )
  6781. /*++
  6782. Routine Description:
  6783. This routine combines the two CM_RESOURCE_LISTs and returns the resulting
  6784. CM_RESOURCE_LIST.
  6785. Parameters:
  6786. ResourceListA - ListA.
  6787. ResourceListB - ListB.
  6788. Return Value:
  6789. Returns the combined CM_RESOURCE_LIST if successful, else NULL.
  6790. --*/
  6791. {
  6792. PCM_RESOURCE_LIST newList;
  6793. ULONG sizeA;
  6794. ULONG sizeB;
  6795. ULONG size;
  6796. ULONG diff;
  6797. PAGED_CODE();
  6798. if (ResourceListA == NULL) {
  6799. return ResourceListB;
  6800. }
  6801. if (ResourceListB == NULL) {
  6802. return ResourceListA;
  6803. }
  6804. newList = NULL;
  6805. sizeA = IopDetermineResourceListSize(ResourceListA);
  6806. sizeB = IopDetermineResourceListSize(ResourceListB);
  6807. if (sizeA && sizeB) {
  6808. diff = sizeof(CM_RESOURCE_LIST) - sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  6809. size = sizeA + sizeB - diff;
  6810. newList = (PCM_RESOURCE_LIST)ExAllocatePoolIORRR(PagedPool, size);
  6811. if (newList) {
  6812. RtlCopyMemory(newList, ResourceListA, sizeA);
  6813. RtlCopyMemory(
  6814. (PUCHAR)newList + sizeA,
  6815. (PUCHAR)ResourceListB + diff,
  6816. sizeB - diff);
  6817. newList->Count += ResourceListB->Count;
  6818. }
  6819. }
  6820. return newList;
  6821. }
  6822. /*++
  6823. SECTION = CLEANUP.
  6824. Description:
  6825. This section contains code that performs clean up like releasing storage
  6826. for various data structures..
  6827. --*/
  6828. VOID
  6829. IopFreeReqAlternative (
  6830. IN PREQ_ALTERNATIVE ReqAlternative
  6831. )
  6832. /*++
  6833. Routine Description:
  6834. This routine release the storage for the ReqAlternative by freeing the
  6835. contained descriptors.
  6836. Parameters:
  6837. ReqList - REQ_ALTERNATIVE to be freed.
  6838. Return Value:
  6839. None.
  6840. --*/
  6841. {
  6842. PREQ_DESC reqDesc;
  6843. PREQ_DESC reqDescx;
  6844. ULONG i;
  6845. PAGED_CODE();
  6846. if (ReqAlternative) {
  6847. //
  6848. // Free all REQ_DESC making this REQ_ALTERNATIVE.
  6849. //
  6850. for (i = 0; i < ReqAlternative->DescCount; i++) {
  6851. //
  6852. // Free the list of translated REQ_DESCs for this REQ_DESC.
  6853. //
  6854. reqDesc = ReqAlternative->DescTable[i];
  6855. reqDescx = reqDesc->TranslatedReqDesc;
  6856. while (reqDescx && IS_TRANSLATED_REQ_DESC(reqDescx)) {
  6857. //
  6858. // Free storage for alternative descriptors if any.
  6859. //
  6860. if (reqDescx->AlternativeTable.Alternatives) {
  6861. ExFreePool(reqDescx->AlternativeTable.Alternatives);
  6862. }
  6863. reqDesc = reqDescx;
  6864. reqDescx = reqDescx->TranslatedReqDesc;
  6865. ExFreePool(reqDesc);
  6866. }
  6867. }
  6868. }
  6869. }
  6870. VOID
  6871. IopFreeReqList (
  6872. IN PREQ_LIST ReqList
  6873. )
  6874. /*++
  6875. Routine Description:
  6876. This routine release the storage for the ReqList by freeing the contained
  6877. alternatives.
  6878. Parameters:
  6879. ReqList - REQ_LIST to be freed.
  6880. Return Value:
  6881. None.
  6882. --*/
  6883. {
  6884. ULONG i;
  6885. PAGED_CODE();
  6886. if (ReqList) {
  6887. //
  6888. // Free all alternatives making this REQ_LIST.
  6889. //
  6890. for (i = 0; i < ReqList->AlternativeCount; i++) {
  6891. IopFreeReqAlternative(ReqList->AlternativeTable[i]);
  6892. }
  6893. ExFreePool(ReqList);
  6894. }
  6895. }
  6896. VOID
  6897. IopFreeResourceRequirementsForAssignTable(
  6898. IN PIOP_RESOURCE_REQUEST RequestTable,
  6899. IN PIOP_RESOURCE_REQUEST RequestTableEnd
  6900. )
  6901. /*++
  6902. Routine Description:
  6903. For each resource request in the table, this routine frees its
  6904. associated REQ_LIST.
  6905. Parameters:
  6906. RequestTable - Start of request table.
  6907. RequestTableEnd - End of request table.
  6908. Return Value:
  6909. None.
  6910. --*/
  6911. {
  6912. PIOP_RESOURCE_REQUEST request;
  6913. PAGED_CODE();
  6914. for (request = RequestTable; request < RequestTableEnd; request++) {
  6915. IopFreeReqList(request->ReqList);
  6916. request->ReqList = NULL;
  6917. if ( request->Flags & IOP_ASSIGN_KEEP_CURRENT_CONFIG &&
  6918. request->ResourceRequirements) {
  6919. //
  6920. // The REAL resreq list is cached in DeviceNode->ResourceRequirements.
  6921. // We need to free the filtered list.
  6922. //
  6923. ExFreePool(request->ResourceRequirements);
  6924. request->ResourceRequirements = NULL;
  6925. }
  6926. }
  6927. }
  6928. #if DBG_SCOPE
  6929. VOID
  6930. IopCheckDataStructures (
  6931. IN PDEVICE_NODE DeviceNode
  6932. )
  6933. {
  6934. PDEVICE_NODE sibling;
  6935. PAGED_CODE();
  6936. //
  6937. // Process all the siblings.
  6938. //
  6939. for (sibling = DeviceNode; sibling; sibling = sibling->Sibling) {
  6940. IopCheckDataStructuresWorker(sibling);
  6941. }
  6942. for (sibling = DeviceNode; sibling; sibling = sibling->Sibling) {
  6943. //
  6944. // Recursively check all the children.
  6945. //
  6946. if (sibling->Child) {
  6947. IopCheckDataStructures(sibling->Child);
  6948. }
  6949. }
  6950. }
  6951. VOID
  6952. IopCheckDataStructuresWorker (
  6953. IN PDEVICE_NODE Device
  6954. )
  6955. /*++
  6956. Routine Description:
  6957. This routine sanity checks the arbiter related data structures for the
  6958. specified device.
  6959. Parameters:
  6960. DeviceNode - Device node whose structures are to be checked.
  6961. Return Value:
  6962. None.
  6963. --*/
  6964. {
  6965. PLIST_ENTRY listHead, listEntry;
  6966. PPI_RESOURCE_ARBITER_ENTRY arbiterEntry;
  6967. PAGED_CODE();
  6968. listHead = &Device->DeviceArbiterList;
  6969. listEntry = listHead->Flink;
  6970. while (listEntry != listHead) {
  6971. arbiterEntry = CONTAINING_RECORD(
  6972. listEntry,
  6973. PI_RESOURCE_ARBITER_ENTRY,
  6974. DeviceArbiterList);
  6975. if (arbiterEntry->ArbiterInterface != NULL) {
  6976. if (!IsListEmpty(&arbiterEntry->ResourceList)) {
  6977. IopDbgPrint((
  6978. IOP_RESOURCE_ERROR_LEVEL,
  6979. "Arbiter on %wZ should have empty resource list\n",
  6980. &Device->InstancePath));
  6981. }
  6982. if (!IsListEmpty(&arbiterEntry->ActiveArbiterList)) {
  6983. IopDbgPrint((
  6984. IOP_RESOURCE_ERROR_LEVEL,
  6985. "Arbiter on %wZ should not be in the active arbiter list\n",
  6986. &Device->InstancePath));
  6987. }
  6988. }
  6989. listEntry = listEntry->Flink;
  6990. }
  6991. }
  6992. VOID
  6993. IopDumpResourceRequirementsList (
  6994. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
  6995. )
  6996. /*++
  6997. Routine Description:
  6998. This routine dumps IoResources
  6999. Parameters:
  7000. IoResources - Supplies a pointer to the IO resource requirements list
  7001. Return Value:
  7002. None.
  7003. --*/
  7004. {
  7005. PIO_RESOURCE_LIST IoResourceList;
  7006. PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor;
  7007. PIO_RESOURCE_DESCRIPTOR IoResourceDescriptorEnd;
  7008. LONG IoResourceListCount;
  7009. PAGED_CODE();
  7010. if (IoResources == NULL) {
  7011. return;
  7012. }
  7013. IoResourceList = IoResources->List;
  7014. IoResourceListCount = (LONG) IoResources->AlternativeLists;
  7015. IopDbgPrint((
  7016. IOP_RESOURCE_VERBOSE_LEVEL,
  7017. "ResReqList: Interface: %x, Bus: %x, Slot: %x, AlternativeLists: %x\n",
  7018. IoResources->InterfaceType,
  7019. IoResources->BusNumber,
  7020. IoResources->SlotNumber,
  7021. IoResources->AlternativeLists));
  7022. while (--IoResourceListCount >= 0) {
  7023. IopDbgPrint((
  7024. IOP_RESOURCE_VERBOSE_LEVEL,
  7025. " Alternative List: DescCount: %x\n",
  7026. IoResourceList->Count));
  7027. IoResourceDescriptor = IoResourceList->Descriptors;
  7028. IoResourceDescriptorEnd = IoResourceDescriptor + IoResourceList->Count;
  7029. while(IoResourceDescriptor < IoResourceDescriptorEnd) {
  7030. IopDumpResourceDescriptor(" ", IoResourceDescriptor++);
  7031. }
  7032. IoResourceList = (PIO_RESOURCE_LIST) IoResourceDescriptorEnd;
  7033. }
  7034. IopDbgPrint((IOP_RESOURCE_VERBOSE_LEVEL,"\n"));
  7035. }
  7036. VOID
  7037. IopDumpResourceDescriptor (
  7038. IN PUCHAR Indent,
  7039. IN PIO_RESOURCE_DESCRIPTOR Desc
  7040. )
  7041. {
  7042. PAGED_CODE();
  7043. IopDbgPrint((
  7044. IOP_RESOURCE_VERBOSE_LEVEL,
  7045. "%sOpt: %x, Share: %x\t",
  7046. Indent,
  7047. Desc->Option,
  7048. Desc->ShareDisposition));
  7049. switch (Desc->Type) {
  7050. case CmResourceTypePort:
  7051. IopDbgPrint((
  7052. IOP_RESOURCE_VERBOSE_LEVEL,
  7053. "IO Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
  7054. Desc->u.Port.MinimumAddress.HighPart,
  7055. Desc->u.Port.MinimumAddress.LowPart,
  7056. Desc->u.Port.MaximumAddress.HighPart,
  7057. Desc->u.Port.MaximumAddress.LowPart,
  7058. Desc->u.Port.Alignment,
  7059. Desc->u.Port.Length));
  7060. break;
  7061. case CmResourceTypeMemory:
  7062. IopDbgPrint((
  7063. IOP_RESOURCE_VERBOSE_LEVEL,
  7064. "MEM Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
  7065. Desc->u.Memory.MinimumAddress.HighPart,
  7066. Desc->u.Memory.MinimumAddress.LowPart,
  7067. Desc->u.Memory.MaximumAddress.HighPart,
  7068. Desc->u.Memory.MaximumAddress.LowPart,
  7069. Desc->u.Memory.Alignment,
  7070. Desc->u.Memory.Length));
  7071. break;
  7072. case CmResourceTypeInterrupt:
  7073. IopDbgPrint((
  7074. IOP_RESOURCE_VERBOSE_LEVEL,
  7075. "INT Min: %x, Max: %x\n",
  7076. Desc->u.Interrupt.MinimumVector,
  7077. Desc->u.Interrupt.MaximumVector));
  7078. break;
  7079. case CmResourceTypeDma:
  7080. IopDbgPrint((
  7081. IOP_RESOURCE_VERBOSE_LEVEL,
  7082. "DMA Min: %x, Max: %x\n",
  7083. Desc->u.Dma.MinimumChannel,
  7084. Desc->u.Dma.MaximumChannel));
  7085. break;
  7086. case CmResourceTypeDevicePrivate:
  7087. IopDbgPrint((
  7088. IOP_RESOURCE_VERBOSE_LEVEL,
  7089. "DevicePrivate Data: %x, %x, %x\n",
  7090. Desc->u.DevicePrivate.Data[0],
  7091. Desc->u.DevicePrivate.Data[1],
  7092. Desc->u.DevicePrivate.Data[2]));
  7093. break;
  7094. default:
  7095. IopDbgPrint((
  7096. IOP_RESOURCE_VERBOSE_LEVEL,
  7097. "Unknown Descriptor type %x\n",
  7098. Desc->Type));
  7099. break;
  7100. }
  7101. }
  7102. VOID
  7103. IopDumpCmResourceList (
  7104. IN PCM_RESOURCE_LIST CmList
  7105. )
  7106. /*++
  7107. Routine Description:
  7108. This routine displays CM resource list.
  7109. Arguments:
  7110. CmList - CM resource list to be dumped.
  7111. Return Value:
  7112. None.
  7113. --*/
  7114. {
  7115. PCM_FULL_RESOURCE_DESCRIPTOR fullDesc;
  7116. PCM_PARTIAL_RESOURCE_LIST partialDesc;
  7117. PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
  7118. ULONG count;
  7119. ULONG i;
  7120. PAGED_CODE();
  7121. if (CmList->Count > 0) {
  7122. if (CmList) {
  7123. fullDesc = &CmList->List[0];
  7124. IopDbgPrint((
  7125. IOP_RESOURCE_VERBOSE_LEVEL,
  7126. "Cm Resource List -\n"));
  7127. IopDbgPrint((
  7128. IOP_RESOURCE_VERBOSE_LEVEL,
  7129. " List Count = %x, Bus Number = %x\n",
  7130. CmList->Count,
  7131. fullDesc->BusNumber));
  7132. partialDesc = &fullDesc->PartialResourceList;
  7133. IopDbgPrint((
  7134. IOP_RESOURCE_VERBOSE_LEVEL,
  7135. " Version = %x, Revision = %x, Desc count = %x\n",
  7136. partialDesc->Version,
  7137. partialDesc->Revision,
  7138. partialDesc->Count));
  7139. count = partialDesc->Count;
  7140. desc = &partialDesc->PartialDescriptors[0];
  7141. for (i = 0; i < count; i++) {
  7142. IopDumpCmResourceDescriptor(" ", desc);
  7143. desc++;
  7144. }
  7145. }
  7146. }
  7147. }
  7148. VOID
  7149. IopDumpCmResourceDescriptor (
  7150. IN PUCHAR Indent,
  7151. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc
  7152. )
  7153. /*++
  7154. Routine Description:
  7155. This routine displays a IO_RESOURCE_DESCRIPTOR.
  7156. Parameters:
  7157. Indent - # char of indentation.
  7158. Desc - CM_RESOURCE_DESCRIPTOR to be displayed.
  7159. Return Value:
  7160. None.
  7161. --*/
  7162. {
  7163. PAGED_CODE();
  7164. switch (Desc->Type) {
  7165. case CmResourceTypePort:
  7166. IopDbgPrint((
  7167. IOP_RESOURCE_VERBOSE_LEVEL,
  7168. "%sIO Start: %x:%08x, Length: %x\n",
  7169. Indent,
  7170. Desc->u.Port.Start.HighPart,
  7171. Desc->u.Port.Start.LowPart,
  7172. Desc->u.Port.Length));
  7173. break;
  7174. case CmResourceTypeMemory:
  7175. IopDbgPrint((
  7176. IOP_RESOURCE_VERBOSE_LEVEL,
  7177. "%sMEM Start: %x:%08x, Length: %x\n",
  7178. Indent,
  7179. Desc->u.Memory.Start.HighPart,
  7180. Desc->u.Memory.Start.LowPart,
  7181. Desc->u.Memory.Length));
  7182. break;
  7183. case CmResourceTypeInterrupt:
  7184. IopDbgPrint((
  7185. IOP_RESOURCE_VERBOSE_LEVEL,
  7186. "%sINT Level: %x, Vector: %x, Affinity: %x\n",
  7187. Indent,
  7188. Desc->u.Interrupt.Level,
  7189. Desc->u.Interrupt.Vector,
  7190. Desc->u.Interrupt.Affinity));
  7191. break;
  7192. case CmResourceTypeDma:
  7193. IopDbgPrint((
  7194. IOP_RESOURCE_VERBOSE_LEVEL,
  7195. "%sDMA Channel: %x, Port: %x\n",
  7196. Indent,
  7197. Desc->u.Dma.Channel,
  7198. Desc->u.Dma.Port));
  7199. break;
  7200. }
  7201. }
  7202. #endif