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.

3179 lines
85 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. res_bios.c
  5. Abstract:
  6. This file contains routines to translate resources between PnP ISA/BIOS
  7. format and Windows NT formats.
  8. Author:
  9. Shie-Lin Tzong (shielint) 12-Apr-1995
  10. Stephane Plante (splante) 20-Nov-1996
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. 20-Nov-1996:
  15. Changed to conform with ACPI environment
  16. 22-Jan-1997:
  17. Changed to remove all traces of original Shie Lin code
  18. --*/
  19. #include "pch.h"
  20. #define RESOURCE_LIST_GROWTH_SIZE 8
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE,PnpiBiosAddressHandleBusFlags)
  23. #pragma alloc_text(PAGE,PnpiBiosAddressHandleGlobalFlags)
  24. #pragma alloc_text(PAGE,PnpiBiosAddressHandleMemoryFlags)
  25. #pragma alloc_text(PAGE,PnpiBiosAddressHandlePortFlags)
  26. #pragma alloc_text(PAGE,PnpiBiosAddressToIoDescriptor)
  27. #pragma alloc_text(PAGE,PnpiBiosAddressDoubleToIoDescriptor)
  28. #pragma alloc_text(PAGE,PnpiBiosAddressQuadToIoDescriptor)
  29. #pragma alloc_text(PAGE,PnpiBiosDmaToIoDescriptor)
  30. #pragma alloc_text(PAGE,PnpiBiosExtendedIrqToIoDescriptor)
  31. #pragma alloc_text(PAGE,PnpiBiosIrqToIoDescriptor)
  32. #pragma alloc_text(PAGE,PnpiBiosMemoryToIoDescriptor)
  33. #pragma alloc_text(PAGE,PnpiBiosPortFixedToIoDescriptor)
  34. #pragma alloc_text(PAGE,PnpiBiosPortToIoDescriptor)
  35. #pragma alloc_text(PAGE,PnpiClearAllocatedMemory)
  36. #pragma alloc_text(PAGE,PnpiGrowResourceDescriptor)
  37. #pragma alloc_text(PAGE,PnpiGrowResourceList)
  38. #pragma alloc_text(PAGE,PnpiUpdateResourceList)
  39. #pragma alloc_text(PAGE,PnpBiosResourcesToNtResources)
  40. #pragma alloc_text(PAGE,PnpIoResourceListToCmResourceList)
  41. #endif
  42. VOID
  43. PnpiBiosAddressHandleBusFlags(
  44. IN PVOID Buffer,
  45. IN PIO_RESOURCE_DESCRIPTOR Descriptor
  46. )
  47. /*++
  48. Routine Description:
  49. This routine handles the Type specific flags in an Address Descriptor of
  50. type Bus
  51. Arguments:
  52. Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
  53. because the initial memory placement is identical
  54. Descriptor - Where to set the flags
  55. Return Value:
  56. None
  57. --*/
  58. {
  59. PAGED_CODE();
  60. ASSERT(Descriptor->u.BusNumber.Length > 0);
  61. }
  62. VOID
  63. PnpiBiosAddressHandleGlobalFlags(
  64. IN PVOID Buffer,
  65. IN PIO_RESOURCE_DESCRIPTOR Descriptor
  66. )
  67. /*++
  68. Routine Descriptoin:
  69. This routine handles all the Global 'generic' flags in an Address Descriptor
  70. Arguments:
  71. Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
  72. because the initial memory placement is identical
  73. Descriptor - Where to set the flags
  74. Return Value:
  75. None
  76. --*/
  77. {
  78. PPNP_WORD_ADDRESS_DESCRIPTOR buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Buffer;
  79. ULONG newValue;
  80. ULONG oldValue;
  81. ULONG bound;
  82. PAGED_CODE();
  83. //
  84. // If the resource is marked as being consumed only, then it is
  85. // exclusive, otherwise, it is shared
  86. //
  87. if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY) {
  88. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  89. } else {
  90. Descriptor->ShareDisposition = CmResourceShareShared;
  91. }
  92. //
  93. // Handle the hints that are given to us
  94. //
  95. if (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED &&
  96. buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) {
  97. if (Descriptor->Type == CmResourceTypeBusNumber) {
  98. oldValue = Descriptor->u.BusNumber.Length;
  99. newValue = Descriptor->u.BusNumber.Length =
  100. Descriptor->u.BusNumber.MaxBusNumber -
  101. Descriptor->u.BusNumber.MinBusNumber + 1;
  102. } else {
  103. oldValue = Descriptor->u.Memory.Length;
  104. newValue = Descriptor->u.Memory.Length =
  105. Descriptor->u.Memory.MaximumAddress.LowPart -
  106. Descriptor->u.Memory.MinimumAddress.LowPart + 1;
  107. }
  108. } else if (buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) {
  109. if (Descriptor->Type == CmResourceTypeBusNumber) {
  110. bound = Descriptor->u.BusNumber.MaxBusNumber;
  111. oldValue = Descriptor->u.BusNumber.MinBusNumber;
  112. newValue = Descriptor->u.BusNumber.MinBusNumber = 1 +
  113. Descriptor->u.BusNumber.MaxBusNumber -
  114. Descriptor->u.BusNumber.Length;
  115. } else {
  116. bound = Descriptor->u.Memory.MaximumAddress.LowPart;
  117. oldValue = Descriptor->u.Memory.MinimumAddress.LowPart;
  118. newValue = Descriptor->u.Memory.MinimumAddress.LowPart = 1 +
  119. Descriptor->u.Memory.MaximumAddress.LowPart -
  120. Descriptor->u.Memory.Length;
  121. }
  122. } else if (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) {
  123. if (Descriptor->Type == CmResourceTypeBusNumber) {
  124. bound = Descriptor->u.BusNumber.MinBusNumber;
  125. oldValue = Descriptor->u.BusNumber.MaxBusNumber;
  126. newValue = Descriptor->u.BusNumber.MaxBusNumber =
  127. Descriptor->u.BusNumber.MinBusNumber +
  128. Descriptor->u.BusNumber.Length - 1;
  129. } else {
  130. bound = Descriptor->u.Memory.MinimumAddress.LowPart;
  131. oldValue = Descriptor->u.Memory.MaximumAddress.LowPart;
  132. newValue = Descriptor->u.Memory.MaximumAddress.LowPart =
  133. Descriptor->u.Memory.MinimumAddress.LowPart -
  134. Descriptor->u.Memory.Length - 1;
  135. }
  136. }
  137. }
  138. VOID
  139. PnpiBiosAddressHandleMemoryFlags(
  140. IN PVOID Buffer,
  141. IN PIO_RESOURCE_DESCRIPTOR Descriptor
  142. )
  143. /*++
  144. Routine Description:
  145. This routine handles the Type specific flags in an Address Descriptor of
  146. type Memory
  147. Arguments:
  148. Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
  149. because the initial memory placement is identical
  150. Descriptor - Where to set the flags
  151. Return Value:
  152. None
  153. --*/
  154. {
  155. PPNP_WORD_ADDRESS_DESCRIPTOR buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Buffer;
  156. PAGED_CODE();
  157. //
  158. // Set the proper memory type flags
  159. //
  160. switch( buffer->TFlag & PNP_ADDRESS_TYPE_MEMORY_MASK) {
  161. case PNP_ADDRESS_TYPE_MEMORY_CACHEABLE:
  162. Descriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE;
  163. break;
  164. case PNP_ADDRESS_TYPE_MEMORY_WRITE_COMBINE:
  165. Descriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE;
  166. break;
  167. case PNP_ADDRESS_TYPE_MEMORY_PREFETCHABLE:
  168. Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
  169. break;
  170. case PNP_ADDRESS_TYPE_MEMORY_NONCACHEABLE:
  171. break;
  172. default:
  173. ACPIPrint( (
  174. ACPI_PRINT_WARNING,
  175. "PnpiBiosAddressHandleMemoryFlags: Unknown Memory TFlag "
  176. "0x%02x\n",
  177. buffer->TFlag
  178. ) );
  179. break;
  180. }
  181. //
  182. // This bit is used to turn on/off write access to memory
  183. //
  184. if (buffer->TFlag & PNP_ADDRESS_TYPE_MEMORY_READ_WRITE) {
  185. Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
  186. } else {
  187. Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
  188. }
  189. }
  190. VOID
  191. PnpiBiosAddressHandlePortFlags(
  192. IN PVOID Buffer,
  193. IN PIO_RESOURCE_DESCRIPTOR Descriptor
  194. )
  195. /*++
  196. Routine Description:
  197. This routine handles the Type specific flags in an Address Descriptor of
  198. type Port
  199. Arguments:
  200. Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
  201. because the initial memory placement is identical
  202. Descriptor - Where to set the flags
  203. Return Value:
  204. None
  205. --*/
  206. {
  207. PPNP_WORD_ADDRESS_DESCRIPTOR buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Buffer;
  208. ULONG granularity = Descriptor->u.Port.Alignment;
  209. PAGED_CODE();
  210. //
  211. // We can determine if the device uses a positive decode or not
  212. //
  213. if ( !(buffer->GFlag & PNP_ADDRESS_FLAG_SUBTRACTIVE_DECODE)) {
  214. Descriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
  215. }
  216. }
  217. NTSTATUS
  218. PnpiBiosAddressToIoDescriptor(
  219. IN PUCHAR Data,
  220. IN PIO_RESOURCE_LIST Array[],
  221. IN ULONG ArrayIndex,
  222. IN ULONG Flags
  223. )
  224. /*++
  225. Routine Description:
  226. Arguments:
  227. Return Value:
  228. --*/
  229. {
  230. NTSTATUS status;
  231. PIO_RESOURCE_DESCRIPTOR rangeDescriptor, privateDescriptor;
  232. PPNP_WORD_ADDRESS_DESCRIPTOR buffer;
  233. ULONG alignment;
  234. ULONG length;
  235. UCHAR decodeLength;
  236. USHORT parentMin, childMin, childMax;
  237. PAGED_CODE();
  238. ASSERT( Array != NULL );
  239. buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Data;
  240. //
  241. // Check to see if we are are allowed to use this resource
  242. //
  243. if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY &&
  244. buffer->RFlag == PNP_ADDRESS_IO_TYPE &&
  245. Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
  246. return STATUS_SUCCESS;
  247. }
  248. //
  249. // If the length of the address range is zero, ignore this descriptor.
  250. // This makes it easier for BIOS writers to set up a template and then
  251. // whack its length to zero if it doesn't apply.
  252. //
  253. if (buffer->AddressLength == 0) {
  254. return STATUS_SUCCESS;
  255. }
  256. //
  257. // Ensure that there is enough space within the chosen list to add the
  258. // resource
  259. //
  260. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &rangeDescriptor );
  261. if (!NT_SUCCESS(status)) {
  262. return status;
  263. }
  264. //
  265. // If this is I/O or Memory, then we will need to make enough space for
  266. // a device private resource too.
  267. //
  268. if ((buffer->RFlag == PNP_ADDRESS_MEMORY_TYPE) ||
  269. (buffer->RFlag == PNP_ADDRESS_IO_TYPE)) {
  270. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &privateDescriptor );
  271. if (!NT_SUCCESS(status)) {
  272. return status;
  273. }
  274. //
  275. // Calling PnpiUpdateResourceList may have invalidated
  276. // rangeDescriptor. So make sure it's OK now.
  277. //
  278. ASSERT(Array[ArrayIndex]->Count >= 2);
  279. rangeDescriptor = privateDescriptor - 1;
  280. privateDescriptor->Type = CmResourceTypeDevicePrivate;
  281. //
  282. // Mark this descriptor as containing the start
  283. // address of the translated resource.
  284. //
  285. privateDescriptor->Flags = TRANSLATION_DATA_PARENT_ADDRESS;
  286. //
  287. // Fill in the top 32 bits of the start address.
  288. //
  289. privateDescriptor->u.DevicePrivate.Data[2] = 0;
  290. }
  291. //
  292. // Do we met the minimum length requirements ?
  293. //
  294. if ( buffer->Length < PNP_ADDRESS_WORD_MINIMUM_LENGTH) {
  295. ACPIPrint( (
  296. ACPI_PRINT_CRITICAL,
  297. "PnpiBiosAddressToIoDescriptor: Descriptor too small 0x%08lx\n",
  298. buffer->Length
  299. ) );
  300. //
  301. // We can go no further
  302. //
  303. KeBugCheckEx(
  304. ACPI_BIOS_ERROR,
  305. ACPI_PNP_RESOURCE_LIST_BUFFER_TOO_SMALL,
  306. (ULONG_PTR) buffer,
  307. buffer->Tag,
  308. buffer->Length
  309. );
  310. }
  311. //
  312. // Length is the stored within the descriptor record
  313. //
  314. length = (ULONG)(buffer->AddressLength);
  315. alignment = (ULONG) (buffer->Granularity) + 1;
  316. //
  317. // Calculate the bounds of both the parent and child sides of
  318. // the bridge.
  319. //
  320. // The translation field applies to the parent address i.e.
  321. // the child address is the address in the buffer and the
  322. // parent address is the addition of the child address and
  323. // the translation field.
  324. //
  325. parentMin = buffer->MinimumAddress + buffer->TranslationAddress;
  326. childMin = buffer->MinimumAddress;
  327. childMax = buffer->MaximumAddress;
  328. //
  329. // Patch the length based on wether or not the min/max flags are set
  330. //
  331. if ( (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) &&
  332. (buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) ) {
  333. ULONG length2;
  334. ULONG alignment2;
  335. //
  336. // Calculate the length based on the fact that the min and
  337. // max addresses are locked down.
  338. //
  339. length2 = childMax - childMin + 1;
  340. //
  341. // Test #1 --- The length had better be correct
  342. //
  343. if (length2 != length) {
  344. //
  345. // Bummer. Let the world know
  346. //
  347. ACPIPrint( (
  348. ACPI_PRINT_WARNING,
  349. "ACPI: Length does not match fixed attributes\n"
  350. ) );
  351. length = length2;
  352. }
  353. //
  354. // Test #2 --- The granularity had also better be correct
  355. //
  356. if ( (childMin & (ULONG) buffer->Granularity ) ) {
  357. //
  358. // Bummer. Let the world know
  359. //
  360. ACPIPrint( (
  361. ACPI_PRINT_WARNING,
  362. "ACPI: Granularity does not match fixed attributes\n"
  363. ) );
  364. alignment = 1;
  365. }
  366. }
  367. //
  368. // Handle the Resource type seperately
  369. //
  370. switch (buffer->RFlag) {
  371. case PNP_ADDRESS_MEMORY_TYPE:
  372. //
  373. // Set the proper ranges
  374. //
  375. rangeDescriptor->u.Memory.Alignment = alignment;
  376. rangeDescriptor->u.Memory.Length = length;
  377. rangeDescriptor->u.Memory.MinimumAddress.LowPart = childMin;
  378. rangeDescriptor->u.Memory.MaximumAddress.LowPart = childMax;
  379. rangeDescriptor->u.Memory.MinimumAddress.HighPart =
  380. rangeDescriptor->u.Memory.MaximumAddress.HighPart = 0;
  381. rangeDescriptor->Type = CmResourceTypeMemory;
  382. //
  383. // The child address is the address in the PnP address
  384. // space descriptor and the child descriptor will inherit
  385. // the descriptor type from the PnP address space
  386. // descriptor.
  387. //
  388. if (buffer->TFlag & TRANSLATION_MEM_TO_IO) {
  389. //
  390. // The device private describes the parent. With this
  391. // flag set, the descriptor type of the parent will
  392. // change from Memory to IO.
  393. //
  394. privateDescriptor->u.DevicePrivate.Data[0] =
  395. CmResourceTypePort;
  396. } else {
  397. //
  398. // The parent descriptor type will not change.
  399. //
  400. privateDescriptor->u.DevicePrivate.Data[0] =
  401. CmResourceTypeMemory;
  402. }
  403. //
  404. // Fill in the bottom 32 bits of the parent's start address.
  405. //
  406. privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
  407. //
  408. // Handle memory flags
  409. //
  410. PnpiBiosAddressHandleMemoryFlags( buffer, rangeDescriptor );
  411. //
  412. // Reset the alignment
  413. //
  414. rangeDescriptor->u.Memory.Alignment = 1;
  415. break;
  416. case PNP_ADDRESS_IO_TYPE:
  417. //
  418. // Any flags that are set here must be handled
  419. // through the use of device privates
  420. //
  421. rangeDescriptor->u.Port.Alignment = alignment;
  422. rangeDescriptor->u.Port.Length = length;
  423. rangeDescriptor->u.Port.MinimumAddress.LowPart = childMin;
  424. rangeDescriptor->u.Port.MaximumAddress.LowPart = childMax;
  425. rangeDescriptor->u.Port.MinimumAddress.HighPart =
  426. rangeDescriptor->u.Port.MaximumAddress.HighPart = 0;
  427. rangeDescriptor->Type = CmResourceTypePort;
  428. if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_SPARSE_TRANSLATION) {
  429. privateDescriptor->Flags |= TRANSLATION_RANGE_SPARSE;
  430. }
  431. if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_TRANSLATE_IO_TO_MEM) {
  432. //
  433. // The device private describes the parent. With this
  434. // flag set, the descriptor type of the parent will
  435. // change from IO to Memory.
  436. //
  437. privateDescriptor->u.DevicePrivate.Data[0] =
  438. CmResourceTypeMemory;
  439. } else {
  440. privateDescriptor->u.DevicePrivate.Data[0] =
  441. CmResourceTypePort;
  442. }
  443. //
  444. // Fill in the bottom 32 bits of the parent's start address.
  445. //
  446. privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
  447. //
  448. // Handle port flags
  449. //
  450. PnpiBiosAddressHandlePortFlags( buffer, rangeDescriptor );
  451. //
  452. // Reset the alignment
  453. //
  454. rangeDescriptor->u.Port.Alignment = 1;
  455. break;
  456. case PNP_ADDRESS_BUS_NUMBER_TYPE:
  457. rangeDescriptor->Type = CmResourceTypeBusNumber;
  458. rangeDescriptor->u.BusNumber.MinBusNumber = (buffer->MinimumAddress);
  459. rangeDescriptor->u.BusNumber.MaxBusNumber = (buffer->MaximumAddress);
  460. rangeDescriptor->u.BusNumber.Length = length;
  461. //
  462. // Handle busnumber flags
  463. //
  464. PnpiBiosAddressHandleBusFlags( buffer, rangeDescriptor );
  465. break;
  466. default:
  467. ACPIPrint( (
  468. ACPI_PRINT_WARNING,
  469. "PnpiBiosAddressToIoDescriptor: Unknown Type 0x%2x\n",
  470. buffer->RFlag ) );
  471. break;
  472. }
  473. //
  474. // Handle global flags
  475. //
  476. PnpiBiosAddressHandleGlobalFlags( buffer, rangeDescriptor );
  477. return STATUS_SUCCESS;
  478. }
  479. NTSTATUS
  480. PnpiBiosAddressDoubleToIoDescriptor(
  481. IN PUCHAR Data,
  482. IN PIO_RESOURCE_LIST Array[],
  483. IN ULONG ArrayIndex,
  484. IN ULONG Flags
  485. )
  486. /*++
  487. Routine Description:
  488. Arguments:
  489. Return Value:
  490. --*/
  491. {
  492. NTSTATUS status;
  493. PIO_RESOURCE_DESCRIPTOR rangeDescriptor, privateDescriptor;
  494. PPNP_DWORD_ADDRESS_DESCRIPTOR buffer;
  495. UCHAR decodeLength;
  496. ULONG alignment;
  497. ULONG length;
  498. ULONG parentMin, childMin, childMax;
  499. PAGED_CODE();
  500. ASSERT( Array != NULL );
  501. buffer = (PPNP_DWORD_ADDRESS_DESCRIPTOR) Data;
  502. //
  503. // Check to see if we are are allowed to use this resource
  504. //
  505. if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY &&
  506. buffer->RFlag == PNP_ADDRESS_IO_TYPE &&
  507. Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
  508. return STATUS_SUCCESS;
  509. }
  510. //
  511. // If the length of the address range is zero, ignore this descriptor.
  512. // This makes it easier for BIOS writers to set up a template and then
  513. // whack its length to zero if it doesn't apply.
  514. //
  515. if (buffer->AddressLength == 0) {
  516. return STATUS_SUCCESS;
  517. }
  518. //
  519. // Ensure that there is enough space within the chosen list to add the
  520. // resource
  521. //
  522. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &rangeDescriptor );
  523. if (!NT_SUCCESS(status)) {
  524. return status;
  525. }
  526. //
  527. // If this is I/O or Memory, then we will need to make enough space for
  528. // a device private resource too.
  529. //
  530. if ((buffer->RFlag == PNP_ADDRESS_MEMORY_TYPE) ||
  531. (buffer->RFlag == PNP_ADDRESS_IO_TYPE)) {
  532. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &privateDescriptor );
  533. if (!NT_SUCCESS(status)) {
  534. return status;
  535. }
  536. //
  537. // Calling PnpiUpdateResourceList may have invalidated
  538. // rangeDescriptor. So make sure it's OK now.
  539. //
  540. ASSERT(Array[ArrayIndex]->Count >= 2);
  541. rangeDescriptor = privateDescriptor - 1;
  542. privateDescriptor->Type = CmResourceTypeDevicePrivate;
  543. //
  544. // Mark this descriptor as containing the start
  545. // address of the translated resource.
  546. //
  547. privateDescriptor->Flags = TRANSLATION_DATA_PARENT_ADDRESS;
  548. //
  549. // Fill in the top 32 bits of the start address.
  550. //
  551. privateDescriptor->u.DevicePrivate.Data[2] = 0;
  552. }
  553. //
  554. //
  555. // Do we met the minimum length requirements ?
  556. //
  557. if ( buffer->Length < PNP_ADDRESS_DWORD_MINIMUM_LENGTH) {
  558. ACPIPrint( (
  559. ACPI_PRINT_CRITICAL,
  560. "PnpiBiosAddressDoubleToIoDescriptor: Descriptor too small 0x%08lx\n",
  561. buffer->Length ) );
  562. //
  563. // We can go no further
  564. //
  565. KeBugCheckEx(
  566. ACPI_BIOS_ERROR,
  567. ACPI_PNP_RESOURCE_LIST_BUFFER_TOO_SMALL,
  568. (ULONG_PTR) buffer,
  569. buffer->Tag,
  570. buffer->Length
  571. );
  572. }
  573. //
  574. // Length is the stored within the descriptor record
  575. //
  576. // Note. AddressLength field and Granularity field are both ULONG
  577. // values and don't require casting. beware if you cut and paste
  578. // this code as other descriptor types don't necessarily match that.
  579. //
  580. length = buffer->AddressLength;
  581. alignment = buffer->Granularity + 1;
  582. //
  583. // Calculate the bounds of both the parent and child sides of
  584. // the bridge.
  585. //
  586. // The translation field applies to the parent address i.e.
  587. // the child address is the address in the buffer and the
  588. // parent address is the addition of the child address and
  589. // the translation field.
  590. //
  591. parentMin = buffer->MinimumAddress + buffer->TranslationAddress;
  592. childMin = buffer->MinimumAddress;
  593. childMax = buffer->MaximumAddress;
  594. //
  595. // Patch the length based on wether or not the min/max flags are set
  596. //
  597. if ( (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) &&
  598. (buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) ) {
  599. ULONG length2;
  600. ULONG alignment2;
  601. //
  602. // Calculate the length based on the fact that the min and
  603. // max addresses are locked down.
  604. //
  605. length2 = childMax - childMin + 1;
  606. //
  607. // Test #1 --- The length had better be correct
  608. //
  609. if (length2 != length) {
  610. //
  611. // Bummer. Let the world know
  612. //
  613. ACPIPrint( (
  614. ACPI_PRINT_WARNING,
  615. "ACPI: Length does not match fixed attributes\n"
  616. ) );
  617. length = length2;
  618. }
  619. //
  620. // Test #2 --- The granularity had also better be correct
  621. //
  622. if ( (childMin & buffer->Granularity) ) {
  623. //
  624. // Bummer. Let the world know
  625. //
  626. ACPIPrint( (
  627. ACPI_PRINT_WARNING,
  628. "ACPI: Granularity does not match fixed attributes\n"
  629. ) );
  630. alignment = 1;
  631. }
  632. }
  633. //
  634. // Handle the Resource type seperately
  635. //
  636. switch (buffer->RFlag) {
  637. case PNP_ADDRESS_MEMORY_TYPE:
  638. //
  639. // Set the proper ranges
  640. //
  641. rangeDescriptor->u.Memory.Alignment = alignment;
  642. rangeDescriptor->u.Memory.Length = length;
  643. rangeDescriptor->u.Memory.MinimumAddress.LowPart = childMin;
  644. rangeDescriptor->u.Memory.MaximumAddress.LowPart = childMax;
  645. rangeDescriptor->u.Memory.MinimumAddress.HighPart =
  646. rangeDescriptor->u.Memory.MaximumAddress.HighPart = 0;
  647. rangeDescriptor->Type = CmResourceTypeMemory;
  648. //
  649. // The child address is the address in the PnP address
  650. // space descriptor and the child descriptor will inherit
  651. // the descriptor type from the PnP address space
  652. // descriptor.
  653. //
  654. if (buffer->TFlag & TRANSLATION_MEM_TO_IO) {
  655. //
  656. // The device private describes the parent. With this
  657. // flag set, the descriptor type of the parent will
  658. // changed from Memory to IO.
  659. //
  660. privateDescriptor->u.DevicePrivate.Data[0] =
  661. CmResourceTypePort;
  662. } else {
  663. //
  664. // The parent descriptor type will not change.
  665. //
  666. privateDescriptor->u.DevicePrivate.Data[0] =
  667. CmResourceTypeMemory;
  668. }
  669. //
  670. // Fill in the bottom 32 bits of the parent's start address.
  671. //
  672. privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
  673. //
  674. // Handle memory flags
  675. //
  676. PnpiBiosAddressHandleMemoryFlags( buffer, rangeDescriptor );
  677. //
  678. // Reset the alignment
  679. //
  680. rangeDescriptor->u.Memory.Alignment = 1;
  681. break;
  682. case PNP_ADDRESS_IO_TYPE:
  683. //
  684. // Any flags that are set here must be handled
  685. // through the use of device privates
  686. //
  687. rangeDescriptor->u.Port.Alignment = alignment;
  688. rangeDescriptor->u.Port.Length = length;
  689. rangeDescriptor->u.Port.MinimumAddress.LowPart = childMin;
  690. rangeDescriptor->u.Port.MaximumAddress.LowPart = childMax;
  691. rangeDescriptor->u.Port.MinimumAddress.HighPart =
  692. rangeDescriptor->u.Port.MaximumAddress.HighPart = 0;
  693. rangeDescriptor->Type = CmResourceTypePort;
  694. if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_SPARSE_TRANSLATION) {
  695. privateDescriptor->Flags |= TRANSLATION_RANGE_SPARSE;
  696. }
  697. if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_TRANSLATE_IO_TO_MEM) {
  698. //
  699. // The device private describes the parent. With this
  700. // flag set, the descriptor type of the parent will
  701. // changed from IO to Memory.
  702. //
  703. privateDescriptor->u.DevicePrivate.Data[0] =
  704. CmResourceTypeMemory;
  705. } else {
  706. //
  707. // The parent descriptor type will not change.
  708. //
  709. privateDescriptor->u.DevicePrivate.Data[0] =
  710. CmResourceTypePort;
  711. }
  712. //
  713. // Fill in the bottom 32 bits of the parent's start address.
  714. //
  715. privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
  716. //
  717. // Handle port flags
  718. //
  719. PnpiBiosAddressHandlePortFlags( buffer, rangeDescriptor );
  720. //
  721. // Reset the alignment
  722. //
  723. rangeDescriptor->u.Port.Alignment = 1;
  724. break;
  725. case PNP_ADDRESS_BUS_NUMBER_TYPE:
  726. rangeDescriptor->Type = CmResourceTypeBusNumber;
  727. rangeDescriptor->u.BusNumber.Length = length;
  728. rangeDescriptor->u.BusNumber.MinBusNumber = (buffer->MinimumAddress);
  729. rangeDescriptor->u.BusNumber.MaxBusNumber = (buffer->MaximumAddress);
  730. //
  731. // Handle busnumber flags
  732. //
  733. PnpiBiosAddressHandleBusFlags( buffer, rangeDescriptor );
  734. break;
  735. default:
  736. ACPIPrint( (
  737. ACPI_PRINT_WARNING,
  738. "PnpiBiosAddressDoubleToIoDescriptor: Unknown Type 0x%2x\n",
  739. buffer->RFlag ) );
  740. break;
  741. }
  742. //
  743. // Handle global flags
  744. //
  745. PnpiBiosAddressHandleGlobalFlags( buffer, rangeDescriptor );
  746. return STATUS_SUCCESS;
  747. }
  748. NTSTATUS
  749. PnpiBiosAddressQuadToIoDescriptor(
  750. IN PUCHAR Data,
  751. IN PIO_RESOURCE_LIST Array[],
  752. IN ULONG ArrayIndex,
  753. IN ULONG Flags
  754. )
  755. /*++
  756. Routine Description:
  757. Arguments:
  758. Return Value:
  759. --*/
  760. {
  761. NTSTATUS status;
  762. PIO_RESOURCE_DESCRIPTOR rangeDescriptor, privateDescriptor;
  763. PPNP_QWORD_ADDRESS_DESCRIPTOR buffer;
  764. UCHAR decodeLength;
  765. ULONGLONG alignment;
  766. ULONGLONG length;
  767. ULONGLONG parentMin, childMin, childMax;
  768. PAGED_CODE();
  769. ASSERT( Array != NULL );
  770. buffer = (PPNP_QWORD_ADDRESS_DESCRIPTOR) Data;
  771. //
  772. // Check to see if we are are allowed to use this resource
  773. //
  774. if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY &&
  775. buffer->RFlag == PNP_ADDRESS_IO_TYPE &&
  776. Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
  777. return STATUS_SUCCESS;
  778. }
  779. //
  780. // If the length of the address range is zero, ignore this descriptor.
  781. // This makes it easier for BIOS writers to set up a template and then
  782. // whack its length to zero if it doesn't apply.
  783. //
  784. if (buffer->AddressLength == 0) {
  785. return STATUS_SUCCESS;
  786. }
  787. //
  788. // Ensure that there is enough space within the chosen list to add the
  789. // resource
  790. //
  791. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &rangeDescriptor );
  792. if (!NT_SUCCESS(status)) {
  793. return status;
  794. }
  795. //
  796. // If this is I/O or Memory, then we will need to make enough space for
  797. // a device private resource too.
  798. //
  799. if ((buffer->RFlag == PNP_ADDRESS_MEMORY_TYPE) ||
  800. (buffer->RFlag == PNP_ADDRESS_IO_TYPE)) {
  801. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &privateDescriptor );
  802. if (!NT_SUCCESS(status)) {
  803. return status;
  804. }
  805. //
  806. // Calling PnpiUpdateResourceList may have invalidated
  807. // rangeDescriptor. So make sure it's OK now.
  808. //
  809. ASSERT(Array[ArrayIndex]->Count >= 2);
  810. rangeDescriptor = privateDescriptor - 1;
  811. privateDescriptor->Type = CmResourceTypeDevicePrivate;
  812. //
  813. // Mark this descriptor as containing the start
  814. // address of the translated resource.
  815. //
  816. privateDescriptor->Flags = TRANSLATION_DATA_PARENT_ADDRESS;
  817. }
  818. //
  819. //
  820. // Do we met the minimum length requirements ?
  821. //
  822. if ( buffer->Length < PNP_ADDRESS_QWORD_MINIMUM_LENGTH) {
  823. ACPIPrint( (
  824. ACPI_PRINT_CRITICAL,
  825. "PnpiBiosAddressQuadToIoDescriptor: Descriptor too small 0x%08lx\n",
  826. buffer->Length ) );
  827. //
  828. // We can go no further
  829. //
  830. KeBugCheckEx(
  831. ACPI_BIOS_ERROR,
  832. ACPI_PNP_RESOURCE_LIST_BUFFER_TOO_SMALL,
  833. (ULONG_PTR) buffer,
  834. buffer->Tag,
  835. buffer->Length
  836. );
  837. }
  838. //
  839. // Length is the stored within the descriptor record
  840. //
  841. length = (ULONGLONG) (buffer->AddressLength);
  842. alignment = (ULONGLONG) (buffer->Granularity) + 1;
  843. //
  844. // Calculate the bounds of both the parent and child sides of
  845. // the bridge.
  846. //
  847. // The translation field applies to the parent address i.e.
  848. // the child address is the address in the buffer and the
  849. // parent address is the addition of the child address and
  850. // the translation field.
  851. //
  852. parentMin = buffer->MinimumAddress + buffer->TranslationAddress;
  853. childMin = buffer->MinimumAddress;
  854. childMax = buffer->MaximumAddress;
  855. //
  856. // Patch the length based on wether or not the min/max flags are set
  857. //
  858. if ( (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) &&
  859. (buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) ) {
  860. ULONGLONG length2;
  861. ULONGLONG alignment2;
  862. //
  863. // Calculate the length based on the fact that the min and
  864. // max addresses are locked down.
  865. //
  866. length2 = childMax - childMin + 1;
  867. //
  868. // Test #1 --- The length had better be correct
  869. //
  870. if (length2 != length) {
  871. //
  872. // Bummer. Let the world know
  873. //
  874. ACPIPrint( (
  875. ACPI_PRINT_WARNING,
  876. "ACPI: Length does not match fixed attributes\n"
  877. ) );
  878. length = length2;
  879. }
  880. //
  881. // Test #2 --- The granularity had also better be correct
  882. //
  883. if ( (childMin & (ULONGLONG) buffer->Granularity) ) {
  884. //
  885. // Bummer. Let the world know
  886. //
  887. ACPIPrint( (
  888. ACPI_PRINT_WARNING,
  889. "ACPI: Granularity does not match fixed attributes\n"
  890. ) );
  891. alignment = 1;
  892. }
  893. }
  894. if (length > MAXULONG) {
  895. ACPIPrint( (
  896. ACPI_PRINT_CRITICAL,
  897. "ACPI: descriptor length %I64x exceeds MAXULONG\n",
  898. length
  899. ) );
  900. if ((!(AcpiOverrideAttributes & ACPI_OVERRIDE_DELL_MAXULONG_BUGCHECK)) || (childMin < MAXULONG)) {
  901. //
  902. // We can go no further
  903. //
  904. KeBugCheckEx(
  905. ACPI_BIOS_ERROR,
  906. ACPI_PNP_RESOURCE_LIST_LENGTH_TOO_LARGE,
  907. (ULONG_PTR) buffer,
  908. buffer->Tag,
  909. (ULONG_PTR)&length
  910. );
  911. }
  912. }
  913. //
  914. // Handle the Resource type seperately
  915. //
  916. switch (buffer->RFlag) {
  917. case PNP_ADDRESS_MEMORY_TYPE:
  918. //
  919. // Set the proper ranges
  920. //
  921. rangeDescriptor->u.Memory.Alignment = (ULONG)alignment ;
  922. rangeDescriptor->u.Memory.Length = (ULONG)length;
  923. rangeDescriptor->u.Memory.MinimumAddress.QuadPart = childMin;
  924. rangeDescriptor->u.Memory.MaximumAddress.QuadPart = childMax;
  925. rangeDescriptor->Type = CmResourceTypeMemory;
  926. //
  927. // The child address is the address in the PnP address
  928. // space descriptor and the child descriptor will inherit
  929. // the descriptor type from the PnP address space
  930. // descriptor.
  931. //
  932. if (buffer->TFlag & TRANSLATION_MEM_TO_IO) {
  933. //
  934. // The device private describes the parent. With this
  935. // flag set, the descriptor type of the parent will
  936. // changed from Memory to IO.
  937. //
  938. privateDescriptor->u.DevicePrivate.Data[0] =
  939. CmResourceTypePort;
  940. } else {
  941. //
  942. // The parent descriptor type will not change.
  943. //
  944. privateDescriptor->u.DevicePrivate.Data[0] =
  945. CmResourceTypeMemory;
  946. }
  947. //
  948. // Fill in all 64 bits of the start address.
  949. //
  950. privateDescriptor->u.DevicePrivate.Data[1] = (ULONG)(parentMin & 0xffffffff);
  951. privateDescriptor->u.DevicePrivate.Data[2] = (ULONG)(parentMin >> 32);
  952. //
  953. // Handle memory flags
  954. //
  955. PnpiBiosAddressHandleMemoryFlags( buffer, rangeDescriptor );
  956. break;
  957. case PNP_ADDRESS_IO_TYPE:
  958. //
  959. // Any flags that are set here must be handled
  960. // through the use of device privates
  961. //
  962. rangeDescriptor->u.Port.Alignment = (ULONG) alignment;
  963. rangeDescriptor->u.Port.Length = (ULONG) length;
  964. rangeDescriptor->u.Port.MinimumAddress.QuadPart = childMin;
  965. rangeDescriptor->u.Port.MaximumAddress.QuadPart = childMax;
  966. rangeDescriptor->Type = CmResourceTypePort;
  967. if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_SPARSE_TRANSLATION) {
  968. privateDescriptor->Flags |= TRANSLATION_RANGE_SPARSE;
  969. }
  970. if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_TRANSLATE_IO_TO_MEM) {
  971. //
  972. // The device private describes the parent. With this
  973. // flag set, the descriptor type of the parent will
  974. // change from IO to Memory.
  975. //
  976. privateDescriptor->u.DevicePrivate.Data[0] = CmResourceTypeMemory;
  977. } else {
  978. //
  979. // Bridges that implement I/O on the parent side never
  980. // implement memory on the child side.
  981. //
  982. privateDescriptor->u.DevicePrivate.Data[0] = CmResourceTypePort;
  983. }
  984. //
  985. // Fill in all 64 bits of the start address.
  986. //
  987. privateDescriptor->u.DevicePrivate.Data[1] = (ULONG)(parentMin & 0xffffffff);
  988. privateDescriptor->u.DevicePrivate.Data[2] = (ULONG)(parentMin >> 32);
  989. //
  990. // Handle port flags
  991. //
  992. PnpiBiosAddressHandlePortFlags( buffer, rangeDescriptor );
  993. //
  994. // Reset the alignment
  995. //
  996. rangeDescriptor->u.Port.Alignment = 1;
  997. break;
  998. case PNP_ADDRESS_BUS_NUMBER_TYPE:
  999. rangeDescriptor->Type = CmResourceTypeBusNumber;
  1000. rangeDescriptor->u.BusNumber.Length = (ULONG) length;
  1001. rangeDescriptor->u.BusNumber.MinBusNumber = (ULONG) (buffer->MinimumAddress);
  1002. rangeDescriptor->u.BusNumber.MaxBusNumber = (ULONG) (buffer->MaximumAddress);
  1003. //
  1004. // Handle busnumber flags
  1005. //
  1006. PnpiBiosAddressHandleBusFlags( buffer, rangeDescriptor );
  1007. break;
  1008. default:
  1009. ACPIPrint( (
  1010. ACPI_PRINT_WARNING,
  1011. "PnpiBiosAddressQuadToIoDescriptor: Unknown Type 0x%2x\n",
  1012. buffer->RFlag ) );
  1013. break;
  1014. }
  1015. //
  1016. // Handle global flags
  1017. //
  1018. PnpiBiosAddressHandleGlobalFlags( buffer, rangeDescriptor );
  1019. return STATUS_SUCCESS;
  1020. }
  1021. NTSTATUS
  1022. PnpiBiosDmaToIoDescriptor (
  1023. IN PUCHAR Data,
  1024. IN UCHAR Channel,
  1025. IN PIO_RESOURCE_LIST Array[],
  1026. IN ULONG ArrayIndex,
  1027. IN USHORT Count,
  1028. IN ULONG Flags
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. Arguments:
  1033. Return Value:
  1034. --*/
  1035. {
  1036. NTSTATUS status = STATUS_SUCCESS;
  1037. PIO_RESOURCE_DESCRIPTOR descriptor;
  1038. PPNP_DMA_DESCRIPTOR buffer;
  1039. PAGED_CODE();
  1040. ASSERT (Array != NULL);
  1041. buffer = (PPNP_DMA_DESCRIPTOR)Data;
  1042. //
  1043. // Ensure that there is enough space within the chosen list to add the
  1044. // resource
  1045. //
  1046. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
  1047. if (!NT_SUCCESS(status)) {
  1048. return status;
  1049. }
  1050. //
  1051. // Fill in Io resource descriptor
  1052. //
  1053. descriptor->Option = (Count ? IO_RESOURCE_ALTERNATIVE : 0);
  1054. descriptor->Type = CmResourceTypeDma;
  1055. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1056. descriptor->u.Dma.MinimumChannel = Channel;
  1057. descriptor->u.Dma.MaximumChannel = Channel;
  1058. //
  1059. // Set some information about the type of DMA channel
  1060. //
  1061. switch ( (buffer->Flags & PNP_DMA_SIZE_MASK) ) {
  1062. case PNP_DMA_SIZE_8:
  1063. descriptor->Flags |= CM_RESOURCE_DMA_8;
  1064. break;
  1065. case PNP_DMA_SIZE_8_AND_16:
  1066. descriptor->Flags |= CM_RESOURCE_DMA_8_AND_16;
  1067. break;
  1068. case PNP_DMA_SIZE_16:
  1069. descriptor->Flags |= CM_RESOURCE_DMA_16;
  1070. break;
  1071. case PNP_DMA_SIZE_RESERVED:
  1072. default:
  1073. ASSERT( (buffer->Flags & 0x3) == 0x3);
  1074. descriptor->Flags |= CM_RESOURCE_DMA_32;
  1075. break;
  1076. }
  1077. if ( (buffer->Flags & PNP_DMA_BUS_MASTER) ) {
  1078. descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
  1079. }
  1080. switch ( (buffer->Flags & PNP_DMA_TYPE_MASK) ) {
  1081. default:
  1082. case PNP_DMA_TYPE_COMPATIBLE:
  1083. break;
  1084. case PNP_DMA_TYPE_A:
  1085. descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A;
  1086. break;
  1087. case PNP_DMA_TYPE_B:
  1088. descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B;
  1089. break;
  1090. case PNP_DMA_TYPE_F:
  1091. descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F;
  1092. break;
  1093. }
  1094. return status;
  1095. }
  1096. NTSTATUS
  1097. PnpiBiosExtendedIrqToIoDescriptor (
  1098. IN PUCHAR Data,
  1099. IN UCHAR DataIndex,
  1100. IN PIO_RESOURCE_LIST Array[],
  1101. IN ULONG ArrayIndex,
  1102. IN ULONG Flags
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. Arguments:
  1107. Return Value:
  1108. --*/
  1109. {
  1110. NTSTATUS status = STATUS_SUCCESS;
  1111. PIO_RESOURCE_DESCRIPTOR descriptor;
  1112. PPNP_EXTENDED_IRQ_DESCRIPTOR buffer;
  1113. PULONG polarity;
  1114. PAGED_CODE();
  1115. ASSERT (Array != NULL);
  1116. buffer = (PPNP_EXTENDED_IRQ_DESCRIPTOR)Data;
  1117. //
  1118. // Are we within bounds?
  1119. //
  1120. if (DataIndex >= buffer->TableSize) {
  1121. return STATUS_INVALID_PARAMETER;
  1122. }
  1123. //
  1124. // Is the vector null? If so, then this is a 'skip' condition
  1125. //
  1126. if (buffer->Table[DataIndex] == 0) {
  1127. return STATUS_SUCCESS;
  1128. }
  1129. //
  1130. // Ensure that there is enough space within the chosen list to add the
  1131. // resource
  1132. //
  1133. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
  1134. if (!NT_SUCCESS(status)) {
  1135. return status;
  1136. }
  1137. //
  1138. // Fill in Io resource descriptor
  1139. //
  1140. descriptor->Option = (DataIndex ? IO_RESOURCE_ALTERNATIVE : 0);
  1141. descriptor->Type = CmResourceTypeInterrupt;
  1142. descriptor->u.Interrupt.MinimumVector =
  1143. descriptor->u.Interrupt.MaximumVector = buffer->Table[DataIndex];
  1144. //
  1145. // Crack the rest of the flags
  1146. //
  1147. descriptor->Flags = 0;
  1148. if ((buffer->Flags & PNP_EXTENDED_IRQ_MODE) == $LVL) {
  1149. descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1150. //
  1151. // Crack the share flags
  1152. //
  1153. if (buffer->Flags & PNP_EXTENDED_IRQ_SHARED) {
  1154. descriptor->ShareDisposition = CmResourceShareShared;
  1155. } else {
  1156. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1157. }
  1158. }
  1159. if ((buffer->Flags & PNP_EXTENDED_IRQ_MODE) == $EDG) {
  1160. descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  1161. //
  1162. // Crack the share flags
  1163. //
  1164. if (buffer->Flags & PNP_EXTENDED_IRQ_SHARED) {
  1165. descriptor->ShareDisposition = CmResourceShareDriverExclusive;
  1166. } else {
  1167. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1168. }
  1169. }
  1170. //
  1171. // Warning! Awful HACK coming.
  1172. //
  1173. // The original designer of the flags for CmResourceTypeInterrupt
  1174. // was bad. Instead of a bit field, it's an enum. Which means
  1175. // that we can't add any flags now. So I'm stuffing the interrupt
  1176. // polarity information into an unused DWORD of the IO_RES_LIST.
  1177. //
  1178. polarity = (PULONG)(&descriptor->u.Interrupt.MaximumVector) + 1;
  1179. if ((buffer->Flags & PNP_EXTENDED_IRQ_POLARITY) == $LOW) {
  1180. *polarity = VECTOR_ACTIVE_LOW;
  1181. } else {
  1182. *polarity = VECTOR_ACTIVE_HIGH;
  1183. }
  1184. //
  1185. // To show anything else, we will need to use device private
  1186. // resources
  1187. //
  1188. return status;
  1189. }
  1190. NTSTATUS
  1191. PnpiBiosIrqToIoDescriptor (
  1192. IN PUCHAR Data,
  1193. IN USHORT Interrupt,
  1194. IN PIO_RESOURCE_LIST Array[],
  1195. IN ULONG ArrayIndex,
  1196. IN USHORT Count,
  1197. IN ULONG Flags
  1198. )
  1199. /*++
  1200. Routine Description:
  1201. Arguments:
  1202. Return Value:
  1203. --*/
  1204. {
  1205. NTSTATUS status = STATUS_SUCCESS;
  1206. PIO_RESOURCE_DESCRIPTOR descriptor;
  1207. PPNP_IRQ_DESCRIPTOR buffer;
  1208. PULONG polarity;
  1209. PAGED_CODE();
  1210. ASSERT (Array != NULL);
  1211. buffer = (PPNP_IRQ_DESCRIPTOR)Data;
  1212. //
  1213. // Ensure that there is enough space within the chosen list to add the
  1214. // resource
  1215. //
  1216. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
  1217. if (!NT_SUCCESS(status)) {
  1218. return status;
  1219. }
  1220. //
  1221. // Fill in the resource descriptor
  1222. //
  1223. descriptor->Option = (Count ? IO_RESOURCE_ALTERNATIVE : 0);
  1224. descriptor->Type = CmResourceTypeInterrupt;
  1225. descriptor->u.Interrupt.MinimumVector = Interrupt;
  1226. descriptor->u.Interrupt.MaximumVector = Interrupt;
  1227. //
  1228. // Warning! Awful HACK coming.
  1229. //
  1230. // The original designer of the flags for CmResourceTypeInterrupt
  1231. // was bad. Instead of a bit field, it's an enum. Which means
  1232. // that we can't add any flags now. So I'm stuffing the interrupt
  1233. // polarity information into an unused DWORD of the IO_RES_LIST.
  1234. //
  1235. polarity = (PULONG)(&descriptor->u.Interrupt.MaximumVector) + 1;
  1236. if ( (buffer->Tag & SMALL_TAG_SIZE_MASK) == 3) {
  1237. //
  1238. // Set the type flags
  1239. //
  1240. descriptor->Flags = 0;
  1241. if (buffer->Information & PNP_IRQ_LATCHED) {
  1242. descriptor->Flags |= CM_RESOURCE_INTERRUPT_LATCHED;
  1243. *polarity = VECTOR_ACTIVE_HIGH;
  1244. //
  1245. // Set the share flags
  1246. //
  1247. if (buffer->Information & PNP_IRQ_SHARED) {
  1248. descriptor->ShareDisposition = CmResourceShareDriverExclusive;
  1249. } else {
  1250. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1251. }
  1252. }
  1253. if (buffer->Information & PNP_IRQ_LEVEL) {
  1254. descriptor->Flags |= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1255. *polarity = VECTOR_ACTIVE_LOW;
  1256. //
  1257. // Set the share flags
  1258. //
  1259. if (buffer->Information & PNP_IRQ_SHARED) {
  1260. descriptor->ShareDisposition = CmResourceShareShared;
  1261. } else {
  1262. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1263. }
  1264. }
  1265. } else {
  1266. descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  1267. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1268. }
  1269. return status;
  1270. }
  1271. NTSTATUS
  1272. PnpiBiosMemoryToIoDescriptor (
  1273. IN PUCHAR Data,
  1274. IN PIO_RESOURCE_LIST Array[],
  1275. IN ULONG ArrayIndex,
  1276. IN ULONG Flags
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. Arguments:
  1281. Return Value:
  1282. --*/
  1283. {
  1284. NTSTATUS status = STATUS_SUCCESS;
  1285. PHYSICAL_ADDRESS minAddr;
  1286. PHYSICAL_ADDRESS maxAddr;
  1287. PIO_RESOURCE_DESCRIPTOR descriptor;
  1288. UCHAR tag;
  1289. ULONG alignment;
  1290. ULONG length = 0;
  1291. USHORT flags;
  1292. PAGED_CODE();
  1293. ASSERT (Array != NULL);
  1294. //
  1295. // Grab the memory range limits
  1296. //
  1297. tag = ((PPNP_MEMORY_DESCRIPTOR)Data)->Tag;
  1298. minAddr.HighPart = 0;
  1299. maxAddr.HighPart = 0;
  1300. flags = 0;
  1301. //
  1302. // Setup the flags
  1303. //
  1304. if ( ((PPNP_MEMORY_DESCRIPTOR)Data)->Information & PNP_MEMORY_READ_WRITE) {
  1305. flags |= CM_RESOURCE_MEMORY_READ_WRITE;
  1306. } else {
  1307. flags |= CM_RESOURCE_MEMORY_READ_ONLY;
  1308. }
  1309. //
  1310. // Grab the other values from the descriptor
  1311. //
  1312. switch (tag) {
  1313. case TAG_MEMORY: {
  1314. PPNP_MEMORY_DESCRIPTOR buffer;
  1315. //
  1316. // 24 Bit Memory
  1317. //
  1318. flags |= CM_RESOURCE_MEMORY_24;
  1319. buffer = (PPNP_MEMORY_DESCRIPTOR) Data;
  1320. length = ( (ULONG)(buffer->MemorySize) ) << 8;
  1321. minAddr.LowPart =( (ULONG)(buffer->MinimumAddress) ) << 8;
  1322. maxAddr.LowPart =( ( (ULONG)(buffer->MaximumAddress) ) << 8) + length - 1;
  1323. if ( (alignment = buffer->Alignment) == 0) {
  1324. alignment = 0x10000;
  1325. }
  1326. break;
  1327. }
  1328. case TAG_MEMORY32: {
  1329. PPNP_MEMORY32_DESCRIPTOR buffer;
  1330. buffer = (PPNP_MEMORY32_DESCRIPTOR) Data;
  1331. length = buffer->MemorySize;
  1332. minAddr.LowPart = buffer->MinimumAddress;
  1333. maxAddr.LowPart = buffer->MaximumAddress +length - 1;
  1334. alignment = buffer->Alignment;
  1335. break;
  1336. }
  1337. case TAG_MEMORY32_FIXED: {
  1338. PPNP_FIXED_MEMORY32_DESCRIPTOR buffer;
  1339. buffer = (PPNP_FIXED_MEMORY32_DESCRIPTOR) Data;
  1340. length = buffer->MemorySize;
  1341. minAddr.LowPart = buffer->BaseAddress;
  1342. maxAddr.LowPart = minAddr.LowPart + length - 1;
  1343. alignment = 1;
  1344. break;
  1345. }
  1346. default:
  1347. ASSERT( (tag != TAG_MEMORY) && (tag != TAG_MEMORY32) &&
  1348. (tag != TAG_MEMORY32_FIXED) );
  1349. }
  1350. //
  1351. // If the length that we calculated is 0, then we don't have a real
  1352. // descriptor that we should report
  1353. //
  1354. if (length == 0) {
  1355. return STATUS_SUCCESS;
  1356. }
  1357. //
  1358. // Ensure that there is enough space within the chosen list to add the
  1359. // resource
  1360. //
  1361. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
  1362. if (!NT_SUCCESS(status)) {
  1363. return status;
  1364. }
  1365. //
  1366. // Fill in common memory buffers
  1367. //
  1368. descriptor->Type = CmResourceTypeMemory;
  1369. descriptor->Flags = (CM_RESOURCE_PORT_MEMORY | flags);
  1370. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1371. //
  1372. // Fill in Memory Descriptor
  1373. //
  1374. descriptor->u.Memory.MinimumAddress = minAddr;
  1375. descriptor->u.Memory.MaximumAddress = maxAddr;
  1376. descriptor->u.Memory.Alignment = alignment;
  1377. descriptor->u.Memory.Length = length;
  1378. return STATUS_SUCCESS;
  1379. }
  1380. NTSTATUS
  1381. PnpiBiosPortFixedToIoDescriptor (
  1382. IN PUCHAR Data,
  1383. IN PIO_RESOURCE_LIST Array[],
  1384. IN ULONG ArrayIndex,
  1385. IN ULONG Flags
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. Arguments:
  1390. Return Value:
  1391. --*/
  1392. {
  1393. NTSTATUS status = STATUS_SUCCESS;
  1394. PIO_RESOURCE_DESCRIPTOR descriptor;
  1395. PPNP_FIXED_PORT_DESCRIPTOR buffer;
  1396. PAGED_CODE();
  1397. ASSERT (Array != NULL);
  1398. buffer = (PPNP_FIXED_PORT_DESCRIPTOR)Data;
  1399. //
  1400. // Check to see if we are are allowed to use this resource
  1401. //
  1402. if (Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
  1403. return STATUS_SUCCESS;
  1404. }
  1405. //
  1406. // If the length of the descriptor is 0, then we don't have a descriptor
  1407. // that we can report to the OS
  1408. //
  1409. if (buffer->Length == 0 ) {
  1410. return STATUS_SUCCESS;
  1411. }
  1412. //
  1413. // Ensure that there is enough space within the chosen list to add the
  1414. // resource
  1415. //
  1416. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
  1417. if (!NT_SUCCESS(status)) {
  1418. return status;
  1419. }
  1420. //
  1421. // Fill in Io resource descriptor
  1422. //
  1423. descriptor->Type = CmResourceTypePort;
  1424. descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE;
  1425. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1426. descriptor->u.Port.Length = (ULONG)buffer->Length;
  1427. descriptor->u.Port.MinimumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff);
  1428. descriptor->u.Port.MaximumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff) +
  1429. (ULONG)buffer->Length - 1;
  1430. descriptor->u.Port.Alignment = 1;
  1431. return STATUS_SUCCESS;
  1432. }
  1433. NTSTATUS
  1434. PnpiBiosPortToIoDescriptor (
  1435. IN PUCHAR Data,
  1436. IN PIO_RESOURCE_LIST Array[],
  1437. IN ULONG ArrayIndex,
  1438. IN ULONG Flags
  1439. )
  1440. /*++
  1441. Routine Description:
  1442. Arguments:
  1443. Return Value:
  1444. --*/
  1445. {
  1446. NTSTATUS status = STATUS_SUCCESS;
  1447. PIO_RESOURCE_DESCRIPTOR descriptor;
  1448. PPNP_PORT_DESCRIPTOR buffer;
  1449. PAGED_CODE();
  1450. ASSERT (Array != NULL);
  1451. buffer = (PPNP_PORT_DESCRIPTOR)Data;
  1452. //
  1453. // Check to see if we are are allowed to use this resource
  1454. //
  1455. if (Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
  1456. return STATUS_SUCCESS;
  1457. }
  1458. //
  1459. // If the length of the descriptor is 0, then we don't have a descriptor
  1460. // that we can report to the OS
  1461. //
  1462. if (buffer->Length == 0 ) {
  1463. return STATUS_SUCCESS;
  1464. }
  1465. //
  1466. // Ensure that there is enough space within the chosen list to add the
  1467. // resource
  1468. //
  1469. status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
  1470. if (!NT_SUCCESS(status)) {
  1471. return status;
  1472. }
  1473. //
  1474. // Fill in Io resource descriptor
  1475. //
  1476. descriptor->Type = CmResourceTypePort;
  1477. descriptor->Flags = CM_RESOURCE_PORT_IO;
  1478. descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1479. descriptor->u.Port.Length = (ULONG)buffer->Length;
  1480. descriptor->u.Port.MinimumAddress.LowPart = (ULONG)buffer->MinimumAddress;
  1481. descriptor->u.Port.MaximumAddress.LowPart = (ULONG)buffer->MaximumAddress +
  1482. buffer->Length - 1;
  1483. descriptor->u.Port.Alignment = (ULONG)buffer->Alignment;
  1484. //
  1485. // Set the flags
  1486. //
  1487. switch (buffer->Information & PNP_PORT_DECODE_MASK) {
  1488. case PNP_PORT_10_BIT_DECODE:
  1489. descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
  1490. break;
  1491. default:
  1492. case PNP_PORT_16_BIT_DECODE:
  1493. descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
  1494. break;
  1495. }
  1496. return STATUS_SUCCESS;
  1497. }
  1498. VOID
  1499. PnpiClearAllocatedMemory(
  1500. IN PIO_RESOURCE_LIST ResourceArray[],
  1501. IN ULONG ResourceArraySize
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. This routine frees all the memory that was allocated in building the resource
  1506. lists in the system
  1507. Arguments:
  1508. ResourceArray - Table of PIO_RESOURCE_LIST
  1509. ResourceArraySize - How large the table is
  1510. Return Value:
  1511. VOID
  1512. --*/
  1513. {
  1514. ULONG i;
  1515. PAGED_CODE();
  1516. if (ResourceArray == NULL) {
  1517. return;
  1518. }
  1519. for (i = 0; i < ResourceArraySize; i++) {
  1520. if (ResourceArray[i] != NULL) {
  1521. ExFreePool( ResourceArray[i] );
  1522. }
  1523. }
  1524. ExFreePool( ResourceArray );
  1525. }
  1526. NTSTATUS
  1527. PnpiGrowResourceDescriptor(
  1528. IN OUT PIO_RESOURCE_LIST *ResourceList
  1529. )
  1530. /*++
  1531. Routine Description:
  1532. This routine takes a pointer to a Resource list and returns a pointer to resource list
  1533. that contained all the old information, but is now larger
  1534. Arguments:
  1535. ResourceList - ResourceList pointer to change
  1536. Return Value:
  1537. NTSTATUS (in case the memory allocation fails)
  1538. --*/
  1539. {
  1540. NTSTATUS status;
  1541. ULONG count = 0;
  1542. ULONG size = 0;
  1543. ULONG size2 = 0;
  1544. PAGED_CODE();
  1545. ASSERT( ResourceList != NULL );
  1546. //
  1547. // Are we looking at a null resource list???
  1548. //
  1549. if (*ResourceList == NULL) {
  1550. //
  1551. // Determine how much space is required
  1552. //
  1553. count = 0;
  1554. size = sizeof(IO_RESOURCE_LIST) + ( (count + 7) * sizeof(IO_RESOURCE_DESCRIPTOR) );
  1555. ACPIPrint( (
  1556. ACPI_PRINT_RESOURCES_2,
  1557. "PnpiGrowResourceDescriptor: Count: %d -> %d, Size: %#08lx\n",
  1558. count, count + RESOURCE_LIST_GROWTH_SIZE, size
  1559. ) );
  1560. //
  1561. // Allocate the ResourceList
  1562. //
  1563. *ResourceList = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
  1564. //
  1565. // Failed?
  1566. //
  1567. if (*ResourceList == NULL) {
  1568. return STATUS_INSUFFICIENT_RESOURCES;
  1569. }
  1570. //
  1571. // Init resource list
  1572. //
  1573. RtlZeroMemory( *ResourceList, size );
  1574. (*ResourceList)->Version = 0x01;
  1575. (*ResourceList)->Revision = 0x01;
  1576. (*ResourceList)->Count = 0x00;
  1577. return STATUS_SUCCESS;
  1578. }
  1579. //
  1580. // We already have a resource list, so what we should do is add 8 to the number of
  1581. // existing blocks that we have now, and copy over the old memory
  1582. //
  1583. count = (*ResourceList)->Count ;
  1584. size = sizeof(IO_RESOURCE_LIST) + ( (count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
  1585. size2 = size + (8 * sizeof(IO_RESOURCE_DESCRIPTOR) );
  1586. ACPIPrint( (
  1587. ACPI_PRINT_RESOURCES_2,
  1588. "PnpiGrowResourceDescriptor: Count: %d -> %d, Size: %#08lx\n",
  1589. count, count + RESOURCE_LIST_GROWTH_SIZE, size2
  1590. ) );
  1591. //
  1592. // Grow the List
  1593. //
  1594. status = ACPIInternalGrowBuffer( ResourceList, size, size2 );
  1595. return status;
  1596. }
  1597. NTSTATUS
  1598. PnpiGrowResourceList(
  1599. IN OUT PIO_RESOURCE_LIST *ResourceListArray[],
  1600. IN OUT ULONG *ResourceListArraySize
  1601. )
  1602. /*++
  1603. Routine Description:
  1604. This function is responsible for growing the array of resource lists
  1605. Arguments:
  1606. ResourceListArray - An array of pointers to IO_RESOURCE_LISTs
  1607. ResourceListSize - The current size of the array
  1608. Return Value:
  1609. NTSTATUS (in case memory allocation fails)
  1610. --*/
  1611. {
  1612. NTSTATUS status;
  1613. ULONG count;
  1614. ULONG size;
  1615. ULONG size2;
  1616. PAGED_CODE();
  1617. ASSERT( ResourceListArray != NULL);
  1618. //
  1619. // Its always a special case if the table is null
  1620. //
  1621. if ( *ResourceListArray == NULL || *ResourceListArraySize == 0) {
  1622. count = 0;
  1623. size = (count + RESOURCE_LIST_GROWTH_SIZE ) * sizeof(PIO_RESOURCE_LIST);
  1624. ACPIPrint( (
  1625. ACPI_PRINT_RESOURCES_2,
  1626. "PnpiGrowResourceList: Count: %d -> %d, Size: %#08lx\n",
  1627. count, count + RESOURCE_LIST_GROWTH_SIZE, size
  1628. ) );
  1629. //
  1630. // Allocate the ResourceListArray
  1631. //
  1632. *ResourceListArray = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
  1633. //
  1634. // Failed?
  1635. //
  1636. if (*ResourceListArray == NULL) {
  1637. return STATUS_INSUFFICIENT_RESOURCES;
  1638. }
  1639. //
  1640. // Increment the size
  1641. //
  1642. *ResourceListArraySize = count + RESOURCE_LIST_GROWTH_SIZE;
  1643. RtlZeroMemory( *ResourceListArray, size );
  1644. return STATUS_SUCCESS;
  1645. }
  1646. count = *ResourceListArraySize;
  1647. size = count * sizeof(PIO_RESOURCE_LIST);
  1648. size2 = size + (RESOURCE_LIST_GROWTH_SIZE * sizeof(PIO_RESOURCE_LIST));
  1649. ACPIPrint( (
  1650. ACPI_PRINT_RESOURCES_2,
  1651. "PnpiGrowResourceList: Count: %d -> %d, Size: %#08lx\n",
  1652. count, count + RESOURCE_LIST_GROWTH_SIZE, size2
  1653. ) );
  1654. status = ACPIInternalGrowBuffer( (PVOID *) ResourceListArray, size, size2 );
  1655. if (!NT_SUCCESS(status)) {
  1656. *ResourceListArraySize = 0;
  1657. } else {
  1658. *ResourceListArraySize = (count + RESOURCE_LIST_GROWTH_SIZE);
  1659. }
  1660. return status;
  1661. }
  1662. NTSTATUS
  1663. PnpiUpdateResourceList(
  1664. IN OUT PIO_RESOURCE_LIST *ResourceList,
  1665. OUT PIO_RESOURCE_DESCRIPTOR *ResourceDesc
  1666. )
  1667. /*++
  1668. Routine Description:
  1669. This function is called when a new resource is about to be added. This routine
  1670. ensures that enough space is present within the list, and gives a pointer to the
  1671. location of the Resource Descriptor where the list should be added...
  1672. Arguments:
  1673. ResourceList - Pointer to list to check
  1674. ResourceDesc - Location to store pointer to descriptor
  1675. Return Value:
  1676. NTSTATUS
  1677. --*/
  1678. {
  1679. NTSTATUS status = STATUS_SUCCESS;
  1680. PAGED_CODE();
  1681. ASSERT( ResourceList != NULL);
  1682. if ( *ResourceList == NULL ||
  1683. (*ResourceList)->Count % RESOURCE_LIST_GROWTH_SIZE == 0) {
  1684. //
  1685. // Oops, not enough space for the next descriptor
  1686. //
  1687. status = PnpiGrowResourceDescriptor( ResourceList );
  1688. if (!NT_SUCCESS(status)) {
  1689. return status;
  1690. }
  1691. }
  1692. //
  1693. // Find the next descriptor to use
  1694. //
  1695. *ResourceDesc = & ( (*ResourceList)->Descriptors[ (*ResourceList)->Count ] );
  1696. //
  1697. // Update the count of in-use descriptors
  1698. //
  1699. (*ResourceList)->Count += 1;
  1700. return status;
  1701. }
  1702. NTSTATUS
  1703. PnpBiosResourcesToNtResources(
  1704. IN PUCHAR Data,
  1705. IN ULONG Flags,
  1706. OUT PIO_RESOURCE_REQUIREMENTS_LIST *List
  1707. )
  1708. /*++
  1709. Routine Description:
  1710. This routine parses the Bios resource list and generates an NT resource list.
  1711. The returned NT resource list must be freed by the caller
  1712. Arguments:
  1713. Data - Pointer to PNP ISA Configuration Information
  1714. Flags - Options to use when parsing the data
  1715. List - Pointer to NT Configuration Information
  1716. Return Value:
  1717. NTSTATUS code
  1718. --*/
  1719. {
  1720. NTSTATUS status;
  1721. PIO_RESOURCE_LIST *Array = NULL;
  1722. PUCHAR buffer;
  1723. UCHAR tagName;
  1724. USHORT increment;
  1725. ULONG ArraySize = 0;
  1726. ULONG ArrayIndex = 0;
  1727. ULONG ArrayAlternateIndex = 0;
  1728. ULONG size;
  1729. ULONG size2;
  1730. ULONG ResourceCount = 0;
  1731. ULONG VendorTagCount = 0;
  1732. PAGED_CODE();
  1733. ASSERT( Data != NULL );
  1734. //
  1735. // First we need to build the pointer list
  1736. //
  1737. status = PnpiGrowResourceList( &Array, &ArraySize );
  1738. if (!NT_SUCCESS(status)) {
  1739. ACPIPrint( (
  1740. ACPI_PRINT_CRITICAL,
  1741. "PnpBiosResourcesToNtResources: PnpiGrowResourceList = 0x%8lx\n",
  1742. status ) );
  1743. return status;
  1744. }
  1745. //
  1746. // Setup initial variables
  1747. //
  1748. buffer = Data;
  1749. tagName = *buffer;
  1750. //
  1751. // Look through all the descriptors.
  1752. //
  1753. while (TRUE) {
  1754. //
  1755. // Determine the size of the PNP resource descriptor
  1756. //
  1757. if ( !(tagName & LARGE_RESOURCE_TAG) ) {
  1758. //
  1759. // Small Tag
  1760. //
  1761. increment = (USHORT) (tagName & SMALL_TAG_SIZE_MASK) + 1;
  1762. tagName &= SMALL_TAG_MASK;
  1763. ACPIPrint( (
  1764. ACPI_PRINT_RESOURCES_2,
  1765. "PnpBiosResourcesToNtResources: small = %#02lx incr = 0x%2lx\n",
  1766. tagName, increment ) );
  1767. } else {
  1768. //
  1769. // Large Tag
  1770. //
  1771. increment = ( *(USHORT UNALIGNED *)(buffer+1) ) + 3;
  1772. ACPIPrint( (
  1773. ACPI_PRINT_RESOURCES_2,
  1774. "PnpBiosResourcesToNtResources: large = %#02lx incr = 0x%2lx\n",
  1775. tagName, increment
  1776. ) );
  1777. }
  1778. //
  1779. // We are done if the current tag is the end tag
  1780. //
  1781. if (tagName == TAG_END) {
  1782. ACPIPrint( (
  1783. ACPI_PRINT_RESOURCES_2,
  1784. "PnpBiosResourcesToNtResources: TAG_END\n"
  1785. ) );
  1786. break;
  1787. }
  1788. ResourceCount++;
  1789. switch(tagName) {
  1790. case TAG_IRQ: {
  1791. USHORT mask = ( (PPNP_IRQ_DESCRIPTOR)buffer)->IrqMask;
  1792. USHORT interrupt = 0;
  1793. USHORT count = 0;
  1794. //
  1795. // Find all of interrupts to set
  1796. //
  1797. for ( ;mask && NT_SUCCESS(status); interrupt++, mask >>= 1) {
  1798. if (mask & 1) {
  1799. status = PnpiBiosIrqToIoDescriptor(
  1800. buffer,
  1801. interrupt,
  1802. Array,
  1803. ArrayIndex,
  1804. count,
  1805. Flags
  1806. );
  1807. count++;
  1808. }
  1809. }
  1810. ACPIPrint( (
  1811. ACPI_PRINT_RESOURCES_2,
  1812. "PnpBiosResourcesToNtResources: TAG_IRQ(count: 0x%2lx) "
  1813. "= 0x%8lx\n",
  1814. count, status
  1815. ) );
  1816. break;
  1817. }
  1818. case TAG_EXTENDED_IRQ: {
  1819. UCHAR tableSize =
  1820. ( (PPNP_EXTENDED_IRQ_DESCRIPTOR)buffer)->TableSize;
  1821. UCHAR irqCount = 0;
  1822. //
  1823. // For each of the interrupts to set, do
  1824. //
  1825. for ( ;irqCount < tableSize && NT_SUCCESS(status); irqCount++) {
  1826. status = PnpiBiosExtendedIrqToIoDescriptor(
  1827. buffer,
  1828. irqCount,
  1829. Array,
  1830. ArrayIndex,
  1831. Flags
  1832. );
  1833. }
  1834. ACPIPrint( (
  1835. ACPI_PRINT_RESOURCES_2,
  1836. "PnpBiosResourcesToNtResources: TAG_EXTENDED_IRQ(count: "
  1837. "0x%2lx) = 0x%8lx\n",
  1838. irqCount, status
  1839. ) );
  1840. break;
  1841. }
  1842. case TAG_DMA: {
  1843. UCHAR mask = ( (PPNP_DMA_DESCRIPTOR)buffer)->ChannelMask;
  1844. UCHAR channel = 0;
  1845. USHORT count = 0;
  1846. //
  1847. // Find all the dma's to set
  1848. //
  1849. for ( ;mask && NT_SUCCESS(status); channel++, mask >>= 1 ) {
  1850. if (mask & 1) {
  1851. status = PnpiBiosDmaToIoDescriptor(
  1852. buffer,
  1853. channel,
  1854. Array,
  1855. ArrayIndex,
  1856. count,
  1857. Flags
  1858. );
  1859. count++;
  1860. }
  1861. }
  1862. ACPIPrint( (
  1863. ACPI_PRINT_RESOURCES_2,
  1864. "PnpBiosResourcesToNtResources: TAG_DMA(count: 0x%2lx) "
  1865. "= 0x%8lx\n",
  1866. count, status
  1867. ) );
  1868. break;
  1869. }
  1870. case TAG_START_DEPEND: {
  1871. //
  1872. // Increment the alternate list index
  1873. //
  1874. ArrayAlternateIndex++;
  1875. //
  1876. // This is now our current index
  1877. //
  1878. ArrayIndex = ArrayAlternateIndex;
  1879. //
  1880. // We need to use DevicePrivate data to give the
  1881. // arbiter a helping hand
  1882. //
  1883. ACPIPrint( (
  1884. ACPI_PRINT_RESOURCES_2,
  1885. "PnpBiosResourcesToNtResources: TAG_START_DEPEND(Index: "
  1886. "0x%2lx)\n",
  1887. ArrayIndex
  1888. ) );
  1889. //
  1890. // Make sure that there is a pointer allocated for this index
  1891. //
  1892. if (ArrayIndex == ArraySize) {
  1893. //
  1894. // Not enough space
  1895. //
  1896. status = PnpiGrowResourceList( &Array, &ArraySize );
  1897. }
  1898. break;
  1899. }
  1900. case TAG_END_DEPEND: {
  1901. //
  1902. // Debug Info
  1903. //
  1904. ACPIPrint( (
  1905. ACPI_PRINT_RESOURCES_2,
  1906. "PnpBiosResourcesToNtResources: TAG_END_DEPEND(Index: "
  1907. "0x%2lx)\n",
  1908. ArrayIndex
  1909. ) );
  1910. //
  1911. // All we have to do is go back to our original index
  1912. //
  1913. ArrayIndex = 0;
  1914. break;
  1915. }
  1916. case TAG_IO: {
  1917. status = PnpiBiosPortToIoDescriptor(
  1918. buffer,
  1919. Array,
  1920. ArrayIndex,
  1921. Flags
  1922. );
  1923. ACPIPrint( (
  1924. ACPI_PRINT_RESOURCES_2,
  1925. "PnpBiosResourcesToNtResources: TAG_IO = 0x%8lx\n",
  1926. status
  1927. ) );
  1928. break;
  1929. }
  1930. case TAG_IO_FIXED: {
  1931. status = PnpiBiosPortFixedToIoDescriptor(
  1932. buffer,
  1933. Array,
  1934. ArrayIndex,
  1935. Flags
  1936. );
  1937. ACPIPrint( (
  1938. ACPI_PRINT_RESOURCES_2,
  1939. "PnpBiosResourcesToNtResources: TAG_IO_FIXED = 0x%8lx\n",
  1940. status
  1941. ) );
  1942. break;
  1943. }
  1944. case TAG_MEMORY:
  1945. case TAG_MEMORY32:
  1946. case TAG_MEMORY32_FIXED: {
  1947. status = PnpiBiosMemoryToIoDescriptor(
  1948. buffer,
  1949. Array,
  1950. ArrayIndex,
  1951. Flags
  1952. );
  1953. ACPIPrint( (
  1954. ACPI_PRINT_RESOURCES_2,
  1955. "PnpBiosResourcesToNtResources: TAG_MEMORY = 0x%8lx\n",
  1956. status
  1957. ) );
  1958. break;
  1959. }
  1960. case TAG_WORD_ADDRESS: {
  1961. status = PnpiBiosAddressToIoDescriptor(
  1962. buffer,
  1963. Array,
  1964. ArrayIndex,
  1965. Flags
  1966. );
  1967. ACPIPrint( (
  1968. ACPI_PRINT_RESOURCES_2,
  1969. "PnpBiosResourcesToNtResources: TAG_WORD_ADDRESS = 0x%8lx\n",
  1970. status
  1971. ) );
  1972. break;
  1973. }
  1974. case TAG_DOUBLE_ADDRESS: {
  1975. status = PnpiBiosAddressDoubleToIoDescriptor(
  1976. buffer,
  1977. Array,
  1978. ArrayIndex,
  1979. Flags
  1980. );
  1981. ACPIPrint( (
  1982. ACPI_PRINT_RESOURCES_2,
  1983. "PnpBiosResourcesToNtResources: TAG_DOUBLE_ADDRESS = 0x%8lx\n",
  1984. status
  1985. ) );
  1986. break;
  1987. }
  1988. case TAG_QUAD_ADDRESS: {
  1989. status = PnpiBiosAddressQuadToIoDescriptor(
  1990. buffer,
  1991. Array,
  1992. ArrayIndex,
  1993. Flags
  1994. );
  1995. ACPIPrint( (
  1996. ACPI_PRINT_RESOURCES_2,
  1997. "PnpBiosResourcesToNtResources: TAG_QUAD_ADDRESS = 0x%8lx\n",
  1998. status
  1999. ) );
  2000. break;
  2001. }
  2002. case TAG_VENDOR:
  2003. case TAG_VENDOR_LONG:{
  2004. //
  2005. // Ignore this tag. Skip over it.
  2006. //
  2007. VendorTagCount++;
  2008. status = STATUS_SUCCESS;
  2009. break;
  2010. }
  2011. default: {
  2012. //
  2013. // Unknown tag. Skip it
  2014. //
  2015. ACPIPrint( (
  2016. ACPI_PRINT_WARNING,
  2017. "PnpBiosResourceToNtResources: TAG_UNKNOWN(tagName:"
  2018. " 0x%2lx)\n",
  2019. tagName ) );
  2020. break;
  2021. }
  2022. } // switch
  2023. //
  2024. // Did we fail?
  2025. //
  2026. if (!NT_SUCCESS(status)) {
  2027. break;
  2028. }
  2029. //
  2030. // Move to the next descriptor
  2031. //
  2032. buffer += increment;
  2033. tagName = *buffer;
  2034. }
  2035. //
  2036. // This is a special case check for cases where a vendor has just a
  2037. // Vendor short or vendor long defined in the _CRS. In this case we
  2038. // dont need to allocate any resources and bail ...
  2039. //
  2040. if (NT_SUCCESS(status) && (ResourceCount) && (VendorTagCount == ResourceCount)) {
  2041. ACPIPrint( (
  2042. ACPI_PRINT_RESOURCES_2,
  2043. "PnpBiosResourcesToNtResources: This _CRS contains vendor defined tags only. No resources will be allocated.\n"
  2044. ) );
  2045. //
  2046. // Clean up any allocated memory and return
  2047. //
  2048. PnpiClearAllocatedMemory( Array, ArraySize );
  2049. *List = NULL;
  2050. return status;
  2051. }
  2052. //
  2053. // At this point, if everything is okay, we should be looking at the end tag
  2054. // If not, we will have a failed status value to account for it...
  2055. //
  2056. if (!NT_SUCCESS(status)) {
  2057. ACPIPrint( (
  2058. ACPI_PRINT_CRITICAL,
  2059. "PnpBiosResourcesToNtResources: Failed on Tag - %d Status %#08lx\n",
  2060. tagName, status
  2061. ) );
  2062. //
  2063. // Clean up any allocated memory and return
  2064. //
  2065. PnpiClearAllocatedMemory( Array, ArraySize );
  2066. return status;
  2067. }
  2068. //
  2069. // Now, we must figure out how many bytes to allocate for the lists...
  2070. // We can start out by determining the size of just the REQUIREMENT_LIST
  2071. //
  2072. size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - sizeof(IO_RESOURCE_LIST);
  2073. //
  2074. // How much many common resources are there?
  2075. //
  2076. if (Array[0] != NULL) {
  2077. size2 = Array[0]->Count;
  2078. } else {
  2079. size2 = 0;
  2080. }
  2081. //
  2082. // This is tricky. The first array is the list of resources that are
  2083. // common to *all* lists, so we don't begin by counting it. Rather, we
  2084. // figure out how much the other lists will take up
  2085. //
  2086. for (ArrayIndex = 1; ArrayIndex <= ArrayAlternateIndex; ArrayIndex++) {
  2087. if (Array[ArrayIndex] == NULL) {
  2088. ACPIPrint( (
  2089. ACPI_PRINT_CRITICAL,
  2090. "PnpBiosResourcesToNtResources: Bad List at Array[%d]\n",
  2091. ArrayIndex
  2092. ) );
  2093. PnpiClearAllocatedMemory( Array, ArraySize );
  2094. *List = NULL;
  2095. return STATUS_UNSUCCESSFUL;
  2096. }
  2097. //
  2098. // Just to make sure that we don't get tricked into adding an alternate list
  2099. // if we do not need to...
  2100. //
  2101. if ( (Array[ArrayIndex])->Count == 0) {
  2102. continue;
  2103. }
  2104. //
  2105. // How much space does the current Resource List take?
  2106. //
  2107. size += sizeof(IO_RESOURCE_LIST) +
  2108. ( (Array[ArrayIndex])->Count - 1 + size2) * sizeof(IO_RESOURCE_DESCRIPTOR);
  2109. ACPIPrint( (
  2110. ACPI_PRINT_RESOURCES_2,
  2111. "PnpBiosResourcesToNtResources: Index %d Size %#08lx\n",
  2112. ArrayIndex, size
  2113. ) );
  2114. } // for
  2115. //
  2116. // This is to account for the case where there are no dependent resources...
  2117. //
  2118. if (ArrayAlternateIndex == 0) {
  2119. if (Array[0] == NULL || Array[0]->Count == 0) {
  2120. ACPIPrint( (
  2121. ACPI_PRINT_WARNING,
  2122. "PnpBiosResourcesToNtResources: No Resources to Report\n"
  2123. ) );
  2124. PnpiClearAllocatedMemory( Array, ArraySize );
  2125. *List = NULL;
  2126. return STATUS_UNSUCCESSFUL;
  2127. }
  2128. size += ( (Array[0])->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) +
  2129. sizeof(IO_RESOURCE_LIST);
  2130. }
  2131. //
  2132. // This is a redundant check. If we don't have at least enough information
  2133. // to create a single list, then we should not be returning anything. Period.
  2134. //
  2135. if (size < sizeof(IO_RESOURCE_REQUIREMENTS_LIST) ) {
  2136. ACPIPrint( (
  2137. ACPI_PRINT_CRITICAL,
  2138. "PnpBiosResourcesToNtResources: Resources smaller than a List\n"
  2139. ) );
  2140. PnpiClearAllocatedMemory( Array, ArraySize );
  2141. *List = NULL;
  2142. return STATUS_UNSUCCESSFUL;
  2143. }
  2144. //
  2145. // Allocate the required amount of space
  2146. //
  2147. (*List) = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
  2148. ACPIPrint( (
  2149. ACPI_PRINT_RESOURCES_2,
  2150. "PnpBiosResourceToNtResources: ResourceRequirementsList = %#08lx (%#08lx)\n",
  2151. (*List), size ) );
  2152. if (*List == NULL) {
  2153. //
  2154. // Oops...
  2155. //
  2156. ACPIPrint( (
  2157. ACPI_PRINT_CRITICAL,
  2158. "PnpBiosResourceToNtResources: Could not allocate memory for "
  2159. "ResourceRequirementList\n" ) );
  2160. //
  2161. // Clean up any allocated memory and return
  2162. //
  2163. PnpiClearAllocatedMemory( Array, ArraySize );
  2164. return STATUS_INSUFFICIENT_RESOURCES;
  2165. }
  2166. RtlZeroMemory( (*List), size );
  2167. //
  2168. // Find the first place to store the information
  2169. //
  2170. (*List)->InterfaceType = PNPBus;
  2171. (*List)->BusNumber = 0;
  2172. (*List)->ListSize = size;
  2173. buffer = (PUCHAR) &( (*List)->List[0]);
  2174. for (ArrayIndex = 1; ArrayIndex <= ArrayAlternateIndex; ArrayIndex++) {
  2175. //
  2176. // Just to make sure that we don't get tricked into adding an alternate list
  2177. // if we do not need to...
  2178. //
  2179. if ( (Array[ArrayIndex])->Count == 0) {
  2180. continue;
  2181. }
  2182. //
  2183. // How much space does the current Resource List take?
  2184. //
  2185. size = ( ( (Array[ArrayIndex])->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) +
  2186. sizeof(IO_RESOURCE_LIST) );
  2187. //
  2188. // This is tricky. Using the sideeffect of if I upgrade the count field
  2189. // in the dependent resource descriptor, then when I copy it over, it will
  2190. // be correct, I avoid issues with trying to message with pointers at a
  2191. // later point in time.
  2192. //
  2193. (Array[ArrayIndex])->Count += size2;
  2194. ACPIPrint( (
  2195. ACPI_PRINT_RESOURCES_2,
  2196. "PnpBiosResourcesToNtResources: %d@%#08lx Size %#04lx Items %#04x\n",
  2197. ArrayIndex, buffer, size, (Array[ArrayIndex])->Count
  2198. ) );
  2199. //
  2200. // Copy the resources
  2201. //
  2202. RtlCopyMemory(buffer, Array[ArrayIndex], size );
  2203. buffer += size;
  2204. //
  2205. // Now we account for the common resources
  2206. //
  2207. if (size2) {
  2208. RtlCopyMemory(
  2209. buffer,
  2210. &( (Array[0])->Descriptors[0]),
  2211. size2 * sizeof(IO_RESOURCE_DESCRIPTOR)
  2212. );
  2213. buffer += (size2 * sizeof(IO_RESOURCE_DESCRIPTOR));
  2214. }
  2215. //
  2216. // Update the number of alternate lists in the ResourceRequirement List
  2217. //
  2218. (*List)->AlternativeLists += 1;
  2219. }
  2220. //
  2221. // This check is required because we might just have a common list, with
  2222. // no dependent resources...
  2223. //
  2224. if (ArrayAlternateIndex == 0) {
  2225. ASSERT( size2 != 0 );
  2226. size = (size2 - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) + sizeof(IO_RESOURCE_LIST);
  2227. RtlCopyMemory(buffer,Array[0],size);
  2228. (*List)->AlternativeLists += 1;
  2229. }
  2230. //
  2231. // Clean up the copies
  2232. //
  2233. PnpiClearAllocatedMemory( Array, ArraySize );
  2234. return STATUS_SUCCESS;
  2235. }
  2236. NTSTATUS
  2237. PnpIoResourceListToCmResourceList(
  2238. IN PIO_RESOURCE_REQUIREMENTS_LIST IoList,
  2239. IN OUT PCM_RESOURCE_LIST *CmList
  2240. )
  2241. /*++
  2242. Routine Description:
  2243. This routine takes an IO_RESOURCE_REQUIREMENTS_LIST and generates a
  2244. CM_RESOURCE_LIST
  2245. Arguments:
  2246. IoList - The list to convert
  2247. CmList - Points to pointer of where to store the new list. The caller is
  2248. responsible for freeing this
  2249. Return Value:
  2250. NTSTATUS
  2251. --*/
  2252. {
  2253. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
  2254. PCM_PARTIAL_RESOURCE_LIST cmPartialList;
  2255. PCM_RESOURCE_LIST cmList;
  2256. PIO_RESOURCE_DESCRIPTOR ioDesc;
  2257. PIO_RESOURCE_LIST ioResList;
  2258. ULONG size;
  2259. ULONG count;
  2260. PAGED_CODE();
  2261. *CmList = NULL;
  2262. //
  2263. // As a trivial check, if there are no lists, than we can simply return
  2264. //
  2265. if (IoList == NULL || IoList->List == NULL || IoList->List[0].Count == 0) {
  2266. return STATUS_INVALID_DEVICE_REQUEST;
  2267. }
  2268. //
  2269. // The first step is to allocate the correct number of bytes for the CmList. The
  2270. // first simplifying assumptions that can be me is that the IoList will not have
  2271. // more than one alternative.
  2272. //
  2273. size = (IoList->List[0].Count - 1) * sizeof( CM_PARTIAL_RESOURCE_DESCRIPTOR ) +
  2274. sizeof( CM_RESOURCE_LIST );
  2275. //
  2276. // Now, allocate this block of memory
  2277. //
  2278. cmList = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
  2279. if (cmList == NULL) {
  2280. return STATUS_INSUFFICIENT_RESOURCES;
  2281. }
  2282. RtlZeroMemory( cmList, size );
  2283. //
  2284. // Setup the initial values for the CmList
  2285. //
  2286. ioResList = &(IoList->List[0]);
  2287. cmList->Count = 1;
  2288. cmList->List[0].InterfaceType = IoList->InterfaceType;
  2289. cmList->List[0].BusNumber = IoList->BusNumber;
  2290. cmPartialList = &(cmList->List[0].PartialResourceList);
  2291. cmPartialList->Version = 1;
  2292. cmPartialList->Revision = 1;
  2293. cmPartialList->Count = ioResList->Count;
  2294. for (count = 0; count < ioResList->Count; count++) {
  2295. //
  2296. // Grab the current CmDescriptor and IoDescriptor
  2297. //
  2298. cmDesc = &(cmPartialList->PartialDescriptors[count]);
  2299. ioDesc = &(ioResList->Descriptors[count]);
  2300. //
  2301. // Now, copy the information from one descriptor to another
  2302. //
  2303. cmDesc->Type = ioDesc->Type;
  2304. cmDesc->ShareDisposition = ioDesc->ShareDisposition;
  2305. cmDesc->Flags = ioDesc->Flags;
  2306. switch (cmDesc->Type) {
  2307. case CmResourceTypeBusNumber:
  2308. cmDesc->u.BusNumber.Start = ioDesc->u.BusNumber.MinBusNumber;
  2309. cmDesc->u.BusNumber.Length = ioDesc->u.BusNumber.Length;
  2310. break;
  2311. case CmResourceTypePort:
  2312. cmDesc->u.Port.Length = ioDesc->u.Port.Length;
  2313. cmDesc->u.Port.Start = ioDesc->u.Port.MinimumAddress;
  2314. break;
  2315. case CmResourceTypeInterrupt:
  2316. cmDesc->u.Interrupt.Level =
  2317. cmDesc->u.Interrupt.Vector = ioDesc->u.Interrupt.MinimumVector;
  2318. cmDesc->u.Interrupt.Affinity = (ULONG)-1;
  2319. break;
  2320. case CmResourceTypeMemory:
  2321. cmDesc->u.Memory.Length = ioDesc->u.Memory.Length;
  2322. cmDesc->u.Memory.Start = ioDesc->u.Memory.MinimumAddress;
  2323. break;
  2324. case CmResourceTypeDma:
  2325. cmDesc->u.Dma.Channel = ioDesc->u.Dma.MinimumChannel;
  2326. cmDesc->u.Dma.Port = 0;
  2327. break;
  2328. default:
  2329. case CmResourceTypeDevicePrivate:
  2330. cmDesc->u.DevicePrivate.Data[0] = ioDesc->u.DevicePrivate.Data[0];
  2331. cmDesc->u.DevicePrivate.Data[1] = ioDesc->u.DevicePrivate.Data[1];
  2332. cmDesc->u.DevicePrivate.Data[2] = ioDesc->u.DevicePrivate.Data[2];
  2333. break;
  2334. }
  2335. }
  2336. //
  2337. // Let the caller know he has a good list
  2338. //
  2339. *CmList = cmList;
  2340. return STATUS_SUCCESS;
  2341. }
  2342. NTSTATUS
  2343. PnpCmResourceListToIoResourceList(
  2344. IN PCM_RESOURCE_LIST CmList,
  2345. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoList
  2346. )
  2347. /*++
  2348. Routine Description:
  2349. This routine generates an IO_RESOURCE_REQUIREMENTS_LIST and from a
  2350. CM_RESOURCE_LIST
  2351. Arguments:
  2352. CmList - The list to convert
  2353. IoList - Points to pointer of where to store the new list. The caller is
  2354. responsible for freeing this
  2355. Return Value:
  2356. NTSTATUS
  2357. --*/
  2358. {
  2359. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
  2360. PCM_PARTIAL_RESOURCE_LIST cmPartialList;
  2361. PIO_RESOURCE_DESCRIPTOR ioDesc;
  2362. PIO_RESOURCE_LIST ioResList;
  2363. PIO_RESOURCE_REQUIREMENTS_LIST ioList;
  2364. ULONG size;
  2365. ULONG count;
  2366. PAGED_CODE();
  2367. *IoList = NULL;
  2368. //
  2369. // As a trivial check, if there are no lists, than we can simply return
  2370. //
  2371. if (CmList == NULL || CmList->List == NULL ||
  2372. CmList->List[0].PartialResourceList.Count == 0) {
  2373. return STATUS_INVALID_DEVICE_REQUEST;
  2374. }
  2375. //
  2376. // Grab the partial list to make walking it easier
  2377. //
  2378. cmPartialList = &(CmList->List[0].PartialResourceList);
  2379. //
  2380. // How much space do we need for the IO list?
  2381. //
  2382. size = (cmPartialList->Count - 1) * sizeof( IO_RESOURCE_DESCRIPTOR ) +
  2383. sizeof( IO_RESOURCE_REQUIREMENTS_LIST );
  2384. //
  2385. // Now, allocate this block of memory
  2386. //
  2387. ioList = ExAllocatePoolWithTag( NonPagedPool, size, ACPI_RESOURCE_POOLTAG );
  2388. if (ioList == NULL) {
  2389. return STATUS_INSUFFICIENT_RESOURCES;
  2390. }
  2391. RtlZeroMemory( ioList, size );
  2392. //
  2393. // Setup the initial values for the IoList
  2394. //
  2395. ioList->ListSize = size;
  2396. ioList->AlternativeLists = 1;
  2397. ioList->InterfaceType = CmList->List[0].InterfaceType;
  2398. ioList->BusNumber = CmList->List[0].BusNumber;
  2399. //
  2400. // Setup the initialize value for the ioResList
  2401. //
  2402. ioResList = &(ioList->List[0]);
  2403. ioResList->Count = cmPartialList->Count;
  2404. ioResList->Version = cmPartialList->Version;
  2405. ioResList->Revision = cmPartialList->Revision;
  2406. //
  2407. // Loop for all the elements in the partial list
  2408. //
  2409. for (count = 0; count < ioResList->Count; count++) {
  2410. //
  2411. // Grab the current CmDescriptor and IoDescriptor
  2412. //
  2413. cmDesc = &(cmPartialList->PartialDescriptors[count]);
  2414. ioDesc = &(ioResList->Descriptors[count]);
  2415. //
  2416. // Now, copy the information from one descriptor to another
  2417. //
  2418. ioDesc->Type = cmDesc->Type;
  2419. ioDesc->ShareDisposition = cmDesc->ShareDisposition;
  2420. ioDesc->Flags = cmDesc->Flags;
  2421. switch (cmDesc->Type) {
  2422. case CmResourceTypeMemory:
  2423. case CmResourceTypePort:
  2424. ioDesc->u.Port.Length = cmDesc->u.Port.Length;
  2425. ioDesc->u.Port.MinimumAddress = cmDesc->u.Port.Start;
  2426. ioDesc->u.Port.MaximumAddress = cmDesc->u.Port.Start;
  2427. ioDesc->u.Port.MaximumAddress.LowPart += cmDesc->u.Port.Length - 1;
  2428. ioDesc->u.Port.Alignment = 1;
  2429. break;
  2430. case CmResourceTypeInterrupt:
  2431. ioDesc->u.Interrupt.MinimumVector = cmDesc->u.Interrupt.Vector;
  2432. ioDesc->u.Interrupt.MaximumVector = cmDesc->u.Interrupt.Vector;
  2433. break;
  2434. case CmResourceTypeDma:
  2435. ioDesc->u.Dma.MinimumChannel = cmDesc->u.Dma.Channel;
  2436. ioDesc->u.Dma.MaximumChannel = cmDesc->u.Dma.Channel;
  2437. break;
  2438. case CmResourceTypeBusNumber:
  2439. ioDesc->u.BusNumber.MinBusNumber = cmDesc->u.BusNumber.Start;
  2440. ioDesc->u.BusNumber.MaxBusNumber = cmDesc->u.BusNumber.Length +
  2441. cmDesc->u.BusNumber.Start;
  2442. ioDesc->u.BusNumber.Length = cmDesc->u.BusNumber.Length;
  2443. break;
  2444. default:
  2445. case CmResourceTypeDevicePrivate:
  2446. ioDesc->u.DevicePrivate.Data[0] = cmDesc->u.DevicePrivate.Data[0];
  2447. ioDesc->u.DevicePrivate.Data[1] = cmDesc->u.DevicePrivate.Data[1];
  2448. ioDesc->u.DevicePrivate.Data[2] = cmDesc->u.DevicePrivate.Data[2];
  2449. break;
  2450. }
  2451. }
  2452. *IoList = ioList;
  2453. return STATUS_SUCCESS;
  2454. }