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.

1960 lines
58 KiB

  1. /*++
  2. Copyright (c) 1995-2000 Microsoft Corporation
  3. Module Name:
  4. isolate.c
  5. Abstract:
  6. Author:
  7. Shie-Lin Tzong (shielint) July-10-1995
  8. Environment:
  9. Kernel mode only.
  10. Revision History:
  11. --*/
  12. #include "busp.h"
  13. #include "pbios.h"
  14. #include "pnpisa.h"
  15. #if ISOLATE_CARDS
  16. #define RANGE_MASK 0xFF000000
  17. BOOLEAN
  18. PipFindIrqInformation (
  19. IN ULONG IrqLevel,
  20. IN PUCHAR BiosRequirements,
  21. OUT PUCHAR Information
  22. );
  23. BOOLEAN
  24. PipFindMemoryInformation (
  25. IN ULONG Index,
  26. IN ULONG Base,
  27. IN ULONG Limit,
  28. IN PUCHAR BiosRequirements,
  29. OUT PUCHAR NameTag,
  30. OUT PUCHAR Information,
  31. OUT PULONG NewLengh OPTIONAL
  32. );
  33. BOOLEAN
  34. PipFindIoPortInformation (
  35. IN ULONG BaseAddress,
  36. IN PUCHAR BiosRequirements,
  37. OUT PUCHAR Information,
  38. OUT PUCHAR Alignment,
  39. OUT PUCHAR RangeLength
  40. );
  41. BOOLEAN
  42. PipFindDmaInformation (
  43. IN UCHAR ChannelMask,
  44. IN PUCHAR BiosRequirements,
  45. OUT PUCHAR Information
  46. );
  47. NTSTATUS
  48. PipReadCardResourceDataBytes (
  49. IN USHORT BytesToRead,
  50. IN PUCHAR Buffer
  51. );
  52. USHORT
  53. PipIrqLevelRequirementsFromDeviceData(
  54. IN PUCHAR BiosRequirements,
  55. ULONG Length
  56. );
  57. //
  58. // Internal type definitions
  59. //
  60. typedef struct _MEMORY_DESC_{
  61. ULONG Base;
  62. ULONG Length;
  63. BOOLEAN Memory32;
  64. } MEMORY_DESC, *PMEMORY_DESC;
  65. typedef struct _IRQ_DESC_{
  66. UCHAR Level;
  67. ULONG Type;
  68. }IRQ_DESC, *PIRQ_DESC;
  69. #ifdef ALLOC_PRAGMA
  70. //#pragma alloc_text(PAGE, PipFindIrqInformation)
  71. //#pragma alloc_text(PAGE, PipFindMemoryInformation)
  72. //#pragma alloc_text(PAGE, PipFindIoPortInformation)
  73. //#pragma alloc_text(PAGE, PipReadCardResourceData)
  74. #pragma alloc_text(PAGE, PipReadDeviceResources)
  75. //#pragma alloc_text(PAGE, PipWriteDeviceResources)
  76. //#pragma alloc_text(PAGE, PipLFSRInitiation)
  77. //#pragma alloc_text(PAGE, PipIsolateCards)
  78. #pragma alloc_text(PAGE, PipFindNextLogicalDeviceTag)
  79. //#pragma alloc_text(PAGE, PipSelectLogicalDevice)
  80. //#pragma alloc_text(PAGE, PipReadCardResourceDataBytes)
  81. #endif
  82. BOOLEAN
  83. PipFindIrqInformation (
  84. IN ULONG IrqLevel,
  85. IN PUCHAR BiosRequirements,
  86. OUT PUCHAR Information
  87. )
  88. /*++
  89. Routine Description:
  90. This routine searches the Bios resource requirement lists for the corresponding
  91. Irq descriptor information. The search stops when we encounter another logical
  92. device id tag or the END tag. On input, the BiosRequirements points to current
  93. logical id tag.
  94. Arguments:
  95. IrqLevel - Supplies the irq level.
  96. BiosRequirements - Supplies a pointer to the bios resource requirement lists. This
  97. parameter must point to the logical device Id tag.
  98. Information - supplies a pointer to a UCHAR to receive the port information/flags.
  99. Return Value:
  100. TRUE - if memory information found. Else False.
  101. --*/
  102. {
  103. UCHAR tag;
  104. ULONG increment;
  105. USHORT irqMask;
  106. PPNP_IRQ_DESCRIPTOR biosDesc;
  107. //
  108. // Skip current logical id tag
  109. //
  110. tag = *BiosRequirements;
  111. ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID);
  112. BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1;
  113. //
  114. // Search the possible resource list to get the information
  115. // for the Irq.
  116. //
  117. irqMask = 1 << IrqLevel;
  118. tag = *BiosRequirements;
  119. while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) {
  120. if ((tag & SMALL_TAG_MASK) == TAG_IRQ) {
  121. biosDesc = (PPNP_IRQ_DESCRIPTOR)BiosRequirements;
  122. if (biosDesc->IrqMask & irqMask) {
  123. if ((tag & SMALL_TAG_SIZE_MASK) == 2) {
  124. //
  125. // if no irq info is available, a value of zero is returned.
  126. // (o is not a valid irq information.)
  127. //
  128. *Information = 0;
  129. } else {
  130. *Information = biosDesc->Information;
  131. }
  132. return TRUE;
  133. }
  134. }
  135. if (tag & LARGE_RESOURCE_TAG) {
  136. increment = *((USHORT UNALIGNED *)(BiosRequirements + 1));
  137. increment += 3; // length of large tag
  138. } else {
  139. increment = tag & SMALL_TAG_SIZE_MASK;
  140. increment += 1; // length of small tag
  141. }
  142. BiosRequirements += increment;
  143. tag = *BiosRequirements;
  144. }
  145. return FALSE;
  146. }
  147. BOOLEAN
  148. PipFindMemoryInformation (
  149. IN ULONG Index,
  150. IN ULONG BaseAddress,
  151. IN ULONG Limit,
  152. IN PUCHAR BiosRequirements,
  153. OUT PUCHAR NameTag,
  154. OUT PUCHAR Information,
  155. OUT PULONG NewLength OPTIONAL
  156. )
  157. /*++
  158. Routine Description:
  159. This routine searches the Bios resource requirement lists for the corresponding
  160. memory descriptor information. The search stops when we encounter another logical
  161. device id tag or the END tag. Note, the memory range specified by Base
  162. and Limit must be within a single Pnp ISA memory descriptor.
  163. Arguments:
  164. Index - Which memory descriptor we're interested in.
  165. BaseAddress - Supplies the base address of the memory range.
  166. Limit - Supplies the upper limit of the memory range.
  167. BiosRequirements - Supplies a pointer to the bios resource requirement lists. This
  168. parameter must point to the logical device Id tag.
  169. NameTag - Supplies a variable to receive the Tag of the memory descriptor which
  170. describes the memory information.
  171. Information - supplies a pointer to a UCHAR to receive the memory information
  172. for the specified memory range.
  173. Return Value:
  174. TRUE - if memory information found. Else False.
  175. --*/
  176. {
  177. UCHAR tag;
  178. BOOLEAN found = FALSE,foundMem24, foundMem;
  179. ULONG minAddr, length, maxAddr, alignment, noMem = 0;
  180. USHORT increment;
  181. //
  182. // Skip current logical id tag.
  183. //
  184. tag = *BiosRequirements;
  185. ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID);
  186. BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1;
  187. //
  188. // Search the possible resource list to get the information
  189. // for the memory range described by Base and Limit.
  190. //
  191. if (NewLength) {
  192. *NewLength=0;
  193. }
  194. tag = *BiosRequirements;
  195. while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) {
  196. foundMem = foundMem24 = FALSE;
  197. switch (tag) {
  198. case TAG_MEMORY:
  199. minAddr = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MinimumAddress)) << 8;
  200. length = ((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MemorySize)) << 8;
  201. maxAddr = (((ULONG)(((PPNP_MEMORY_DESCRIPTOR)BiosRequirements)->MaximumAddress)) << 8)
  202. + length - 1;
  203. foundMem24 = TRUE;
  204. foundMem = TRUE;
  205. break;
  206. case TAG_MEMORY32:
  207. length = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize;
  208. minAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MinimumAddress;
  209. maxAddr = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->MaximumAddress
  210. + length - 1;
  211. foundMem = TRUE;
  212. break;
  213. case TAG_MEMORY32_FIXED:
  214. length = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->MemorySize;
  215. minAddr = ((PPNP_FIXED_MEMORY32_DESCRIPTOR)BiosRequirements)->BaseAddress;
  216. maxAddr = minAddr + length - 1;
  217. foundMem = TRUE;
  218. break;
  219. }
  220. if (foundMem) {
  221. //
  222. // Work around cards that don't set register 43 correctly.
  223. // if the boot config has a value that equals the rom data, but
  224. // has the range type flipped, allow it, and reset
  225. // the length
  226. //
  227. if ((minAddr <= BaseAddress &&
  228. ((maxAddr >= Limit) || ((foundMem24 && (maxAddr >= (BaseAddress+(~Limit & ~RANGE_MASK))))))) && (noMem == Index)) {
  229. *Information = ((PPNP_MEMORY32_DESCRIPTOR)BiosRequirements)->Information;
  230. *NameTag = tag;
  231. found = TRUE;
  232. //
  233. // did we find a 16-bit tag
  234. //
  235. if (NewLength && foundMem24) {
  236. if (maxAddr >= (BaseAddress+(~Limit & ~RANGE_MASK))) {
  237. *NewLength = length;
  238. }
  239. }
  240. break;
  241. } else {
  242. noMem++;
  243. }
  244. }
  245. //
  246. // Advance to next tag
  247. //
  248. if (tag & LARGE_RESOURCE_TAG) {
  249. increment = *(USHORT UNALIGNED *)(BiosRequirements + 1);
  250. increment += 3; // length of large tag
  251. } else {
  252. increment = tag & SMALL_TAG_SIZE_MASK;
  253. increment += 1; // length of small tag
  254. }
  255. BiosRequirements += increment;
  256. tag = *BiosRequirements;
  257. }
  258. return found;
  259. }
  260. BOOLEAN
  261. PipFindIoPortInformation (
  262. IN ULONG BaseAddress,
  263. IN PUCHAR BiosRequirements,
  264. OUT PUCHAR Information,
  265. OUT PUCHAR Alignment,
  266. OUT PUCHAR RangeLength
  267. )
  268. /*++
  269. Routine Description:
  270. This routine searches the Bios resource requirement lists for the corresponding
  271. Io port descriptor information. The search stops when we encounter another logical
  272. device id tag or the END tag.
  273. Arguments:
  274. BaseAddress - Supplies the base address of the Io port range.
  275. BiosRequirements - Supplies a pointer to the bios resource requirement lists. This
  276. parameter must point to the logical device Id tag.
  277. Information - supplies a pointer to a UCHAR to receive the port information/flags.
  278. Alignment - supplies a pointer to a UCHAR to receive the port alignment
  279. information.
  280. RangeLength - supplies a pointer to a UCHAR to receive the port range length
  281. information.
  282. Return Value:
  283. TRUE - if memory information found. Else False.
  284. --*/
  285. {
  286. UCHAR tag;
  287. BOOLEAN found = FALSE;
  288. ULONG minAddr, length, maxAddr, alignment;
  289. USHORT increment;
  290. PPNP_PORT_DESCRIPTOR portDesc;
  291. PPNP_FIXED_PORT_DESCRIPTOR fixedPortDesc;
  292. tag = *BiosRequirements;
  293. ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID);
  294. BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1;
  295. //
  296. // Search the possible resource list to get the information
  297. // for the io port range described by Base.
  298. //
  299. tag = *BiosRequirements;
  300. while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) {
  301. switch (tag & SMALL_TAG_MASK) {
  302. case TAG_IO:
  303. portDesc = (PPNP_PORT_DESCRIPTOR)BiosRequirements;
  304. minAddr = portDesc->MinimumAddress;
  305. maxAddr = portDesc->MaximumAddress;
  306. if (minAddr <= BaseAddress && maxAddr >= BaseAddress) {
  307. *Information = portDesc->Information;
  308. *Alignment = portDesc->Alignment;
  309. *RangeLength = portDesc->Length;
  310. found = TRUE;
  311. }
  312. break;
  313. case TAG_IO_FIXED:
  314. fixedPortDesc = (PPNP_FIXED_PORT_DESCRIPTOR)BiosRequirements;
  315. minAddr = fixedPortDesc->MinimumAddress;
  316. if (BaseAddress == minAddr) {
  317. *Information = 0; // 10 bit decode
  318. *Alignment = 1;
  319. *RangeLength = fixedPortDesc->Length;
  320. found = TRUE;
  321. }
  322. break;
  323. }
  324. if (found) {
  325. break;
  326. }
  327. //
  328. // Advance to next tag
  329. //
  330. if (tag & LARGE_RESOURCE_TAG) {
  331. increment = *(USHORT UNALIGNED *)(BiosRequirements + 1);
  332. increment += 3; // length of large tag
  333. } else {
  334. increment = tag & SMALL_TAG_SIZE_MASK;
  335. increment += 1; // length of small tag
  336. }
  337. BiosRequirements += increment;
  338. tag = *BiosRequirements;
  339. }
  340. return found;
  341. }
  342. BOOLEAN
  343. PipFindDmaInformation (
  344. IN UCHAR ChannelMask,
  345. IN PUCHAR BiosRequirements,
  346. OUT PUCHAR Information
  347. )
  348. /*++
  349. Routine Description:
  350. This routine searches the Bios resource requirement lists for the corresponding
  351. Io port descriptor information. The search stops when we encounter another logical
  352. device id tag or the END tag.
  353. Arguments:
  354. BaseAddress - Supplies the channel mask.
  355. BiosRequirements - Supplies a pointer to the bios resource requirement lists. This
  356. parameter must point to the logical device Id tag.
  357. Information - supplies a pointer to a UCHAR to receive the port information/flags.
  358. Return Value:
  359. TRUE - if memory information found. Else False.
  360. --*/
  361. {
  362. UCHAR tag;
  363. BOOLEAN found = FALSE;
  364. USHORT increment;
  365. PPNP_DMA_DESCRIPTOR dmaDesc;
  366. UCHAR biosMask;
  367. tag = *BiosRequirements;
  368. ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID);
  369. BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1;
  370. //
  371. // Search the possible resource list to get the information
  372. // for the io port range described by Base.
  373. //
  374. tag = *BiosRequirements;
  375. while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) {
  376. if ((tag & SMALL_TAG_MASK) == TAG_DMA) {
  377. dmaDesc = (PPNP_DMA_DESCRIPTOR)BiosRequirements;
  378. biosMask = dmaDesc->ChannelMask;
  379. if (ChannelMask & biosMask) {
  380. *Information = dmaDesc->Flags;
  381. found = TRUE;
  382. }
  383. }
  384. if (found) {
  385. break;
  386. }
  387. //
  388. // Advance to next tag
  389. //
  390. if (tag & LARGE_RESOURCE_TAG) {
  391. increment = *(USHORT UNALIGNED *)(BiosRequirements + 1);
  392. increment += 3; // length of large tag
  393. } else {
  394. increment = tag & SMALL_TAG_SIZE_MASK;
  395. increment += 1; // length of small tag
  396. }
  397. BiosRequirements += increment;
  398. tag = *BiosRequirements;
  399. }
  400. return found;
  401. }
  402. NTSTATUS
  403. PipReadCardResourceData (
  404. OUT PUCHAR NumberLogicalDevices,
  405. IN PUCHAR *ResourceData,
  406. OUT PULONG ResourceDataLength
  407. )
  408. /*++
  409. Routine Description:
  410. This routine reads resources data from a specified PnP ISA card. It is
  411. caller's responsibility to release the memory. Before calling this routine,
  412. the Pnp ISA card should be in sleep state (i.e. Initiation Key was sent.)
  413. After exiting this routine, the card will be left in Config state.
  414. Arguments:
  415. NumberLogicalDevices - supplies a variable to receive the number of logical devices
  416. associated with the Pnp Isa card.
  417. ResourceData - Supplies a variable to receive the pointer to the resource data.
  418. ResourceDataLength - Supplies a variable to receive the length of the ResourceData.
  419. Return Value:
  420. NT STATUS code.
  421. --*/
  422. {
  423. PUCHAR buffer, p;
  424. LONG sizeToRead, limit, i;
  425. USHORT size;
  426. UCHAR tag;
  427. UCHAR noDevices;
  428. BOOLEAN failed;
  429. NTSTATUS status;
  430. //
  431. // Allocate memory to store the resource data.
  432. // N.B. The buffer size should cover 99.999% of the machines.
  433. //
  434. sizeToRead = 4096;
  435. tryAgain:
  436. noDevices = 0;
  437. buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, sizeToRead, 'iPnP');
  438. if (!buffer) {
  439. DebugPrint((DEBUG_ERROR, "PipReadCardResourceData returning STATUS_INSUFFICIENT_RESOURCES\n"));
  440. return STATUS_INSUFFICIENT_RESOURCES;
  441. }
  442. //
  443. // Send card from sleep state to configuration state
  444. // Note, by doing this the resource data includes 9 bytes Id.
  445. //
  446. DebugPrint((DEBUG_STATE, "Read resources\n"));
  447. //
  448. // Read card id bytes
  449. //
  450. p = buffer;
  451. status = PipReadCardResourceDataBytes(NUMBER_CARD_ID_BYTES, p);
  452. if (!NT_SUCCESS(status)) {
  453. ExFreePool(buffer);
  454. DebugPrint((DEBUG_STATE | DEBUG_ERROR,
  455. "Read resources failed\n"));
  456. DebugPrint((DEBUG_ERROR, "PipReadCardResourceDataBytes Failed %x\n",status));
  457. return status;
  458. }
  459. i = NUMBER_CARD_ID_BYTES;
  460. p += NUMBER_CARD_ID_BYTES;
  461. //
  462. // read all the tag descriptors of the card resource data
  463. //
  464. failed = FALSE;
  465. limit = sizeToRead - 4 - NUMBER_CARD_ID_BYTES;;
  466. while (TRUE) {
  467. //
  468. // Read tag byte. Make sure it's a valid tag and determine
  469. // the size of the descriptor.
  470. //
  471. PipReadCardResourceDataBytes(1, p);
  472. tag = *p;
  473. i++;
  474. p++;
  475. if (tag == TAG_COMPLETE_END) {
  476. PipReadCardResourceDataBytes(1, p);
  477. p++;
  478. i++;
  479. break;
  480. } else if (tag == TAG_END) { // With NO checksum
  481. *p = 0;
  482. i++;
  483. p++;
  484. break;
  485. }
  486. if (tag & LARGE_RESOURCE_TAG) {
  487. if (tag & 0x70) {
  488. failed = TRUE;
  489. #if VERBOSE_DEBUG
  490. DbgPrint ("Failing Resource read on large tag: %x\n",tag);
  491. #endif
  492. break;
  493. } else {
  494. PipReadCardResourceDataBytes(2, p);
  495. size = *((USHORT UNALIGNED *)p);
  496. p += 2;
  497. i += 2;
  498. }
  499. } else {
  500. if ((tag & 0x70) == 0x50 || (tag & 0x70) == 0x60 || (((tag & 0x70) == 0) && (tag != 0xa))) {
  501. failed = TRUE;
  502. #if VERBOSE_DEBUG
  503. DbgPrint ("Failing Resource read on small tag: %x\n",tag);
  504. #endif
  505. break;
  506. } else {
  507. if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) {
  508. noDevices++;
  509. }
  510. size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
  511. }
  512. }
  513. //
  514. // read 'size' number of bytes for the current descriptor
  515. //
  516. i += size;
  517. if (i < limit) {
  518. PipReadCardResourceDataBytes(size, p);
  519. p += size;
  520. } else {
  521. ExFreePool(buffer);
  522. sizeToRead <<= 1; // double the buffer
  523. //
  524. // If we can find the END tag with 32K byte, assume the resource
  525. // requirement list is bad.
  526. //
  527. if (sizeToRead > 0x80000) {
  528. DebugPrint ((DEBUG_STATE | DEBUG_ERROR, "PipReadCardResourceData returning STATUS_INVALID_PARAMETER, Sleep\n"));
  529. return STATUS_INVALID_PARAMETER;
  530. } else {
  531. goto tryAgain;
  532. }
  533. }
  534. }
  535. if (failed) {
  536. ExFreePool(buffer);
  537. #if VERBOSE_DEBUG
  538. DbgPrint ("PipReadCardResourceData returning FAILED\n");
  539. #endif
  540. return STATUS_UNSUCCESSFUL;
  541. }
  542. //
  543. // Determine the real size of the buffer required and
  544. // resize the buffer.
  545. //
  546. size = (USHORT)(p - buffer); // i
  547. p = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, size, 'iPnP');
  548. if (p) {
  549. RtlMoveMemory(p, buffer, size);
  550. ExFreePool(buffer);
  551. } else {
  552. //
  553. // Fail to resize the buffer. Simply leave it alone.
  554. //
  555. p = buffer;
  556. }
  557. *ResourceData = p;
  558. *NumberLogicalDevices = noDevices;
  559. *ResourceDataLength = size;
  560. return STATUS_SUCCESS;
  561. }
  562. NTSTATUS
  563. PipReadDeviceResources (
  564. IN ULONG BusNumber,
  565. IN PUCHAR BiosRequirements,
  566. IN ULONG CardFlags,
  567. OUT PCM_RESOURCE_LIST *ResourceData,
  568. OUT PULONG Length,
  569. OUT PUSHORT irqFlags
  570. )
  571. /*++
  572. Routine Description:
  573. This routine reads boot resource data from an enabled logical device of a PNP ISA
  574. card. Caller must put the card into configuration state and select the logical
  575. device before calling this function. It is caller's responsibility to release
  576. the memory. ( The boot resource data is the resources that a card assigned during
  577. boot.)
  578. Arguments:
  579. BusNumber - specifies the bus number of the device whose resource data to be read.
  580. BiosRequirements - Supplies a pointer to the resource requirement list for the logical
  581. device. This parameter must point to the logical device Id tag.
  582. CardFlags - Flags that may indicate the need to apply a workaround.
  583. ResourceData - Supplies a variable to receive the pointer to the resource data.
  584. Length - Supplies a variable to recieve the length of the resource data.
  585. Return Value:
  586. NT STATUS code.
  587. --*/
  588. {
  589. UCHAR c, junk1, junk2, info;
  590. PUCHAR base;
  591. ULONG l, resourceCount;
  592. BOOLEAN limit;
  593. LONG i, j, noMemoryDesc = 0, noIoDesc = 0, noDmaDesc =0, noIrqDesc = 0;
  594. MEMORY_DESC memoryDesc[NUMBER_MEMORY_DESCRIPTORS + NUMBER_32_MEMORY_DESCRIPTORS];
  595. IRQ_DESC irqDesc[NUMBER_IRQ_DESCRIPTORS];
  596. UCHAR dmaDesc[NUMBER_DMA_DESCRIPTORS];
  597. USHORT ioDesc[NUMBER_IO_DESCRIPTORS];
  598. PCM_RESOURCE_LIST cmResource;
  599. PCM_PARTIAL_RESOURCE_LIST partialResList;
  600. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc;
  601. ULONG dumpData[2];
  602. //
  603. // First make sure the specified BiosRequirements is valid and at the right tag.
  604. //
  605. if ((*BiosRequirements & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
  606. return STATUS_INVALID_PARAMETER;
  607. }
  608. //
  609. // If card is not activated, don't read boot resource.
  610. // Because boot resource of non activated NEC98's ISAPNP card is not 0.
  611. //
  612. *irqFlags = CM_RESOURCE_INTERRUPT_LATCHED;
  613. PipWriteAddress(ACTIVATE_PORT);
  614. if (!(PipReadData() & 1)) {
  615. *ResourceData = NULL;
  616. *Length = 0;
  617. return STATUS_UNSUCCESSFUL;
  618. }
  619. //
  620. // Read memory configuration
  621. //
  622. base = (PUCHAR)ADDRESS_MEMORY_BASE;
  623. for (i = 0; i < NUMBER_MEMORY_DESCRIPTORS; i++) {
  624. //
  625. // Read memory base address
  626. //
  627. PipWriteAddress(base + ADDRESS_MEMORY_HI);
  628. c = PipReadData();
  629. l = c;
  630. l <<= 8;
  631. PipWriteAddress(base + ADDRESS_MEMORY_LO);
  632. c = PipReadData();
  633. l |= c;
  634. l <<= 8; // l = memory base address
  635. if (l == 0) {
  636. break;
  637. }
  638. memoryDesc[noMemoryDesc].Base = l;
  639. //
  640. // Read memory control byte
  641. //
  642. PipWriteAddress(base + ADDRESS_MEMORY_CTL);
  643. c= PipReadData();
  644. limit = c & 1;
  645. //
  646. // Read memory upper limit address or range length
  647. //
  648. PipWriteAddress(base + ADDRESS_MEMORY_UPPER_HI);
  649. c = PipReadData();
  650. l = c;
  651. l <<= 8;
  652. PipWriteAddress(base + ADDRESS_MEMORY_UPPER_LO);
  653. c = PipReadData();
  654. l |= c;
  655. l <<= 8;
  656. //
  657. //If bit[0] of memory control is 0, this is the range length.
  658. //If bit[0] of memory control is 1, this is upper limit for memory
  659. //address (equal to memory base address plus the range length allocated).
  660. //
  661. if (limit == ADDRESS_MEMORY_CTL_LIMIT) {
  662. l = l - memoryDesc[noMemoryDesc].Base;
  663. }else {
  664. l = (~l+1) & ~(RANGE_MASK);
  665. }
  666. // IBM0001 Token Ring card has write-only registers 0x4B-0x4C.
  667. // The boot configed length comes back 0 instead of 0x2000
  668. if ((CardFlags & CF_IBM_MEMBOOTCONFIG) && (l == 0) &&
  669. (noMemoryDesc == 1)) {
  670. l = 0x2000;
  671. }
  672. memoryDesc[noMemoryDesc].Length = l;
  673. memoryDesc[noMemoryDesc].Memory32 = FALSE;
  674. noMemoryDesc++;
  675. base += ADDRESS_MEMORY_INCR;
  676. }
  677. //
  678. // Read memory 32 configuration
  679. //
  680. // Spec says you can't mix 24 bit and 32bit memory. Helps on
  681. // cards with flakey 32 bit memory registers until we examine only
  682. // the boot configed resources specified in the requirements.
  683. if (noMemoryDesc == 0) {
  684. for (i = 0; i < NUMBER_32_MEMORY_DESCRIPTORS; i++) {
  685. base = ADDRESS_32_MEMORY_BASE(i);
  686. //
  687. // Read memory base address
  688. //
  689. l = 0;
  690. for (j = ADDRESS_32_MEMORY_B3; j <= ADDRESS_32_MEMORY_B0; j++) {
  691. PipWriteAddress(base + j);
  692. c = PipReadData();
  693. l <<= 8;
  694. l |= c;
  695. }
  696. if (l == 0) {
  697. break;
  698. }
  699. memoryDesc[noMemoryDesc].Base = l;
  700. //
  701. // Read memory control byte
  702. //
  703. PipWriteAddress(base + ADDRESS_32_MEMORY_CTL);
  704. c= PipReadData();
  705. limit = c & 1;
  706. //
  707. // Read memory upper limit address or range length
  708. //
  709. l = 0;
  710. for (j = ADDRESS_32_MEMORY_E3; j <= ADDRESS_32_MEMORY_E0; j++) {
  711. PipWriteAddress(base + j);
  712. c = PipReadData();
  713. l <<= 8;
  714. l |= c;
  715. }
  716. if (limit == ADDRESS_MEMORY_CTL_LIMIT) {
  717. l = l - memoryDesc[noMemoryDesc].Base;
  718. }else {
  719. l = ((~l)+1) & ~(RANGE_MASK);
  720. }
  721. memoryDesc[noMemoryDesc].Length = l;
  722. memoryDesc[noMemoryDesc].Memory32 = TRUE;
  723. noMemoryDesc++;
  724. }
  725. }
  726. //
  727. // Read Io Port Configuration
  728. //
  729. base = (PUCHAR)ADDRESS_IO_BASE;
  730. for (i = 0; i < NUMBER_IO_DESCRIPTORS; i++) {
  731. PipWriteAddress(base + ADDRESS_IO_BASE_HI);
  732. c = PipReadData();
  733. l = c;
  734. PipWriteAddress(base + ADDRESS_IO_BASE_LO);
  735. c = PipReadData();
  736. l <<= 8;
  737. l |= c;
  738. if (l == 0) {
  739. break;
  740. }
  741. ioDesc[noIoDesc++] = (USHORT)l;
  742. base += ADDRESS_IO_INCR;
  743. }
  744. //
  745. // Read Interrupt configuration
  746. //
  747. base = (PUCHAR)ADDRESS_IRQ_BASE;
  748. for (i = 0; i < NUMBER_IRQ_DESCRIPTORS; i++) {
  749. PipWriteAddress(base + ADDRESS_IRQ_VALUE);
  750. c = PipReadData() & 0xf;
  751. if (c == 0) {
  752. break;
  753. }
  754. irqDesc[noIrqDesc].Level = c;
  755. PipWriteAddress(base + ADDRESS_IRQ_TYPE);
  756. c = PipReadData();
  757. irqDesc[noIrqDesc++].Type = c;
  758. base += ADDRESS_IRQ_INCR;
  759. DebugPrint((DEBUG_IRQ, "card boot config byte %x\n", (ULONG) c));
  760. // only if card is configured to low level do we respect level.
  761. // register is probably busted
  762. if ((c & 3) == 1) {
  763. *irqFlags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  764. }
  765. }
  766. //
  767. // Read DMA configuration
  768. //
  769. base = (PUCHAR)ADDRESS_DMA_BASE;
  770. for (i = 0; i < NUMBER_DMA_DESCRIPTORS; i++) {
  771. PipWriteAddress(base + ADDRESS_DMA_VALUE);
  772. c = PipReadData() & 0x7;
  773. if (c == 4) {
  774. break;
  775. }
  776. if (!PipFindDmaInformation ( (UCHAR)(1 << c), BiosRequirements, &info)) {
  777. break;
  778. }
  779. dmaDesc[noDmaDesc++] = c;
  780. base += ADDRESS_DMA_INCR;
  781. }
  782. //
  783. // Construct CM_RESOURCE_LIST structure based on the resource data
  784. // we collect so far.
  785. //
  786. resourceCount = noMemoryDesc + noIoDesc + noDmaDesc + noIrqDesc;
  787. //
  788. // if empty bios resources, simply return.
  789. //
  790. if (resourceCount == 0) {
  791. *ResourceData = NULL;
  792. *Length = 0;
  793. return STATUS_SUCCESS;
  794. }
  795. l = sizeof(CM_RESOURCE_LIST) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) *
  796. ( resourceCount - 1);
  797. cmResource = ExAllocatePoolWithTag(PagedPool, l, 'iPnP');
  798. if (!cmResource) {
  799. return STATUS_INSUFFICIENT_RESOURCES;
  800. }
  801. RtlZeroMemory(cmResource, l);
  802. *Length = l; // Set returned resource data length
  803. cmResource->Count = 1;
  804. cmResource->List[0].InterfaceType = Isa;
  805. cmResource->List[0].BusNumber = BusNumber;
  806. partialResList = (PCM_PARTIAL_RESOURCE_LIST)&cmResource->List[0].PartialResourceList;
  807. partialResList->Version = 0;
  808. partialResList->Revision = 0x3000;
  809. partialResList->Count = resourceCount;
  810. partialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)&partialResList->PartialDescriptors[0];
  811. //
  812. // Set up all the CM memory descriptors
  813. //
  814. for (i = 0; i < noMemoryDesc; i++) {
  815. ULONG NewLength;
  816. partialDesc->Type = CmResourceTypeMemory;
  817. partialDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  818. partialDesc->u.Memory.Length = memoryDesc[i].Length;
  819. partialDesc->u.Memory.Start.HighPart = 0;
  820. partialDesc->u.Memory.Start.LowPart = memoryDesc[i].Base;
  821. //
  822. // Need to consult configuration data for the Flags
  823. //
  824. l = memoryDesc[i].Base + memoryDesc[i].Length - 1;
  825. if (PipFindMemoryInformation (i, memoryDesc[i].Base, l, BiosRequirements, &junk1, &c,&NewLength)) {
  826. if (NewLength != 0 ) {
  827. partialDesc->u.Memory.Length = NewLength;
  828. }
  829. // Mark the memory descriptor as read-only if the tags describe as
  830. // expansion ROM or generic non-writable memory
  831. if ((c & PNP_MEMORY_ROM_MASK) ||
  832. !(c & PNP_MEMORY_WRITE_STATUS_MASK)) {
  833. partialDesc->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  834. }
  835. } else {
  836. DebugPrint((DEBUG_CARDRES|DEBUG_WARN,
  837. "ReadDeviceResources: No matched memory req for %x to %x\n",
  838. memoryDesc[i].Base, l));
  839. ExFreePool(cmResource);
  840. return STATUS_UNSUCCESSFUL;
  841. }
  842. partialDesc->Flags |= CM_RESOURCE_MEMORY_24;
  843. partialDesc++;
  844. }
  845. //
  846. // Set up all the CM io/port descriptors
  847. //
  848. for (i = 0; i < noIoDesc; i++) {
  849. partialDesc->Type = CmResourceTypePort;
  850. partialDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  851. partialDesc->Flags = CM_RESOURCE_PORT_IO;
  852. partialDesc->u.Port.Start.LowPart = ioDesc[i];
  853. //
  854. // Need to consult configuration data for the Port length
  855. //
  856. if (PipFindIoPortInformation (ioDesc[i], BiosRequirements, &info, &junk2, &c)) {
  857. if (info & 1) {
  858. partialDesc->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
  859. } else {
  860. partialDesc->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
  861. }
  862. partialDesc->u.Port.Length = c;
  863. partialDesc++;
  864. } else {
  865. DebugPrint((DEBUG_CARDRES|DEBUG_WARN,
  866. "ReadDeviceResources: No matched port req for %x\n",
  867. ioDesc[i]));
  868. ExFreePool(cmResource);
  869. return STATUS_UNSUCCESSFUL;
  870. }
  871. }
  872. //
  873. // Set up all the CM DMA descriptors
  874. //
  875. for (i = 0; i < noDmaDesc; i++) {
  876. partialDesc->Type = CmResourceTypeDma;
  877. partialDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  878. partialDesc->Flags = 0; // no flags for DMA descriptor
  879. partialDesc->u.Dma.Channel = (ULONG) dmaDesc[i];
  880. partialDesc->u.Dma.Port = 0;
  881. partialDesc->u.Dma.Reserved1 = 0;
  882. partialDesc++;
  883. }
  884. //
  885. // Set up all the CM interrupt descriptors
  886. //
  887. for (i = 0; i < noIrqDesc; i++) {
  888. partialDesc->Type = CmResourceTypeInterrupt;
  889. partialDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  890. partialDesc->Flags = *irqFlags;
  891. partialDesc->u.Interrupt.Vector =
  892. partialDesc->u.Interrupt.Level = irqDesc[i].Level;
  893. partialDesc->u.Interrupt.Affinity = (ULONG)-1;
  894. partialDesc++;
  895. }
  896. *ResourceData = cmResource;
  897. return STATUS_SUCCESS;
  898. }
  899. NTSTATUS
  900. PipWriteDeviceResources (
  901. IN PUCHAR BiosRequirements,
  902. IN PCM_RESOURCE_LIST CmResources
  903. )
  904. /*++
  905. Routine Description:
  906. This routine writes boot resource data to an enabled logical device of
  907. a Pnp ISA card. Caller must put the card into configuration state and select
  908. the logical device before calling this function.
  909. Arguments:
  910. BiosRequirements - Supplies a pointer to the possible resources for the logical
  911. device. This parameter must point to the logical device Id tag.
  912. ResourceData - Supplies a pointer to the cm resource data.
  913. Return Value:
  914. NT STATUS code.
  915. --*/
  916. {
  917. UCHAR c, information, tag;
  918. ULONG count, i, j, pass, base, limit;
  919. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
  920. ULONG noIrq =0, noIo = 0, noDma = 0, noMemory24 = 0, noMemory32 = 0, noMemory;
  921. PUCHAR memoryBase, irqBase, dmaBase, ioBase, tmp;
  922. ULONG memory32Base;
  923. //
  924. // First make sure the specified BiosRequirements is valid and at the right tag.
  925. //
  926. if ((*BiosRequirements & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
  927. return STATUS_INVALID_PARAMETER;
  928. }
  929. count = CmResources->List[0].PartialResourceList.Count;
  930. memoryBase = (PUCHAR)ADDRESS_MEMORY_BASE;
  931. memory32Base = 0;
  932. ioBase = (PUCHAR)ADDRESS_IO_BASE;
  933. irqBase = (PUCHAR)ADDRESS_IRQ_BASE;
  934. dmaBase = (PUCHAR)ADDRESS_DMA_BASE;
  935. for (pass = 1; pass <= 2; pass++) {
  936. //
  937. // First pass we make sure the resources to be set is acceptable.
  938. // Second pass we actually write the resources to the logical device's
  939. // configuration space.
  940. //
  941. noMemory = 0;
  942. cmDesc = CmResources->List[0].PartialResourceList.PartialDescriptors;
  943. for (i = 0; i < count; i++) {
  944. switch (cmDesc->Type) {
  945. case CmResourceTypePort:
  946. if (pass == 1) {
  947. noIo++;
  948. if (noIo > NUMBER_IO_DESCRIPTORS ||
  949. cmDesc->u.Port.Start.HighPart != 0 ||
  950. cmDesc->u.Port.Start.LowPart & 0xffff0000 ||
  951. cmDesc->u.Port.Length & 0xffffff00) {
  952. return STATUS_INVALID_PARAMETER;
  953. }
  954. } else {
  955. //
  956. // Set the Io port base address to logical device configuration space
  957. //
  958. c = (UCHAR)cmDesc->u.Port.Start.LowPart;
  959. PipWriteAddress(ioBase + ADDRESS_IO_BASE_LO);
  960. PipWriteData(c);
  961. c = (UCHAR)(cmDesc->u.Port.Start.LowPart >> 8);
  962. PipWriteAddress(ioBase + ADDRESS_IO_BASE_HI);
  963. PipWriteData(c);
  964. ioBase += ADDRESS_IO_INCR;
  965. }
  966. break;
  967. case CmResourceTypeInterrupt:
  968. if (pass == 1) {
  969. noIrq++;
  970. if (noIrq > NUMBER_IRQ_DESCRIPTORS ||
  971. (cmDesc->u.Interrupt.Level & 0xfffffff0)) {
  972. return STATUS_INVALID_PARAMETER;
  973. }
  974. //
  975. // See if we can get the interrupt information from possible resource
  976. // data. We need it to set the configuration register.
  977. //
  978. if (!PipFindIrqInformation(cmDesc->u.Interrupt.Level, BiosRequirements, &information)) {
  979. return STATUS_INVALID_PARAMETER;
  980. }
  981. } else {
  982. //
  983. // Set the Irq to logical device configuration space
  984. //
  985. c = (UCHAR)cmDesc->u.Interrupt.Level;
  986. PipWriteAddress(irqBase + ADDRESS_IRQ_VALUE);
  987. PipWriteData(c);
  988. // Set IRQ to high edge or low level. Explicitly
  989. // ignore what was in the requirements as it may
  990. // specify low edge or high level which don't
  991. // actually work.
  992. if (cmDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
  993. c = 2;
  994. } else {
  995. c = 1;
  996. }
  997. PipWriteAddress(irqBase + ADDRESS_IRQ_TYPE);
  998. PipWriteData(c);
  999. DebugPrint((DEBUG_IRQ, "Wrote 0x%x to port %x\n",
  1000. (ULONG) c, irqBase));
  1001. PipWriteAddress(irqBase + ADDRESS_IRQ_TYPE);
  1002. c = PipReadData();
  1003. DebugPrint((DEBUG_IRQ, "Read back 0x%x at port %x\n",
  1004. (ULONG) c, irqBase));
  1005. irqBase += ADDRESS_IRQ_INCR;
  1006. }
  1007. break;
  1008. case CmResourceTypeDma:
  1009. if (pass == 1) {
  1010. noDma++;
  1011. if (noDma > NUMBER_IRQ_DESCRIPTORS ||
  1012. (cmDesc->u.Dma.Channel & 0xfffffff8)) {
  1013. return STATUS_INVALID_PARAMETER;
  1014. }
  1015. } else {
  1016. //
  1017. // Set the Dma channel to logical device configuration space
  1018. //
  1019. c = (UCHAR)cmDesc->u.Dma.Channel;
  1020. PipWriteAddress(dmaBase + ADDRESS_DMA_VALUE);
  1021. PipWriteData(c);
  1022. dmaBase += ADDRESS_DMA_INCR;
  1023. }
  1024. break;
  1025. case CmResourceTypeMemory:
  1026. if (pass == 1) {
  1027. base = cmDesc->u.Memory.Start.LowPart;
  1028. limit = base + cmDesc->u.Memory.Length - 1;
  1029. if (!PipFindMemoryInformation(noMemory, base, limit, BiosRequirements, &tag, &information,NULL)) {
  1030. return STATUS_INVALID_PARAMETER;
  1031. } else {
  1032. if (tag == TAG_MEMORY) {
  1033. noMemory24++;
  1034. //
  1035. // Make sure the lower 8 bits of the base address are zero.
  1036. //
  1037. if (noMemory24 > NUMBER_MEMORY_DESCRIPTORS ||
  1038. base & 0xff) {
  1039. return STATUS_INVALID_PARAMETER;
  1040. }
  1041. } else {
  1042. noMemory32++;
  1043. if (noMemory32 > NUMBER_32_MEMORY_DESCRIPTORS) {
  1044. return STATUS_INVALID_PARAMETER;
  1045. }
  1046. }
  1047. }
  1048. } else {
  1049. //
  1050. // Find information in BiosRequirements to help determine how to write
  1051. // the memory configuration space.
  1052. //
  1053. base = cmDesc->u.Memory.Start.LowPart;
  1054. limit = base + cmDesc->u.Memory.Length - 1;
  1055. PipFindMemoryInformation(noMemory, base, limit, BiosRequirements, &tag, &information,NULL);
  1056. if (tag == TAG_MEMORY) {
  1057. PipWriteAddress(memoryBase + ADDRESS_MEMORY_LO);
  1058. PipWriteData(base >> 0x8);
  1059. PipWriteAddress(memoryBase + ADDRESS_MEMORY_HI);
  1060. PipWriteData(base >> 0x10);
  1061. if ((information & 0x18) == 0) { // 8 bit memory only
  1062. c = 0;
  1063. } else {
  1064. c = 2;
  1065. }
  1066. //
  1067. // Check range or limit
  1068. //
  1069. PipWriteAddress(memoryBase + ADDRESS_MEMORY_CTL);
  1070. if (PipReadData() & ADDRESS_MEMORY_CTL_LIMIT) {
  1071. c += ADDRESS_MEMORY_CTL_LIMIT;
  1072. limit = base + cmDesc->u.Memory.Length;
  1073. } else {
  1074. limit = cmDesc->u.Memory.Length; // Range
  1075. limit = (~limit)+1;
  1076. }
  1077. PipWriteAddress(memoryBase + ADDRESS_MEMORY_CTL);
  1078. PipWriteData(c);
  1079. PipWriteAddress(memoryBase + ADDRESS_MEMORY_UPPER_LO);
  1080. PipWriteData((UCHAR)(limit >> 0x8));
  1081. PipWriteAddress(memoryBase + ADDRESS_MEMORY_UPPER_HI);
  1082. PipWriteData((UCHAR)(limit >> 0x10));
  1083. memoryBase += ADDRESS_MEMORY_INCR;
  1084. } else {
  1085. tmp = ADDRESS_32_MEMORY_BASE(memory32Base);
  1086. PipWriteAddress(tmp + ADDRESS_32_MEMORY_B0);
  1087. PipWriteData(base);
  1088. PipWriteAddress(tmp + ADDRESS_32_MEMORY_B1);
  1089. PipWriteData(base >> 0x8);
  1090. PipWriteAddress(tmp + ADDRESS_32_MEMORY_B2);
  1091. PipWriteData(base >> 0x10);
  1092. PipWriteAddress(tmp + ADDRESS_32_MEMORY_B3);
  1093. PipWriteData(base >> 0x18);
  1094. switch (information & 0x18) {
  1095. case 0: // 8 bit only
  1096. c = 0;
  1097. case 8: // 16 bit only
  1098. case 0x10: // 8 and 16 bit supported
  1099. c = 2;
  1100. break;
  1101. case 0x18: // 32 bit only
  1102. c = 4;
  1103. break;
  1104. }
  1105. PipWriteAddress(ADDRESS_32_MEMORY_CTL);
  1106. if (PipReadData() & ADDRESS_MEMORY_CTL_LIMIT) {
  1107. c += ADDRESS_MEMORY_CTL_LIMIT;
  1108. limit = base + cmDesc->u.Memory.Length;
  1109. } else {
  1110. limit = cmDesc->u.Memory.Length; // Range
  1111. limit = (~limit) + 1;
  1112. }
  1113. PipWriteAddress(ADDRESS_32_MEMORY_CTL);
  1114. PipWriteData(c);
  1115. PipWriteAddress(tmp + ADDRESS_32_MEMORY_E0);
  1116. PipWriteData(limit);
  1117. PipWriteAddress(tmp + ADDRESS_32_MEMORY_E1);
  1118. PipWriteData(limit >> 0x8);
  1119. PipWriteAddress(tmp + ADDRESS_32_MEMORY_E2);
  1120. PipWriteData(limit >> 0x10);
  1121. PipWriteAddress(tmp + ADDRESS_32_MEMORY_E3);
  1122. PipWriteData(limit >> 0x18);
  1123. memory32Base++;
  1124. }
  1125. }
  1126. noMemory++;
  1127. }
  1128. cmDesc++;
  1129. }
  1130. }
  1131. //
  1132. // Finally, mark all the unused descriptors as disabled.
  1133. //
  1134. for (i = noMemory24; i < NUMBER_MEMORY_DESCRIPTORS; i++) {
  1135. for (j = 0; j < 5; j++) {
  1136. PipWriteAddress(memoryBase + j);
  1137. PipWriteData(0);
  1138. }
  1139. memoryBase += ADDRESS_MEMORY_INCR;
  1140. }
  1141. for (i = noMemory32; i < NUMBER_32_MEMORY_DESCRIPTORS; i++) {
  1142. tmp = ADDRESS_32_MEMORY_BASE(memory32Base);
  1143. for (j = 0; j < 9; j++) {
  1144. PipWriteAddress(tmp + j);
  1145. PipWriteData(0);
  1146. }
  1147. memory32Base++;
  1148. }
  1149. for (i = noIo; i < NUMBER_IO_DESCRIPTORS; i++) {
  1150. for (j = 0; j < 2; j++) {
  1151. PipWriteAddress(ioBase + j);
  1152. PipWriteData(0);
  1153. }
  1154. ioBase += ADDRESS_IO_INCR;
  1155. }
  1156. for (i = noIrq; i < NUMBER_IRQ_DESCRIPTORS; i++) {
  1157. for (j = 0; j < 2; j++) {
  1158. PipWriteAddress(irqBase + j);
  1159. PipWriteData(0);
  1160. }
  1161. irqBase += ADDRESS_IRQ_INCR;
  1162. }
  1163. for (i = noDma; i < NUMBER_DMA_DESCRIPTORS; i++) {
  1164. PipWriteAddress(dmaBase);
  1165. PipWriteData(4);
  1166. dmaBase += ADDRESS_DMA_INCR;
  1167. }
  1168. return STATUS_SUCCESS;
  1169. }
  1170. VOID
  1171. PipLFSRInitiation(
  1172. VOID
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. This routine insures the LFSR (linear feedback shift register) is in its
  1177. initial state and then performs 32 writes to the ADDRESS port to initiation
  1178. LFSR function.
  1179. Pnp software sends the initiation key to all the Pnp ISA cards to place them
  1180. into configuration mode. The software then ready to perform isolation
  1181. protocol.
  1182. Arguments:
  1183. None.
  1184. Return Value:
  1185. None.
  1186. --*/
  1187. {
  1188. UCHAR seed, bit7;
  1189. ULONG i;
  1190. ASSERT(PipState == PiSWaitForKey);
  1191. //
  1192. // First perform two writes of value zero to insure the LFSR is in the
  1193. // initial state.
  1194. //
  1195. PipWriteAddress (0);
  1196. PipWriteAddress (0);
  1197. //
  1198. // Perform the initiation key.
  1199. //
  1200. seed = LFSR_SEED; // initial value of 0x6a
  1201. for (i = 0; i < 32; i++) {
  1202. PipWriteAddress (seed);
  1203. bit7=(((seed & 2) >> 1) ^ (seed & 1)) << 7;
  1204. seed =(seed >> 1) | bit7;
  1205. }
  1206. DebugPrint((DEBUG_ISOLATE, "Sent initiation key\n"));
  1207. PipReportStateChange(PiSSleep);
  1208. }
  1209. VOID
  1210. PipIsolateCards (
  1211. OUT PUCHAR NumberCSNs
  1212. )
  1213. /*++
  1214. Routine Description:
  1215. This routine performs PnP ISA cards isolation sequence.
  1216. Arguments:
  1217. NumberCSNs - supplies the addr of a variable to receive the number of
  1218. Pnp Isa cards isolated.
  1219. ReadDataPort - Supplies the address of a variable to supply ReadData port
  1220. address.
  1221. Return Value:
  1222. None.
  1223. --*/
  1224. {
  1225. USHORT j, i;
  1226. UCHAR cardId[NUMBER_CARD_ID_BYTES];
  1227. UCHAR bit, bit7, checksum, byte1, byte2;
  1228. UCHAR csn;
  1229. //
  1230. // First send Initiation Key to all the PNP ISA cards to enable PnP auto-config
  1231. // ports and put all cards into sleep state
  1232. //
  1233. PipLFSRInitiation();
  1234. //
  1235. // Reset all Pnp ISA cards' CSN to 0 and return to wait-for-key state
  1236. //
  1237. PipWriteAddress (CONFIG_CONTROL_PORT);
  1238. PipWriteData (CONTROL_RESET_CSN + CONTROL_WAIT_FOR_KEY);
  1239. DebugPrint((DEBUG_STATE, "Reset CSNs, going to WaitForKey\n"));
  1240. PipReportStateChange(PiSWaitForKey);
  1241. csn=*NumberCSNs = 0;
  1242. //
  1243. // Delay 2 msec for cards to load initial configuration state.
  1244. //
  1245. KeStallExecutionProcessor(2000); // delay 2 msec
  1246. //
  1247. // Put cards into configuration mode to ready isolation process.
  1248. // The hardware on each PnP Isa card expects 72 pairs of I/O read
  1249. // access to the read data port.
  1250. //
  1251. PipLFSRInitiation();
  1252. //
  1253. // Starting Pnp Isa card isolation process.
  1254. //
  1255. //
  1256. // Send WAKE[CSN=0] to force all cards without CSN into isolation
  1257. // state to set READ DATA PORT.
  1258. //
  1259. PipIsolation();
  1260. KeStallExecutionProcessor(1000); // delay 1 msec
  1261. DebugPrint((DEBUG_STATE, "Wake all cards without CSN, Isolation\n"));
  1262. //
  1263. // Set read data port to current testing value.
  1264. //
  1265. PipWriteAddress(SET_READ_DATA_PORT);
  1266. PipWriteData((UCHAR)((ULONG_PTR)PipReadDataPort >> 2));
  1267. DebugPrint((DEBUG_STATE, "Set RDP to %x\n", PipReadDataPort));
  1268. //
  1269. // Isolate one PnP ISA card until fail
  1270. //
  1271. PipIsolation();
  1272. while (TRUE) {
  1273. //
  1274. // Read serial isolation port to cause PnP cards in the isolation
  1275. // state to compare one bit of the boards ID.
  1276. //
  1277. PipWriteAddress(SERIAL_ISOLATION_PORT);
  1278. //
  1279. // We need to delay 1 msec prior to starting the first pair of isolation
  1280. // reads and must wait 250usec between each subsequent pair of isolation
  1281. // reads. This delay gives the ISA cards time to access information from
  1282. // possible very slow storage device.
  1283. //
  1284. KeStallExecutionProcessor(1000); // delay 1 msec
  1285. RtlZeroMemory(cardId, NUMBER_CARD_ID_BYTES);
  1286. checksum = LFSR_SEED;
  1287. for (j = 0; j < NUMBER_CARD_ID_BITS; j++) {
  1288. //
  1289. // Read card id bit by bit
  1290. //
  1291. byte1 = PipReadData();
  1292. byte2 = PipReadData();
  1293. bit = (byte1 == ISOLATION_TEST_BYTE_1) && (byte2 == ISOLATION_TEST_BYTE_2);
  1294. cardId[j / 8] |= bit << (j % 8);
  1295. if (j < CHECKSUMED_BITS) {
  1296. //
  1297. // Calculate checksum and only do it for the first 64 bits
  1298. //
  1299. bit7 = (((checksum & 2) >> 1) ^ (checksum & 1) ^ (bit)) << 7;
  1300. checksum = (checksum >> 1) | bit7;
  1301. }
  1302. KeStallExecutionProcessor(250); // delay 250 usec
  1303. }
  1304. //
  1305. // Verify the card id we read is legitimate
  1306. // First make sure checksum is valid. Note zero checksum is considered valid.
  1307. //
  1308. DebugPrint((DEBUG_ISOLATE, "Card Bytes: %X %X %X %X %X %X %X %X %X\n",cardId[0],cardId[1],cardId[2],cardId[3],cardId[4],cardId[5],cardId[6],cardId[7],cardId[8]));
  1309. if (cardId[8] == 0 || checksum == cardId[8]) {
  1310. //
  1311. // Next make sure cardId is not zero
  1312. //
  1313. byte1 = 0;
  1314. for (j = 0; j < NUMBER_CARD_ID_BYTES; j++) {
  1315. byte1 |= cardId[j];
  1316. }
  1317. if (byte1 != 0) {
  1318. //
  1319. // Make sure the vender EISA ID bytes are nonzero
  1320. //
  1321. if ((cardId[0] & 0x7f) != 0 && cardId[1] != 0) {
  1322. //
  1323. // We found a valid Pnp Isa card, assign it a CSN number
  1324. //
  1325. DebugPrint((DEBUG_ISOLATE, "Assigning csn %d\n",csn+1));
  1326. PipWriteAddress(SET_CSN_PORT);
  1327. PipWriteData(++csn);
  1328. if (PipReadData() != csn) {
  1329. csn--;
  1330. DebugPrint((DEBUG_ISOLATE, "Assigning csn %d FAILED, bailing!\n",csn+1));
  1331. PipIsolation();
  1332. PipSleep();
  1333. *NumberCSNs = csn;
  1334. return;
  1335. }
  1336. //
  1337. // Do Wake[CSN] command to put the newly isolated card to
  1338. // sleep state and other un-isolated cards to isolation
  1339. // state.
  1340. //
  1341. PipIsolation();
  1342. DebugPrint((DEBUG_STATE, "Put card in Sleep, other in Isolation\n"));
  1343. continue; // ... to isolate more cards ...
  1344. }
  1345. }
  1346. }else {
  1347. DebugPrint ((DEBUG_ISOLATE, "invalid read during isolation\n"));
  1348. }
  1349. break; // could not isolate more cards ...
  1350. }
  1351. //
  1352. // Finaly put all cards into sleep state
  1353. //
  1354. PipSleep();
  1355. *NumberCSNs = csn;
  1356. }
  1357. ULONG
  1358. PipFindNextLogicalDeviceTag (
  1359. IN OUT PUCHAR *CardData,
  1360. IN OUT LONG *Limit
  1361. )
  1362. /*++
  1363. Routine Description:
  1364. This function searches the Pnp Isa card data for the Next logical
  1365. device tag encountered. The input *CardData should point to an logical device id tag,
  1366. which is the current logical device tag. If the *CardData does not point to a logical
  1367. device id tag (but, it must point to some kind of tag), it will be moved to next
  1368. logical device id tag.
  1369. Arguments:
  1370. CardData - a variable to supply a pointer to the pnp Isa resource descriptors and to
  1371. receive next logical device tag pointer.
  1372. Limit - a variable to supply the maximum length of the search and to receive the new
  1373. lemit after the search.
  1374. Return Value:
  1375. Length of the data between current and next logical device tags, ie the data length
  1376. of the current logical device.
  1377. In case there is no 'next' logical device tag, the returned *CardData = NULL,
  1378. *Limit = zero and the data length of current logical tag is returned as function
  1379. returned value.
  1380. --*/
  1381. {
  1382. UCHAR tag;
  1383. USHORT size;
  1384. LONG l;
  1385. ULONG retLength;
  1386. PUCHAR p;
  1387. BOOLEAN atIdTag = FALSE;;
  1388. p = *CardData;
  1389. l = *Limit;
  1390. tag = *p;
  1391. retLength = 0;
  1392. while (tag != TAG_COMPLETE_END && l > 0) {
  1393. //
  1394. // Determine the size of the BIOS resource descriptor
  1395. //
  1396. if (!(tag & LARGE_RESOURCE_TAG)) {
  1397. size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
  1398. size += 1; // length of small tag
  1399. } else {
  1400. size = *((USHORT UNALIGNED *)(p + 1));
  1401. size += 3; // length of large tag
  1402. }
  1403. p += size;
  1404. retLength += size;
  1405. l -= size;
  1406. tag = *p;
  1407. if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) {
  1408. *CardData = p;
  1409. *Limit = l;
  1410. return retLength;
  1411. }
  1412. }
  1413. *CardData = NULL;
  1414. *Limit = 0;
  1415. if (tag == TAG_COMPLETE_END) {
  1416. return (retLength + 2); // add 2 for the length of end tag descriptor
  1417. } else {
  1418. return 0;
  1419. }
  1420. }
  1421. NTSTATUS
  1422. PipReadCardResourceDataBytes (
  1423. IN USHORT BytesToRead,
  1424. IN PUCHAR Buffer
  1425. )
  1426. /*++
  1427. Routine Description:
  1428. This function reads specified number of bytes of card resource data .
  1429. Arguments:
  1430. BytesToRead - supplies number of bytes to read.
  1431. Buffer - supplies a pointer to a buffer to receive the read bytes.
  1432. Return Value:
  1433. None
  1434. --*/
  1435. {
  1436. USHORT i, j;
  1437. PUCHAR p;
  1438. for (i = 0, p = Buffer; i < BytesToRead; i++, p++) {
  1439. PipWriteAddress(CONFIG_DATA_STATUS_PORT);
  1440. //
  1441. // Waiting for data ready status bit
  1442. //
  1443. j = 0;
  1444. while ((PipReadData() & 1) != 1) {
  1445. if (j == 10000) {
  1446. return STATUS_NO_SUCH_DEVICE;
  1447. }
  1448. KeStallExecutionProcessor(1000); // delay 1 msec
  1449. j++;
  1450. }
  1451. //
  1452. // Read the data ...
  1453. //
  1454. PipWriteAddress(CONFIG_DATA_PORT);
  1455. *p = PipReadData();
  1456. }
  1457. return STATUS_SUCCESS;
  1458. }
  1459. USHORT
  1460. PipIrqLevelRequirementsFromDeviceData(
  1461. IN PUCHAR BiosRequirements,
  1462. IN ULONG Length
  1463. )
  1464. /*++
  1465. Routine Description:
  1466. This routine searches the resource data for IRQ tags and extracts
  1467. information on whether edge/level is specified. This is on a per
  1468. logical device basis.
  1469. Arguments:
  1470. BiosRequirements - the per-device tags.
  1471. Length - Length of per-device tag area.
  1472. Return Value:
  1473. edge/level as specified by the device requirements.
  1474. --*/
  1475. {
  1476. UCHAR tag, level;
  1477. ULONG increment;
  1478. USHORT irqFlags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1479. PPNP_IRQ_DESCRIPTOR biosDesc;
  1480. BOOLEAN sawIrq = FALSE;
  1481. //
  1482. // Skip current logical id tag
  1483. //
  1484. tag = *BiosRequirements;
  1485. ASSERT((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID);
  1486. BiosRequirements += (tag & SMALL_TAG_SIZE_MASK) + 1;
  1487. //
  1488. // Search the possible resource list to get the information
  1489. // for the Irq.
  1490. //
  1491. tag = *BiosRequirements;
  1492. while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID)) {
  1493. if ((tag & SMALL_TAG_MASK) == TAG_IRQ) {
  1494. sawIrq = TRUE;
  1495. biosDesc = (PPNP_IRQ_DESCRIPTOR)BiosRequirements;
  1496. if ((tag & SMALL_TAG_SIZE_MASK) == 2) {
  1497. irqFlags = CM_RESOURCE_INTERRUPT_LATCHED;
  1498. } else {
  1499. level = biosDesc->Information;
  1500. DebugPrint((DEBUG_IRQ, "Irq req info is %x\n", (ULONG) level));
  1501. if (level == 0xF) {
  1502. // register is broken, assume edge
  1503. irqFlags = CM_RESOURCE_INTERRUPT_LATCHED;
  1504. } else if (level & 0x3) {
  1505. irqFlags = CM_RESOURCE_INTERRUPT_LATCHED;
  1506. } else if (level & 0xC) {
  1507. irqFlags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1508. }
  1509. }
  1510. }
  1511. if (tag & LARGE_RESOURCE_TAG) {
  1512. increment = *((USHORT UNALIGNED *)(BiosRequirements + 1));
  1513. increment += 3; // length of large tag
  1514. } else {
  1515. increment = tag & SMALL_TAG_SIZE_MASK;
  1516. increment += 1; // length of small tag
  1517. }
  1518. BiosRequirements += increment;
  1519. tag = *BiosRequirements;
  1520. }
  1521. if (!sawIrq) {
  1522. return CM_RESOURCE_INTERRUPT_LATCHED;
  1523. }
  1524. return irqFlags;
  1525. }
  1526. VOID
  1527. PipFixBootConfigIrqs(
  1528. IN PCM_RESOURCE_LIST BootResources,
  1529. IN USHORT irqFlags
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. This routine modifies the boot config resources list to reflect
  1534. whether the devices's irqs should be considered edge or level.
  1535. This is on a per logical device basis.
  1536. Arguments:
  1537. BootResources - Boot config as determined by PipReadDeviceResources()
  1538. irqFlags - level/edge setting to apply to boot config resources
  1539. --*/
  1540. {
  1541. PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
  1542. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
  1543. ULONG count = 0, size, i, j;
  1544. if (BootResources == NULL) {
  1545. return;
  1546. }
  1547. cmFullDesc = &BootResources->List[0];
  1548. for (i = 0; i < BootResources->Count; i++) {
  1549. cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
  1550. for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
  1551. size = 0;
  1552. if (cmPartDesc->Type == CmResourceTypeInterrupt) {
  1553. cmPartDesc->Flags = irqFlags;
  1554. if (cmPartDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
  1555. cmPartDesc->ShareDisposition = CmResourceShareDeviceExclusive;
  1556. }
  1557. } else if (cmPartDesc->Type == CmResourceTypeDeviceSpecific) {
  1558. size = cmPartDesc->u.DeviceSpecificData.DataSize;
  1559. }
  1560. cmPartDesc++;
  1561. cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
  1562. }
  1563. cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
  1564. }
  1565. }
  1566. #endif