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.

2563 lines
76 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. ixpciir.c
  5. Abstract:
  6. This module implements the code to provide Pci Irq Routing
  7. support. It reads the routing table, provides the Irq arbiter
  8. and uses the chipset miniport library to program the links.
  9. Author:
  10. Santosh Jodh (santoshj) 10-June-1998
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. --*/
  15. //
  16. // This module is compatible with PAE mode and therefore treats physical
  17. // addresses as 64-bit entities.
  18. //
  19. #if !defined(_PHYS64_)
  20. #define _PHYS64_
  21. #endif
  22. #include "halp.h"
  23. #include <pci.h>
  24. #include <stdio.h>
  25. #ifndef _IN_KERNEL_
  26. #define _IN_KERNEL_
  27. #include <regstr.h>
  28. #undef _IN_KERNEL_
  29. #else
  30. #include <regstr.h>
  31. #endif
  32. #include "pcip.h"
  33. #include "ixpciir.h"
  34. #ifndef MAXIMUM_VALUE_NAME_LENGTH
  35. #define MAXIMUM_VALUE_NAME_LENGTH 256
  36. #endif
  37. //
  38. // MS specification for PCI IRQ Routing specifies that the BIOS
  39. // provide the table in the ROM between the physical addresses
  40. // of 0xF0000 and 0xFFFFF. The table starts on a 16-byte boundary
  41. // with a 4-byte signature of "$PIR".
  42. //
  43. // Other restrictions:
  44. //
  45. // Version: Should be 1.0
  46. // Size: Must be integral multiple of 16 bytes and > 32 bytes
  47. // Checksum: The entire table should checksum to 0.
  48. //
  49. #define PIRT_BIOS_START 0xf0000
  50. #define PIRT_BIOS_END 0xfffff
  51. #define PIRT_BIOS_SIZE (PIRT_BIOS_END - PIRT_BIOS_START + 1)
  52. #define PIRT_ALIGNMENT 16
  53. #define PIRT_SIGNATURE 'RIP$' // $PIR little endian
  54. #define PIRT_VERSION 0x0100
  55. ULONG
  56. HalpGetIrqRoutingTable (
  57. OUT PPCI_IRQ_ROUTING_TABLE *PciIrqRoutingTable,
  58. IN ULONG Options
  59. );
  60. ULONG
  61. HalpInitializeMiniport (
  62. IN OUT PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo
  63. );
  64. NTSTATUS
  65. HalpInitLinkNodes (
  66. PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo
  67. );
  68. PPCI_IRQ_ROUTING_TABLE
  69. HalpGetRegistryTable (
  70. IN const WCHAR* KeyName,
  71. IN const WCHAR* ValueName,
  72. IN ULONG HeaderSize OPTIONAL
  73. );
  74. PPCI_IRQ_ROUTING_TABLE
  75. HalpGetPCIBIOSTableFromRealMode(
  76. VOID
  77. );
  78. PPCI_IRQ_ROUTING_TABLE
  79. HalpGet$PIRTable (
  80. VOID
  81. );
  82. PPCI_IRQ_ROUTING_TABLE
  83. HalpCopy$PIRTable (
  84. IN PUCHAR BiosPtr,
  85. IN PUCHAR BiosEnd
  86. );
  87. BOOLEAN
  88. HalpSanityCheckTable (
  89. IN PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable,
  90. IN BOOLEAN IgnoreChecksum
  91. );
  92. PSLOT_INFO
  93. HalpBarberPole (
  94. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  95. IN PDEVICE_OBJECT Pdo,
  96. IN ULONG Bus,
  97. IN ULONG Slot,
  98. IN OUT PUCHAR Pin
  99. );
  100. BOOLEAN
  101. HalpBarberPolePin (
  102. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  103. IN PDEVICE_OBJECT Parent,
  104. IN ULONG Bus,
  105. IN ULONG Device,
  106. IN OUT PUCHAR Pin
  107. );
  108. PSLOT_INFO
  109. HalpGetSlotInfo (
  110. IN PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable,
  111. IN UCHAR Bus,
  112. IN UCHAR Device
  113. );
  114. NTSTATUS
  115. HalpReadRegistryDwordValue (
  116. IN HANDLE Root,
  117. IN const WCHAR* KeyName,
  118. IN const WCHAR* ValueName,
  119. OUT PULONG Data
  120. );
  121. NTSTATUS
  122. HalpWriteRegistryDwordValue (
  123. IN HANDLE Root,
  124. IN const WCHAR* KeyName,
  125. IN const WCHAR* ValueName,
  126. IN ULONG Value
  127. );
  128. #ifdef ALLOC_PRAGMA
  129. #pragma alloc_text(INIT, HalpInitPciIrqRouting)
  130. #pragma alloc_text(INIT, HalpGetIrqRoutingTable)
  131. #pragma alloc_text(INIT, HalpInitializeMiniport)
  132. #pragma alloc_text(INIT, HalpInitLinkNodes)
  133. #pragma alloc_text(INIT, HalpGetRegistryTable)
  134. #pragma alloc_text(INIT, HalpGetPCIBIOSTableFromRealMode)
  135. #pragma alloc_text(INIT, HalpGet$PIRTable)
  136. #pragma alloc_text(INIT, HalpCopy$PIRTable)
  137. #pragma alloc_text(INIT, HalpSanityCheckTable)
  138. #pragma alloc_text(PAGE, HalpBarberPole)
  139. #pragma alloc_text(PAGE, HalpBarberPolePin)
  140. #pragma alloc_text(PAGE, HalpFindLinkNode)
  141. #pragma alloc_text(PAGE, HalpGetSlotInfo)
  142. #pragma alloc_text(PAGE, HalpReadRegistryDwordValue)
  143. #pragma alloc_text(PAGE, HalpWriteRegistryDwordValue)
  144. #pragma alloc_text(PAGE, HalpProgramInterruptLine)
  145. #pragma alloc_text(PAGELK, HalpCommitLink)
  146. #endif
  147. extern PULONG InitSafeBootMode;
  148. #ifdef ALLOC_DATA_PRAGMA
  149. #pragma const_seg("PAGECONST")
  150. #endif // ALLOC_DATA_PRAGMA
  151. //
  152. // Global key for Pci Irq Routing.
  153. //
  154. const WCHAR rgzPciIrqRouting[] = REGSTR_PATH_PCIIR;
  155. //
  156. // Pci Irq Routing options value.
  157. //
  158. const WCHAR rgzOptions[] = REGSTR_VAL_OPTIONS;
  159. //
  160. // Pci Irq Routing status values.
  161. //
  162. const WCHAR rgzStatus[] = REGSTR_VAL_STAT;
  163. //
  164. // Pci Irq Routing Table status values.
  165. //
  166. const WCHAR rgzTableStatus[] = REGSTR_VAL_TABLE_STAT;
  167. //
  168. // Pci Irq Routing Miniport status values.
  169. //
  170. const WCHAR rgzMiniportStatus[] = REGSTR_VAL_MINIPORT_STAT;
  171. //
  172. // Offset from 0xF0000 where $PIR table was last found.
  173. //
  174. const WCHAR rgz$PIROffset[] = L"$PIROffset";
  175. //
  176. // Irq Miniports key under rgzPciIrqRouting.
  177. // This key contains keys whose name is the device-vendor id
  178. // for the chipsets we support.
  179. //
  180. const WCHAR rgzIrqMiniports[] = REGSTR_PATH_PCIIR L"\\IrqMiniports";
  181. //
  182. // Each miniport key contains a instance value which
  183. // corresponds to the entry for the chipset in the
  184. // miniport table.
  185. //
  186. const WCHAR rgzInstance[] = L"Instance";
  187. //
  188. // This key overrides all miniports if present.
  189. //
  190. const WCHAR rgzOverride[] = L"Override";
  191. //
  192. // Registry key for the routing table.
  193. //
  194. const WCHAR rgzIrqRoutingTable[] = REGSTR_PATH_PCIIR L"\\IrqRoutingTables";
  195. //
  196. // Registry key for BIOS attributes.
  197. //
  198. const WCHAR rgzBiosInfo[] = REGSTR_PATH_BIOSINFO L"\\PciIrqRouting";
  199. const WCHAR rgzAttributes[] = L"Attributes";
  200. const WCHAR rgzPciParameters[] = L"Parameters";
  201. #ifdef ALLOC_DATA_PRAGMA
  202. #pragma const_seg()
  203. #endif // ALLOC_DATA_PRAGMA
  204. PCI_IRQ_ROUTING_INFO HalpPciIrqRoutingInfo = {0};
  205. ULONG HalpIrqMiniportInitialized = 0;
  206. NTSTATUS
  207. HalpInitPciIrqRouting(
  208. OUT PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo
  209. )
  210. /*++
  211. Routine Description:
  212. This routine initializes Pci Irq Routing by reading the
  213. Irq routing table, initializing the chipset miniport and
  214. initializing the Pci Interrupt Routing interface.
  215. Input Parameters:
  216. PciIrqRoutingInfo - Pci Irq Routing information.
  217. Return Value:
  218. --*/
  219. {
  220. NTSTATUS status;
  221. ULONG pirStatus;
  222. ULONG tableStatus;
  223. ULONG miniportStatus;
  224. ULONG pirOptions;
  225. PAGED_CODE();
  226. //
  227. // Setup to return failure.
  228. //
  229. HalpIrqMiniportInitialized = 0;
  230. status = STATUS_UNSUCCESSFUL;
  231. pirStatus = PIR_STATUS_MAX;
  232. tableStatus = PIR_STATUS_TABLE_MAX | (PIR_STATUS_TABLE_MAX << 16);
  233. miniportStatus = PIR_STATUS_MINIPORT_MAX | (PIR_STATUS_MINIPORT_MAX << 16);
  234. //
  235. // No IRQ routing in safe boot.
  236. //
  237. if (!(*InitSafeBootMode))
  238. {
  239. pirStatus = PIR_STATUS_DISABLED;
  240. //
  241. // Read Pci Interrupt Routing options set by the user.
  242. //
  243. pirOptions = 0;
  244. HalpReadRegistryDwordValue(NULL, rgzPciIrqRouting, rgzOptions, &pirOptions);
  245. //
  246. // Make sure Pci Interrupt Routing is not disabled.
  247. //
  248. if (pirOptions & PIR_OPTION_ENABLED)
  249. {
  250. //
  251. // First get the interface from Pci.
  252. //
  253. if (PciIrqRoutingInfo->PciInterface)
  254. {
  255. HalPrint(("Obtained the Pci Interrupt Routing Interface from Pci driver!"));
  256. status = STATUS_UNSUCCESSFUL;
  257. //
  258. // Get the Pci Interrupt Routing table for this motherboard.
  259. //
  260. tableStatus = HalpGetIrqRoutingTable(&PciIrqRoutingInfo->PciIrqRoutingTable, pirOptions);
  261. if ((tableStatus & 0xFFFF) < PIR_STATUS_TABLE_NONE)
  262. {
  263. //
  264. // Get the miniport instance for this motherboard.
  265. //
  266. miniportStatus = HalpInitializeMiniport(PciIrqRoutingInfo);
  267. if ((miniportStatus & 0xFFFF) < PIR_STATUS_MINIPORT_NONE)
  268. {
  269. //
  270. // Validate the Pci Irq Routing table with the miniport.
  271. //
  272. status = PciirqmpValidateTable( PciIrqRoutingInfo->PciIrqRoutingTable,
  273. ((tableStatus & 0xFFFF) == PIR_STATUS_TABLE_REALMODE)? 1 : 0);
  274. if (!NT_SUCCESS(status))
  275. {
  276. HalPrint(("Pci irq miniport failed to validate the routing table!"));
  277. miniportStatus |= (PIR_STATUS_MINIPORT_INVALID << 16);
  278. }
  279. else
  280. {
  281. HalPrint(("Pci irq miniport validated routing table!"));
  282. miniportStatus |= (PIR_STATUS_MINIPORT_SUCCESS << 16);
  283. pirStatus = PIR_STATUS_ENABLED;
  284. HalpIrqMiniportInitialized = TRUE;
  285. }
  286. }
  287. }
  288. }
  289. else
  290. {
  291. pirStatus = PIR_STATUS_ERROR;
  292. }
  293. }
  294. else
  295. {
  296. HalPrint(("Pci Irq Routing disabled!"));
  297. }
  298. //
  299. // Create list of links.
  300. //
  301. if (NT_SUCCESS(status))
  302. {
  303. status = HalpInitLinkNodes(PciIrqRoutingInfo);
  304. }
  305. //
  306. // Free the memory for the routing table if there was any error.
  307. //
  308. if (!NT_SUCCESS(status))
  309. {
  310. if (PciIrqRoutingInfo->PciIrqRoutingTable != NULL)
  311. {
  312. ExFreePool(PciIrqRoutingInfo->PciIrqRoutingTable);
  313. PciIrqRoutingInfo->PciIrqRoutingTable = NULL;
  314. }
  315. if (PciIrqRoutingInfo->PciInterface)
  316. {
  317. PciIrqRoutingInfo->PciInterface = NULL;
  318. }
  319. }
  320. //
  321. // Initialize the miniport if not done yet.
  322. //
  323. if (!HalpIrqMiniportInitialized)
  324. {
  325. PCI_IRQ_ROUTING_TABLE table;
  326. //
  327. // Use a local routing table variable since the miniport initialization
  328. // just needs to look at certain fields in the table.
  329. //
  330. PciIrqRoutingInfo->PciIrqRoutingTable = &table;
  331. PciIrqRoutingInfo->PciIrqRoutingTable->RouterBus = 0;
  332. PciIrqRoutingInfo->PciIrqRoutingTable->RouterDevFunc = 0;
  333. PciIrqRoutingInfo->PciIrqRoutingTable->CompatibleRouter = 0xFFFFFFFF;
  334. PciIrqRoutingInfo->PciIrqRoutingTable->MiniportData = 0;
  335. HalpIrqMiniportInitialized = ((HalpInitializeMiniport(PciIrqRoutingInfo) & 0xFFFF) < PIR_STATUS_MINIPORT_NONE)? TRUE : FALSE;
  336. //
  337. // Reset the routing table to NULL since we dont need it any more.
  338. //
  339. PciIrqRoutingInfo->PciIrqRoutingTable = NULL;
  340. }
  341. }
  342. //
  343. // Record the status in the registry for user display.
  344. //
  345. HalpWriteRegistryDwordValue(NULL, rgzPciIrqRouting, rgzStatus, pirStatus);
  346. HalpWriteRegistryDwordValue(NULL, rgzPciIrqRouting, rgzTableStatus, tableStatus);
  347. HalpWriteRegistryDwordValue(NULL, rgzPciIrqRouting, rgzMiniportStatus, miniportStatus);
  348. return (status);
  349. }
  350. ULONG
  351. HalpGetIrqRoutingTable(
  352. OUT PPCI_IRQ_ROUTING_TABLE *PciIrqRoutingTable,
  353. IN ULONG Options
  354. )
  355. /*++
  356. Routine Description:
  357. Reads the Pci Irq Routing table. First tries to
  358. read the table from the registry if available. Otherwise
  359. scans the BIOS ROM for the $PIR table.
  360. Input Parameters:
  361. PciIrqRoutingTable is the pointer to the variable
  362. that recieves the pointer to the routing table.
  363. Return Value:
  364. Status value indicating the source of the table.
  365. --*/
  366. {
  367. ULONG tableStatus = PIR_STATUS_TABLE_NONE | (PIR_STATUS_TABLE_MAX << 16);
  368. ULONG biosAttributes = 0;
  369. PAGED_CODE();
  370. *PciIrqRoutingTable = NULL;
  371. HalpReadRegistryDwordValue(NULL, rgzBiosInfo, rgzAttributes, &biosAttributes);
  372. if (Options & PIR_OPTION_REGISTRY)
  373. {
  374. //
  375. // First try getting it from the registry.
  376. //
  377. *PciIrqRoutingTable = HalpGetRegistryTable(rgzIrqRoutingTable, rgzOverride, 0);
  378. if (*PciIrqRoutingTable != NULL)
  379. {
  380. HalPrint(("Pci Irq Table read from the registry!"));
  381. tableStatus = PIR_STATUS_TABLE_REGISTRY;
  382. }
  383. }
  384. if ((Options & PIR_OPTION_MSSPEC) && !(biosAttributes & PIR_OPTION_MSSPEC))
  385. {
  386. if (*PciIrqRoutingTable == NULL)
  387. {
  388. //
  389. // Next try getting it by scanning the BIOS ROM for $PIR table.
  390. //
  391. *PciIrqRoutingTable = HalpGet$PIRTable();
  392. if (*PciIrqRoutingTable != NULL)
  393. {
  394. HalPrint(("Pci Irq Routing table read from $PIR table in BIOS ROM!"));
  395. tableStatus = PIR_STATUS_TABLE_MSSPEC;
  396. }
  397. }
  398. }
  399. if ((Options & PIR_OPTION_REALMODE) && !(biosAttributes & PIR_OPTION_REALMODE))
  400. {
  401. if (*PciIrqRoutingTable == NULL)
  402. {
  403. //
  404. // First try getting it from the registry.
  405. //
  406. *PciIrqRoutingTable = HalpGetPCIBIOSTableFromRealMode();
  407. if (*PciIrqRoutingTable != NULL)
  408. {
  409. HalPrint(("Pci Irq Table read from PCI BIOS using real-mode interface!"));
  410. tableStatus = PIR_STATUS_TABLE_REALMODE;
  411. }
  412. }
  413. }
  414. if (*PciIrqRoutingTable == NULL)
  415. {
  416. if (biosAttributes)
  417. {
  418. tableStatus = PIR_STATUS_TABLE_BAD | (PIR_STATUS_TABLE_MAX << 16);
  419. }
  420. HalPrint(("No Pci Irq Routing table found for this system!"));
  421. }
  422. else
  423. {
  424. tableStatus |= (PIR_STATUS_TABLE_SUCCESS << 16);
  425. }
  426. return (tableStatus);
  427. }
  428. ULONG
  429. HalpInitializeMiniport(
  430. IN OUT PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo
  431. )
  432. /*++
  433. Routine Description:
  434. Initializes the appropriate miniport for this motherboard.
  435. Input Parameters:
  436. PciIrqRoutingTable - Routing Table for which miniport
  437. needs to be initialized.
  438. Return Value:
  439. Status value indicating whether the miniport initialized or not.
  440. --*/
  441. {
  442. ULONG miniportStatus;
  443. NTSTATUS status;
  444. PBUS_HANDLER busHandler;
  445. PCI_SLOT_NUMBER slotNumber;
  446. ULONG device;
  447. ULONG function;
  448. ULONG routerId;
  449. ULONG miniportInstance;
  450. HANDLE irqMiniport;
  451. UCHAR headerType;
  452. WCHAR buffer[10];
  453. UNICODE_STRING keyName;
  454. PPCI_IRQ_ROUTING_TABLE pciIrqRoutingTable = PciIrqRoutingInfo->PciIrqRoutingTable;
  455. PAGED_CODE();
  456. //
  457. // Setup to return failure.
  458. //
  459. miniportStatus = PIR_STATUS_MINIPORT_NONE;
  460. //
  461. // Open the Pci Interrupt Miniport key.
  462. //
  463. RtlInitUnicodeString( &keyName, rgzIrqMiniports);
  464. status = HalpOpenRegistryKey( &irqMiniport,
  465. NULL,
  466. &keyName,
  467. KEY_READ,
  468. FALSE);
  469. if (NT_SUCCESS(status))
  470. {
  471. //
  472. // First see if there is any overriding miniport.
  473. //
  474. status = HalpReadRegistryDwordValue( irqMiniport,
  475. rgzOverride,
  476. rgzInstance,
  477. &miniportInstance);
  478. if (!NT_SUCCESS(status))
  479. {
  480. //
  481. // Next see if there is an entry for the specified device.
  482. //
  483. busHandler = HalpHandlerForBus(PCIBus, pciIrqRoutingTable->RouterBus);
  484. if (busHandler)
  485. {
  486. slotNumber.u.bits.DeviceNumber = pciIrqRoutingTable->RouterDevFunc >> 3;
  487. slotNumber.u.bits.FunctionNumber = pciIrqRoutingTable->RouterDevFunc & 0x07;
  488. routerId = 0xFFFFFFFF;
  489. HalpReadPCIConfig( busHandler,
  490. slotNumber,
  491. &routerId,
  492. 0,
  493. 4);
  494. if (routerId != 0xFFFFFFFF)
  495. {
  496. _snwprintf(buffer, sizeof(buffer) / sizeof(*buffer), L"%08X", routerId);
  497. buffer[(sizeof(buffer) / sizeof(*buffer)) - 1] = UNICODE_NULL;
  498. status = HalpReadRegistryDwordValue( irqMiniport,
  499. buffer,
  500. rgzInstance,
  501. &miniportInstance);
  502. if (NT_SUCCESS(status))
  503. {
  504. HalPrint(("Found miniport instance %08X for this motherboard!", miniportInstance));
  505. miniportStatus = PIR_STATUS_MINIPORT_NORMAL;
  506. HalpReadRegistryDwordValue(irqMiniport, buffer, rgzPciParameters, &PciIrqRoutingInfo->Parameters);
  507. }
  508. }
  509. }
  510. }
  511. else
  512. {
  513. HalPrint(("Overriding miniport instance %08X found for this motherboard!", miniportInstance));
  514. miniportStatus = PIR_STATUS_MINIPORT_OVERRIDE;
  515. }
  516. //
  517. // Next see if we have a miniport for the compatible router.
  518. //
  519. if (miniportStatus == PIR_STATUS_MINIPORT_NONE)
  520. {
  521. //
  522. // Make sure there is a valid compatible router.
  523. //
  524. if ( pciIrqRoutingTable->CompatibleRouter != 0xFFFFFFFF &&
  525. pciIrqRoutingTable->CompatibleRouter != 0)
  526. {
  527. _snwprintf(buffer, sizeof(buffer) / sizeof(*buffer), L"%08X", pciIrqRoutingTable->CompatibleRouter);
  528. buffer[(sizeof(buffer) / sizeof(*buffer)) - 1] = UNICODE_NULL;
  529. status = HalpReadRegistryDwordValue( irqMiniport,
  530. buffer,
  531. rgzInstance,
  532. &miniportInstance);
  533. if (NT_SUCCESS(status))
  534. {
  535. HalPrint(("Found miniport instance %08X for this motherboard using compatible router %08X!", miniportInstance, pciIrqRoutingTable->CompatibleRouter));
  536. miniportStatus = PIR_STATUS_MINIPORT_COMPATIBLE;
  537. HalpReadRegistryDwordValue(irqMiniport, buffer, rgzPciParameters, &PciIrqRoutingInfo->Parameters);
  538. }
  539. }
  540. }
  541. if (miniportStatus == PIR_STATUS_MINIPORT_NONE)
  542. {
  543. //
  544. // Last see if any device on bus 0 matches any of our supported
  545. // routers.
  546. //
  547. busHandler = HalpHandlerForBus(PCIBus, 0);
  548. if (busHandler)
  549. {
  550. slotNumber.u.AsULONG = 0;
  551. for ( device = 0;
  552. device < PCI_MAX_DEVICES && (miniportStatus == PIR_STATUS_MINIPORT_NONE);
  553. device++)
  554. {
  555. slotNumber.u.bits.DeviceNumber = device;
  556. for (function = 0; function < PCI_MAX_FUNCTION; function++)
  557. {
  558. slotNumber.u.bits.FunctionNumber = function;
  559. routerId = 0xFFFFFFFF;
  560. HalpReadPCIConfig( busHandler,
  561. slotNumber,
  562. &routerId,
  563. 0,
  564. 4);
  565. if (routerId == 0xFFFFFFFF)
  566. continue;
  567. _snwprintf(buffer, sizeof(buffer) / sizeof(*buffer), L"%08X", routerId);
  568. buffer[(sizeof(buffer) / sizeof(*buffer)) - 1] = UNICODE_NULL;
  569. status = HalpReadRegistryDwordValue( irqMiniport,
  570. buffer,
  571. rgzInstance,
  572. &miniportInstance);
  573. if (NT_SUCCESS(status))
  574. {
  575. HalPrint(("Found miniport instance %08X for this motherboard for bus 0 device %08X", miniportInstance, routerId));
  576. pciIrqRoutingTable->RouterBus = 0;
  577. pciIrqRoutingTable->RouterDevFunc = (UCHAR)((device << 3) + function);
  578. miniportStatus = PIR_STATUS_MINIPORT_NORMAL;
  579. HalpReadRegistryDwordValue(irqMiniport, buffer, rgzPciParameters, &PciIrqRoutingInfo->Parameters);
  580. break;
  581. }
  582. //
  583. // Dont waste time if this is not a multifunction device.
  584. //
  585. if (function == 0)
  586. {
  587. headerType = 0;
  588. HalpReadPCIConfig( busHandler,
  589. slotNumber,
  590. &headerType,
  591. 0x0E,
  592. sizeof(headerType));
  593. if (!(headerType & PCI_MULTIFUNCTION))
  594. break;
  595. }
  596. }
  597. }
  598. }
  599. }
  600. ZwClose(irqMiniport);
  601. //
  602. // Initialize the miniport if we found one.
  603. //
  604. if (miniportStatus != PIR_STATUS_MINIPORT_NONE)
  605. {
  606. status = PciirqmpInit( miniportInstance,
  607. pciIrqRoutingTable->RouterBus,
  608. pciIrqRoutingTable->RouterDevFunc);
  609. if (!NT_SUCCESS(status))
  610. {
  611. HalPrint(("Pci Irq miniport %08X failed to initialize!", miniportInstance));
  612. miniportStatus |= (PIR_STATUS_MINIPORT_ERROR << 16);
  613. }
  614. else
  615. {
  616. HalPrint(("Pci Irq miniport %08X successfully initialized!", miniportInstance));
  617. }
  618. }
  619. else
  620. {
  621. HalPrint(("No Pci Irq miniport found for this system!"));
  622. miniportStatus |= (PIR_STATUS_MINIPORT_MAX << 16);
  623. }
  624. }
  625. else
  626. {
  627. HalPrint(("Could not open the Pci Irq Miniports key, no miniports provided!"));
  628. miniportStatus = PIR_STATUS_MINIPORT_NOKEY | (PIR_STATUS_MINIPORT_MAX << 16);
  629. }
  630. return (miniportStatus);
  631. }
  632. NTSTATUS
  633. HalpInitLinkNodes(
  634. PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo
  635. )
  636. /*++
  637. Routine Description:
  638. This routine creates a singly linked list of link nodes
  639. structures from the Pci Irq Routing table.
  640. Input Parameters:
  641. PciIrqRoutingInfo - Pci Irq Routing Information.
  642. Return Value:
  643. STATUS_SUCCESS iff successful. Else STATUS_UNSUCCESSFUL.
  644. --*/
  645. {
  646. PPCI_IRQ_ROUTING_TABLE pciIrqRoutingTable;
  647. PSLOT_INFO slotInfo;
  648. PSLOT_INFO lastSlot;
  649. PPIN_INFO pinInfo;
  650. PPIN_INFO lastPin;
  651. PLINK_NODE linkNode;
  652. NTSTATUS status = STATUS_SUCCESS;
  653. PLINK_NODE temp;
  654. PAGED_CODE();
  655. ASSERT(PciIrqRoutingInfo);
  656. pciIrqRoutingTable = PciIrqRoutingInfo->PciIrqRoutingTable;
  657. PciIrqRoutingInfo->LinkNodeHead = NULL;
  658. //
  659. // Process all slots in this table.
  660. //
  661. slotInfo = (PSLOT_INFO)((PUCHAR)pciIrqRoutingTable +
  662. sizeof(PCI_IRQ_ROUTING_TABLE));
  663. lastSlot = (PSLOT_INFO)((PUCHAR)pciIrqRoutingTable +
  664. pciIrqRoutingTable->TableSize);
  665. while (slotInfo < lastSlot)
  666. {
  667. //
  668. // Process all pins.
  669. //
  670. pinInfo = &slotInfo->PinInfo[0];
  671. lastPin = &slotInfo->PinInfo[NUM_IRQ_PINS];
  672. while (pinInfo < lastPin)
  673. {
  674. //
  675. // Only process valid link values.
  676. //
  677. if(pinInfo->Link)
  678. {
  679. //
  680. // Have we seen this link before.
  681. //
  682. for ( linkNode = PciIrqRoutingInfo->LinkNodeHead;
  683. linkNode && linkNode->Link != pinInfo->Link;
  684. linkNode = linkNode->Next);
  685. if (linkNode == NULL)
  686. {
  687. //
  688. // Allocate memory for new link info.
  689. //
  690. linkNode = ExAllocatePoolWithTag( NonPagedPool,
  691. sizeof(LINK_NODE),
  692. HAL_POOL_TAG);
  693. if (linkNode)
  694. {
  695. linkNode->Allocation = ExAllocatePoolWithTag( NonPagedPool,
  696. sizeof(LINK_STATE),
  697. HAL_POOL_TAG);
  698. linkNode->PossibleAllocation = ExAllocatePoolWithTag( NonPagedPool,
  699. sizeof(LINK_STATE),
  700. HAL_POOL_TAG);
  701. if ( linkNode->Allocation &&
  702. linkNode->PossibleAllocation)
  703. {
  704. linkNode->Signature = PCI_LINK_SIGNATURE;
  705. linkNode->Next = PciIrqRoutingInfo->LinkNodeHead;
  706. PciIrqRoutingInfo->LinkNodeHead = linkNode;
  707. linkNode->Link = pinInfo->Link;
  708. linkNode->InterruptMap = pinInfo->InterruptMap;
  709. linkNode->Allocation->Interrupt = 0;
  710. linkNode->Allocation->RefCount = 0;
  711. linkNode->PossibleAllocation->Interrupt = 0;
  712. linkNode->PossibleAllocation->RefCount = 0;
  713. }
  714. else
  715. {
  716. status = STATUS_UNSUCCESSFUL;
  717. break;
  718. }
  719. }
  720. else
  721. {
  722. status = STATUS_UNSUCCESSFUL;
  723. break;
  724. }
  725. }
  726. }
  727. //
  728. // Next pin.
  729. //
  730. pinInfo++;
  731. }
  732. //
  733. // Next slot.
  734. //
  735. slotInfo++;
  736. }
  737. //
  738. // Clean up if there was an error.
  739. //
  740. if (!NT_SUCCESS(status))
  741. {
  742. linkNode = PciIrqRoutingInfo->LinkNodeHead;
  743. while (linkNode)
  744. {
  745. if (linkNode->Allocation)
  746. {
  747. ExFreePool(linkNode->Allocation);
  748. }
  749. if (linkNode->PossibleAllocation)
  750. {
  751. ExFreePool(linkNode->PossibleAllocation);
  752. }
  753. temp = linkNode;
  754. linkNode = linkNode->Next;
  755. ExFreePool(temp);
  756. }
  757. PciIrqRoutingInfo->LinkNodeHead = NULL;
  758. }
  759. return (status);
  760. }
  761. PPCI_IRQ_ROUTING_TABLE
  762. HalpGetRegistryTable(
  763. IN const WCHAR* KeyName,
  764. IN const WCHAR* ValueName,
  765. IN ULONG HeaderSize OPTIONAL
  766. )
  767. /*++
  768. Routine Description:
  769. Reads the Pci Irq Routing Table from the registry. The table is
  770. saved as Override value under IrqRoutingTable key.
  771. Input Parameters:
  772. KeyName - Name of key that needs to be read.
  773. ValueName - Name of the value to be read.
  774. HeaderSize - Header to be skipped from the value read.
  775. Return Value:
  776. Pointer to the Pci Irq Routing Table if successful.
  777. NULL if there is no valid table in the registry.
  778. --*/
  779. {
  780. PVOID table = NULL;
  781. NTSTATUS status;
  782. HANDLE hPIR;
  783. ULONG tableSize;
  784. PKEY_VALUE_FULL_INFORMATION valueInfo;
  785. PVOID buffer;
  786. UNICODE_STRING override;
  787. UNICODE_STRING keyName;
  788. PAGED_CODE();
  789. //
  790. // Open the PciInterruptRouting registry key.
  791. //
  792. RtlInitUnicodeString(&keyName, KeyName);
  793. status = HalpOpenRegistryKey(&hPIR, NULL, &keyName, KEY_READ, FALSE);
  794. if (NT_SUCCESS(status))
  795. {
  796. //
  797. // Get the size of the table.
  798. //
  799. tableSize = 0;
  800. RtlInitUnicodeString(&override, ValueName);
  801. status = ZwQueryValueKey( hPIR,
  802. &override,
  803. KeyValueFullInformation,
  804. NULL,
  805. 0,
  806. &tableSize);
  807. if ((status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) && tableSize != 0)
  808. {
  809. //
  810. // Allocate memory for the table.
  811. //
  812. buffer = ExAllocatePoolWithTag( PagedPool,
  813. tableSize,
  814. HAL_POOL_TAG);
  815. if (buffer != NULL)
  816. {
  817. //
  818. // Read the table.
  819. //
  820. status = ZwQueryValueKey( hPIR,
  821. &override,
  822. KeyValueFullInformation,
  823. buffer,
  824. tableSize,
  825. &tableSize);
  826. if (NT_SUCCESS(status))
  827. {
  828. valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
  829. table = ExAllocatePoolWithTag( PagedPool,
  830. valueInfo->DataLength - HeaderSize,
  831. HAL_POOL_TAG);
  832. if (table != NULL)
  833. {
  834. RtlCopyMemory( table,
  835. (PUCHAR)buffer + valueInfo->DataOffset + HeaderSize,
  836. valueInfo->DataLength - HeaderSize);
  837. if (HalpSanityCheckTable(table, TRUE) == FALSE)
  838. {
  839. ExFreePool(table);
  840. table = NULL;
  841. }
  842. }
  843. else
  844. {
  845. HalPrint(("Could not allocate memory to read the Pci Irq Routing Table from the registry!"));
  846. ASSERT(table);
  847. }
  848. }
  849. ExFreePool(buffer);
  850. }
  851. else
  852. {
  853. HalPrint(("Could not allocate memory to read the Pci Irq Routing Table from the registry!"));
  854. ASSERT(buffer);
  855. }
  856. }
  857. ZwClose(hPIR);
  858. }
  859. return (table);
  860. }
  861. PPCI_IRQ_ROUTING_TABLE
  862. HalpGet$PIRTable(
  863. VOID
  864. )
  865. /*++
  866. Routine Description:
  867. Reads the Pci Irq Routing Table from $PIR table in the BIOS ROM.
  868. Input Parameters:
  869. None.
  870. Return Value:
  871. Pointer to the Pci Irq Routing Table if successful.
  872. NULL if there is no valid table in the ROM.
  873. --*/
  874. {
  875. PUCHAR biosStart;
  876. PUCHAR biosEnd;
  877. PUCHAR searchPtr;
  878. NTSTATUS status;
  879. ULONG offset;
  880. PPCI_IRQ_ROUTING_TABLE table;
  881. PHYSICAL_ADDRESS biosStartPhysical;
  882. PAGED_CODE();
  883. //
  884. // Setup to return failure.
  885. //
  886. table = NULL;
  887. biosStartPhysical.QuadPart = PIRT_BIOS_START;
  888. biosStart = (PUCHAR)HalpMapPhysicalMemory( biosStartPhysical,
  889. PIRT_BIOS_SIZE >> PAGE_SHIFT);
  890. if (biosStart != NULL)
  891. {
  892. biosEnd = biosStart + PIRT_BIOS_SIZE;
  893. //
  894. // First try the cached location from the registry.
  895. //
  896. status = HalpReadRegistryDwordValue( NULL,
  897. rgzPciIrqRouting,
  898. rgz$PIROffset,
  899. &offset);
  900. if (NT_SUCCESS(status))
  901. {
  902. table = HalpCopy$PIRTable(biosStart + offset, biosEnd);
  903. }
  904. if (table == NULL)
  905. {
  906. for ( searchPtr = biosStart;
  907. searchPtr < biosEnd;
  908. searchPtr += PIRT_ALIGNMENT)
  909. {
  910. table = HalpCopy$PIRTable(searchPtr, biosEnd);
  911. if (table != NULL)
  912. {
  913. //
  914. // Record this offset so it can be used on the next boot.
  915. //
  916. offset = searchPtr - biosStart;
  917. HalPrint(("Recording location %08X of $PIR table in the registry!", PIRT_BIOS_START + offset));
  918. HalpWriteRegistryDwordValue( NULL,
  919. rgzPciIrqRouting,
  920. rgz$PIROffset,
  921. offset);
  922. break;
  923. }
  924. }
  925. }
  926. else
  927. {
  928. HalPrint(("Used cached location %08X to read $PIR table!", PIRT_BIOS_START + offset));
  929. }
  930. //
  931. // Unmap now that we are done.
  932. //
  933. HalpUnmapVirtualAddress(biosStart, PIRT_BIOS_SIZE >> PAGE_SHIFT);
  934. }
  935. else
  936. {
  937. HalPrint(("Failed to map BIOS ROM to scan for $PIR Pci Irq Routing Table!"));
  938. ASSERT(biosStart);
  939. }
  940. return (table);
  941. }
  942. PPCI_IRQ_ROUTING_TABLE
  943. HalpGetPCIBIOSTableFromRealMode(
  944. VOID
  945. )
  946. /*++
  947. Routine Description:
  948. Gets the PCI IRQ routing table from PCI BIOS using real-mode
  949. interface. The table is read by ntdetect.com and added to the
  950. ARC tree in the registry.
  951. Input Parameters:
  952. None.
  953. Return Value:
  954. Pointer to the Pci Irq Routing Table if successful.
  955. NULL if there is no valid table.
  956. --*/
  957. {
  958. PPCI_IRQ_ROUTING_TABLE table = NULL;
  959. NTSTATUS status;
  960. HANDLE mf;
  961. HANDLE child = NULL;
  962. UNICODE_STRING unicodeString;
  963. ULONG index;
  964. ULONG length;
  965. ULONG temp;
  966. BOOLEAN done;
  967. BOOLEAN error;
  968. PKEY_BASIC_INFORMATION keyInfo;
  969. PKEY_VALUE_FULL_INFORMATION childInfo;
  970. PAGED_CODE();
  971. length = PAGE_SIZE;
  972. keyInfo = ExAllocatePoolWithTag( PagedPool,
  973. length,
  974. HAL_POOL_TAG);
  975. if (keyInfo == NULL)
  976. {
  977. HalPrint(("Could not allocate memory to enumerate keys!"));
  978. return (table);
  979. }
  980. childInfo = ExAllocatePoolWithTag( PagedPool,
  981. length,
  982. HAL_POOL_TAG);
  983. if (childInfo == NULL)
  984. {
  985. ExFreePool(keyInfo);
  986. HalPrint(("Could not allocate memory to query value!"));
  987. return (table);
  988. }
  989. //
  990. // Search for the IRQ routing table under the multifunction branch of the registry.
  991. //
  992. RtlInitUnicodeString( &unicodeString,
  993. L"\\Registry\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter");
  994. status = HalpOpenRegistryKey(&mf, NULL, &unicodeString, MAXIMUM_ALLOWED, FALSE);
  995. if (NT_SUCCESS(status))
  996. {
  997. index = 0;
  998. done = FALSE;
  999. error = FALSE;
  1000. while (!done && !error)
  1001. {
  1002. error = TRUE;
  1003. status = ZwEnumerateKey( mf,
  1004. index++,
  1005. KeyBasicInformation,
  1006. keyInfo,
  1007. length,
  1008. &temp);
  1009. if (NT_SUCCESS(status))
  1010. {
  1011. keyInfo->Name[keyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  1012. RtlInitUnicodeString(&unicodeString, keyInfo->Name);
  1013. status = HalpOpenRegistryKey( &child,
  1014. mf,
  1015. &unicodeString,
  1016. MAXIMUM_ALLOWED,
  1017. FALSE);
  1018. if (NT_SUCCESS(status))
  1019. {
  1020. //
  1021. // Read the "identifier".
  1022. //
  1023. RtlInitUnicodeString(&unicodeString, L"Identifier");
  1024. status = ZwQueryValueKey( child,
  1025. &unicodeString,
  1026. KeyValueFullInformation,
  1027. childInfo,
  1028. length,
  1029. &temp);
  1030. if (NT_SUCCESS(status))
  1031. {
  1032. error = FALSE;
  1033. if ((8 * sizeof(WCHAR) + sizeof(UNICODE_NULL)) == childInfo->DataLength)
  1034. {
  1035. done = RtlEqualMemory( (PCHAR)childInfo + childInfo->DataOffset,
  1036. L"PCI BIOS",
  1037. childInfo->DataLength);
  1038. }
  1039. }
  1040. else
  1041. {
  1042. HalPrint(("Failed to query value!"));
  1043. }
  1044. }
  1045. else
  1046. {
  1047. HalPrint(("Could not open child key!"));
  1048. }
  1049. }
  1050. else
  1051. {
  1052. HalPrint(("Failed to enumerate keys!"));
  1053. }
  1054. //
  1055. // Close the child key if it was successfully opened.
  1056. //
  1057. if (child)
  1058. {
  1059. ZwClose(child);
  1060. child = NULL;
  1061. }
  1062. }
  1063. //
  1064. // Close the MF adapter key.
  1065. //
  1066. ZwClose(mf);
  1067. if (done && !error)
  1068. {
  1069. unicodeString.Length = 0;
  1070. unicodeString.MaximumLength = (USHORT)(256 * sizeof(WCHAR) + keyInfo->NameLength);
  1071. unicodeString.Buffer = ExAllocatePoolWithTag( PagedPool,
  1072. unicodeString.MaximumLength,
  1073. HAL_POOL_TAG);
  1074. if (unicodeString.Buffer)
  1075. {
  1076. RtlAppendUnicodeToString( &unicodeString,
  1077. L"\\Registry\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter\\");
  1078. RtlAppendUnicodeToString(&unicodeString, keyInfo->Name);
  1079. RtlAppendUnicodeToString(&unicodeString, L"\\RealModeIrqRoutingTable\\0");
  1080. table = HalpGetRegistryTable(unicodeString.Buffer, L"Configuration Data", sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
  1081. if (table == NULL)
  1082. {
  1083. HalPrint(("Could not read table from PCIBIOS using real-mode interface!"));
  1084. }
  1085. ExFreePool(unicodeString.Buffer);
  1086. }
  1087. else
  1088. {
  1089. HalPrint(("Could not allocate memory to read routing table from PCIBIOS real-mode interface!"));
  1090. }
  1091. }
  1092. ExFreePool(keyInfo);
  1093. ExFreePool(childInfo);
  1094. }
  1095. return (table);
  1096. }
  1097. PPCI_IRQ_ROUTING_TABLE
  1098. HalpCopy$PIRTable(
  1099. IN PUCHAR BiosPtr,
  1100. IN PUCHAR BiosEnd
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. Allocates memory and copies the $PIR table if found at the specified
  1105. address.
  1106. Input Parameters:
  1107. BiosPtr - Location that possibly contains the $PIR table.
  1108. BiosEnd - Last possible BIOS ROM address.
  1109. Return Value:
  1110. Pointer to the Pci Irq Routing Table if successful.
  1111. NULL if there is no valid table at the specified address.
  1112. --*/
  1113. {
  1114. PPCI_IRQ_ROUTING_TABLE table = (PPCI_IRQ_ROUTING_TABLE)BiosPtr;
  1115. PVOID buffer = NULL;
  1116. PAGED_CODE();
  1117. //
  1118. // Validate this table.
  1119. //
  1120. if ( (table->Signature == PIRT_SIGNATURE) &&
  1121. (BiosPtr + table->TableSize <= BiosEnd) &&
  1122. (table->Signature == PIRT_SIGNATURE) &&
  1123. (table->TableSize > 0) )
  1124. {
  1125. //
  1126. // Allocate memory for the table.
  1127. //
  1128. buffer = ExAllocatePoolWithTag( PagedPool,
  1129. table->TableSize,
  1130. HAL_POOL_TAG);
  1131. if (buffer != NULL)
  1132. {
  1133. //
  1134. // Copy the table from the ROM into the allocated memory.
  1135. //
  1136. RtlCopyMemory(buffer, table, table->TableSize);
  1137. if (!HalpSanityCheckTable(buffer, FALSE))
  1138. {
  1139. ExFreePool(buffer);
  1140. buffer = NULL;
  1141. }
  1142. }
  1143. else
  1144. {
  1145. HalPrint(("Failed to allocate memory for $PIR Pci Irq Routing Table!"));
  1146. ASSERT(buffer);
  1147. }
  1148. }
  1149. return (buffer);
  1150. }
  1151. BOOLEAN
  1152. HalpSanityCheckTable(
  1153. IN PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable,
  1154. IN BOOLEAN IgnoreChecksum
  1155. )
  1156. /*++
  1157. Routine Description:
  1158. Validate the Pci Irq Routing Table.
  1159. Input Parameters:
  1160. PciIrqRoutingTable - Pointer to the Pci Irq Routing Table.
  1161. IgnoreChecksum - Ignore checksum iff TRUE.
  1162. Return Value:
  1163. TRUE if this is a valid table, else FALSE.
  1164. --*/
  1165. {
  1166. CHAR checkSum;
  1167. PUCHAR tablePtr;
  1168. PUCHAR tableEnd;
  1169. PSLOT_INFO slotInfo;
  1170. PSLOT_INFO lastSlot;
  1171. PPIN_INFO pinInfo;
  1172. PPIN_INFO lastPin;
  1173. BOOLEAN hasNonZeroBusEntries = FALSE;
  1174. BOOLEAN valid = TRUE;
  1175. PSLOT_INFO testSlot;
  1176. ULONG pin;
  1177. PAGED_CODE();
  1178. //
  1179. // Test1: Should have a valid signature.
  1180. //
  1181. if (PciIrqRoutingTable->Signature != PIRT_SIGNATURE)
  1182. {
  1183. HalPrint(("Pci Irq Routing Table has invalid signature %08X!", PciIrqRoutingTable->Signature));
  1184. valid = FALSE;
  1185. }
  1186. //
  1187. // Test2 - Should have a valid version.
  1188. //
  1189. else if (PciIrqRoutingTable->Version != PIRT_VERSION)
  1190. {
  1191. HalPrint(("Pci Irq Routing Table has invalid version %04X!", PciIrqRoutingTable->Version));
  1192. valid = FALSE;
  1193. }
  1194. //
  1195. // Test3 - Should have a valid size.
  1196. //
  1197. else if ( PciIrqRoutingTable->TableSize % 16 != 0 ||
  1198. PciIrqRoutingTable->TableSize <= sizeof (PCI_IRQ_ROUTING_TABLE))
  1199. {
  1200. HalPrint(("Pci Irq Routing Table has invalid size %04X!", PciIrqRoutingTable->TableSize));
  1201. valid = FALSE;
  1202. }
  1203. else if (!IgnoreChecksum)
  1204. {
  1205. //
  1206. // Test4 - Should have a valid checksum.
  1207. //
  1208. checkSum = 0;
  1209. tablePtr = (PUCHAR)PciIrqRoutingTable;
  1210. for ( tableEnd = tablePtr + PciIrqRoutingTable->TableSize;
  1211. tablePtr < tableEnd;
  1212. tablePtr++)
  1213. {
  1214. checkSum += *tablePtr;
  1215. }
  1216. if (checkSum != 0)
  1217. {
  1218. HalPrint(("Pci Irq Routing Table checksum is invalid!"));
  1219. valid = FALSE;
  1220. }
  1221. }
  1222. if(valid)
  1223. {
  1224. //
  1225. // First get rid of sutpid entries.
  1226. //
  1227. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + sizeof(PCI_IRQ_ROUTING_TABLE));
  1228. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + PciIrqRoutingTable->TableSize);
  1229. while (slotInfo < lastSlot && valid)
  1230. {
  1231. //
  1232. // Process all pins.
  1233. //
  1234. pinInfo = &slotInfo->PinInfo[0];
  1235. lastPin = &slotInfo->PinInfo[NUM_IRQ_PINS];
  1236. while (pinInfo < lastPin)
  1237. {
  1238. //
  1239. // Check for bad cases.
  1240. //
  1241. if(pinInfo->Link)
  1242. {
  1243. if ( pinInfo->InterruptMap == 0x0000 ||
  1244. pinInfo->InterruptMap == 0x0001)
  1245. {
  1246. HalPrint(("Removing stupid maps (%04X) from IRQ routing table entry (b=%02X, d=%02X, s=%02X)!", pinInfo->InterruptMap, slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1247. pinInfo->InterruptMap = 0;
  1248. pinInfo->Link = 0;
  1249. }
  1250. }
  1251. //
  1252. // Next pin.
  1253. //
  1254. pinInfo++;
  1255. }
  1256. //
  1257. // Remove this entry if all pins have NULL links.
  1258. //
  1259. if ( slotInfo->PinInfo[0].Link == 0 &&
  1260. slotInfo->PinInfo[1].Link == 0 &&
  1261. slotInfo->PinInfo[2].Link == 0 &&
  1262. slotInfo->PinInfo[3].Link == 0)
  1263. {
  1264. HalPrint(("Removed redundant entry (b=%02X, d=%02X, s=%02X) from IRQ routing table!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1265. *slotInfo = *(--lastSlot);
  1266. PciIrqRoutingTable->TableSize -= sizeof(SLOT_INFO);
  1267. //
  1268. // Need to test the newly copied entry.
  1269. //
  1270. continue;
  1271. }
  1272. //
  1273. // Merge entries for MF devices.
  1274. //
  1275. testSlot = slotInfo + 1;
  1276. while (testSlot < lastSlot)
  1277. {
  1278. if ( (testSlot->DeviceNumber & 0xF8) == (slotInfo->DeviceNumber & 0xF8) &&
  1279. testSlot->BusNumber == slotInfo->BusNumber)
  1280. {
  1281. //
  1282. // Process all pins.
  1283. //
  1284. for (pin = 0; pin < NUM_IRQ_PINS; pin++)
  1285. {
  1286. if (testSlot->PinInfo[pin].Link)
  1287. {
  1288. if (slotInfo->PinInfo[pin].Link)
  1289. {
  1290. HalPrint(("Multiple entries for the same device (b=%02X, d=%02X, s=%02X) and link (%04X) in IRQ routing table!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber, slotInfo->PinInfo[pin].Link));
  1291. valid = FALSE;
  1292. break;
  1293. }
  1294. else
  1295. {
  1296. HalPrint(("Merging multiple entries for same device (b=%02X, d=%02X, s=%02X) in IRQ routing table!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1297. slotInfo->PinInfo[pin] = testSlot->PinInfo[pin];
  1298. }
  1299. }
  1300. }
  1301. if (!valid)
  1302. {
  1303. break;
  1304. }
  1305. *testSlot = *(--lastSlot);
  1306. PciIrqRoutingTable->TableSize -= sizeof(SLOT_INFO);
  1307. //
  1308. // Need to test the newly copied entry.
  1309. //
  1310. continue;
  1311. }
  1312. testSlot++;
  1313. }
  1314. if (slotInfo->BusNumber > 0)
  1315. {
  1316. hasNonZeroBusEntries = TRUE;
  1317. }
  1318. //
  1319. // Next slot.
  1320. //
  1321. slotInfo++;
  1322. }
  1323. if (valid && PciIrqRoutingTable->TableSize == sizeof(PCI_IRQ_ROUTING_TABLE))
  1324. {
  1325. HalPrint(("No IRQ routing table left after sanity checking!"));
  1326. valid = FALSE;
  1327. }
  1328. }
  1329. //
  1330. // Make sure there are entries for all bus 0 devices in the table.
  1331. //
  1332. if (valid)
  1333. {
  1334. PBUS_HANDLER busHandler;
  1335. PCI_SLOT_NUMBER slotNumber;
  1336. ULONG device;
  1337. ULONG function;
  1338. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  1339. PPCI_COMMON_CONFIG pciData = (PPCI_COMMON_CONFIG)&buffer[0];
  1340. busHandler = HalpHandlerForBus(PCIBus, 0);
  1341. if (busHandler)
  1342. {
  1343. slotNumber.u.AsULONG = 0;
  1344. for ( device = 0;
  1345. device < PCI_MAX_DEVICES && valid;
  1346. device++)
  1347. {
  1348. slotNumber.u.bits.DeviceNumber = device;
  1349. for (function = 0; function < PCI_MAX_FUNCTION && valid; function++)
  1350. {
  1351. slotNumber.u.bits.FunctionNumber = function;
  1352. //
  1353. // Read the standard config space.
  1354. //
  1355. HalpReadPCIConfig(busHandler, slotNumber, pciData, 0, PCI_COMMON_HDR_LENGTH);
  1356. //
  1357. // Make sure this is a valid device.
  1358. //
  1359. if (pciData->VendorID != 0xFFFF && pciData->DeviceID != 0xFFFF)
  1360. {
  1361. //
  1362. // Ignore IDE devices.
  1363. //
  1364. if ( (pciData->BaseClass != PCI_CLASS_MASS_STORAGE_CTLR && pciData->SubClass != PCI_SUBCLASS_MSC_IDE_CTLR) ||
  1365. (pciData->ProgIf & 0x05))
  1366. {
  1367. //
  1368. // Handle P-P bridges separately.
  1369. //
  1370. if ( ((pciData->HeaderType & 0x7F) == PCI_BRIDGE_TYPE) &&
  1371. pciData->BaseClass == PCI_CLASS_BRIDGE_DEV && pciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)
  1372. {
  1373. //
  1374. // P-P bridge.
  1375. //
  1376. if (!hasNonZeroBusEntries)
  1377. {
  1378. //
  1379. // Must have the bridge with at least one entry.
  1380. //
  1381. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + sizeof(PCI_IRQ_ROUTING_TABLE));
  1382. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + PciIrqRoutingTable->TableSize);
  1383. valid = FALSE;
  1384. while (slotInfo < lastSlot && !valid)
  1385. {
  1386. if ((slotInfo->DeviceNumber>>3) == (UCHAR)device)
  1387. {
  1388. //
  1389. // Process all pins.
  1390. //
  1391. pinInfo = &slotInfo->PinInfo[0];
  1392. lastPin = &slotInfo->PinInfo[NUM_IRQ_PINS];
  1393. while (pinInfo < lastPin)
  1394. {
  1395. if(pinInfo->Link)
  1396. {
  1397. valid = TRUE;
  1398. break;
  1399. }
  1400. pinInfo++;
  1401. }
  1402. }
  1403. slotInfo++;
  1404. }
  1405. if (!valid)
  1406. {
  1407. HalPrint(("All links missing for bridge (b=%02X, d=%02X, s=%02X)!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1408. }
  1409. }
  1410. }
  1411. else
  1412. {
  1413. UCHAR intLine;
  1414. UCHAR intPin;
  1415. //
  1416. // Normal device.
  1417. //
  1418. if ((pciData->HeaderType & 0x7F) == PCI_CARDBUS_BRIDGE_TYPE)
  1419. {
  1420. intPin = pciData->u.type2.InterruptPin;
  1421. intLine = pciData->u.type2.InterruptLine;
  1422. }
  1423. else
  1424. {
  1425. intPin = pciData->u.type0.InterruptPin;
  1426. intLine = pciData->u.type0.InterruptLine;
  1427. }
  1428. if (intPin && intPin <= NUM_IRQ_PINS)
  1429. {
  1430. if ( !(pciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) ||
  1431. (intLine && intLine <= 0x0F))
  1432. {
  1433. intPin--;
  1434. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + sizeof(PCI_IRQ_ROUTING_TABLE));
  1435. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + PciIrqRoutingTable->TableSize);
  1436. valid = FALSE;
  1437. while (slotInfo < lastSlot)
  1438. {
  1439. if ( (slotInfo->DeviceNumber>>3) == (UCHAR)device &&
  1440. slotInfo->PinInfo[intPin].Link)
  1441. {
  1442. valid = TRUE;
  1443. break;
  1444. }
  1445. slotInfo++;
  1446. }
  1447. if (!valid)
  1448. {
  1449. HalPrint(("Missing entry for device (b=%02X, d=%02X, s=%02X) in the IRQ routing table!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1450. }
  1451. }
  1452. }
  1453. }
  1454. }
  1455. //
  1456. // Dont waste time if this is not a multifunction device or
  1457. // device does not exist.
  1458. //
  1459. if ((function == 0 && !(pciData->HeaderType & PCI_MULTIFUNCTION)))
  1460. {
  1461. break;
  1462. }
  1463. }
  1464. }
  1465. }
  1466. }
  1467. }
  1468. if (!valid) {
  1469. HalPrint (("Failing IRQ routing table. IRQ routing will be disabled"));
  1470. }
  1471. return (valid);
  1472. }
  1473. NTSTATUS
  1474. HalpFindLinkNode(
  1475. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  1476. IN PDEVICE_OBJECT Pdo,
  1477. IN ULONG Bus,
  1478. IN ULONG Slot,
  1479. OUT PLINK_NODE *LinkNode
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. This routine finds the link node for the specified PCI PDO.
  1484. Input Parameters:
  1485. PciIrqRoutingInfo - Pci Irq Routing information.
  1486. Pdo - Pci device object for which we barber pole.
  1487. Bus - Bus number for the device.
  1488. Slot - Slot number for the device.
  1489. LinkNode - Recieves the link node for the PCI PDO.
  1490. Return Value:
  1491. NTSTATUS.
  1492. --*/
  1493. {
  1494. PINT_ROUTE_INTERFACE_STANDARD pciInterface;
  1495. NTSTATUS status;
  1496. ULONG dummy;
  1497. UCHAR classCode;
  1498. UCHAR subClassCode;
  1499. ROUTING_TOKEN routingToken;
  1500. PSLOT_INFO slotInfo;
  1501. PLINK_NODE linkNode;
  1502. UCHAR pin;
  1503. PBUS_HANDLER busHandler;
  1504. PCI_SLOT_NUMBER ideSlotInfo;
  1505. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  1506. PPCI_COMMON_CONFIG pciData;
  1507. BOOLEAN nativeMode;
  1508. PAGED_CODE();
  1509. ASSERT(IsPciIrqRoutingEnabled());
  1510. *LinkNode = NULL;
  1511. pciInterface = PciIrqRoutingInfo->PciInterface;
  1512. //
  1513. // Call Pci driver to get info about the Pdo.
  1514. //
  1515. status = pciInterface->GetInterruptRouting( Pdo,
  1516. &Bus,
  1517. &Slot,
  1518. (PUCHAR)&dummy,
  1519. &pin,
  1520. &classCode,
  1521. &subClassCode,
  1522. (PDEVICE_OBJECT *)&dummy,
  1523. &routingToken,
  1524. (PUCHAR)&dummy);
  1525. //
  1526. // This means that it is not a Pci device.
  1527. //
  1528. if (!NT_SUCCESS(status))
  1529. {
  1530. return (STATUS_NOT_FOUND);
  1531. }
  1532. //
  1533. // Pci Ide Irqs behave differently than other Pci devices.
  1534. //
  1535. if ( classCode == PCI_CLASS_MASS_STORAGE_CTLR &&
  1536. subClassCode == PCI_SUBCLASS_MSC_IDE_CTLR)
  1537. {
  1538. nativeMode = FALSE;
  1539. //
  1540. // Check for native mode IDE controller.
  1541. //
  1542. busHandler = HalpHandlerForBus(PCIBus, Bus);
  1543. if (busHandler)
  1544. {
  1545. pciData = (PPCI_COMMON_CONFIG)&buffer[0];
  1546. ideSlotInfo.u.AsULONG = Slot;
  1547. HalpReadPCIConfig(busHandler, ideSlotInfo, pciData, 0, PCI_COMMON_HDR_LENGTH);
  1548. if ( pciData->VendorID != 0xFFFF &&
  1549. pciData->DeviceID != 0xFFFF &&
  1550. pciData->BaseClass == classCode &&
  1551. pciData->SubClass == subClassCode)
  1552. {
  1553. //
  1554. // Check if either channel is in native mode?
  1555. //
  1556. if (pciData->ProgIf & 0x05)
  1557. {
  1558. nativeMode = TRUE;
  1559. }
  1560. }
  1561. }
  1562. if (!nativeMode)
  1563. {
  1564. return (STATUS_RESOURCE_REQUIREMENTS_CHANGED);
  1565. }
  1566. }
  1567. //
  1568. // Have we cached this before?
  1569. //
  1570. if (routingToken.LinkNode != NULL)
  1571. {
  1572. ASSERT(((PLINK_NODE)routingToken.LinkNode)->Signature == PCI_LINK_SIGNATURE);
  1573. *LinkNode = (PLINK_NODE)routingToken.LinkNode;
  1574. return (STATUS_SUCCESS);
  1575. }
  1576. //
  1577. // Get the slot info for this device.
  1578. //
  1579. slotInfo = HalpBarberPole( PciIrqRoutingInfo,
  1580. Pdo,
  1581. Bus,
  1582. Slot,
  1583. &pin);
  1584. if (slotInfo != NULL)
  1585. {
  1586. ASSERT(pin <4);
  1587. for ( linkNode = PciIrqRoutingInfo->LinkNodeHead;
  1588. linkNode && linkNode->Link != slotInfo->PinInfo[pin].Link;
  1589. linkNode = linkNode->Next);
  1590. if (linkNode != NULL)
  1591. {
  1592. *LinkNode = linkNode;
  1593. //
  1594. // Initialize the routing token.
  1595. //
  1596. routingToken.LinkNode = linkNode;
  1597. routingToken.StaticVector = 0;
  1598. routingToken.Flags = 0;
  1599. //
  1600. // Save the routing token.
  1601. //
  1602. status = pciInterface->SetInterruptRoutingToken( Pdo,
  1603. &routingToken);
  1604. if (!NT_SUCCESS(status))
  1605. {
  1606. HalPrint(("Failed to set Pci routing token!"));
  1607. ASSERT(NT_SUCCESS(status));
  1608. }
  1609. }
  1610. }
  1611. return (STATUS_SUCCESS);
  1612. }
  1613. PSLOT_INFO
  1614. HalpBarberPole(
  1615. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  1616. IN PDEVICE_OBJECT Pdo,
  1617. IN ULONG Bus,
  1618. IN ULONG Slot,
  1619. IN OUT PUCHAR Pin
  1620. )
  1621. /*++
  1622. Routine Description:
  1623. This routine implements the "barber pole" algorithm to determine the interrupt
  1624. pin for Pci devices behind bridges.
  1625. Input Parameters:
  1626. PciIrqRoutingInfo - Pci Irq Routing information.
  1627. Pdo - Pci device object for which we barber pole.
  1628. Bus - Child device objects bus number.
  1629. Slot - Slot number for the device.
  1630. Pin - Interrupt pin for the Pci device entry in the routing table we reached.
  1631. Return Value:
  1632. Slot info for the specified device iff successful.
  1633. --*/
  1634. {
  1635. ULONG dummy;
  1636. UCHAR pin;
  1637. PDEVICE_OBJECT parent;
  1638. ROUTING_TOKEN routingToken;
  1639. BOOLEAN success;
  1640. PSLOT_INFO slotInfo;
  1641. NTSTATUS status;
  1642. PINT_ROUTE_INTERFACE_STANDARD pciInterface;
  1643. PAGED_CODE();
  1644. ASSERT(IsPciIrqRoutingEnabled());
  1645. pciInterface = PciIrqRoutingInfo->PciInterface;
  1646. //
  1647. // This device MUST be a PCI device with a valid interrupt pin.
  1648. //
  1649. status = pciInterface->GetInterruptRouting( Pdo,
  1650. &Bus,
  1651. &Slot,
  1652. (PUCHAR)&dummy,
  1653. &pin,
  1654. (PUCHAR)&dummy,
  1655. (PUCHAR)&dummy,
  1656. &parent,
  1657. &routingToken,
  1658. (PUCHAR)&dummy);
  1659. if (!NT_SUCCESS(status) || pin == 0)
  1660. {
  1661. return (NULL);
  1662. }
  1663. //
  1664. // Normalize the pin.
  1665. //
  1666. pin--;
  1667. success = TRUE;
  1668. while (success)
  1669. {
  1670. slotInfo = HalpGetSlotInfo( PciIrqRoutingInfo->PciIrqRoutingTable,
  1671. (UCHAR)Bus,
  1672. (UCHAR)(Slot & 0x1F));
  1673. if (slotInfo != NULL)
  1674. {
  1675. break;
  1676. }
  1677. //
  1678. // Get barber pole info for the parent.
  1679. //
  1680. success = HalpBarberPolePin( PciIrqRoutingInfo,
  1681. parent,
  1682. Bus,
  1683. Slot & 0x1F,
  1684. &pin);
  1685. Bus = (ULONG)-1;
  1686. Slot = (ULONG)-1;
  1687. //
  1688. // Get parent's info.
  1689. //
  1690. status = pciInterface->GetInterruptRouting( parent,
  1691. &Bus,
  1692. &Slot,
  1693. (PUCHAR)&dummy,
  1694. (PUCHAR)&dummy,
  1695. (PUCHAR)&dummy,
  1696. (PUCHAR)&dummy,
  1697. &parent,
  1698. &routingToken,
  1699. (PUCHAR)&dummy);
  1700. if (!NT_SUCCESS(status))
  1701. {
  1702. success = FALSE;
  1703. break;
  1704. }
  1705. }
  1706. //
  1707. // Return unsuccessfully if we encountered any weird error.
  1708. //
  1709. if (success == FALSE)
  1710. slotInfo = NULL;
  1711. if (slotInfo)
  1712. {
  1713. *Pin = pin;
  1714. }
  1715. return (slotInfo);
  1716. }
  1717. BOOLEAN
  1718. HalpBarberPolePin(
  1719. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  1720. IN PDEVICE_OBJECT Parent,
  1721. IN ULONG Bus,
  1722. IN ULONG Device,
  1723. IN OUT PUCHAR Pin
  1724. )
  1725. /*++
  1726. Routine Description:
  1727. This routine returns the info used for barber poling.
  1728. Input Parameters:
  1729. PciIrqRoutingInfo - Pci Irq Routing information.
  1730. Parent - Parent device object as we barber pole.
  1731. Bus - Child device objects bus number.
  1732. Device - Device number for the child device.
  1733. Pin - Child device objects interrupt pin number (normalized) on entry.
  1734. Return Value:
  1735. TRUE iff successful.
  1736. --*/
  1737. {
  1738. ULONG parentBus;
  1739. ULONG parentSlot;
  1740. ULONG dummy;
  1741. UCHAR parentPin;
  1742. UCHAR classCode;
  1743. UCHAR subClassCode;
  1744. ROUTING_TOKEN routingToken;
  1745. NTSTATUS status;
  1746. PINT_ROUTE_INTERFACE_STANDARD pciInterface;
  1747. PAGED_CODE();
  1748. ASSERT(IsPciIrqRoutingEnabled());
  1749. pciInterface = PciIrqRoutingInfo->PciInterface;
  1750. //
  1751. // Read the registry flags and see if this device supports straight
  1752. // through routing.
  1753. //
  1754. //
  1755. // Check if the pin table is present in the registry.
  1756. //
  1757. parentBus = (ULONG)-1;
  1758. parentSlot = (ULONG)-1;
  1759. //
  1760. // Get info about the parent from Pci.
  1761. //
  1762. status = pciInterface->GetInterruptRouting( Parent,
  1763. &parentBus,
  1764. &parentSlot,
  1765. (PUCHAR)&dummy,
  1766. &parentPin,
  1767. &classCode,
  1768. &subClassCode,
  1769. (PDEVICE_OBJECT *)&dummy,
  1770. &routingToken,
  1771. (PUCHAR)&dummy);
  1772. if (NT_SUCCESS(status) && classCode == PCI_CLASS_BRIDGE_DEV)
  1773. {
  1774. switch (subClassCode)
  1775. {
  1776. case PCI_SUBCLASS_BR_PCI_TO_PCI:
  1777. *Pin = (*Pin + (UCHAR)Device) % 4;
  1778. break;
  1779. case PCI_SUBCLASS_BR_CARDBUS:
  1780. *Pin = parentPin - 1;
  1781. break;
  1782. default:
  1783. HalPrint(("Pci device (bus=%02lx, slot=%02lx) does not have a PCI bridge as its parent!", Bus, Device));
  1784. ASSERT(FALSE);
  1785. return (FALSE);
  1786. }
  1787. }
  1788. return (TRUE);
  1789. }
  1790. PSLOT_INFO
  1791. HalpGetSlotInfo(
  1792. IN PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable,
  1793. IN UCHAR Bus,
  1794. IN UCHAR Device
  1795. )
  1796. /*++
  1797. Routine Description:
  1798. This routine searches the Pci Irq Routing Table for an entry for the specified
  1799. Pci device on the given bus number.
  1800. Input Parameters:
  1801. PciIrqRoutingInfo - Pci Irq Routing information.
  1802. Bus - Bus number of the Pci device.
  1803. Device - Device number of the Pci device.
  1804. Return Value:
  1805. Pointer to the slot info for the specified device iff successful.
  1806. --*/
  1807. {
  1808. PSLOT_INFO slotInfo;
  1809. PSLOT_INFO lastSlot;
  1810. PAGED_CODE();
  1811. ASSERT(IsPciIrqRoutingEnabled());
  1812. //
  1813. // Process all slots in this table.
  1814. //
  1815. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable +
  1816. sizeof(PCI_IRQ_ROUTING_TABLE));
  1817. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable +
  1818. PciIrqRoutingTable->TableSize);
  1819. while (slotInfo < lastSlot)
  1820. {
  1821. if ( slotInfo->BusNumber == Bus &&
  1822. (slotInfo->DeviceNumber >> 3) == Device)
  1823. {
  1824. return (slotInfo);
  1825. }
  1826. slotInfo++;
  1827. }
  1828. return (NULL);
  1829. }
  1830. NTSTATUS
  1831. HalpReadRegistryDwordValue(
  1832. IN HANDLE Root,
  1833. IN const WCHAR* KeyName,
  1834. IN const WCHAR* ValueName,
  1835. OUT PULONG Data
  1836. )
  1837. /*++
  1838. Routine Description:
  1839. Reads the value for the valuename under the key specified.
  1840. Input Parameters:
  1841. Root - Handle of the root key, if any.
  1842. KeyName - Name of the key under which this value appears.
  1843. ValueName - Name of the value to be read.
  1844. Data - Variable that receives the value read.
  1845. Return Value:
  1846. NTSTATUS.
  1847. --*/
  1848. {
  1849. UNICODE_STRING valueName;
  1850. HANDLE hKey;
  1851. NTSTATUS status;
  1852. ULONG cbData;
  1853. UNICODE_STRING keyName;
  1854. PKEY_VALUE_FULL_INFORMATION p;
  1855. PAGED_CODE();
  1856. RtlInitUnicodeString( &keyName, KeyName);
  1857. status = HalpOpenRegistryKey(&hKey, Root, &keyName, KEY_READ, FALSE);
  1858. if (NT_SUCCESS(status))
  1859. {
  1860. cbData = 0;
  1861. RtlInitUnicodeString(&valueName, ValueName);
  1862. status = ZwQueryValueKey( hKey,
  1863. &valueName,
  1864. KeyValueFullInformation,
  1865. NULL,
  1866. 0,
  1867. &cbData);
  1868. if ((status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) && cbData)
  1869. {
  1870. p = ExAllocatePoolWithTag(
  1871. PagedPool,
  1872. cbData,
  1873. HAL_POOL_TAG);
  1874. if (p)
  1875. {
  1876. status = ZwQueryValueKey( hKey,
  1877. &valueName,
  1878. KeyValueFullInformation,
  1879. p,
  1880. cbData,
  1881. &cbData);
  1882. if (NT_SUCCESS(status) && p->Type == REG_DWORD && p->DataLength == sizeof(ULONG))
  1883. {
  1884. *Data = *(PULONG)((PUCHAR)p + p->DataOffset);
  1885. }
  1886. ExFreePool(p);
  1887. }
  1888. }
  1889. ZwClose(hKey);
  1890. }
  1891. return (status);
  1892. }
  1893. NTSTATUS
  1894. HalpWriteRegistryDwordValue(
  1895. IN HANDLE Root,
  1896. IN const WCHAR* KeyName,
  1897. IN const WCHAR* ValueName,
  1898. IN ULONG Value
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. Writes the value for the valuename under the key specified.
  1903. Input Parameters:
  1904. Root - Handle of the root key, if any.
  1905. KeyName - Name of the key under which this value appears.
  1906. ValueName - Name of the value to be read.
  1907. Value - Value to be written.
  1908. Return Value:
  1909. Standard NT status value.
  1910. --*/
  1911. {
  1912. NTSTATUS status;
  1913. UNICODE_STRING valueName;
  1914. HANDLE hKey;
  1915. UNICODE_STRING keyName;
  1916. PAGED_CODE();
  1917. RtlInitUnicodeString(&keyName, KeyName);
  1918. status = HalpOpenRegistryKey(&hKey, Root, &keyName, KEY_WRITE, FALSE);
  1919. if (NT_SUCCESS(status))
  1920. {
  1921. RtlInitUnicodeString(&valueName, ValueName);
  1922. status = ZwSetValueKey( hKey,
  1923. &valueName,
  1924. 0,
  1925. REG_DWORD,
  1926. &Value,
  1927. sizeof(Value));
  1928. ZwClose(hKey);
  1929. }
  1930. return (status);
  1931. }
  1932. NTSTATUS
  1933. HalpCommitLink(
  1934. IN PLINK_NODE LinkNode
  1935. )
  1936. /*++
  1937. Routine Description:
  1938. Calls the IRQ miniport to program the link.
  1939. Input Parameters:
  1940. LinkNode - Link that needs to be programmed.
  1941. Return Value:
  1942. STATUS_SUCCESS.
  1943. --*/
  1944. {
  1945. NTSTATUS status;
  1946. ULONG interrupt;
  1947. PLINK_STATE temp;
  1948. BOOLEAN disableInterrupt;
  1949. PLINK_NODE node;
  1950. //
  1951. // Read the current state of this link.
  1952. //
  1953. interrupt = 0;
  1954. status = PciirqmpGetIrq((PUCHAR)&interrupt, (UCHAR)LinkNode->Link);
  1955. if (LinkNode->PossibleAllocation->RefCount)
  1956. {
  1957. //
  1958. // Program the link.
  1959. //
  1960. if (NT_SUCCESS(status) && interrupt != LinkNode->PossibleAllocation->Interrupt)
  1961. {
  1962. PciirqmpSetIrq((UCHAR)LinkNode->PossibleAllocation->Interrupt, (UCHAR)LinkNode->Link);
  1963. }
  1964. }
  1965. else if (LinkNode->Allocation->RefCount)
  1966. {
  1967. //
  1968. // Disable the link.
  1969. //
  1970. if (NT_SUCCESS(status) && interrupt)
  1971. {
  1972. //
  1973. // If this is the last link with this interrupt, disable it in case
  1974. // the driver did not do the right thing. Just checking the linknodes
  1975. // should be good enough even for the case where we change assignment
  1976. // for an IRQ from PCI to ISA device. When the ISA device gets
  1977. // started, on the subsequent connect, the interrupt would get enabled.
  1978. //
  1979. disableInterrupt = TRUE;
  1980. for ( node = HalpPciIrqRoutingInfo.LinkNodeHead;
  1981. node;
  1982. node = node->Next)
  1983. {
  1984. if (node->PossibleAllocation->RefCount && interrupt == node->PossibleAllocation->Interrupt)
  1985. {
  1986. //
  1987. // Interrupt in use.
  1988. //
  1989. disableInterrupt = FALSE;
  1990. }
  1991. }
  1992. if (disableInterrupt)
  1993. {
  1994. HalPrint(("Disabling IRQ %08x since the last link %08x programmed to it is getting disabled\n", interrupt, LinkNode->Link));
  1995. HalDisableSystemInterrupt(interrupt + PRIMARY_VECTOR_BASE, 0);
  1996. } else {
  1997. HalPrint(("Not disabling IRQ %08x since some other link is still programmed to it\n", interrupt));
  1998. }
  1999. PciirqmpSetIrq((UCHAR)0, (UCHAR)LinkNode->Link);
  2000. }
  2001. }
  2002. #if defined(NEC_98)
  2003. else if (!(LinkNode->PossibleAllocation->Interrupt))
  2004. {
  2005. //
  2006. // Disable the link.
  2007. //
  2008. PciirqmpSetIrq((UCHAR)0, (UCHAR)LinkNode->Link);
  2009. }
  2010. #endif
  2011. //
  2012. // Swap the possible with the allocation.
  2013. //
  2014. temp = LinkNode->Allocation;
  2015. LinkNode->Allocation = LinkNode->PossibleAllocation;
  2016. LinkNode->PossibleAllocation = temp;
  2017. return (STATUS_SUCCESS);
  2018. }
  2019. VOID
  2020. HalpProgramInterruptLine(
  2021. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  2022. IN PDEVICE_OBJECT Pdo,
  2023. IN ULONG Interrupt
  2024. )
  2025. /*++
  2026. Routine Description:
  2027. Calls the PCI interface to write the interrupt value to config space.
  2028. Input Parameters:
  2029. PciIrqRoutingInfo - Pointer to IRQ routing info.
  2030. Pdo - PCI PDO whose interrupt line needs to be written.
  2031. Interrupt - Interrupt value to be written.
  2032. Return Value:
  2033. None.
  2034. --*/
  2035. {
  2036. PAGED_CODE();
  2037. //
  2038. // We should never be here if Pci Irq routing is not enabled.
  2039. //
  2040. ASSERT(IsPciIrqRoutingEnabled());
  2041. PciIrqRoutingInfo->PciInterface->UpdateInterruptLine(Pdo, (UCHAR)Interrupt);
  2042. }