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.

1899 lines
56 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. convert.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. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. Note:
  14. This file is shared between the io subsystem and the ISAPNP bus driver.
  15. It is not compiled directly but is included by:
  16. base\ntos\io\pnpmgr\pnpcvrt.c
  17. base\busdrv\isapnp\convert.c
  18. ***** If you change this file make sure you build in *BOTH* places *****
  19. --*/
  20. #include "pbios.h"
  21. #include "pnpcvrt.h"
  22. #if UMODETEST
  23. #undef IsNEC_98
  24. #define IsNEC_98 0
  25. #endif
  26. //
  27. // internal structures for resource translation
  28. //
  29. typedef struct _PB_DEPENDENT_RESOURCES {
  30. ULONG Count;
  31. UCHAR Flags;
  32. UCHAR Priority;
  33. struct _PB_DEPENDENT_RESOURCES *Next;
  34. } PB_DEPENDENT_RESOURCES, *PPB_DEPENDENT_RESOURCES;
  35. #define DEPENDENT_FLAGS_END 1
  36. typedef struct _PB_ATERNATIVE_INFORMATION {
  37. PPB_DEPENDENT_RESOURCES Resources;
  38. ULONG NoDependentFunctions;
  39. ULONG TotalResourceCount;
  40. } PB_ALTERNATIVE_INFORMATION, *PPB_ALTERNATIVE_INFORMATION;
  41. //
  42. // Internal function references
  43. //
  44. PPB_DEPENDENT_RESOURCES
  45. PbAddDependentResourcesToList (
  46. IN OUT PUCHAR *ResourceDescriptor,
  47. IN ULONG ListNo,
  48. IN PPB_ALTERNATIVE_INFORMATION AlternativeList
  49. );
  50. NTSTATUS
  51. PbBiosIrqToIoDescriptor (
  52. IN OUT PUCHAR *BiosData,
  53. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor
  54. );
  55. NTSTATUS
  56. PbBiosDmaToIoDescriptor (
  57. IN OUT PUCHAR *BiosData,
  58. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor
  59. );
  60. NTSTATUS
  61. PbBiosPortFixedToIoDescriptor (
  62. IN OUT PUCHAR *BiosData,
  63. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor,
  64. IN BOOLEAN ForceFixedIoTo16bit
  65. );
  66. NTSTATUS
  67. PbBiosPortToIoDescriptor (
  68. IN OUT PUCHAR *BiosData,
  69. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor
  70. );
  71. NTSTATUS
  72. PbBiosMemoryToIoDescriptor (
  73. IN OUT PUCHAR *BiosData,
  74. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor
  75. );
  76. NTSTATUS
  77. PpCmResourcesToBiosResources (
  78. IN PCM_RESOURCE_LIST CmResources,
  79. IN PUCHAR BiosRequirements,
  80. IN PUCHAR *BiosResources,
  81. IN PULONG Length
  82. );
  83. NTSTATUS
  84. PbCmIrqToBiosDescriptor (
  85. IN PUCHAR BiosRequirements,
  86. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  87. OUT PVOID ReturnDescriptor,
  88. OUT PULONG Length
  89. );
  90. NTSTATUS
  91. PbCmDmaToBiosDescriptor (
  92. IN PUCHAR BiosRequirements,
  93. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  94. OUT PVOID ReturnDescriptor,
  95. OUT PULONG Length
  96. );
  97. NTSTATUS
  98. PbCmPortToBiosDescriptor (
  99. IN PUCHAR BiosRequirements,
  100. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  101. OUT PVOID ReturnDescriptor,
  102. OUT PULONG Length
  103. );
  104. NTSTATUS
  105. PbCmMemoryToBiosDescriptor (
  106. IN PUCHAR BiosRequirements,
  107. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  108. OUT PVOID ReturnDescriptor,
  109. OUT PULONG Length
  110. );
  111. #ifdef ALLOC_PRAGMA
  112. #pragma alloc_text(PAGE, PpBiosResourcesToNtResources)
  113. #pragma alloc_text(PAGE, PpBiosResourcesSetToDisabled)
  114. #pragma alloc_text(PAGE, PbAddDependentResourcesToList)
  115. #pragma alloc_text(PAGE, PbBiosIrqToIoDescriptor)
  116. #pragma alloc_text(PAGE, PbBiosDmaToIoDescriptor)
  117. #pragma alloc_text(PAGE, PbBiosPortFixedToIoDescriptor)
  118. #pragma alloc_text(PAGE, PbBiosPortToIoDescriptor)
  119. #pragma alloc_text(PAGE, PbBiosMemoryToIoDescriptor)
  120. #pragma alloc_text(PAGE, PpCmResourcesToBiosResources)
  121. #pragma alloc_text(PAGE, PbCmIrqToBiosDescriptor)
  122. #pragma alloc_text(PAGE, PbCmDmaToBiosDescriptor)
  123. #pragma alloc_text(PAGE, PbCmPortToBiosDescriptor)
  124. #pragma alloc_text(PAGE, PbCmMemoryToBiosDescriptor)
  125. #endif
  126. #ifdef ALLOC_DATA_PRAGMA
  127. #pragma data_seg("PAGEDATA")
  128. #endif
  129. NTSTATUS
  130. PpBiosResourcesToNtResources (
  131. IN ULONG BusNumber,
  132. IN ULONG SlotNumber,
  133. IN OUT PUCHAR *BiosData,
  134. IN ULONG ConvertFlags,
  135. OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList,
  136. OUT PULONG ReturnedLength
  137. )
  138. /*++
  139. Routine Description:
  140. This routine parses the Bios resource list and generates
  141. a NT resource list. The returned Nt resource list could be either IO
  142. format or CM format. It is caller's responsibility to release the
  143. returned data buffer.
  144. Arguments:
  145. SlotNumber - specifies the slot number of the BIOS resource.
  146. BiosData - Supplies a pointer to a variable which specifies the bios resource
  147. data buffer and which to receive the pointer to next bios resource data.
  148. ReturnedList - supplies a variable to receive the desired resource list.
  149. ReturnedLength - Supplies a variable to receive the length of the resource list.
  150. Return Value:
  151. NTSTATUS code
  152. --*/
  153. {
  154. PUCHAR buffer;
  155. USHORT mask16, increment;
  156. UCHAR tagName, mask8;
  157. NTSTATUS status;
  158. PPB_ALTERNATIVE_INFORMATION alternativeList = NULL;
  159. ULONG commonResCount = 0, dependDescCount = 0, i, j;
  160. ULONG alternativeListCount = 0, dependFunctionCount = 0;
  161. PIO_RESOURCE_DESCRIPTOR ioDesc;
  162. PPB_DEPENDENT_RESOURCES dependResList = NULL, dependResources;
  163. BOOLEAN dependent = FALSE;
  164. BOOLEAN forceFixedIoTo16bit;
  165. ULONG listSize, noResLists;
  166. ULONG totalDescCount, descCount;
  167. PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList;
  168. PIO_RESOURCE_LIST ioResList;
  169. PAGED_CODE();
  170. //
  171. // First, scan the bios data to determine the memory requirement and
  172. // the information to build internal data structures.
  173. //
  174. *ReturnedLength = 0;
  175. alternativeListCount = 0;
  176. buffer = *BiosData;
  177. tagName = *buffer;
  178. forceFixedIoTo16bit =
  179. (BOOLEAN)((ConvertFlags & PPCONVERTFLAG_FORCE_FIXED_IO_16BIT_DECODE) != 0);
  180. for ( ; ; ) {
  181. //
  182. // Determine the size of the BIOS resource descriptor
  183. //
  184. if (!(tagName & LARGE_RESOURCE_TAG)) {
  185. increment = (USHORT)(tagName & SMALL_TAG_SIZE_MASK);
  186. increment += 1; // length of small tag
  187. tagName &= SMALL_TAG_MASK;
  188. } else {
  189. increment = *(USHORT UNALIGNED *)(buffer+1);
  190. increment += 3; // length of large tag
  191. }
  192. if (tagName == TAG_END) {
  193. buffer += increment;
  194. break;
  195. }
  196. //
  197. // Based on the type of the BIOS resource, determine the count of
  198. // the IO descriptors.
  199. //
  200. switch (tagName) {
  201. case TAG_IRQ:
  202. mask16 = ((PPNP_IRQ_DESCRIPTOR)buffer)->IrqMask;
  203. i = 0;
  204. while (mask16) {
  205. if(mask16 & 1) {
  206. i++;
  207. }
  208. mask16 >>= 1;
  209. }
  210. if (!dependent) {
  211. commonResCount += i;
  212. } else {
  213. dependDescCount += i;
  214. }
  215. break;
  216. case TAG_DMA:
  217. mask8 = ((PPNP_DMA_DESCRIPTOR)buffer)->ChannelMask;
  218. i = 0;
  219. while (mask8) {
  220. if (mask8 & 1) {
  221. i++;
  222. }
  223. mask8 >>= 1;
  224. }
  225. if (!dependent) {
  226. commonResCount += i;
  227. } else {
  228. dependDescCount += i;
  229. }
  230. break;
  231. case TAG_START_DEPEND:
  232. dependent = TRUE;
  233. dependFunctionCount++;
  234. break;
  235. case TAG_END_DEPEND:
  236. dependent = FALSE;
  237. alternativeListCount++;
  238. break;
  239. case TAG_IO_FIXED:
  240. case TAG_IO:
  241. case TAG_MEMORY:
  242. case TAG_MEMORY32:
  243. case TAG_MEMORY32_FIXED:
  244. if (!dependent) {
  245. commonResCount++;
  246. } else {
  247. dependDescCount++;
  248. }
  249. break;
  250. default:
  251. //
  252. // Unknown tag. Skip it.
  253. //
  254. break;
  255. }
  256. //
  257. // Move to next bios resource descriptor.
  258. //
  259. buffer += increment;
  260. tagName = *buffer;
  261. if ((tagName & SMALL_TAG_MASK) == TAG_LOGICAL_ID) {
  262. break;
  263. }
  264. }
  265. if (dependent) {
  266. //
  267. // TAG_END_DEPEND was not found before we hit TAG_COMPLETE_END, so
  268. // simulate it.
  269. //
  270. dependent = FALSE;
  271. alternativeListCount++;
  272. }
  273. //
  274. // if empty bios resources, simply return.
  275. //
  276. if (commonResCount == 0 && dependFunctionCount == 0) {
  277. *ReturnedList = NULL;
  278. *ReturnedLength = 0;
  279. *BiosData = buffer;
  280. return STATUS_SUCCESS;
  281. }
  282. //
  283. // Allocate memory for our internal data structures
  284. //
  285. dependFunctionCount += commonResCount;
  286. dependResources = (PPB_DEPENDENT_RESOURCES)ExAllocatePoolWithTag(
  287. PagedPool,
  288. dependFunctionCount * sizeof(PB_DEPENDENT_RESOURCES) +
  289. (commonResCount + dependDescCount) * sizeof(IO_RESOURCE_DESCRIPTOR),
  290. 'bPnP'
  291. );
  292. if (!dependResources) {
  293. return STATUS_INSUFFICIENT_RESOURCES;
  294. }
  295. dependResList = dependResources; // remember it so we can free it.
  296. alternativeListCount += commonResCount;
  297. alternativeList = (PPB_ALTERNATIVE_INFORMATION)ExAllocatePoolWithTag(
  298. PagedPool,
  299. sizeof(PB_ALTERNATIVE_INFORMATION) * (alternativeListCount + 1),
  300. 'bPnP'
  301. );
  302. if (!alternativeList) {
  303. status = STATUS_INSUFFICIENT_RESOURCES;
  304. goto exit0;
  305. }
  306. RtlZeroMemory(alternativeList,
  307. sizeof(PB_ALTERNATIVE_INFORMATION) * alternativeListCount
  308. );
  309. alternativeList[0].Resources = dependResources;
  310. ioDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1);
  311. //
  312. // Now start over again to process the bios data and initialize our internal
  313. // resource representation.
  314. //
  315. dependDescCount = 0;
  316. alternativeListCount = 0;
  317. buffer = *BiosData;
  318. tagName = *buffer;
  319. dependent = FALSE;
  320. for ( ; ; ) {
  321. if (!(tagName & LARGE_RESOURCE_TAG)) {
  322. tagName &= SMALL_TAG_MASK;
  323. }
  324. if (tagName == TAG_END) {
  325. buffer += (*buffer & SMALL_TAG_SIZE_MASK) + 1;
  326. break;
  327. }
  328. switch (tagName) {
  329. case TAG_DMA:
  330. case TAG_IRQ:
  331. case TAG_IO:
  332. case TAG_IO_FIXED:
  333. case TAG_MEMORY:
  334. case TAG_MEMORY32:
  335. case TAG_MEMORY32_FIXED:
  336. if (tagName == TAG_DMA) {
  337. status = PbBiosDmaToIoDescriptor(&buffer, ioDesc);
  338. } else if (tagName == TAG_IRQ) {
  339. status = PbBiosIrqToIoDescriptor(&buffer, ioDesc);
  340. } else if (tagName == TAG_IO) {
  341. status = PbBiosPortToIoDescriptor(&buffer, ioDesc);
  342. } else if (tagName == TAG_IO_FIXED) {
  343. status = PbBiosPortFixedToIoDescriptor(&buffer, ioDesc, forceFixedIoTo16bit);
  344. } else {
  345. status = PbBiosMemoryToIoDescriptor(&buffer, ioDesc);
  346. }
  347. if (NT_SUCCESS(status)) {
  348. ioDesc++;
  349. if (dependent) {
  350. dependDescCount++;
  351. } else {
  352. alternativeList[alternativeListCount].NoDependentFunctions = 1;
  353. alternativeList[alternativeListCount].TotalResourceCount = 1;
  354. dependResources->Count = 1;
  355. dependResources->Flags = DEPENDENT_FLAGS_END;
  356. dependResources->Next = alternativeList[alternativeListCount].Resources;
  357. alternativeListCount++;
  358. alternativeList[alternativeListCount].Resources = (PPB_DEPENDENT_RESOURCES)ioDesc;
  359. dependResources = alternativeList[alternativeListCount].Resources;
  360. ioDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1);
  361. }
  362. }
  363. break;
  364. case TAG_START_DEPEND:
  365. //
  366. // Some card (OPTI) put empty START_DEPENDENT functions
  367. //
  368. dependent = TRUE;
  369. if (alternativeList[alternativeListCount].NoDependentFunctions != 0) {
  370. //
  371. // End of current dependent function
  372. //
  373. dependResources->Count = dependDescCount;
  374. dependResources->Flags = 0;
  375. dependResources->Next = (PPB_DEPENDENT_RESOURCES)ioDesc;
  376. dependResources = dependResources->Next;
  377. ioDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1);
  378. alternativeList[alternativeListCount].TotalResourceCount += dependDescCount;
  379. }
  380. alternativeList[alternativeListCount].NoDependentFunctions++;
  381. if (*buffer & SMALL_TAG_SIZE_MASK) {
  382. dependResources->Priority = *(buffer + 1);
  383. }
  384. dependDescCount = 0;
  385. buffer += 1 + (*buffer & SMALL_TAG_SIZE_MASK);
  386. break;
  387. case TAG_END_DEPEND:
  388. alternativeList[alternativeListCount].TotalResourceCount += dependDescCount;
  389. dependResources->Count = dependDescCount;
  390. dependResources->Flags = DEPENDENT_FLAGS_END;
  391. dependResources->Next = alternativeList[alternativeListCount].Resources;
  392. dependent = FALSE;
  393. dependDescCount = 0;
  394. alternativeListCount++;
  395. alternativeList[alternativeListCount].Resources = (PPB_DEPENDENT_RESOURCES)ioDesc;
  396. dependResources = alternativeList[alternativeListCount].Resources;
  397. ioDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1);
  398. buffer++;
  399. break;
  400. default:
  401. //
  402. // Don't-care tag simply advance the buffer pointer to next tag.
  403. //
  404. if (*buffer & LARGE_RESOURCE_TAG) {
  405. increment = *(USHORT UNALIGNED *)(buffer+1);
  406. increment += 3; // length of large tag
  407. } else {
  408. increment = (USHORT)(*buffer & SMALL_TAG_SIZE_MASK);
  409. increment += 1; // length of small tag
  410. }
  411. buffer += increment;
  412. }
  413. tagName = *buffer;
  414. if ((tagName & SMALL_TAG_MASK) == TAG_LOGICAL_ID) {
  415. break;
  416. }
  417. }
  418. if (dependent) {
  419. //
  420. // TAG_END_DEPEND was not found before we hit TAG_COMPLETE_END, so
  421. // simulate it.
  422. //
  423. alternativeList[alternativeListCount].TotalResourceCount += dependDescCount;
  424. dependResources->Count = dependDescCount;
  425. dependResources->Flags = DEPENDENT_FLAGS_END;
  426. dependResources->Next = alternativeList[alternativeListCount].Resources;
  427. dependent = FALSE;
  428. dependDescCount = 0;
  429. alternativeListCount++;
  430. alternativeList[alternativeListCount].Resources = (PPB_DEPENDENT_RESOURCES)ioDesc;
  431. dependResources = alternativeList[alternativeListCount].Resources;
  432. ioDesc = (PIO_RESOURCE_DESCRIPTOR)(dependResources + 1);
  433. }
  434. if (alternativeListCount != 0) {
  435. alternativeList[alternativeListCount].Resources = NULL; // dummy alternativeList record
  436. }
  437. *BiosData = buffer;
  438. //
  439. // prepare IoResourceList
  440. //
  441. noResLists = 1;
  442. for (i = 0; i < alternativeListCount; i++) {
  443. noResLists *= alternativeList[i].NoDependentFunctions;
  444. }
  445. totalDescCount = 0;
  446. for (i = 0; i < alternativeListCount; i++) {
  447. descCount = 1;
  448. for (j = 0; j < alternativeListCount; j++) {
  449. if (j == i) {
  450. descCount *= alternativeList[j].TotalResourceCount;
  451. } else {
  452. descCount *= alternativeList[j].NoDependentFunctions;
  453. }
  454. }
  455. totalDescCount += descCount;
  456. }
  457. listSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  458. sizeof(IO_RESOURCE_LIST) * (noResLists - 1) +
  459. sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescCount -
  460. sizeof(IO_RESOURCE_DESCRIPTOR) * noResLists +
  461. sizeof(IO_RESOURCE_DESCRIPTOR) * commonResCount * noResLists;
  462. if (ConvertFlags & PPCONVERTFLAG_SET_RESTART_LCPRI) {
  463. listSize += noResLists * sizeof(IO_RESOURCE_DESCRIPTOR);
  464. }
  465. ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePoolWithTag(PagedPool, listSize, 'bPnP');
  466. if (!ioResReqList) {
  467. status = STATUS_INSUFFICIENT_RESOURCES;
  468. goto exit1;
  469. }
  470. ioResReqList->ListSize = listSize;
  471. ioResReqList->InterfaceType = Isa;
  472. ioResReqList->BusNumber = BusNumber;
  473. ioResReqList->SlotNumber = SlotNumber;
  474. ioResReqList->Reserved[0] = 0;
  475. ioResReqList->Reserved[1] = 0;
  476. ioResReqList->Reserved[2] = 0;
  477. ioResReqList->AlternativeLists = noResLists;
  478. ioResList = &ioResReqList->List[0];
  479. //
  480. // Build resource lists
  481. //
  482. for (i = 0; i < noResLists; i++) {
  483. ioResList->Version = 1;
  484. ioResList->Revision = 0x30 | (USHORT)i;
  485. if (ConvertFlags & PPCONVERTFLAG_SET_RESTART_LCPRI) {
  486. RtlZeroMemory(&ioResList->Descriptors[0], sizeof(IO_RESOURCE_DESCRIPTOR));
  487. ioResList->Descriptors[0].Option = IO_RESOURCE_PREFERRED;
  488. ioResList->Descriptors[0].Type = CmResourceTypeConfigData;
  489. ioResList->Descriptors[0].u.ConfigData.Priority = LCPRI_RESTART;
  490. buffer = (PUCHAR)&ioResList->Descriptors[1];
  491. } else {
  492. buffer = (PUCHAR)&ioResList->Descriptors[0];
  493. }
  494. //
  495. // Copy dependent functions if any.
  496. //
  497. if (alternativeList) {
  498. PbAddDependentResourcesToList(&buffer, 0, alternativeList);
  499. }
  500. //
  501. // Update io resource list ptr
  502. //
  503. ioResList->Count = ((ULONG)((ULONG_PTR)buffer - (ULONG_PTR)&ioResList->Descriptors[0])) /
  504. sizeof(IO_RESOURCE_DESCRIPTOR);
  505. //
  506. // Hack for user mode pnp mgr
  507. //
  508. for (j = 0; j < ioResList->Count; j++) {
  509. ioResList->Descriptors[j].Spare2 = (USHORT)j;
  510. }
  511. ioResList = (PIO_RESOURCE_LIST)buffer;
  512. }
  513. *ReturnedLength = listSize;
  514. status = STATUS_SUCCESS;
  515. *ReturnedList = ioResReqList;
  516. exit1:
  517. if (alternativeList) {
  518. ExFreePool(alternativeList);
  519. }
  520. exit0:
  521. if (dependResList) {
  522. ExFreePool(dependResList);
  523. }
  524. return status;
  525. }
  526. VOID
  527. PpBiosResourcesSetToDisabled (
  528. IN OUT PUCHAR BiosData,
  529. OUT PULONG Length
  530. )
  531. /*++
  532. Routine Description:
  533. This routine modifies the passed in Bios resource list so that it reflects
  534. what PnPBIOS expects to see if a device is disabled.
  535. Arguments:
  536. BiosData - Supplies a pointer to the bios resource data buffer
  537. Length - This points to a ULONG that will contain the length of the single
  538. resource list that has been programmed to look disabled.
  539. Return Value:
  540. None.
  541. --*/
  542. {
  543. PUCHAR buffer;
  544. USHORT increment;
  545. UCHAR tagName;
  546. PAGED_CODE();
  547. //
  548. // First, scan the bios data to determine the memory requirement and
  549. // the information to build internal data structures.
  550. //
  551. buffer = BiosData;
  552. do {
  553. tagName = *buffer;
  554. //
  555. // Determine the size of the BIOS resource descriptor
  556. //
  557. if (!(tagName & LARGE_RESOURCE_TAG)) {
  558. increment = (USHORT)(tagName & SMALL_TAG_SIZE_MASK);
  559. tagName &= SMALL_TAG_MASK;
  560. //
  561. // Be careful not to wipe out the version field. That's very bad.
  562. //
  563. if (tagName != TAG_VERSION) {
  564. RtlZeroMemory(buffer+1, increment);
  565. }
  566. increment += 1; // length of small tag
  567. } else {
  568. increment = *(USHORT UNALIGNED *)(buffer+1);
  569. RtlZeroMemory(buffer+3, increment);
  570. increment += 3; // length of large tag
  571. }
  572. buffer += increment;
  573. } while (tagName != TAG_END) ;
  574. *Length = (ULONG)(buffer - BiosData) ;
  575. }
  576. PPB_DEPENDENT_RESOURCES
  577. PbAddDependentResourcesToList (
  578. IN OUT PUCHAR *ResourceDescriptor,
  579. IN ULONG ListNo,
  580. IN PPB_ALTERNATIVE_INFORMATION AlternativeList
  581. )
  582. /*++
  583. Routine Description:
  584. This routine adds dependent functions to caller specified list.
  585. Arguments:
  586. ResourceDescriptor - supplies a pointer to the descriptor buffer.
  587. ListNo - supplies an index to the AlternativeList.
  588. AlternativeList - supplies a pointer to the alternativelist array.
  589. Return Value:
  590. return NTSTATUS code to indicate the result of the operation.
  591. --*/
  592. {
  593. PPB_DEPENDENT_RESOURCES dependentResources, ptr;
  594. ULONG size;
  595. PAGED_CODE();
  596. //
  597. // Copy dependent resources to caller supplied list buffer and
  598. // update the list buffer pointer.
  599. //
  600. dependentResources = AlternativeList[ListNo].Resources;
  601. size = sizeof(IO_RESOURCE_DESCRIPTOR) * dependentResources->Count;
  602. RtlMoveMemory(*ResourceDescriptor, dependentResources + 1, size);
  603. *ResourceDescriptor = *ResourceDescriptor + size;
  604. //
  605. // Add dependent resource of next list to caller's buffer
  606. //
  607. if (AlternativeList[ListNo + 1].Resources) {
  608. ptr = PbAddDependentResourcesToList(ResourceDescriptor, ListNo + 1, AlternativeList);
  609. } else {
  610. ptr = NULL;
  611. }
  612. if (ptr == NULL) {
  613. AlternativeList[ListNo].Resources = dependentResources->Next;
  614. if (!(dependentResources->Flags & DEPENDENT_FLAGS_END)) {
  615. ptr = dependentResources->Next;
  616. }
  617. }
  618. return ptr;
  619. }
  620. NTSTATUS
  621. PbBiosIrqToIoDescriptor (
  622. IN OUT PUCHAR *BiosData,
  623. PIO_RESOURCE_DESCRIPTOR IoDescriptor
  624. )
  625. /*++
  626. Routine Description:
  627. This routine translates BIOS IRQ information to NT usable format.
  628. This routine stops when an irq io resource is generated. if there are
  629. more irq io resource descriptors available, the BiosData pointer will
  630. not advance. So caller will pass us the same resource tag again.
  631. Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated
  632. for each seperated channel required.
  633. Arguments:
  634. BiosData - Supplies a pointer to the bios resource data buffer.
  635. IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer.
  636. Converted resource will be stored here.
  637. Return Value:
  638. return NTSTATUS code to indicate the result of the operation.
  639. --*/
  640. {
  641. static ULONG bitPosition = 0;
  642. USHORT mask;
  643. ULONG irq;
  644. PPNP_IRQ_DESCRIPTOR buffer;
  645. UCHAR size, option;
  646. NTSTATUS status = STATUS_SUCCESS;
  647. PAGED_CODE();
  648. buffer = (PPNP_IRQ_DESCRIPTOR)*BiosData;
  649. //
  650. // if this is not the first descriptor for the tag, set
  651. // its option to alternative.
  652. //
  653. if (bitPosition == 0) {
  654. option = 0;
  655. } else {
  656. option = IO_RESOURCE_ALTERNATIVE;
  657. }
  658. size = buffer->Tag & SMALL_TAG_SIZE_MASK;
  659. mask = buffer->IrqMask;
  660. mask >>= bitPosition;
  661. irq = (ULONG) -1;
  662. while (mask) {
  663. if (mask & 1) {
  664. irq = bitPosition;
  665. break;
  666. }
  667. mask >>= 1;
  668. bitPosition++;
  669. }
  670. //
  671. // Fill in Io resource descriptor
  672. //
  673. if (irq != (ULONG)-1) {
  674. IoDescriptor->Option = option;
  675. IoDescriptor->Type = CmResourceTypeInterrupt;
  676. IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  677. IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  678. if (size == 3 && buffer->Information & 0x0C) {
  679. IoDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  680. IoDescriptor->ShareDisposition = CmResourceShareShared;
  681. }
  682. IoDescriptor->Spare1 = 0;
  683. IoDescriptor->Spare2 = 0;
  684. IoDescriptor->u.Interrupt.MinimumVector = irq;
  685. IoDescriptor->u.Interrupt.MaximumVector = irq;
  686. } else {
  687. status = STATUS_INVALID_PARAMETER;
  688. }
  689. if (NT_SUCCESS(status)) {
  690. //
  691. // try to move bitPosition to next 1 bit.
  692. //
  693. while (mask) {
  694. mask >>= 1;
  695. bitPosition++;
  696. if (mask & 1) {
  697. return status;
  698. }
  699. }
  700. }
  701. //
  702. // Done with current irq tag, advance pointer to next tag
  703. //
  704. bitPosition = 0;
  705. *BiosData = (PUCHAR)buffer + size + 1;
  706. return status;
  707. }
  708. NTSTATUS
  709. PbBiosDmaToIoDescriptor (
  710. IN OUT PUCHAR *BiosData,
  711. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor
  712. )
  713. /*++
  714. Routine Description:
  715. This routine translates BIOS DMA information to NT usable format.
  716. This routine stops when an dma io resource is generated. if there are
  717. more dma io resource descriptors available, the BiosData pointer will
  718. not advance. So caller will pass us the same resource tag again.
  719. Note, BIOS DMA info alway uses SMALL TAG. A tag structure is repeated
  720. for each seperated channel required.
  721. Arguments:
  722. BiosData - Supplies a pointer to the bios resource data buffer.
  723. IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer.
  724. Converted resource will be stored here.
  725. Return Value:
  726. return NTSTATUS code to indicate the result of the operation.
  727. --*/
  728. {
  729. static ULONG bitPosition = 0;
  730. ULONG dma;
  731. PPNP_DMA_DESCRIPTOR buffer;
  732. UCHAR mask, option;
  733. NTSTATUS status = STATUS_SUCCESS;
  734. PAGED_CODE();
  735. buffer = (PPNP_DMA_DESCRIPTOR)*BiosData;
  736. //
  737. // if this is not the first descriptor for the tag, set
  738. // its option to alternative.
  739. //
  740. if (bitPosition == 0) {
  741. option = 0;
  742. } else {
  743. option = IO_RESOURCE_ALTERNATIVE;
  744. }
  745. mask = buffer->ChannelMask;
  746. mask >>= bitPosition;
  747. dma = (ULONG) -1;
  748. while (mask) {
  749. if (mask & 1) {
  750. dma = bitPosition;
  751. break;
  752. }
  753. mask >>= 1;
  754. bitPosition++;
  755. }
  756. //
  757. // Fill in Io resource descriptor
  758. //
  759. if (dma != (ULONG)-1) {
  760. IoDescriptor->Option = option;
  761. IoDescriptor->Type = CmResourceTypeDma;
  762. IoDescriptor->Flags = 0;
  763. IoDescriptor->ShareDisposition = CmResourceShareUndetermined;
  764. IoDescriptor->Spare1 = 0;
  765. IoDescriptor->Spare2 = 0;
  766. IoDescriptor->u.Dma.MinimumChannel = dma;
  767. IoDescriptor->u.Dma.MaximumChannel = dma;
  768. } else {
  769. status = STATUS_INVALID_PARAMETER;
  770. }
  771. if (NT_SUCCESS(status)) {
  772. //
  773. // try to move bitPosition to next 1 bit.
  774. //
  775. while (mask) {
  776. mask >>= 1;
  777. bitPosition++;
  778. if (mask & 1) {
  779. return status;
  780. }
  781. }
  782. }
  783. //
  784. // Done with current dma tag, advance pointer to next tag
  785. //
  786. bitPosition = 0;
  787. buffer += 1;
  788. *BiosData = (PUCHAR)buffer;
  789. return status;
  790. }
  791. NTSTATUS
  792. PbBiosPortFixedToIoDescriptor (
  793. IN OUT PUCHAR *BiosData,
  794. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor,
  795. IN BOOLEAN ForceFixedIoTo16bit
  796. )
  797. /*++
  798. Routine Description:
  799. This routine translates BIOS FIXED IO information to NT usable format.
  800. Arguments:
  801. BiosData - Supplies a pointer to the bios resource data buffer.
  802. IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer.
  803. Converted resource will be stored here.
  804. ForceFixedIoTo16bit - hack option to force fixed I/O resources to 16bit
  805. for far too pessimistic BIOS's.
  806. Return Value:
  807. return NTSTATUS code to indicate the result of the operation.
  808. --*/
  809. {
  810. PPNP_FIXED_PORT_DESCRIPTOR buffer;
  811. PAGED_CODE();
  812. buffer = (PPNP_FIXED_PORT_DESCRIPTOR)*BiosData;
  813. //
  814. // Fill in Io resource descriptor
  815. //
  816. IoDescriptor->Option = 0;
  817. IoDescriptor->Type = CmResourceTypePort;
  818. if (ForceFixedIoTo16bit) {
  819. IoDescriptor->Flags = CM_RESOURCE_PORT_IO + CM_RESOURCE_PORT_16_BIT_DECODE;
  820. } else {
  821. IoDescriptor->Flags = CM_RESOURCE_PORT_IO + CM_RESOURCE_PORT_10_BIT_DECODE;
  822. }
  823. #if defined(_X86_)
  824. //
  825. // Workaround:
  826. // NEC PC9800 series's PnPBIOS report I/O resources between 0x00 and 0xFF as FIXED IO.
  827. // But These resources are 16bit DECODE resource, not 10bit DECODE one. We need to check
  828. // the range of I/O resources .
  829. //
  830. if (IsNEC_98) {
  831. if ( (ULONG)buffer->MinimumAddress < 0x100 ) {
  832. IoDescriptor->Flags = CM_RESOURCE_PORT_IO + CM_RESOURCE_PORT_16_BIT_DECODE;
  833. }
  834. }
  835. #endif // <--end changing code
  836. IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  837. IoDescriptor->Spare1 = 0;
  838. IoDescriptor->Spare2 = 0;
  839. IoDescriptor->u.Port.Length = (ULONG)buffer->Length;
  840. IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff);
  841. IoDescriptor->u.Port.MinimumAddress.HighPart = 0;
  842. IoDescriptor->u.Port.MaximumAddress.LowPart = IoDescriptor->u.Port.MinimumAddress.LowPart +
  843. IoDescriptor->u.Port.Length - 1;
  844. IoDescriptor->u.Port.MaximumAddress.HighPart = 0;
  845. IoDescriptor->u.Port.Alignment = 1;
  846. //
  847. // Done with current fixed port tag, advance pointer to next tag
  848. //
  849. buffer += 1;
  850. *BiosData = (PUCHAR)buffer;
  851. return STATUS_SUCCESS;
  852. }
  853. NTSTATUS
  854. PbBiosPortToIoDescriptor (
  855. IN OUT PUCHAR *BiosData,
  856. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor
  857. )
  858. /*++
  859. Routine Description:
  860. This routine translates BIOS IO information to NT usable format.
  861. Arguments:
  862. BiosData - Supplies a pointer to the bios resource data buffer.
  863. IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer.
  864. Converted resource will be stored here.
  865. Return Value:
  866. return NTSTATUS code to indicate the result of the operation.
  867. --*/
  868. {
  869. PPNP_PORT_DESCRIPTOR buffer;
  870. PAGED_CODE();
  871. buffer = (PPNP_PORT_DESCRIPTOR)*BiosData;
  872. //
  873. // Fill in Io resource descriptor
  874. //
  875. IoDescriptor->Option = 0;
  876. IoDescriptor->Type = CmResourceTypePort;
  877. IoDescriptor->Flags = CM_RESOURCE_PORT_IO;
  878. if (buffer->Information & 1) {
  879. IoDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
  880. } else {
  881. IoDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
  882. }
  883. IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  884. IoDescriptor->Spare1 = 0;
  885. IoDescriptor->Spare2 = 0;
  886. IoDescriptor->u.Port.Length = (ULONG)buffer->Length;
  887. #if defined(_X86_)
  888. if (IsNEC_98) {
  889. if (buffer->Information & 0x80) {
  890. IoDescriptor->u.Port.Length *= 2;
  891. }
  892. }
  893. #endif
  894. IoDescriptor->u.Port.MinimumAddress.LowPart = (ULONG)buffer->MinimumAddress;
  895. IoDescriptor->u.Port.MinimumAddress.HighPart = 0;
  896. IoDescriptor->u.Port.MaximumAddress.LowPart = (ULONG)buffer->MaximumAddress +
  897. IoDescriptor->u.Port.Length - 1;
  898. IoDescriptor->u.Port.MaximumAddress.HighPart = 0;
  899. IoDescriptor->u.Port.Alignment = (ULONG)buffer->Alignment;
  900. //
  901. // Done with current fixed port tag, advance pointer to next tag
  902. //
  903. buffer += 1;
  904. *BiosData = (PUCHAR)buffer;
  905. return STATUS_SUCCESS;
  906. }
  907. NTSTATUS
  908. PbBiosMemoryToIoDescriptor (
  909. IN OUT PUCHAR *BiosData,
  910. IN PIO_RESOURCE_DESCRIPTOR IoDescriptor
  911. )
  912. /*++
  913. Routine Description:
  914. This routine translates BIOS MEMORY information to NT usable format.
  915. Arguments:
  916. BiosData - Supplies a pointer to the bios resource data buffer.
  917. IoDescriptor - supplies a pointer to an IO_RESOURCE_DESCRIPTOR buffer.
  918. Converted resource will be stored here.
  919. Return Value:
  920. return NTSTATUS code to indicate the result of the operation.
  921. --*/
  922. {
  923. PUCHAR buffer;
  924. UCHAR tag;
  925. PHYSICAL_ADDRESS minAddr, maxAddr;
  926. ULONG alignment, length;
  927. USHORT increment;
  928. USHORT flags = 0;
  929. PAGED_CODE();
  930. buffer = *BiosData;
  931. tag = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Tag;
  932. increment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Length + 3; // larg tag size = 3
  933. minAddr.HighPart = 0;
  934. maxAddr.HighPart = 0;
  935. switch (tag) {
  936. case TAG_MEMORY:
  937. minAddr.LowPart = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MinimumAddress)) << 8;
  938. if ((alignment = ((PPNP_MEMORY_DESCRIPTOR)buffer)->Alignment) == 0) {
  939. alignment = 0x10000;
  940. }
  941. length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MemorySize)) << 8;
  942. maxAddr.LowPart = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)buffer)->MaximumAddress)) << 8) + length - 1;
  943. flags = CM_RESOURCE_MEMORY_24;
  944. break;
  945. case TAG_MEMORY32:
  946. length = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MemorySize;
  947. minAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MinimumAddress;
  948. maxAddr.LowPart = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->MaximumAddress + length - 1;
  949. alignment = ((PPNP_MEMORY32_DESCRIPTOR)buffer)->Alignment;
  950. break;
  951. case TAG_MEMORY32_FIXED:
  952. length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->MemorySize;
  953. minAddr.LowPart = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)buffer)->BaseAddress;
  954. maxAddr.LowPart = minAddr.LowPart + length - 1;
  955. alignment = 1;
  956. break;
  957. default:
  958. alignment = 0;
  959. length = 0;
  960. break;
  961. }
  962. //
  963. // Fill in Io resource descriptor
  964. //
  965. IoDescriptor->Option = 0;
  966. IoDescriptor->Type = CmResourceTypeMemory;
  967. IoDescriptor->Flags = CM_RESOURCE_PORT_MEMORY + flags;
  968. IoDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  969. IoDescriptor->Spare1 = 0;
  970. IoDescriptor->Spare2 = 0;
  971. IoDescriptor->u.Memory.MinimumAddress = minAddr;
  972. IoDescriptor->u.Memory.MaximumAddress = maxAddr;
  973. IoDescriptor->u.Memory.Alignment = alignment;
  974. IoDescriptor->u.Memory.Length = length;
  975. //
  976. // Done with current tag, advance pointer to next tag
  977. //
  978. buffer += increment;
  979. *BiosData = (PUCHAR)buffer;
  980. return STATUS_SUCCESS;
  981. }
  982. NTSTATUS
  983. PpCmResourcesToBiosResources (
  984. IN PCM_RESOURCE_LIST CmResources,
  985. IN PUCHAR BiosRequirements,
  986. IN PUCHAR *BiosResources,
  987. IN PULONG Length
  988. )
  989. /*++
  990. Routine Description:
  991. This routine parses the Cm resource list and generates
  992. a Pnp BIOS resource list. It is caller's responsibility to release the
  993. returned data buffer.
  994. Arguments:
  995. CmResources - Supplies a pointer to a Cm resource list buffer.
  996. BiosRequirements - supplies a pointer to the PnP BIOS possible resources.
  997. BiosResources - Supplies a variable to receive the pointer to the
  998. converted bios resource buffer.
  999. Length - supplies a pointer to a variable to receive the length
  1000. of the Pnp Bios resources.
  1001. Return Value:
  1002. a pointer to a Pnp Bios resource list if succeeded. Else,
  1003. a NULL pointer will be returned.
  1004. --*/
  1005. {
  1006. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  1007. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
  1008. ULONG i, l, count, length, totalSize = 0;
  1009. PUCHAR p, px;
  1010. PNP_MEMORY_DESCRIPTOR biosDesc;
  1011. NTSTATUS status;
  1012. PAGED_CODE();
  1013. *BiosResources = NULL;
  1014. *Length = 0;
  1015. CmResources->Count;
  1016. if (CmResources->Count == 0) {
  1017. return STATUS_SUCCESS;
  1018. }
  1019. //
  1020. // Determine pool size needed
  1021. //
  1022. count = 0;
  1023. cmFullDesc = &CmResources->List[0];
  1024. for (l = 0; l < CmResources->Count; l++) {
  1025. cmDesc = cmFullDesc->PartialResourceList.PartialDescriptors;
  1026. for (i = 0; i < cmFullDesc->PartialResourceList.Count; i++) {
  1027. switch (cmDesc->Type) {
  1028. case CmResourceTypePort:
  1029. case CmResourceTypeInterrupt:
  1030. case CmResourceTypeMemory:
  1031. case CmResourceTypeDma:
  1032. count++;
  1033. cmDesc++;
  1034. break;
  1035. case CmResourceTypeDeviceSpecific:
  1036. length = cmDesc->u.DeviceSpecificData.DataSize;
  1037. cmDesc++;
  1038. cmDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDesc + length);
  1039. break;
  1040. default:
  1041. count++;
  1042. cmDesc++;
  1043. break;
  1044. }
  1045. }
  1046. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDesc;
  1047. }
  1048. if (count == 0) {
  1049. return STATUS_SUCCESS;
  1050. }
  1051. //
  1052. // Allocate max amount of memory
  1053. //
  1054. px = p= ExAllocatePoolWithTag(PagedPool,
  1055. count * sizeof(PNP_MEMORY_DESCRIPTOR),
  1056. 'bPnP');
  1057. if (!p) {
  1058. return STATUS_INSUFFICIENT_RESOURCES;
  1059. }
  1060. status = STATUS_RESOURCE_TYPE_NOT_FOUND;
  1061. cmFullDesc = &CmResources->List[0];
  1062. for (l = 0; l < CmResources->Count; l++) {
  1063. cmDesc = cmFullDesc->PartialResourceList.PartialDescriptors;
  1064. for (i = 0; i < cmFullDesc->PartialResourceList.Count; i++) {
  1065. switch (cmDesc->Type) {
  1066. case CmResourceTypePort:
  1067. status = PbCmPortToBiosDescriptor (
  1068. BiosRequirements,
  1069. cmDesc,
  1070. &biosDesc,
  1071. &length
  1072. );
  1073. break;
  1074. case CmResourceTypeInterrupt:
  1075. status = PbCmIrqToBiosDescriptor(
  1076. BiosRequirements,
  1077. cmDesc,
  1078. &biosDesc,
  1079. &length
  1080. );
  1081. break;
  1082. case CmResourceTypeMemory:
  1083. status = PbCmMemoryToBiosDescriptor (
  1084. BiosRequirements,
  1085. cmDesc,
  1086. &biosDesc,
  1087. &length
  1088. );
  1089. break;
  1090. case CmResourceTypeDma:
  1091. status = PbCmDmaToBiosDescriptor (
  1092. BiosRequirements,
  1093. cmDesc,
  1094. &biosDesc,
  1095. &length
  1096. );
  1097. break;
  1098. case CmResourceTypeDeviceSpecific:
  1099. length = cmDesc->u.DeviceSpecificData.DataSize;
  1100. cmDesc++;
  1101. cmDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDesc + length);
  1102. continue;
  1103. default:
  1104. cmDesc++;
  1105. continue;
  1106. }
  1107. if (NT_SUCCESS(status)) {
  1108. cmDesc++;
  1109. RtlCopyMemory(p, &biosDesc, length);
  1110. p += length;
  1111. totalSize += length;
  1112. } else {
  1113. ExFreePool(px);
  1114. goto exit;
  1115. }
  1116. }
  1117. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDesc;
  1118. }
  1119. exit:
  1120. if (NT_SUCCESS(status)) {
  1121. *p = TAG_COMPLETE_END;
  1122. p++;
  1123. *p = 0; // checksum ignored
  1124. totalSize += 2;
  1125. *BiosResources = px;
  1126. *Length = totalSize;
  1127. }
  1128. return status;
  1129. }
  1130. NTSTATUS
  1131. PbCmIrqToBiosDescriptor (
  1132. IN PUCHAR BiosRequirements,
  1133. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  1134. OUT PVOID ReturnDescriptor,
  1135. OUT PULONG Length
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. This routine translates CM IRQ information to Pnp BIOS format.
  1140. Since there is not enough information in the CM int descriptor to
  1141. convert it to Pnp BIOS descriptor. We will search the Bios
  1142. possible resource lists for the corresponding resource information.
  1143. Arguments:
  1144. BiosRequirements - Supplies a pointer to the bios possible resource lists.
  1145. CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer.
  1146. ReturnDescriptor - Supplies a buffer to receive the returned BIOS descriptor.
  1147. Length - Supplies a variable to receive the length of the returned bios descriptor.
  1148. Return Value:
  1149. return a pointer to the desired dma descriptor in the BiosRequirements. Null
  1150. if not found.
  1151. --*/
  1152. {
  1153. USHORT irqMask;
  1154. UCHAR tag;
  1155. PPNP_IRQ_DESCRIPTOR biosDesc;
  1156. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1157. ULONG increment;
  1158. PPNP_IRQ_DESCRIPTOR irqDesc = (PPNP_IRQ_DESCRIPTOR)ReturnDescriptor;
  1159. PAGED_CODE();
  1160. if (!(CmDescriptor->u.Interrupt.Level & 0xfffffff0)) {
  1161. irqMask = (USHORT)(1 << CmDescriptor->u.Interrupt.Level);
  1162. } else {
  1163. return STATUS_INVALID_PARAMETER;
  1164. }
  1165. if (!BiosRequirements) {
  1166. irqDesc->Tag = TAG_IRQ | (sizeof(PNP_IRQ_DESCRIPTOR) - 2); // No Information
  1167. irqDesc->IrqMask = irqMask;
  1168. *Length = sizeof(PNP_IRQ_DESCRIPTOR) - 1;
  1169. status = STATUS_SUCCESS;
  1170. } else {
  1171. tag = *BiosRequirements;
  1172. while (tag != TAG_COMPLETE_END) {
  1173. if ((tag & SMALL_TAG_MASK) == TAG_IRQ) {
  1174. biosDesc = (PPNP_IRQ_DESCRIPTOR)BiosRequirements;
  1175. if (biosDesc->IrqMask & irqMask) {
  1176. *Length = (biosDesc->Tag & SMALL_TAG_SIZE_MASK) + 1;
  1177. RtlCopyMemory(ReturnDescriptor, BiosRequirements, *Length);
  1178. ((PPNP_IRQ_DESCRIPTOR)ReturnDescriptor)->IrqMask = irqMask;
  1179. status = STATUS_SUCCESS;
  1180. break;
  1181. }
  1182. }
  1183. //
  1184. // Don't-care tag simply advance the buffer pointer to next tag.
  1185. //
  1186. if (tag & LARGE_RESOURCE_TAG) {
  1187. increment = *(USHORT UNALIGNED *)(BiosRequirements + 1);
  1188. increment += 3; // length of large tag
  1189. } else {
  1190. increment = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
  1191. increment += 1; // length of small tag
  1192. }
  1193. BiosRequirements += increment;
  1194. tag = *BiosRequirements;
  1195. }
  1196. }
  1197. return status;
  1198. }
  1199. NTSTATUS
  1200. PbCmDmaToBiosDescriptor (
  1201. IN PUCHAR BiosRequirements,
  1202. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  1203. OUT PVOID ReturnDescriptor,
  1204. OUT PULONG Length
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. This routine translates CM DMA information to Pnp BIOS format.
  1209. Since there is not enough information in the CM descriptor to
  1210. convert it to Pnp BIOS descriptor. We will search the Bios
  1211. possible resource lists for the corresponding resource information.
  1212. Arguments:
  1213. BiosRequirements - Supplies a pointer to the bios possible resource lists.
  1214. CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer.
  1215. BiosDescriptor - Supplies a variable to receive the returned BIOS descriptor.
  1216. Length - Supplies a variable to receive the length of the returned bios descriptor.
  1217. Return Value:
  1218. return a pointer to the desired dma descriptor in the BiosRequirements. Null
  1219. if not found.
  1220. --*/
  1221. {
  1222. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1223. UCHAR dmaMask, tag;
  1224. PPNP_DMA_DESCRIPTOR biosDesc;
  1225. ULONG increment;
  1226. PPNP_DMA_DESCRIPTOR dmaDesc = (PPNP_DMA_DESCRIPTOR)ReturnDescriptor;
  1227. USHORT flags = CmDescriptor->Flags;
  1228. PAGED_CODE();
  1229. if (!(CmDescriptor->u.Dma.Channel & 0xfffffff0)) {
  1230. dmaMask = (UCHAR)(1 << CmDescriptor->u.Dma.Channel);
  1231. } else {
  1232. return STATUS_INVALID_PARAMETER;
  1233. }
  1234. if (!BiosRequirements) {
  1235. dmaDesc->Tag = TAG_DMA | (sizeof(PNP_DMA_DESCRIPTOR) - 1);
  1236. dmaDesc->ChannelMask = dmaMask;
  1237. dmaDesc->Flags = 0;
  1238. if (flags & CM_RESOURCE_DMA_8_AND_16) {
  1239. dmaDesc->Flags += 1;
  1240. } else if (flags & CM_RESOURCE_DMA_16) {
  1241. dmaDesc->Flags += 2;
  1242. }
  1243. if (flags & CM_RESOURCE_DMA_BUS_MASTER) {
  1244. dmaDesc->Flags += 4;
  1245. }
  1246. if (flags & CM_RESOURCE_DMA_TYPE_A) {
  1247. dmaDesc->Flags += 32;
  1248. }
  1249. if (flags & CM_RESOURCE_DMA_TYPE_B) {
  1250. dmaDesc->Flags += 64;
  1251. }
  1252. if (flags & CM_RESOURCE_DMA_TYPE_F) {
  1253. dmaDesc->Flags += 96;
  1254. }
  1255. *Length = sizeof(PNP_DMA_DESCRIPTOR);
  1256. status = STATUS_SUCCESS;
  1257. } else {
  1258. tag = *BiosRequirements;
  1259. while (tag != TAG_COMPLETE_END) {
  1260. if ((tag & SMALL_TAG_MASK) == TAG_DMA) {
  1261. biosDesc = (PPNP_DMA_DESCRIPTOR)BiosRequirements;
  1262. if (biosDesc->ChannelMask & dmaMask) {
  1263. *Length = (biosDesc->Tag & SMALL_TAG_SIZE_MASK) + 1;
  1264. RtlMoveMemory(ReturnDescriptor, BiosRequirements, *Length);
  1265. ((PPNP_DMA_DESCRIPTOR)ReturnDescriptor)->ChannelMask = dmaMask;
  1266. status = STATUS_SUCCESS;
  1267. break;
  1268. }
  1269. }
  1270. //
  1271. // Don't-care tag simply advance the buffer pointer to next tag.
  1272. //
  1273. if (tag & LARGE_RESOURCE_TAG) {
  1274. increment = *(USHORT UNALIGNED *)(BiosRequirements + 1);
  1275. increment += 3; // length of large tag
  1276. } else {
  1277. increment = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
  1278. increment += 1; // length of small tag
  1279. }
  1280. BiosRequirements += increment;
  1281. tag = *BiosRequirements;
  1282. }
  1283. }
  1284. return status;
  1285. }
  1286. NTSTATUS
  1287. PbCmPortToBiosDescriptor (
  1288. IN PUCHAR BiosRequirements,
  1289. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  1290. OUT PVOID ReturnDescriptor,
  1291. OUT PULONG Length
  1292. )
  1293. /*++
  1294. Routine Description:
  1295. This routine translates CM PORT information to Pnp BIOS format.
  1296. Since there is not enough information in the CM descriptor to
  1297. convert it to Pnp BIOS full function port descriptor. We will
  1298. convert it to Pnp Bios fixed PORT descriptor. It is caller's
  1299. responsibility to release the returned data buffer.
  1300. Arguments:
  1301. CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer.
  1302. BiosDescriptor - supplies a variable to receive the buffer which contains
  1303. the desired Bios Port descriptor.
  1304. Length - supplies a variable to receive the size the returned bios port
  1305. descriptor.
  1306. ReturnDescriptor - supplies a buffer to receive the desired Bios Port descriptor.
  1307. Length - Supplies a variable to receive the length of the returned bios descriptor.
  1308. Return Value:
  1309. A NTSTATUS code.
  1310. --*/
  1311. {
  1312. PPNP_PORT_DESCRIPTOR portDesc = (PPNP_PORT_DESCRIPTOR)ReturnDescriptor;
  1313. USHORT minAddr, maxAddr, address;
  1314. UCHAR alignment, length, size, information = 0, tag, returnTag;
  1315. USHORT increment;
  1316. BOOLEAN test = FALSE;
  1317. PAGED_CODE();
  1318. if (CmDescriptor->u.Port.Start.HighPart != 0 ||
  1319. CmDescriptor->u.Port.Start.LowPart & 0xffff0000 ||
  1320. CmDescriptor->u.Port.Length & 0xffffff00) {
  1321. return STATUS_INVALID_PARAMETER;
  1322. }
  1323. //
  1324. // Search the possible resource list to get the information
  1325. // for the port range described by CmDescriptor.
  1326. //
  1327. address = (USHORT) CmDescriptor->u.Port.Start.LowPart;
  1328. size = (UCHAR) CmDescriptor->u.Port.Length;
  1329. if (!BiosRequirements) {
  1330. //
  1331. // No BiosRequirement. Use TAG_IO as default.
  1332. //
  1333. portDesc->Tag = TAG_IO | (sizeof(PNP_PORT_DESCRIPTOR) - 1);
  1334. if (CmDescriptor->Flags & CM_RESOURCE_PORT_16_BIT_DECODE) {
  1335. portDesc->Information = 1;
  1336. } else {
  1337. portDesc->Information = 0;
  1338. }
  1339. portDesc->Length = size;
  1340. portDesc->Alignment = 1;
  1341. portDesc->MinimumAddress = (USHORT)CmDescriptor->u.Port.Start.LowPart;
  1342. portDesc->MaximumAddress = (USHORT)CmDescriptor->u.Port.Start.LowPart;
  1343. *Length = sizeof(PNP_PORT_DESCRIPTOR);
  1344. } else {
  1345. returnTag = TAG_END;
  1346. tag = *BiosRequirements;
  1347. minAddr = 0;
  1348. maxAddr = 0;
  1349. alignment = 0;
  1350. while (tag != TAG_COMPLETE_END) {
  1351. test = FALSE;
  1352. switch (tag & SMALL_TAG_MASK) {
  1353. case TAG_IO:
  1354. minAddr = ((PPNP_PORT_DESCRIPTOR)BiosRequirements)->MinimumAddress;
  1355. alignment = ((PPNP_PORT_DESCRIPTOR)BiosRequirements)->Alignment;
  1356. length = ((PPNP_PORT_DESCRIPTOR)BiosRequirements)->Length;
  1357. maxAddr = ((PPNP_PORT_DESCRIPTOR)BiosRequirements)->MaximumAddress;
  1358. information = ((PPNP_PORT_DESCRIPTOR)BiosRequirements)->Information;
  1359. test = TRUE;
  1360. returnTag = TAG_IO;
  1361. if (!alignment) {
  1362. if (minAddr == maxAddr) {
  1363. //
  1364. // If the max is equal to the min, the alignment is
  1365. // meaningless. As we told OEMs 0 is appropriate here,
  1366. // let us handle it.
  1367. //
  1368. alignment = 1;
  1369. }
  1370. }
  1371. maxAddr += length - 1;
  1372. break;
  1373. case TAG_IO_FIXED:
  1374. length = ((PPNP_FIXED_PORT_DESCRIPTOR)BiosRequirements)->Length;
  1375. minAddr = ((PPNP_FIXED_PORT_DESCRIPTOR)BiosRequirements)->MinimumAddress;
  1376. maxAddr = minAddr + length - 1;
  1377. alignment = 1;
  1378. information = 0; // 10 bit decode
  1379. returnTag = TAG_IO_FIXED;
  1380. test = TRUE;
  1381. break;
  1382. }
  1383. if (test) {
  1384. if (minAddr <= address && maxAddr >= (address + size - 1) && !(address & (alignment - 1 ))) {
  1385. break;
  1386. }
  1387. test = FALSE;
  1388. }
  1389. //
  1390. // Advance to next tag
  1391. //
  1392. if (tag & LARGE_RESOURCE_TAG) {
  1393. increment = *(USHORT UNALIGNED *)(BiosRequirements + 1);
  1394. increment += 3; // length of large tag
  1395. } else {
  1396. increment = (USHORT) tag & SMALL_TAG_SIZE_MASK;
  1397. increment += 1; // length of small tag
  1398. }
  1399. BiosRequirements += increment;
  1400. tag = *BiosRequirements;
  1401. }
  1402. if (tag == TAG_COMPLETE_END) {
  1403. return STATUS_UNSUCCESSFUL;
  1404. }
  1405. //
  1406. // Set the return port descriptor
  1407. //
  1408. if (returnTag == TAG_IO) {
  1409. portDesc->Tag = TAG_IO + (sizeof(PNP_PORT_DESCRIPTOR) - 1);
  1410. portDesc->Information = information;
  1411. portDesc->Length = size;
  1412. portDesc->Alignment = alignment;
  1413. portDesc->MinimumAddress = (USHORT)CmDescriptor->u.Port.Start.LowPart;
  1414. portDesc->MaximumAddress = (USHORT)CmDescriptor->u.Port.Start.LowPart;
  1415. *Length = sizeof(PNP_PORT_DESCRIPTOR);
  1416. } else {
  1417. PPNP_FIXED_PORT_DESCRIPTOR fixedPortDesc = (PPNP_FIXED_PORT_DESCRIPTOR)ReturnDescriptor;
  1418. fixedPortDesc->Tag = TAG_IO_FIXED + (sizeof(PPNP_FIXED_PORT_DESCRIPTOR) - 1);
  1419. fixedPortDesc->MinimumAddress = (USHORT)CmDescriptor->u.Port.Start.LowPart;
  1420. fixedPortDesc->Length = size;
  1421. *Length = sizeof(PNP_FIXED_PORT_DESCRIPTOR);
  1422. }
  1423. }
  1424. return STATUS_SUCCESS;
  1425. }
  1426. NTSTATUS
  1427. PbCmMemoryToBiosDescriptor (
  1428. IN PUCHAR BiosRequirements,
  1429. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor,
  1430. OUT PVOID ReturnDescriptor,
  1431. OUT PULONG Length
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. This routine translates CM Memory information to Pnp BIOS format.
  1436. Since there is not enough information in the CM descriptor to
  1437. convert it to Pnp BIOS descriptor. We will search the Bios
  1438. possible resource lists for the corresponding resource information and
  1439. build a Pnp BIOS memory descriptor from there. It is caller's responsibility
  1440. to release the returned buffer.
  1441. Arguments:
  1442. BiosRequirements - Supplies a pointer to the bios possible resource lists.
  1443. CmDescriptor - supplies a pointer to an CM_PARTIAL_RESOURCE_DESCRIPTOR buffer.
  1444. ReturnDescriptor - supplies a buffer to receive the desired Bios Memory descriptor.
  1445. Length - supplies a variable to receive the size the returned bios port
  1446. descriptor.
  1447. Return Value:
  1448. A NTSTATUS code.
  1449. --*/
  1450. {
  1451. UCHAR tag, information;
  1452. PPNP_FIXED_MEMORY32_DESCRIPTOR memoryDesc = (PPNP_FIXED_MEMORY32_DESCRIPTOR)ReturnDescriptor;
  1453. ULONG address, size, length, minAddr, maxAddr, alignment;
  1454. USHORT increment;
  1455. BOOLEAN test = FALSE;
  1456. PAGED_CODE();
  1457. //
  1458. // Search the possible resource list to get the information
  1459. // for the memory range described by CmDescriptor.
  1460. //
  1461. address = CmDescriptor->u.Memory.Start.LowPart;
  1462. size = CmDescriptor->u.Memory.Length;
  1463. if (!BiosRequirements) {
  1464. //
  1465. // We don't support reserving legacy device's memory ranges from PNP
  1466. // BIOS. There isn't really any reason why not it just wasn't
  1467. // implemented for Windows 2000. It isn't near as necessary as it is
  1468. // for I/O ports since ROM memory has a signature and is self
  1469. // describing.
  1470. //
  1471. *Length = 0;
  1472. return STATUS_SUCCESS;
  1473. }
  1474. information = 0;
  1475. tag = *BiosRequirements;
  1476. while (tag != TAG_COMPLETE_END) {
  1477. switch (tag & SMALL_TAG_MASK) {
  1478. case TAG_MEMORY:
  1479. minAddr = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MinimumAddress)) << 8;
  1480. if ((alignment = ((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->Alignment) == 0) {
  1481. alignment = 0x10000;
  1482. }
  1483. length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MemorySize)) << 8;
  1484. maxAddr = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MaximumAddress)) << 8)
  1485. + length - 1;
  1486. test = TRUE;
  1487. break;
  1488. case TAG_MEMORY32:
  1489. length = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize;
  1490. minAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MinimumAddress;
  1491. maxAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MaximumAddress
  1492. + length - 1;
  1493. alignment = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->Alignment;
  1494. break;
  1495. case TAG_MEMORY32_FIXED:
  1496. length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize;
  1497. minAddr = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->BaseAddress;
  1498. maxAddr = minAddr + length - 1;
  1499. alignment = 1;
  1500. test = TRUE;
  1501. break;
  1502. default:
  1503. //
  1504. // Any tag we don't understand is treated as a corrupt list.
  1505. //
  1506. ASSERT (FALSE);
  1507. return STATUS_UNSUCCESSFUL;
  1508. }
  1509. if (test) {
  1510. if (minAddr <= address && maxAddr >= (address + size - 1) && !(address & (alignment - 1 ))) {
  1511. information = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->Information;
  1512. break;
  1513. }
  1514. test = FALSE;
  1515. }
  1516. //
  1517. // Advance to next tag
  1518. //
  1519. if (tag & LARGE_RESOURCE_TAG) {
  1520. increment = *(USHORT UNALIGNED *)(BiosRequirements + 1);
  1521. increment += 3; // length of large tag
  1522. } else {
  1523. increment = (USHORT) tag & SMALL_TAG_SIZE_MASK;
  1524. increment += 1; // length of small tag
  1525. }
  1526. BiosRequirements += increment;
  1527. tag = *BiosRequirements;
  1528. }
  1529. if (tag == TAG_COMPLETE_END) {
  1530. return STATUS_UNSUCCESSFUL;
  1531. }
  1532. //
  1533. // Set up Pnp BIOS memory descriptor
  1534. //
  1535. memoryDesc->Tag = TAG_MEMORY32_FIXED;
  1536. memoryDesc->Length = sizeof (PNP_FIXED_MEMORY32_DESCRIPTOR);
  1537. memoryDesc->Information = information;
  1538. memoryDesc->BaseAddress = address;
  1539. memoryDesc->MemorySize = size;
  1540. *Length = sizeof(PNP_FIXED_MEMORY32_DESCRIPTOR);
  1541. return STATUS_SUCCESS;
  1542. }
  1543. #ifdef ALLOC_DATA_PRAGMA
  1544. #pragma data_seg()
  1545. #endif