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

1985 lines
63 KiB

  1. /*++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. Module Name:
  4. devres.c
  5. Abstract:
  6. This module contains the high level device resources support routines.
  7. Author:
  8. Shie-Lin Tzong (shielint) July-27-1995
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "busp.h"
  14. #include "pnpisa.h"
  15. #include "pbios.h"
  16. #include "pnpcvrt.h"
  17. #if ISOLATE_CARDS
  18. #define IDBG 0
  19. #if 0
  20. NTSTATUS
  21. PipFilterResourceRequirementsList(
  22. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
  23. );
  24. #endif
  25. PIO_RESOURCE_REQUIREMENTS_LIST
  26. PipCmResourcesToIoResources (
  27. IN PCM_RESOURCE_LIST CmResourceList
  28. );
  29. NTSTATUS
  30. PipMergeResourceRequirementsLists (
  31. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList1,
  32. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList2,
  33. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *MergedList
  34. );
  35. NTSTATUS
  36. PipBuildBootResourceRequirementsList (
  37. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList,
  38. IN PCM_RESOURCE_LIST CmList,
  39. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *FilteredList,
  40. OUT PBOOLEAN ExactMatch
  41. );
  42. VOID
  43. PipMergeBootResourcesToRequirementsList(
  44. PDEVICE_INFORMATION DeviceInfo,
  45. PCM_RESOURCE_LIST BootResources,
  46. PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
  47. );
  48. #pragma alloc_text(PAGE, PipGetCardIdentifier)
  49. #pragma alloc_text(PAGE, PipGetFunctionIdentifier)
  50. #pragma alloc_text(PAGE, PipGetCompatibleDeviceId)
  51. #pragma alloc_text(PAGE, PipQueryDeviceId)
  52. #pragma alloc_text(PAGE, PipQueryDeviceUniqueId)
  53. //#pragma alloc_text(PAGE, PipQueryDeviceResources)
  54. #pragma alloc_text(PAGE, PipQueryDeviceResourceRequirements)
  55. //#pragma alloc_text(PAGE, PipFilterResourceRequirementsList)
  56. #pragma alloc_text(PAGE, PipCmResourcesToIoResources)
  57. #pragma alloc_text(PAGE, PipMergeResourceRequirementsLists)
  58. #pragma alloc_text(PAGE, PipBuildBootResourceRequirementsList)
  59. #pragma alloc_text(PAGE, PipMergeBootResourcesToRequirementsList)
  60. //#pragma alloc_text(PAGE, PipSetDeviceResources)
  61. NTSTATUS
  62. PipGetCardIdentifier (
  63. PUCHAR CardData,
  64. PWCHAR *Buffer,
  65. PULONG BufferLength
  66. )
  67. /*++
  68. Routine Description:
  69. This function returns the identifier for a pnpisa card.
  70. Arguments:
  71. CardData - supplies a pointer to the pnp isa device data.
  72. Buffer - supplies a pointer to variable to receive a pointer to the Id.
  73. BufferLength - supplies a pointer to a variable to receive the size of the id buffer.
  74. Return Value:
  75. NTSTATUS code
  76. --*/
  77. {
  78. NTSTATUS status = STATUS_SUCCESS;
  79. UCHAR tag;
  80. LONG size, length;
  81. UNICODE_STRING unicodeString;
  82. ANSI_STRING ansiString;
  83. PCHAR ansiBuffer;
  84. *Buffer = NULL;
  85. *BufferLength = 0;
  86. if (CardData == NULL) {
  87. return status;
  88. }
  89. tag = *CardData;
  90. //
  91. // Make sure CardData does *NOT* point to a Logical Device Id tag
  92. //
  93. if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) {
  94. DbgPrint("PipGetCardIdentifier: CardData is at a Logical Id tag\n");
  95. return status;
  96. }
  97. //
  98. // Find the resource descriptor which describle identifier string
  99. //
  100. do {
  101. //
  102. // Do we find the identifer resource tag?
  103. //
  104. if (tag == TAG_ANSI_ID) {
  105. CardData++;
  106. length = *(USHORT UNALIGNED *)CardData;
  107. CardData += 2;
  108. ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1);
  109. if (ansiBuffer == NULL) {
  110. status = STATUS_INSUFFICIENT_RESOURCES;
  111. break;
  112. }
  113. RtlMoveMemory(ansiBuffer, CardData, length);
  114. ansiBuffer[length] = 0;
  115. RtlInitAnsiString(&ansiString, ansiBuffer);
  116. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  117. ExFreePool(ansiBuffer);
  118. if (!NT_SUCCESS(status)) {
  119. status = STATUS_INSUFFICIENT_RESOURCES;
  120. break;
  121. }
  122. *Buffer = unicodeString.Buffer;
  123. *BufferLength = unicodeString.Length + sizeof(WCHAR);
  124. break;
  125. }
  126. //
  127. // Determine the size of the BIOS resource descriptor and
  128. // advance to next resource descriptor.
  129. //
  130. if (!(tag & LARGE_RESOURCE_TAG)) {
  131. size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
  132. size += 1; // length of small tag
  133. } else {
  134. size = *(USHORT UNALIGNED *)(CardData + 1);
  135. size += 3; // length of large tag
  136. }
  137. CardData += size;
  138. tag = *CardData;
  139. } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
  140. return status;
  141. }
  142. NTSTATUS
  143. PipGetFunctionIdentifier (
  144. PUCHAR DeviceData,
  145. PWCHAR *Buffer,
  146. PULONG BufferLength
  147. )
  148. /*++
  149. Routine Description:
  150. This function returns the desired pnp isa identifier for the specified
  151. DeviceData/LogicalFunction. The Identifier for a logical function is
  152. optional. If no Identifier available , Buffer is set to NULL.
  153. Arguments:
  154. DeviceData - supplies a pointer to the pnp isa device data.
  155. Buffer - supplies a pointer to variable to receive a pointer to the Id.
  156. BufferLength - supplies a pointer to a variable to receive the size of the id buffer.
  157. Return Value:
  158. NTSTATUS code
  159. --*/
  160. {
  161. NTSTATUS status = STATUS_SUCCESS;
  162. UCHAR tag;
  163. LONG size, length;
  164. UNICODE_STRING unicodeString;
  165. ANSI_STRING ansiString;
  166. PCHAR ansiBuffer;
  167. *Buffer = NULL;
  168. *BufferLength = 0;
  169. if (DeviceData==NULL) {
  170. return status;
  171. }
  172. tag = *DeviceData;
  173. #if DBG
  174. //
  175. // Make sure device data points to Logical Device Id tag
  176. //
  177. if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
  178. DbgPrint("PipGetFunctionIdentifier: DeviceData is not at a Logical Id tag\n");
  179. }
  180. #endif
  181. //
  182. // Skip all the resource descriptors to find compatible Id descriptor
  183. //
  184. do {
  185. //
  186. // Determine the size of the BIOS resource descriptor and
  187. // advance to next resource descriptor.
  188. //
  189. if (!(tag & LARGE_RESOURCE_TAG)) {
  190. size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
  191. size += 1; // length of small tag
  192. } else {
  193. size = *(USHORT UNALIGNED *)(DeviceData + 1);
  194. size += 3; // length of large tag
  195. }
  196. DeviceData += size;
  197. tag = *DeviceData;
  198. //
  199. // Do we find the identifer resource tag?
  200. //
  201. if (tag == TAG_ANSI_ID) {
  202. DeviceData++;
  203. length = *(USHORT UNALIGNED *)DeviceData;
  204. DeviceData += 2;
  205. ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1);
  206. if (ansiBuffer == NULL) {
  207. status = STATUS_INSUFFICIENT_RESOURCES;
  208. break;
  209. }
  210. RtlMoveMemory(ansiBuffer, DeviceData, length);
  211. ansiBuffer[length] = 0;
  212. RtlInitAnsiString(&ansiString, ansiBuffer);
  213. status = RtlAnsiStringToUnicodeString(&unicodeString,
  214. &ansiString,
  215. TRUE);
  216. ExFreePool(ansiBuffer);
  217. if (!NT_SUCCESS(status)) {
  218. status = STATUS_INSUFFICIENT_RESOURCES;
  219. break;
  220. }
  221. *Buffer = unicodeString.Buffer;
  222. *BufferLength = unicodeString.Length + sizeof(WCHAR);
  223. break;
  224. }
  225. } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
  226. return status;
  227. }
  228. NTSTATUS
  229. PipGetCompatibleDeviceId (
  230. PUCHAR DeviceData,
  231. ULONG IdIndex,
  232. PWCHAR *Buffer
  233. )
  234. /*++
  235. Routine Description:
  236. This function returns the desired pnp isa id for the specified DeviceData
  237. and Id index. If Id index = 0, the Hardware ID will be return; if id
  238. index = n, the Nth compatible id will be returned.
  239. Arguments:
  240. DeviceData - supplies a pointer to the pnp isa device data.
  241. IdIndex - supplies the index of the compatible id desired.
  242. Buffer - supplies a pointer to variable to receive a pointer to the compatible Id.
  243. Return Value:
  244. NTSTATUS code
  245. --*/
  246. {
  247. NTSTATUS status = STATUS_NO_MORE_ENTRIES;
  248. UCHAR tag;
  249. ULONG count = 0,length;
  250. LONG size;
  251. UNICODE_STRING unicodeString;
  252. ANSI_STRING ansiString;
  253. UCHAR eisaId[8];
  254. ULONG id;
  255. //
  256. // Bail out BEFORE we touch the device data for the RDP
  257. //
  258. if (IdIndex == -1) {
  259. length = 2* sizeof(WCHAR);
  260. *Buffer = (PWCHAR) ExAllocatePool(PagedPool, length);
  261. if (*Buffer) {
  262. RtlZeroMemory (*Buffer,length);
  263. }else {
  264. return STATUS_INSUFFICIENT_RESOURCES;
  265. }
  266. return STATUS_SUCCESS;
  267. }
  268. tag = *DeviceData;
  269. #if DBG
  270. //
  271. // Make sure device data points to Logical Device Id tag
  272. //
  273. if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
  274. DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n");
  275. }
  276. #endif
  277. if (IdIndex == 0) {
  278. //
  279. // Caller is asking for hardware id
  280. //
  281. DeviceData++; // Skip tag
  282. id = *(ULONG UNALIGNED *)DeviceData;
  283. status = STATUS_SUCCESS;
  284. } else {
  285. //
  286. // caller is asking for compatible id
  287. //
  288. IdIndex--;
  289. //
  290. // Skip all the resource descriptors to find compatible Id descriptor
  291. //
  292. do {
  293. //
  294. // Determine the size of the BIOS resource descriptor and
  295. // advance to next resource descriptor.
  296. //
  297. if (!(tag & LARGE_RESOURCE_TAG)) {
  298. size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
  299. size += 1; // length of small tag
  300. } else {
  301. size = *(USHORT UNALIGNED *)(DeviceData + 1);
  302. size += 3; // length of large tag
  303. }
  304. DeviceData += size;
  305. tag = *DeviceData;
  306. //
  307. // Do we reach the compatible ID descriptor?
  308. //
  309. if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) {
  310. if (count == IdIndex) {
  311. id = *(ULONG UNALIGNED *)(DeviceData + 1);
  312. status = STATUS_SUCCESS;
  313. break;
  314. } else {
  315. count++;
  316. }
  317. }
  318. } while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
  319. }
  320. if (NT_SUCCESS(status)) {
  321. PipDecompressEisaId(id, eisaId);
  322. RtlInitAnsiString(&ansiString, eisaId);
  323. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  324. if (!NT_SUCCESS(status)) {
  325. return status;
  326. }
  327. *Buffer = (PWCHAR)ExAllocatePool (
  328. PagedPool,
  329. sizeof(L"*") + sizeof(WCHAR) + unicodeString.Length
  330. );
  331. if (*Buffer) {
  332. swprintf(*Buffer, L"*%s", unicodeString.Buffer);
  333. } else {
  334. status = STATUS_INSUFFICIENT_RESOURCES;
  335. }
  336. RtlFreeUnicodeString(&unicodeString);
  337. }
  338. return status;
  339. }
  340. NTSTATUS
  341. PipQueryDeviceUniqueId (
  342. PDEVICE_INFORMATION DeviceInfo,
  343. PWCHAR *DeviceId
  344. )
  345. /*++
  346. Routine Description:
  347. This function returns the unique id for the particular device.
  348. Arguments:
  349. DeviceData - Device data information for the specificied device.
  350. DeviceId - supplies a pointer to a variable to receive device id.
  351. Return Value:
  352. NTSTATUS code.
  353. --*/
  354. {
  355. NTSTATUS status = STATUS_SUCCESS;
  356. //
  357. // Set up device's unique id.
  358. // device unique id = SerialNumber of the card
  359. //
  360. *DeviceId = (PWCHAR)ExAllocatePool (
  361. PagedPool,
  362. (8 + 1) * sizeof(WCHAR) // serial number + null
  363. );
  364. if (*DeviceId) {
  365. if (DeviceInfo->Flags & DF_READ_DATA_PORT) {
  366. //
  367. // Override the unique ID for the RDP
  368. //
  369. swprintf (*DeviceId,
  370. L"0"
  371. );
  372. } else {
  373. swprintf (*DeviceId,
  374. L"%01X",
  375. ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber
  376. );
  377. }
  378. #if IDBG
  379. {
  380. ANSI_STRING ansiString;
  381. UNICODE_STRING unicodeString;
  382. RtlInitUnicodeString(&unicodeString, *DeviceId);
  383. RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
  384. DbgPrint("PnpIsa: return Unique Id = %s\n", ansiString.Buffer);
  385. RtlFreeAnsiString(&ansiString);
  386. }
  387. #endif
  388. } else {
  389. status = STATUS_INSUFFICIENT_RESOURCES;
  390. }
  391. return status;
  392. }
  393. NTSTATUS
  394. PipQueryDeviceId (
  395. PDEVICE_INFORMATION DeviceInfo,
  396. PWCHAR *DeviceId,
  397. ULONG IdIndex
  398. )
  399. /*++
  400. Routine Description:
  401. This function returns the device id for the particular device.
  402. Arguments:
  403. DeviceInfo - Device information for the specificied device.
  404. DeviceId - supplies a pointer to a variable to receive the device id.
  405. IdIndex - specifies device id or compatible id (0 - device id)
  406. Return Value:
  407. NTSTATUS code.
  408. --*/
  409. {
  410. NTSTATUS status = STATUS_SUCCESS;
  411. PWSTR format;
  412. ULONG size,length;
  413. UCHAR eisaId[8];
  414. UNICODE_STRING unicodeString;
  415. ANSI_STRING ansiString;
  416. //
  417. // Bail out BEFORE we touch the device data for the RDP
  418. //
  419. if (DeviceInfo->Flags & DF_READ_DATA_PORT) {
  420. length = (sizeof (wReadDataPort)+
  421. + sizeof(WCHAR) +sizeof (L"ISAPNP\\"));
  422. *DeviceId = (PWCHAR) ExAllocatePool(PagedPool, length);
  423. if (*DeviceId) {
  424. _snwprintf(*DeviceId, length, L"ISAPNP\\%s",wReadDataPort);
  425. } else {
  426. return STATUS_INSUFFICIENT_RESOURCES;
  427. }
  428. return STATUS_SUCCESS;
  429. }
  430. //
  431. // Set up device's id.
  432. // device id = VenderId + Logical device number
  433. //
  434. if (DeviceInfo->CardInformation->NumberLogicalDevices == 1) {
  435. format = L"ISAPNP\\%s";
  436. size = sizeof(L"ISAPNP\\*") + sizeof(WCHAR);
  437. } else {
  438. format = L"ISAPNP\\%s_DEV%04X";
  439. size = sizeof(L"ISAPNP\\_DEV") + 4 * sizeof(WCHAR) + sizeof(WCHAR);
  440. }
  441. PipDecompressEisaId(
  442. ((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->VenderId,
  443. eisaId
  444. );
  445. RtlInitAnsiString(&ansiString, eisaId);
  446. status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
  447. if (!NT_SUCCESS(status)) {
  448. return STATUS_INSUFFICIENT_RESOURCES;
  449. }
  450. size += unicodeString.Length;
  451. *DeviceId = (PWCHAR)ExAllocatePool (PagedPool, size);
  452. if (*DeviceId) {
  453. swprintf (*DeviceId,
  454. format,
  455. unicodeString.Buffer,
  456. DeviceInfo->LogicalDeviceNumber
  457. );
  458. #if IDBG
  459. {
  460. ANSI_STRING dbgAnsiString;
  461. UNICODE_STRING dbgUnicodeString;
  462. RtlInitUnicodeString(&dbgUnicodeString, *DeviceId);
  463. RtlUnicodeStringToAnsiString(&dbgAnsiString, &dbgUnicodeString, TRUE);
  464. DbgPrint("PnpIsa: return device Id = %s\n", dbgAnsiString.Buffer);
  465. RtlFreeAnsiString(&dbgAnsiString);
  466. }
  467. #endif
  468. } else {
  469. status = STATUS_INSUFFICIENT_RESOURCES;
  470. }
  471. RtlFreeUnicodeString(&unicodeString);
  472. return status;
  473. }
  474. NTSTATUS
  475. PipQueryDeviceResources (
  476. PDEVICE_INFORMATION DeviceInfo,
  477. ULONG BusNumber,
  478. PCM_RESOURCE_LIST *CmResources,
  479. ULONG *Size
  480. )
  481. /*++
  482. Routine Description:
  483. This function returns the bus resources being used by the specified device
  484. Arguments:
  485. DeviceInfo - Device information for the specificied slot
  486. BusNumber - should always be 0
  487. CmResources - supplies a pointer to a variable to receive the device resource
  488. data.
  489. Size - Supplies a pointer to avariable to receive the size of device resource
  490. data.
  491. Return Value:
  492. NTSTATUS code.
  493. --*/
  494. {
  495. ULONG length;
  496. NTSTATUS status = STATUS_SUCCESS;
  497. PCM_RESOURCE_LIST cmResources;
  498. *CmResources = NULL;
  499. *Size = 0;
  500. if (DeviceInfo->BootResources){ // && DeviceInfo->LogConfHandle) {
  501. *CmResources = ExAllocatePool(PagedPool, DeviceInfo->BootResourcesLength);
  502. if (*CmResources) {
  503. RtlMoveMemory(*CmResources, DeviceInfo->BootResources, DeviceInfo->BootResourcesLength);
  504. *Size = DeviceInfo->BootResourcesLength;
  505. } else {
  506. status = STATUS_INSUFFICIENT_RESOURCES;
  507. }
  508. }
  509. return status;
  510. }
  511. NTSTATUS
  512. PipQueryDeviceResourceRequirements (
  513. PDEVICE_INFORMATION DeviceInfo,
  514. ULONG BusNumber,
  515. ULONG Slot,
  516. PCM_RESOURCE_LIST BootResources,
  517. USHORT IrqFlags,
  518. PIO_RESOURCE_REQUIREMENTS_LIST *IoResources,
  519. ULONG *Size
  520. )
  521. /*++
  522. Routine Description:
  523. This function returns the possible bus resources that this device may be
  524. satisfied with.
  525. Arguments:
  526. DeviceData - Device data information for the specificied slot
  527. BusNumber - Supplies the bus number
  528. Slot - supplies the slot number of the BusNumber
  529. IoResources - supplies a pointer to a variable to receive the IO resource
  530. requirements list
  531. Return Value:
  532. The device control is completed
  533. --*/
  534. {
  535. ULONG length = 0;
  536. NTSTATUS status;
  537. PUCHAR deviceData;
  538. PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
  539. deviceData = DeviceInfo->DeviceData;
  540. status = PpBiosResourcesToNtResources (
  541. BusNumber,
  542. Slot,
  543. &deviceData,
  544. 0,
  545. &ioResources,
  546. &length
  547. );
  548. //
  549. // Return results
  550. //
  551. if (NT_SUCCESS(status)) {
  552. if (length == 0) {
  553. ioResources = NULL; // Just to make sure
  554. } else {
  555. // * Set the irq level/edge requirements to be consistent
  556. // with the our determination earlier as to what is
  557. // likely to work for this card
  558. //
  559. // * Make requirements reflect boot configed ROM if any.
  560. //
  561. // Make these changes across all alternatives.
  562. PipTrimResourceRequirements(&ioResources,
  563. IrqFlags,
  564. BootResources);
  565. //PipFilterResourceRequirementsList(&ioResources);
  566. PipMergeBootResourcesToRequirementsList(DeviceInfo,
  567. BootResources,
  568. &ioResources
  569. );
  570. ASSERT(ioResources);
  571. length = ioResources->ListSize;
  572. }
  573. *IoResources = ioResources;
  574. *Size = length;
  575. #if IDBG
  576. PipDumpIoResourceList(ioResources);
  577. #endif
  578. }
  579. return status;
  580. }
  581. NTSTATUS
  582. PipSetDeviceResources (
  583. PDEVICE_INFORMATION DeviceInfo,
  584. PCM_RESOURCE_LIST CmResources
  585. )
  586. /*++
  587. Routine Description:
  588. This function configures the device to the specified device setttings
  589. Arguments:
  590. DeviceInfo - Device information for the specificied slot
  591. CmResources - pointer to the desired resource list
  592. Return Value:
  593. NTSTATUS code.
  594. --*/
  595. {
  596. NTSTATUS status = STATUS_SUCCESS;
  597. if (CmResources && (CmResources->Count != 0)) {
  598. //
  599. // Set resource settings for the device
  600. //
  601. status = PipWriteDeviceResources (
  602. DeviceInfo->DeviceData,
  603. (PCM_RESOURCE_LIST) CmResources
  604. );
  605. //
  606. // Put all cards into wait for key state.
  607. //
  608. DebugPrint((DEBUG_STATE,
  609. "SetDeviceResources CSN %d/LDN %d\n",
  610. DeviceInfo->CardInformation->CardSelectNumber,
  611. DeviceInfo->LogicalDeviceNumber));
  612. //
  613. // Delay some time for the newly set resources to be avaiable.
  614. // This is required on some slow machines.
  615. //
  616. KeStallExecutionProcessor(10000); // delay 10 ms
  617. }
  618. return status;
  619. }
  620. #if 0
  621. NTSTATUS
  622. PipFilterResourceRequirementsList(
  623. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
  624. )
  625. /*++
  626. Routine Description:
  627. This routine removes the length zero entries from the input Io resource
  628. requirements list.
  629. Parameters:
  630. IoResources - supplies a pointer to an address to Io resource requirements List.
  631. Return Value:
  632. NTSTATUS code.
  633. --*/
  634. {
  635. NTSTATUS status;
  636. PIO_RESOURCE_REQUIREMENTS_LIST oldIoResources = *IoResources, newIoResources;
  637. PIO_RESOURCE_LIST oldIoResourceList = oldIoResources->List;
  638. PIO_RESOURCE_LIST newIoResourceList;
  639. PIO_RESOURCE_DESCRIPTOR oldIoResourceDescriptor, newIoResourceDescriptor;
  640. PIO_RESOURCE_DESCRIPTOR oldIoResourceDescriptorEnd;
  641. #if DBG
  642. PIO_RESOURCE_DESCRIPTOR newIoResourceDescriptorEnd;
  643. #endif
  644. LONG IoResourceListCount = (LONG) oldIoResources->AlternativeLists;
  645. ULONG size;
  646. PAGED_CODE();
  647. //
  648. // Make sure there is some resource requirements to be fulfilled.
  649. //
  650. if (IoResourceListCount == 0) {
  651. return STATUS_SUCCESS;
  652. }
  653. size = oldIoResources->ListSize;
  654. //
  655. // Check if there is any length zero descriptor
  656. //
  657. while (--IoResourceListCount >= 0) {
  658. oldIoResourceDescriptor = oldIoResourceList->Descriptors;
  659. oldIoResourceDescriptorEnd = oldIoResourceDescriptor + oldIoResourceList->Count;
  660. while (oldIoResourceDescriptor < oldIoResourceDescriptorEnd) {
  661. switch (oldIoResourceDescriptor->Type) {
  662. case CmResourceTypePort:
  663. case CmResourceTypeMemory:
  664. if (oldIoResourceDescriptor->u.Generic.Length == 0) {
  665. size -= sizeof(IO_RESOURCE_DESCRIPTOR);
  666. }
  667. break;
  668. default:
  669. break;
  670. }
  671. oldIoResourceDescriptor++;
  672. }
  673. ASSERT(oldIoResourceDescriptor == oldIoResourceDescriptorEnd);
  674. oldIoResourceList = (PIO_RESOURCE_LIST) oldIoResourceDescriptorEnd;
  675. }
  676. if (size == oldIoResources->ListSize) {
  677. return STATUS_SUCCESS;
  678. }
  679. //
  680. // We have length zero descriptor. Rebuild the resources requirements list
  681. //
  682. newIoResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool (
  683. PagedPool, size);
  684. if (newIoResources == NULL) {
  685. return STATUS_NO_MEMORY;
  686. } else {
  687. RtlMoveMemory(newIoResources,
  688. oldIoResources,
  689. FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List)
  690. );
  691. newIoResources->ListSize = size;
  692. newIoResourceList = newIoResources->List;
  693. #if DBG
  694. newIoResourceDescriptorEnd = (PIO_RESOURCE_DESCRIPTOR)
  695. ((PUCHAR)newIoResourceList + size);
  696. #endif
  697. }
  698. //
  699. // filter the IO ResReq list
  700. //
  701. oldIoResourceList = oldIoResources->List;
  702. IoResourceListCount = (LONG) oldIoResources->AlternativeLists;
  703. while (--IoResourceListCount >= 0) {
  704. newIoResourceList->Version = oldIoResourceList->Version;
  705. newIoResourceList->Revision = oldIoResourceList->Revision;
  706. newIoResourceList->Count = oldIoResourceList->Count;
  707. oldIoResourceDescriptor = oldIoResourceList->Descriptors;
  708. newIoResourceDescriptor = newIoResourceList->Descriptors;
  709. oldIoResourceDescriptorEnd = oldIoResourceDescriptor + oldIoResourceList->Count;
  710. while (oldIoResourceDescriptor < oldIoResourceDescriptorEnd) {
  711. switch (oldIoResourceDescriptor->Type) {
  712. case CmResourceTypePort:
  713. case CmResourceTypeMemory:
  714. if (oldIoResourceDescriptor->u.Generic.Length == 0) {
  715. newIoResourceList->Count--;
  716. break;
  717. }
  718. default:
  719. *newIoResourceDescriptor = *oldIoResourceDescriptor;
  720. newIoResourceDescriptor++;
  721. break;
  722. }
  723. oldIoResourceDescriptor++;
  724. }
  725. ASSERT(oldIoResourceDescriptor == oldIoResourceDescriptorEnd);
  726. oldIoResourceList = (PIO_RESOURCE_LIST) oldIoResourceDescriptor;
  727. newIoResourceList = (PIO_RESOURCE_LIST) newIoResourceDescriptor;
  728. }
  729. ASSERT(newIoResourceDescriptor <= newIoResourceDescriptorEnd);
  730. ExFreePool(oldIoResources);
  731. *IoResources = newIoResources;
  732. return STATUS_SUCCESS;
  733. }
  734. #endif
  735. PIO_RESOURCE_REQUIREMENTS_LIST
  736. PipCmResourcesToIoResources (
  737. IN PCM_RESOURCE_LIST CmResourceList
  738. )
  739. /*++
  740. Routine Description:
  741. This routines converts the input CmResourceList to IO_RESOURCE_REQUIREMENTS_LIST.
  742. Arguments:
  743. CmResourceList - the cm resource list to convert.
  744. Return Value:
  745. returns a IO_RESOURCE_REQUIREMENTS_LISTST if succeeds. Otherwise a NULL value is
  746. returned.
  747. --*/
  748. {
  749. PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList;
  750. ULONG count = 0, size, i, j;
  751. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  752. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
  753. PIO_RESOURCE_DESCRIPTOR ioDesc;
  754. //
  755. // First determine number of descriptors required.
  756. //
  757. cmFullDesc = &CmResourceList->List[0];
  758. for (i = 0; i < CmResourceList->Count; i++) {
  759. count += cmFullDesc->PartialResourceList.Count;
  760. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  761. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  762. size = 0;
  763. switch (cmPartDesc->Type) {
  764. case CmResourceTypeDeviceSpecific:
  765. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  766. count--;
  767. break;
  768. }
  769. cmPartDesc++;
  770. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  771. }
  772. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  773. }
  774. if (count == 0) {
  775. return NULL;
  776. }
  777. //
  778. // Count the extra descriptors for InterfaceType and BusNumber information.
  779. //
  780. count += CmResourceList->Count - 1;
  781. //
  782. // Allocate heap space for IO RESOURCE REQUIREMENTS LIST
  783. //
  784. count++; // add one for CmResourceTypeConfigData
  785. ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool(
  786. PagedPool,
  787. sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  788. count * sizeof(IO_RESOURCE_DESCRIPTOR)
  789. );
  790. if (!ioResReqList) {
  791. return NULL;
  792. }
  793. //
  794. // Parse the cm resource descriptor and build its corresponding IO resource descriptor
  795. //
  796. ioResReqList->InterfaceType = CmResourceList->List[0].InterfaceType;
  797. ioResReqList->BusNumber = CmResourceList->List[0].BusNumber;
  798. ioResReqList->SlotNumber = 0;
  799. ioResReqList->Reserved[0] = 0;
  800. ioResReqList->Reserved[1] = 0;
  801. ioResReqList->Reserved[2] = 0;
  802. ioResReqList->AlternativeLists = 1;
  803. ioResReqList->List[0].Version = 1;
  804. ioResReqList->List[0].Revision = 1;
  805. ioResReqList->List[0].Count = count;
  806. //
  807. // Generate a CmResourceTypeConfigData descriptor
  808. //
  809. ioDesc = &ioResReqList->List[0].Descriptors[0];
  810. ioDesc->Option = IO_RESOURCE_PREFERRED;
  811. ioDesc->Type = CmResourceTypeConfigData;
  812. ioDesc->ShareDisposition = CmResourceShareShared;
  813. ioDesc->Flags = 0;
  814. ioDesc->Spare1 = 0;
  815. ioDesc->Spare2 = 0;
  816. ioDesc->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY;
  817. ioDesc++;
  818. cmFullDesc = &CmResourceList->List[0];
  819. for (i = 0; i < CmResourceList->Count; i++) {
  820. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  821. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  822. ioDesc->Option = IO_RESOURCE_PREFERRED;
  823. ioDesc->Type = cmPartDesc->Type;
  824. ioDesc->ShareDisposition = cmPartDesc->ShareDisposition;
  825. ioDesc->Flags = cmPartDesc->Flags;
  826. ioDesc->Spare1 = 0;
  827. ioDesc->Spare2 = 0;
  828. size = 0;
  829. switch (cmPartDesc->Type) {
  830. case CmResourceTypePort:
  831. ioDesc->u.Port.MinimumAddress = cmPartDesc->u.Port.Start;
  832. ioDesc->u.Port.MaximumAddress.QuadPart = cmPartDesc->u.Port.Start.QuadPart +
  833. cmPartDesc->u.Port.Length - 1;
  834. ioDesc->u.Port.Alignment = 1;
  835. ioDesc->u.Port.Length = cmPartDesc->u.Port.Length;
  836. ioDesc++;
  837. break;
  838. case CmResourceTypeInterrupt:
  839. #if defined(_X86_)
  840. ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector =
  841. cmPartDesc->u.Interrupt.Level;
  842. #else
  843. ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector =
  844. cmPartDesc->u.Interrupt.Vector;
  845. #endif
  846. ioDesc++;
  847. break;
  848. case CmResourceTypeMemory:
  849. ioDesc->u.Memory.MinimumAddress = cmPartDesc->u.Memory.Start;
  850. ioDesc->u.Memory.MaximumAddress.QuadPart = cmPartDesc->u.Memory.Start.QuadPart +
  851. cmPartDesc->u.Memory.Length - 1;
  852. ioDesc->u.Memory.Alignment = 1;
  853. ioDesc->u.Memory.Length = cmPartDesc->u.Memory.Length;
  854. ioDesc++;
  855. break;
  856. case CmResourceTypeDma:
  857. ioDesc->u.Dma.MinimumChannel = cmPartDesc->u.Dma.Channel;
  858. ioDesc->u.Dma.MaximumChannel = cmPartDesc->u.Dma.Channel;
  859. ioDesc++;
  860. break;
  861. case CmResourceTypeDeviceSpecific:
  862. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  863. break;
  864. case CmResourceTypeBusNumber:
  865. ioDesc->u.BusNumber.MinBusNumber = cmPartDesc->u.BusNumber.Start;
  866. ioDesc->u.BusNumber.MaxBusNumber = cmPartDesc->u.BusNumber.Start +
  867. cmPartDesc->u.BusNumber.Length - 1;
  868. ioDesc->u.BusNumber.Length = cmPartDesc->u.BusNumber.Length;
  869. ioDesc++;
  870. break;
  871. default:
  872. ioDesc->u.DevicePrivate.Data[0] = cmPartDesc->u.DevicePrivate.Data[0];
  873. ioDesc->u.DevicePrivate.Data[1] = cmPartDesc->u.DevicePrivate.Data[1];
  874. ioDesc->u.DevicePrivate.Data[2] = cmPartDesc->u.DevicePrivate.Data[2];
  875. ioDesc++;
  876. break;
  877. }
  878. cmPartDesc++;
  879. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  880. }
  881. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  882. }
  883. ioResReqList->ListSize = (ULONG)((ULONG_PTR)ioDesc - (ULONG_PTR)ioResReqList);
  884. return ioResReqList;
  885. }
  886. NTSTATUS
  887. PipMergeResourceRequirementsLists (
  888. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList1,
  889. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList2,
  890. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *MergedList
  891. )
  892. /*++
  893. Routine Description:
  894. This routines merges two IoLists into one.
  895. Arguments:
  896. IoList1 - supplies the pointer to the first IoResourceRequirementsList
  897. IoList2 - supplies the pointer to the second IoResourceRequirementsList
  898. MergedList - Supplies a variable to receive the merged resource
  899. requirements list.
  900. Return Value:
  901. A NTSTATUS code to indicate the result of the function.
  902. --*/
  903. {
  904. NTSTATUS status = STATUS_SUCCESS;
  905. PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList;
  906. ULONG size;
  907. PUCHAR p;
  908. PAGED_CODE();
  909. *MergedList = NULL;
  910. //
  911. // First handle the easy cases that both IO Lists are empty or any one of
  912. // them is empty.
  913. //
  914. if ((IoList1 == NULL || IoList1->AlternativeLists == 0) &&
  915. (IoList2 == NULL || IoList2->AlternativeLists == 0)) {
  916. return status;
  917. }
  918. ioList = NULL;
  919. if (IoList1 == NULL || IoList1->AlternativeLists == 0) {
  920. ioList = IoList2;
  921. } else if (IoList2 == NULL || IoList2->AlternativeLists == 0) {
  922. ioList = IoList1;
  923. }
  924. if (ioList) {
  925. newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, ioList->ListSize);
  926. if (newList == NULL) {
  927. return STATUS_INSUFFICIENT_RESOURCES;
  928. }
  929. RtlMoveMemory(newList, ioList, ioList->ListSize);
  930. *MergedList = newList;
  931. return status;
  932. }
  933. //
  934. // Do real work...
  935. //
  936. size = IoList1->ListSize + IoList2->ListSize - FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List);
  937. newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(
  938. PagedPool,
  939. size
  940. );
  941. if (newList == NULL) {
  942. return STATUS_INSUFFICIENT_RESOURCES;
  943. }
  944. p = (PUCHAR)newList;
  945. RtlMoveMemory(p, IoList1, IoList1->ListSize);
  946. p += IoList1->ListSize;
  947. RtlMoveMemory(p,
  948. &IoList2->List[0],
  949. size - IoList1->ListSize
  950. );
  951. newList->ListSize = size;
  952. newList->AlternativeLists += IoList2->AlternativeLists;
  953. *MergedList = newList;
  954. return status;
  955. }
  956. VOID
  957. PipMergeBootResourcesToRequirementsList(
  958. PDEVICE_INFORMATION DeviceInfo,
  959. PCM_RESOURCE_LIST BootResources,
  960. PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
  961. )
  962. /*++
  963. Routine Description:
  964. This routines merges two IoLists into one.
  965. Arguments:
  966. IoList1 - supplies the pointer to the first IoResourceRequirementsList
  967. IoList2 - supplies the pointer to the second IoResourceRequirementsList
  968. MergedList - Supplies a variable to receive the merged resource
  969. requirements list.
  970. Return Value:
  971. A NTSTATUS code to indicate the result of the function.
  972. --*/
  973. {
  974. NTSTATUS status = STATUS_SUCCESS;
  975. PIO_RESOURCE_REQUIREMENTS_LIST ioResources = *IoResources, bootResReq = NULL, newList = NULL;
  976. BOOLEAN exactMatch;
  977. PAGED_CODE();
  978. if (DeviceInfo->BootResources) {
  979. PipBuildBootResourceRequirementsList (ioResources, BootResources, &bootResReq, &exactMatch);
  980. if (bootResReq) {
  981. if (exactMatch && ioResources->AlternativeLists == 1) {
  982. ExFreePool(ioResources);
  983. *IoResources = bootResReq;
  984. } else {
  985. PipMergeResourceRequirementsLists (bootResReq, ioResources, &newList);
  986. if (newList) {
  987. ExFreePool(ioResources);
  988. *IoResources = newList;
  989. }
  990. ExFreePool(bootResReq);
  991. }
  992. }
  993. }
  994. }
  995. NTSTATUS
  996. PipBuildBootResourceRequirementsList (
  997. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList,
  998. IN PCM_RESOURCE_LIST CmList,
  999. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *FilteredList,
  1000. OUT PBOOLEAN ExactMatch
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. This routines adjusts the input IoList based on input BootConfig.
  1005. Arguments:
  1006. IoList - supplies the pointer to an IoResourceRequirementsList
  1007. CmList - supplies the pointer to a BootConfig.
  1008. FilteredList - Supplies a variable to receive the filtered resource
  1009. requirements list.
  1010. Return Value:
  1011. A NTSTATUS code to indicate the result of the function.
  1012. --*/
  1013. {
  1014. NTSTATUS status;
  1015. PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList;
  1016. PIO_RESOURCE_LIST ioResourceList, newIoResourceList;
  1017. PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor, ioResourceDescriptorEnd;
  1018. PIO_RESOURCE_DESCRIPTOR newIoResourceDescriptor, configDataDescriptor;
  1019. LONG ioResourceDescriptorCount = 0;
  1020. USHORT version;
  1021. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  1022. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor;
  1023. ULONG cmDescriptorCount = 0;
  1024. ULONG size, i, j, oldCount, phase;
  1025. LONG k, alternativeLists;
  1026. BOOLEAN exactMatch;
  1027. PAGED_CODE();
  1028. *FilteredList = NULL;
  1029. *ExactMatch = FALSE;
  1030. //
  1031. // Make sure there is some resource requirements to be filtered.
  1032. // If no, we will convert CmList/BootConfig to an IoResourceRequirementsList
  1033. //
  1034. if (IoList == NULL || IoList->AlternativeLists == 0) {
  1035. if (CmList && CmList->Count != 0) {
  1036. *FilteredList = PipCmResourcesToIoResources (CmList);
  1037. }
  1038. return STATUS_SUCCESS;
  1039. }
  1040. //
  1041. // Make a copy of the Io Resource Requirements List
  1042. //
  1043. ioList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, IoList->ListSize);
  1044. if (ioList == NULL) {
  1045. return STATUS_INSUFFICIENT_RESOURCES;
  1046. }
  1047. RtlMoveMemory(ioList, IoList, IoList->ListSize);
  1048. //
  1049. // If there is no BootConfig, simply return the copy of the input Io list.
  1050. //
  1051. if (CmList == NULL || CmList->Count == 0) {
  1052. *FilteredList = ioList;
  1053. return STATUS_SUCCESS;
  1054. }
  1055. //
  1056. // First determine minimum number of descriptors required.
  1057. //
  1058. cmFullDesc = &CmList->List[0];
  1059. for (i = 0; i < CmList->Count; i++) {
  1060. cmDescriptorCount += cmFullDesc->PartialResourceList.Count;
  1061. cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  1062. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  1063. size = 0;
  1064. switch (cmDescriptor->Type) {
  1065. case CmResourceTypeConfigData:
  1066. case CmResourceTypeDevicePrivate:
  1067. cmDescriptorCount--;
  1068. break;
  1069. case CmResourceTypeDeviceSpecific:
  1070. size = cmDescriptor->u.DeviceSpecificData.DataSize;
  1071. cmDescriptorCount--;
  1072. break;
  1073. default:
  1074. //
  1075. // Invalid cmresource list. Ignore it and use io resources
  1076. //
  1077. if (cmDescriptor->Type == CmResourceTypeNull ||
  1078. cmDescriptor->Type >= CmResourceTypeMaximum) {
  1079. cmDescriptorCount--;
  1080. }
  1081. }
  1082. cmDescriptor++;
  1083. cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size);
  1084. }
  1085. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor;
  1086. }
  1087. if (cmDescriptorCount == 0) {
  1088. *FilteredList = ioList;
  1089. return STATUS_SUCCESS;
  1090. }
  1091. //
  1092. // cmDescriptorCount is the number of BootConfig Descriptors needs.
  1093. //
  1094. // For each IO list Alternative ...
  1095. //
  1096. ioResourceList = ioList->List;
  1097. k = ioList->AlternativeLists;
  1098. while (--k >= 0) {
  1099. ioResourceDescriptor = ioResourceList->Descriptors;
  1100. ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
  1101. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1102. ioResourceDescriptor->Spare1 = 0;
  1103. ioResourceDescriptor++;
  1104. }
  1105. ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd;
  1106. }
  1107. ioResourceList = ioList->List;
  1108. k = alternativeLists = ioList->AlternativeLists;
  1109. while (--k >= 0) {
  1110. version = ioResourceList->Version;
  1111. if (version == 0xffff) { // Convert bogus version to valid number
  1112. version = 1;
  1113. }
  1114. //
  1115. // We use Version field to store number of BootConfig found.
  1116. // Count field to store new number of descriptor in the alternative list.
  1117. //
  1118. ioResourceList->Version = 0;
  1119. oldCount = ioResourceList->Count;
  1120. ioResourceDescriptor = ioResourceList->Descriptors;
  1121. ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
  1122. if (ioResourceDescriptor == ioResourceDescriptorEnd) {
  1123. //
  1124. // An alternative list with zero descriptor count
  1125. //
  1126. ioResourceList->Version = 0xffff; // Mark it as invalid
  1127. ioList->AlternativeLists--;
  1128. continue;
  1129. }
  1130. exactMatch = TRUE;
  1131. //
  1132. // For each Cm Resource descriptor ... except DevicePrivate and
  1133. // DeviceSpecific...
  1134. //
  1135. cmFullDesc = &CmList->List[0];
  1136. for (i = 0; i < CmList->Count; i++) {
  1137. cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  1138. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  1139. size = 0;
  1140. switch (cmDescriptor->Type) {
  1141. case CmResourceTypeDevicePrivate:
  1142. break;
  1143. case CmResourceTypeDeviceSpecific:
  1144. size = cmDescriptor->u.DeviceSpecificData.DataSize;
  1145. break;
  1146. default:
  1147. if (cmDescriptor->Type == CmResourceTypeNull ||
  1148. cmDescriptor->Type >= CmResourceTypeMaximum) {
  1149. break;
  1150. }
  1151. //
  1152. // Check CmDescriptor against current Io Alternative list
  1153. //
  1154. for (phase = 0; phase < 2; phase++) {
  1155. ioResourceDescriptor = ioResourceList->Descriptors;
  1156. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1157. if ((ioResourceDescriptor->Type == cmDescriptor->Type) &&
  1158. (ioResourceDescriptor->Spare1 == 0)) {
  1159. ULONGLONG min1, max1, min2, max2;
  1160. ULONG len1 = 1, len2 = 1, align1, align2;
  1161. UCHAR share1, share2;
  1162. share2 = ioResourceDescriptor->ShareDisposition;
  1163. share1 = cmDescriptor->ShareDisposition;
  1164. if ((share1 == CmResourceShareUndetermined) ||
  1165. (share1 > CmResourceShareShared)) {
  1166. share1 = share2;
  1167. }
  1168. if ((share2 == CmResourceShareUndetermined) ||
  1169. (share2 > CmResourceShareShared)) {
  1170. share2 = share1;
  1171. }
  1172. align1 = align2 = 1;
  1173. switch (cmDescriptor->Type) {
  1174. case CmResourceTypePort:
  1175. case CmResourceTypeMemory:
  1176. min1 = cmDescriptor->u.Port.Start.QuadPart;
  1177. max1 = cmDescriptor->u.Port.Start.QuadPart + cmDescriptor->u.Port.Length - 1;
  1178. len1 = cmDescriptor->u.Port.Length;
  1179. min2 = ioResourceDescriptor->u.Port.MinimumAddress.QuadPart;
  1180. max2 = ioResourceDescriptor->u.Port.MaximumAddress.QuadPart;
  1181. len2 = ioResourceDescriptor->u.Port.Length;
  1182. align2 = ioResourceDescriptor->u.Port.Alignment;
  1183. break;
  1184. case CmResourceTypeInterrupt:
  1185. max1 = min1 = cmDescriptor->u.Interrupt.Vector;
  1186. min2 = ioResourceDescriptor->u.Interrupt.MinimumVector;
  1187. max2 = ioResourceDescriptor->u.Interrupt.MaximumVector;
  1188. break;
  1189. case CmResourceTypeDma:
  1190. min1 = max1 =cmDescriptor->u.Dma.Channel;
  1191. min2 = ioResourceDescriptor->u.Dma.MinimumChannel;
  1192. max2 = ioResourceDescriptor->u.Dma.MaximumChannel;
  1193. break;
  1194. case CmResourceTypeBusNumber:
  1195. min1 = cmDescriptor->u.BusNumber.Start;
  1196. max1 = cmDescriptor->u.BusNumber.Start + cmDescriptor->u.BusNumber.Length - 1;
  1197. len1 = cmDescriptor->u.BusNumber.Length;
  1198. min2 = ioResourceDescriptor->u.BusNumber.MinBusNumber;
  1199. max2 = ioResourceDescriptor->u.BusNumber.MaxBusNumber;
  1200. len2 = ioResourceDescriptor->u.BusNumber.Length;
  1201. break;
  1202. default:
  1203. ASSERT(0);
  1204. break;
  1205. }
  1206. if (phase == 0) {
  1207. if (share1 == share2 && min2 == min1 && max2 >= max1 && len2 >= len1) {
  1208. //
  1209. // For phase 0 match, we want near exact match...
  1210. //
  1211. if (max2 != max1) {
  1212. exactMatch = FALSE;
  1213. }
  1214. ioResourceList->Version++;
  1215. ioResourceDescriptor->Spare1 = 0x80;
  1216. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  1217. PIO_RESOURCE_DESCRIPTOR ioDesc;
  1218. ioDesc = ioResourceDescriptor;
  1219. ioDesc--;
  1220. while (ioDesc >= ioResourceList->Descriptors) {
  1221. ioDesc->Type = CmResourceTypeNull;
  1222. ioResourceList->Count--;
  1223. if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) {
  1224. ioDesc--;
  1225. } else {
  1226. break;
  1227. }
  1228. }
  1229. }
  1230. ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
  1231. if (ioResourceDescriptor->Type == CmResourceTypePort ||
  1232. ioResourceDescriptor->Type == CmResourceTypeMemory) {
  1233. ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1;
  1234. ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1;
  1235. ioResourceDescriptor->u.Port.Alignment = 1;
  1236. } else if (ioResourceDescriptor->Type == CmResourceTypeBusNumber) {
  1237. ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1;
  1238. ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1);
  1239. }
  1240. ioResourceDescriptor++;
  1241. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1242. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  1243. ioResourceDescriptor->Type = CmResourceTypeNull;
  1244. ioResourceDescriptor++;
  1245. ioResourceList->Count--;
  1246. } else {
  1247. break;
  1248. }
  1249. }
  1250. phase = 1; // skip phase 1
  1251. break;
  1252. } else {
  1253. ioResourceDescriptor++;
  1254. }
  1255. } else {
  1256. exactMatch = FALSE;
  1257. if (share1 == share2 && min2 <= min1 && max2 >= max1 && len2 >= len1 &&
  1258. (min1 & (align2 - 1)) == 0) {
  1259. //
  1260. // Io range covers Cm range ... Change the Io range to what is specified
  1261. // in BootConfig.
  1262. //
  1263. //
  1264. switch (cmDescriptor->Type) {
  1265. case CmResourceTypePort:
  1266. case CmResourceTypeMemory:
  1267. ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1;
  1268. ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1;
  1269. break;
  1270. case CmResourceTypeInterrupt:
  1271. case CmResourceTypeDma:
  1272. ioResourceDescriptor->u.Interrupt.MinimumVector = (ULONG)min1;
  1273. ioResourceDescriptor->u.Interrupt.MaximumVector = (ULONG)max1;
  1274. break;
  1275. case CmResourceTypeBusNumber:
  1276. ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1;
  1277. ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1);
  1278. break;
  1279. }
  1280. ioResourceList->Version++;
  1281. ioResourceDescriptor->Spare1 = 0x80;
  1282. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  1283. PIO_RESOURCE_DESCRIPTOR ioDesc;
  1284. ioDesc = ioResourceDescriptor;
  1285. ioDesc--;
  1286. while (ioDesc >= ioResourceList->Descriptors) {
  1287. ioDesc->Type = CmResourceTypeNull;
  1288. ioResourceList->Count--;
  1289. if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) {
  1290. ioDesc--;
  1291. } else {
  1292. break;
  1293. }
  1294. }
  1295. }
  1296. ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
  1297. ioResourceDescriptor++;
  1298. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1299. if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
  1300. ioResourceDescriptor->Type = CmResourceTypeNull;
  1301. ioResourceList->Count--;
  1302. ioResourceDescriptor++;
  1303. } else {
  1304. break;
  1305. }
  1306. }
  1307. break;
  1308. } else {
  1309. ioResourceDescriptor++;
  1310. }
  1311. }
  1312. } else {
  1313. ioResourceDescriptor++;
  1314. }
  1315. } // Don't add any instruction after this ...
  1316. } // phase
  1317. } // switch
  1318. //
  1319. // Move to next Cm Descriptor
  1320. //
  1321. cmDescriptor++;
  1322. cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size);
  1323. }
  1324. //
  1325. // Move to next Cm List
  1326. //
  1327. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor;
  1328. }
  1329. if (ioResourceList->Version != (USHORT)cmDescriptorCount) {
  1330. //
  1331. // If the current alternative list does not cover all the boot config
  1332. // descriptors, make it as invalid.
  1333. //
  1334. ioResourceList->Version = 0xffff;
  1335. ioList->AlternativeLists--;
  1336. } else {
  1337. ioResourceDescriptorCount += ioResourceList->Count;
  1338. ioResourceList->Version = version;
  1339. ioResourceList->Count = oldCount; // ++ single alternative list
  1340. break; // ++ single alternative list
  1341. }
  1342. ioResourceList->Count = oldCount;
  1343. //
  1344. // Move to next Io alternative list.
  1345. //
  1346. ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd;
  1347. }
  1348. //
  1349. // If there is not any valid alternative, convert CmList to Io list.
  1350. //
  1351. if (ioList->AlternativeLists == 0) {
  1352. *FilteredList = PipCmResourcesToIoResources (CmList);
  1353. ExFreePool(ioList);
  1354. return STATUS_SUCCESS;
  1355. }
  1356. //
  1357. // we have finished filtering the resource requirements list. Now allocate memory
  1358. // and rebuild a new list.
  1359. //
  1360. size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  1361. //sizeof(IO_RESOURCE_LIST) * (ioList->AlternativeLists - 1) + // ++ Single Alternative list
  1362. sizeof(IO_RESOURCE_DESCRIPTOR) * (ioResourceDescriptorCount);
  1363. newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
  1364. if (newList == NULL) {
  1365. ExFreePool(ioList);
  1366. return STATUS_INSUFFICIENT_RESOURCES;
  1367. }
  1368. //
  1369. // Walk through the io resource requirements list and pick up any valid descriptor.
  1370. //
  1371. newList->ListSize = size;
  1372. newList->InterfaceType = CmList->List->InterfaceType;
  1373. newList->BusNumber = CmList->List->BusNumber;
  1374. newList->SlotNumber = ioList->SlotNumber;
  1375. #if 0 // ++ Single Alternative list
  1376. newList->AlternativeLists = ioList->AlternativeLists;
  1377. #else
  1378. newList->AlternativeLists = 1;
  1379. #endif
  1380. ioResourceList = ioList->List;
  1381. newIoResourceList = newList->List;
  1382. while (--alternativeLists >= 0) {
  1383. ioResourceDescriptor = ioResourceList->Descriptors;
  1384. ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
  1385. if (ioResourceList->Version == 0xffff) {
  1386. ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd;
  1387. continue;
  1388. }
  1389. newIoResourceList->Version = ioResourceList->Version;
  1390. newIoResourceList->Revision = ioResourceList->Revision;
  1391. newIoResourceDescriptor = newIoResourceList->Descriptors;
  1392. if (ioResourceDescriptor->Type != CmResourceTypeConfigData) {
  1393. newIoResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
  1394. newIoResourceDescriptor->Type = CmResourceTypeConfigData;
  1395. newIoResourceDescriptor->ShareDisposition = CmResourceShareShared;
  1396. newIoResourceDescriptor->Flags = 0;
  1397. newIoResourceDescriptor->Spare1 = 0;
  1398. newIoResourceDescriptor->Spare2 = 0;
  1399. newIoResourceDescriptor->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY;
  1400. configDataDescriptor = newIoResourceDescriptor;
  1401. newIoResourceDescriptor++;
  1402. } else {
  1403. newList->ListSize -= sizeof(IO_RESOURCE_DESCRIPTOR);
  1404. configDataDescriptor = newIoResourceDescriptor;
  1405. }
  1406. while (ioResourceDescriptor < ioResourceDescriptorEnd) {
  1407. if (ioResourceDescriptor->Type != CmResourceTypeNull) {
  1408. *newIoResourceDescriptor = *ioResourceDescriptor;
  1409. newIoResourceDescriptor++;
  1410. }
  1411. ioResourceDescriptor++;
  1412. }
  1413. newIoResourceList->Count = (ULONG)(newIoResourceDescriptor - newIoResourceList->Descriptors);
  1414. configDataDescriptor->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY;
  1415. break;
  1416. }
  1417. ASSERT((PUCHAR)newIoResourceDescriptor == ((PUCHAR)newList + newList->ListSize));
  1418. *FilteredList = newList;
  1419. *ExactMatch = exactMatch;
  1420. ExFreePool(ioList);
  1421. return STATUS_SUCCESS;
  1422. }
  1423. PCM_PARTIAL_RESOURCE_DESCRIPTOR
  1424. PipFindMatchingBootMemResource(
  1425. IN ULONG Index,
  1426. IN PIO_RESOURCE_DESCRIPTOR IoDesc,
  1427. IN PCM_RESOURCE_LIST BootResources
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. This routine finds boot resources that match the i/o descriptor
  1432. Arguments:
  1433. Index - Index of memory boot config resource the caller is interested in.
  1434. IoDesc - I/O descriptor
  1435. BootResources - boot config
  1436. Return Value:
  1437. A pointer to a matching descriptor in the boot config
  1438. --*/
  1439. {
  1440. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  1441. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
  1442. ULONG count = 0, size, i, j, noMem;
  1443. if (BootResources == NULL) {
  1444. return NULL;
  1445. }
  1446. cmFullDesc = &BootResources->List[0];
  1447. for (i = 0; i < BootResources->Count; i++) {
  1448. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  1449. noMem = 0;
  1450. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  1451. size = 0;
  1452. if (cmPartDesc->Type == CmResourceTypeMemory) {
  1453. if (((cmPartDesc->u.Memory.Start.QuadPart >=
  1454. IoDesc->u.Memory.MinimumAddress.QuadPart) &&
  1455. ((cmPartDesc->u.Memory.Start.QuadPart +
  1456. cmPartDesc->u.Memory.Length - 1) <=
  1457. IoDesc->u.Memory.MaximumAddress.QuadPart)) &&
  1458. noMem == Index) {
  1459. return cmPartDesc;
  1460. }
  1461. noMem++;
  1462. } else if (cmPartDesc->Type == CmResourceTypeDeviceSpecific) {
  1463. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  1464. }
  1465. cmPartDesc++;
  1466. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  1467. }
  1468. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  1469. }
  1470. return NULL;
  1471. }
  1472. NTSTATUS
  1473. PipTrimResourceRequirements (
  1474. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoList,
  1475. IN USHORT IrqFlags,
  1476. IN PCM_RESOURCE_LIST BootResources
  1477. )
  1478. /*++
  1479. Routine Description:
  1480. This routine:
  1481. * adjusts the irq requirements level/edge to the value
  1482. decided on in PipCheckBus()
  1483. * adjusts the memory requirements to reflect the memory boot
  1484. config.
  1485. Arguments:
  1486. IoList - supplies the pointer to an IoResourceRequirementsList
  1487. IrqFlags - level/edge irq reuirements to be applied to all interrupt requirements in all alternatives.
  1488. BootResources - Used as a reference.
  1489. --*/
  1490. {
  1491. PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
  1492. PIO_RESOURCE_LIST resList, newList;
  1493. PIO_RESOURCE_DESCRIPTOR resDesc, newDesc;
  1494. PCM_PARTIAL_RESOURCE_DESCRIPTOR bootDesc;
  1495. ULONG listCount, i, j, pass, size, noMem;
  1496. BOOLEAN goodAlt;
  1497. if (IoList == NULL) {
  1498. return STATUS_SUCCESS;
  1499. }
  1500. // The only way to create a new req list only if absolutely
  1501. // necessary and make it the perfect size is perform this
  1502. // operation in two passes.
  1503. // 1. figure out how many alternatives will be eliminated and
  1504. // compute size of new req list. if all of the alternatives
  1505. // survived, return the original list (now modified)
  1506. //
  1507. // 2. construct new reqlist minus the bad alternatives.
  1508. listCount = 0;
  1509. size = 0;
  1510. for (pass = 0; pass < 2; pass++) {
  1511. if (pass == 0) {
  1512. size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) -
  1513. sizeof(IO_RESOURCE_LIST);
  1514. } else {
  1515. newReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
  1516. if (newReqList == NULL) {
  1517. return STATUS_INSUFFICIENT_RESOURCES;
  1518. }
  1519. *newReqList = **IoList;
  1520. newReqList->ListSize = size;
  1521. newReqList->AlternativeLists = listCount;
  1522. newList = &newReqList->List[0];
  1523. }
  1524. resList = &(*IoList)->List[0];
  1525. for (i = 0; i < (*IoList)->AlternativeLists; i++) {
  1526. if (pass == 1) {
  1527. *newList = *resList;
  1528. newDesc = &newList->Descriptors[0];
  1529. }
  1530. resDesc = &resList->Descriptors[0];
  1531. goodAlt = TRUE;
  1532. noMem = 0;
  1533. for (j = 0; j < resList->Count; j++) {
  1534. if (resDesc->Type == CmResourceTypeInterrupt) {
  1535. resDesc->Flags = IrqFlags;
  1536. if (resDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
  1537. resDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  1538. }
  1539. } else if (resDesc->Type == CmResourceTypeMemory) {
  1540. resDesc->Flags |= CM_RESOURCE_MEMORY_24;
  1541. if (BootResources) {
  1542. bootDesc = PipFindMatchingBootMemResource(noMem, resDesc, BootResources);
  1543. // have matching boot config resource, can trim requirements
  1544. if (bootDesc) {
  1545. if (bootDesc->Flags & CM_RESOURCE_MEMORY_READ_ONLY) {
  1546. // exact or inclusive ROM match is
  1547. // converted into a fixed requirement.
  1548. resDesc->u.Memory.MinimumAddress.QuadPart =
  1549. bootDesc->u.Memory.Start.QuadPart;
  1550. if (bootDesc->u.Memory.Length) {
  1551. resDesc->u.Memory.MaximumAddress.QuadPart =
  1552. bootDesc->u.Memory.Start.QuadPart +
  1553. bootDesc->u.Memory.Length - 1;
  1554. } else {
  1555. resDesc->u.Memory.MaximumAddress.QuadPart =
  1556. bootDesc->u.Memory.Start.QuadPart;
  1557. }
  1558. resDesc->u.Memory.Length = bootDesc->u.Memory.Length;
  1559. resDesc->u.Memory.Alignment = 1;
  1560. resDesc->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
  1561. }
  1562. } else {
  1563. goodAlt = FALSE;
  1564. }
  1565. } else {
  1566. resDesc->Flags &= ~CM_RESOURCE_MEMORY_READ_ONLY;
  1567. }
  1568. noMem++;
  1569. }
  1570. if (pass == 1) {
  1571. *newDesc = *resDesc;
  1572. PipDumpIoResourceDescriptor(" ", newDesc);
  1573. newDesc++;
  1574. }
  1575. resDesc++;
  1576. }
  1577. if (pass == 0) {
  1578. if (goodAlt) {
  1579. size += sizeof(IO_RESOURCE_LIST) +
  1580. sizeof(IO_RESOURCE_DESCRIPTOR) * (resList->Count - 1);
  1581. listCount++;
  1582. }
  1583. } else {
  1584. if (goodAlt) {
  1585. newList = (PIO_RESOURCE_LIST) newDesc;
  1586. } else {
  1587. DebugPrint((DEBUG_RESOURCE, "An alternative trimmed off of reqlist\n"));
  1588. }
  1589. }
  1590. resList = (PIO_RESOURCE_LIST) resDesc;
  1591. }
  1592. // If we have the same number of alternatives as before use
  1593. // the use existing (modified in-place) requirements list
  1594. if (!pass && (listCount == (*IoList)->AlternativeLists)) {
  1595. return STATUS_SUCCESS;
  1596. }
  1597. // if all alternatives have been eliminated, then it is better
  1598. // to use the existing requirements list than to hope to build
  1599. // one out of the boot config alone.
  1600. if (!pass && (listCount == 0)) {
  1601. DebugPrint((DEBUG_RESOURCE, "All alternatives trimmed off of reqlist, going with original\n"));
  1602. return STATUS_SUCCESS;
  1603. }
  1604. }
  1605. ExFreePool(*IoList);
  1606. *IoList = newReqList;
  1607. return STATUS_SUCCESS;
  1608. }
  1609. #endif