Leaked source code of windows server 2003
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.

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