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

2431 lines
70 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  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. HalpReadRegistryValue (
  116. IN HANDLE Root,
  117. IN const WCHAR* KeyName,
  118. IN const WCHAR* ValueName,
  119. OUT PULONG Data
  120. );
  121. NTSTATUS
  122. HalpWriteRegistryValue (
  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(PAGE, HalpInitPciIrqRouting)
  130. #pragma alloc_text(PAGE, HalpGetIrqRoutingTable)
  131. #pragma alloc_text(PAGE, HalpInitializeMiniport)
  132. #pragma alloc_text(PAGE, HalpInitLinkNodes)
  133. #pragma alloc_text(PAGE, HalpGetRegistryTable)
  134. #pragma alloc_text(PAGE, HalpGetPCIBIOSTableFromRealMode)
  135. #pragma alloc_text(PAGE, HalpGet$PIRTable)
  136. #pragma alloc_text(PAGE, HalpCopy$PIRTable)
  137. #pragma alloc_text(PAGE, 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, HalpReadRegistryValue)
  143. #pragma alloc_text(PAGE, HalpWriteRegistryValue)
  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. HalpReadRegistryValue(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. HalpWriteRegistryValue(NULL, rgzPciIrqRouting, rgzStatus, pirStatus);
  346. HalpWriteRegistryValue(NULL, rgzPciIrqRouting, rgzTableStatus, tableStatus);
  347. HalpWriteRegistryValue(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. HalpReadRegistryValue(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 = HalpReadRegistryValue( 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. swprintf(buffer, L"%08X", routerId);
  497. status = HalpReadRegistryValue( irqMiniport,
  498. buffer,
  499. rgzInstance,
  500. &miniportInstance);
  501. if (NT_SUCCESS(status))
  502. {
  503. HalPrint(("Found miniport instance %08X for this motherboard!", miniportInstance));
  504. miniportStatus = PIR_STATUS_MINIPORT_NORMAL;
  505. HalpReadRegistryValue(irqMiniport, buffer, rgzPciParameters, &PciIrqRoutingInfo->Parameters);
  506. }
  507. }
  508. }
  509. }
  510. else
  511. {
  512. HalPrint(("Overriding miniport instance %08X found for this motherboard!", miniportInstance));
  513. miniportStatus = PIR_STATUS_MINIPORT_OVERRIDE;
  514. }
  515. //
  516. // Next see if we have a miniport for the compatible router.
  517. //
  518. if (miniportStatus == PIR_STATUS_MINIPORT_NONE)
  519. {
  520. //
  521. // Make sure there is a valid compatible router.
  522. //
  523. if ( pciIrqRoutingTable->CompatibleRouter != 0xFFFFFFFF &&
  524. pciIrqRoutingTable->CompatibleRouter != 0)
  525. {
  526. swprintf(buffer, L"%08X", pciIrqRoutingTable->CompatibleRouter);
  527. status = HalpReadRegistryValue( irqMiniport,
  528. buffer,
  529. rgzInstance,
  530. &miniportInstance);
  531. if (NT_SUCCESS(status))
  532. {
  533. HalPrint(("Found miniport instance %08X for this motherboard using compatible router %08X!", miniportInstance, pciIrqRoutingTable->CompatibleRouter));
  534. miniportStatus = PIR_STATUS_MINIPORT_COMPATIBLE;
  535. HalpReadRegistryValue(irqMiniport, buffer, rgzPciParameters, &PciIrqRoutingInfo->Parameters);
  536. }
  537. }
  538. }
  539. if (miniportStatus == PIR_STATUS_MINIPORT_NONE)
  540. {
  541. //
  542. // Last see if any device on bus 0 matches any of our supported
  543. // routers.
  544. //
  545. busHandler = HalpHandlerForBus(PCIBus, 0);
  546. if (busHandler)
  547. {
  548. slotNumber.u.AsULONG = 0;
  549. for ( device = 0;
  550. device < PCI_MAX_DEVICES && (miniportStatus == PIR_STATUS_MINIPORT_NONE);
  551. device++)
  552. {
  553. slotNumber.u.bits.DeviceNumber = device;
  554. for (function = 0; function < PCI_MAX_FUNCTION; function++)
  555. {
  556. slotNumber.u.bits.FunctionNumber = function;
  557. //
  558. // Dont waste time if this is not a multifunction device.
  559. //
  560. if (function == 1)
  561. {
  562. headerType = 0;
  563. HalpReadPCIConfig( busHandler,
  564. slotNumber,
  565. &headerType,
  566. 0x0E,
  567. sizeof(headerType));
  568. if (!(headerType & PCI_MULTIFUNCTION))
  569. break;
  570. }
  571. routerId = 0xFFFFFFFF;
  572. HalpReadPCIConfig( busHandler,
  573. slotNumber,
  574. &routerId,
  575. 0,
  576. 4);
  577. if (routerId == 0xFFFFFFFF)
  578. continue;
  579. swprintf(buffer, L"%08X", routerId);
  580. status = HalpReadRegistryValue( irqMiniport,
  581. buffer,
  582. rgzInstance,
  583. &miniportInstance);
  584. if (NT_SUCCESS(status))
  585. {
  586. HalPrint(("Found miniport instance %08X for this motherboard for bus 0 device %08X", miniportInstance, routerId));
  587. pciIrqRoutingTable->RouterBus = 0;
  588. pciIrqRoutingTable->RouterDevFunc = (UCHAR)((device << 3) + function);
  589. miniportStatus = PIR_STATUS_MINIPORT_NORMAL;
  590. HalpReadRegistryValue(irqMiniport, buffer, rgzPciParameters, &PciIrqRoutingInfo->Parameters);
  591. break;
  592. }
  593. }
  594. }
  595. }
  596. }
  597. ZwClose(irqMiniport);
  598. //
  599. // Initialize the miniport if we found one.
  600. //
  601. if (miniportStatus != PIR_STATUS_MINIPORT_NONE)
  602. {
  603. status = PciirqmpInit( miniportInstance,
  604. pciIrqRoutingTable->RouterBus,
  605. pciIrqRoutingTable->RouterDevFunc);
  606. if (!NT_SUCCESS(status))
  607. {
  608. HalPrint(("Pci Irq miniport %08X failed to initialize!", miniportInstance));
  609. miniportStatus |= (PIR_STATUS_MINIPORT_ERROR << 16);
  610. }
  611. else
  612. {
  613. HalPrint(("Pci Irq miniport %08X successfully initialized!", miniportInstance));
  614. }
  615. }
  616. else
  617. {
  618. HalPrint(("No Pci Irq miniport found for this system!"));
  619. miniportStatus |= (PIR_STATUS_MINIPORT_MAX << 16);
  620. }
  621. }
  622. else
  623. {
  624. HalPrint(("Could not open the Pci Irq Miniports key, no miniports provided!"));
  625. miniportStatus = PIR_STATUS_MINIPORT_NOKEY | (PIR_STATUS_MINIPORT_MAX << 16);
  626. }
  627. return (miniportStatus);
  628. }
  629. NTSTATUS
  630. HalpInitLinkNodes (
  631. PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo
  632. )
  633. /*++
  634. Routine Description:
  635. This routine creates a singly linked list of link nodes
  636. structures from the Pci Irq Routing table.
  637. Input Parameters:
  638. PciIrqRoutingInfo - Pci Irq Routing Information.
  639. Return Value:
  640. STATUS_SUCCESS iff successful. Else STATUS_UNSUCCESSFUL.
  641. --*/
  642. {
  643. PPCI_IRQ_ROUTING_TABLE pciIrqRoutingTable;
  644. PSLOT_INFO slotInfo;
  645. PSLOT_INFO lastSlot;
  646. PPIN_INFO pinInfo;
  647. PPIN_INFO lastPin;
  648. PLINK_NODE linkNode;
  649. NTSTATUS status = STATUS_SUCCESS;
  650. PLINK_NODE temp;
  651. ASSERT(PciIrqRoutingInfo);
  652. pciIrqRoutingTable = PciIrqRoutingInfo->PciIrqRoutingTable;
  653. PciIrqRoutingInfo->LinkNodeHead = NULL;
  654. //
  655. // Process all slots in this table.
  656. //
  657. slotInfo = (PSLOT_INFO)((PUCHAR)pciIrqRoutingTable +
  658. sizeof(PCI_IRQ_ROUTING_TABLE));
  659. lastSlot = (PSLOT_INFO)((PUCHAR)pciIrqRoutingTable +
  660. pciIrqRoutingTable->TableSize);
  661. while (slotInfo < lastSlot)
  662. {
  663. //
  664. // Process all pins.
  665. //
  666. pinInfo = &slotInfo->PinInfo[0];
  667. lastPin = &slotInfo->PinInfo[NUM_IRQ_PINS];
  668. while (pinInfo < lastPin)
  669. {
  670. //
  671. // Only process valid link values.
  672. //
  673. if(pinInfo->Link)
  674. {
  675. //
  676. // Have we seen this link before.
  677. //
  678. for ( linkNode = PciIrqRoutingInfo->LinkNodeHead;
  679. linkNode && linkNode->Link != pinInfo->Link;
  680. linkNode = linkNode->Next);
  681. if (linkNode == NULL)
  682. {
  683. //
  684. // Allocate memory for new link info.
  685. //
  686. linkNode = ExAllocatePoolWithTag( NonPagedPool,
  687. sizeof(LINK_NODE),
  688. HAL_POOL_TAG);
  689. if (linkNode)
  690. {
  691. linkNode->Allocation = ExAllocatePoolWithTag( NonPagedPool,
  692. sizeof(LINK_STATE),
  693. HAL_POOL_TAG);
  694. linkNode->PossibleAllocation = ExAllocatePoolWithTag( NonPagedPool,
  695. sizeof(LINK_STATE),
  696. HAL_POOL_TAG);
  697. if ( linkNode->Allocation &&
  698. linkNode->PossibleAllocation)
  699. {
  700. linkNode->Signature = PCI_LINK_SIGNATURE;
  701. linkNode->Next = PciIrqRoutingInfo->LinkNodeHead;
  702. PciIrqRoutingInfo->LinkNodeHead = linkNode;
  703. linkNode->Link = pinInfo->Link;
  704. linkNode->InterruptMap = pinInfo->InterruptMap;
  705. linkNode->Allocation->Interrupt = 0;
  706. linkNode->Allocation->RefCount = 0;
  707. linkNode->PossibleAllocation->Interrupt = 0;
  708. linkNode->PossibleAllocation->RefCount = 0;
  709. }
  710. else
  711. {
  712. status = STATUS_UNSUCCESSFUL;
  713. break;
  714. }
  715. }
  716. else
  717. {
  718. status = STATUS_UNSUCCESSFUL;
  719. break;
  720. }
  721. }
  722. }
  723. //
  724. // Next pin.
  725. //
  726. pinInfo++;
  727. }
  728. //
  729. // Next slot.
  730. //
  731. slotInfo++;
  732. }
  733. //
  734. // Clean up if there was an error.
  735. //
  736. if (!NT_SUCCESS(status))
  737. {
  738. linkNode = PciIrqRoutingInfo->LinkNodeHead;
  739. while (linkNode)
  740. {
  741. if (linkNode->Allocation)
  742. {
  743. ExFreePool(linkNode->Allocation);
  744. }
  745. if (linkNode->PossibleAllocation)
  746. {
  747. ExFreePool(linkNode->PossibleAllocation);
  748. }
  749. temp = linkNode;
  750. linkNode = linkNode->Next;
  751. ExFreePool(temp);
  752. }
  753. PciIrqRoutingInfo->LinkNodeHead = NULL;
  754. }
  755. return (status);
  756. }
  757. PPCI_IRQ_ROUTING_TABLE
  758. HalpGetRegistryTable (
  759. IN const WCHAR* KeyName,
  760. IN const WCHAR* ValueName,
  761. IN ULONG HeaderSize OPTIONAL
  762. )
  763. /*++
  764. Routine Description:
  765. Reads the Pci Irq Routing Table from the registry. The table is
  766. saved as Override value under IrqRoutingTable key.
  767. Input Parameters:
  768. None.
  769. Return Value:
  770. Pointer to the Pci Irq Routing Table if successful.
  771. NULL if there is no valid table in the registry.
  772. --*/
  773. {
  774. PVOID table = NULL;
  775. NTSTATUS status;
  776. HANDLE hPIR;
  777. ULONG tableSize;
  778. PKEY_VALUE_FULL_INFORMATION valueInfo;
  779. PVOID buffer;
  780. UNICODE_STRING override;
  781. UNICODE_STRING keyName;
  782. PAGED_CODE();
  783. //
  784. // Open the PciInterruptRouting registry key.
  785. //
  786. RtlInitUnicodeString(&keyName, KeyName);
  787. status = HalpOpenRegistryKey(&hPIR, NULL, &keyName, KEY_ALL_ACCESS, FALSE);
  788. if (NT_SUCCESS(status))
  789. {
  790. //
  791. // Get the size of the table.
  792. //
  793. tableSize = 0;
  794. RtlInitUnicodeString(&override, ValueName);
  795. status = ZwQueryValueKey( hPIR,
  796. &override,
  797. KeyValueFullInformation,
  798. NULL,
  799. 0,
  800. &tableSize);
  801. if (tableSize != 0)
  802. {
  803. //
  804. // Allocate memory for the table.
  805. //
  806. buffer = ExAllocatePoolWithTag( PagedPool,
  807. tableSize,
  808. HAL_POOL_TAG);
  809. if (buffer != NULL)
  810. {
  811. //
  812. // Read the table.
  813. //
  814. status = ZwQueryValueKey( hPIR,
  815. &override,
  816. KeyValueFullInformation,
  817. buffer,
  818. tableSize,
  819. &tableSize);
  820. if (NT_SUCCESS(status))
  821. {
  822. valueInfo = (PKEY_VALUE_FULL_INFORMATION)buffer;
  823. table = ExAllocatePoolWithTag( PagedPool,
  824. valueInfo->DataLength - HeaderSize,
  825. HAL_POOL_TAG);
  826. if (table != NULL)
  827. {
  828. memcpy( table,
  829. (PUCHAR)buffer + valueInfo->DataOffset + HeaderSize,
  830. valueInfo->DataLength - HeaderSize);
  831. if (HalpSanityCheckTable(table, TRUE) == FALSE)
  832. {
  833. ExFreePool(table);
  834. table = NULL;
  835. }
  836. }
  837. else
  838. {
  839. HalPrint(("Could not allocate memory to read the Pci Irq Routing Table from the registry!"));
  840. ASSERT(table);
  841. }
  842. }
  843. ExFreePool(buffer);
  844. }
  845. else
  846. {
  847. HalPrint(("Could not allocate memory to read the Pci Irq Routing Table from the registry!"));
  848. ASSERT(buffer);
  849. }
  850. }
  851. ZwClose(hPIR);
  852. }
  853. return (table);
  854. }
  855. PPCI_IRQ_ROUTING_TABLE
  856. HalpGet$PIRTable (
  857. VOID
  858. )
  859. /*++
  860. Routine Description:
  861. Reads the Pci Irq Routing Table from $PIR table in the BIOS ROM.
  862. Input Parameters:
  863. None.
  864. Return Value:
  865. Pointer to the Pci Irq Routing Table if successful.
  866. NULL if there is no valid table in the ROM.
  867. --*/
  868. {
  869. PUCHAR biosStart;
  870. PUCHAR biosEnd;
  871. PUCHAR searchPtr;
  872. NTSTATUS status;
  873. ULONG offset;
  874. PPCI_IRQ_ROUTING_TABLE table;
  875. PHYSICAL_ADDRESS biosStartPhysical;
  876. PAGED_CODE();
  877. //
  878. // Setup to return failure.
  879. //
  880. table = NULL;
  881. biosStartPhysical.QuadPart = PIRT_BIOS_START;
  882. biosStart = (PUCHAR)HalpMapPhysicalMemory( biosStartPhysical,
  883. PIRT_BIOS_SIZE >> PAGE_SHIFT);
  884. if (biosStart != NULL)
  885. {
  886. biosEnd = biosStart + PIRT_BIOS_SIZE;
  887. //
  888. // First try the cached location from the registry.
  889. //
  890. status = HalpReadRegistryValue( NULL,
  891. rgzPciIrqRouting,
  892. rgz$PIROffset,
  893. &offset);
  894. if (NT_SUCCESS(status))
  895. {
  896. table = HalpCopy$PIRTable(biosStart + offset, biosEnd);
  897. }
  898. if (table == NULL)
  899. {
  900. for ( searchPtr = biosStart;
  901. searchPtr < biosEnd;
  902. searchPtr += PIRT_ALIGNMENT)
  903. {
  904. table = HalpCopy$PIRTable(searchPtr, biosEnd);
  905. if (table != NULL)
  906. {
  907. //
  908. // Record this offset so it can be used on the next boot.
  909. //
  910. offset = searchPtr - biosStart;
  911. HalPrint(("Recording location %08X of $PIR table in the registry!", PIRT_BIOS_START + offset));
  912. HalpWriteRegistryValue( NULL,
  913. rgzPciIrqRouting,
  914. rgz$PIROffset,
  915. offset);
  916. break;
  917. }
  918. }
  919. }
  920. else
  921. {
  922. HalPrint(("Used cached location %08X to read $PIR table!", PIRT_BIOS_START + offset));
  923. }
  924. }
  925. else
  926. {
  927. HalPrint(("Failed to map BIOS ROM to scan for $PIR Pci Irq Routing Table!"));
  928. ASSERT(biosStart);
  929. }
  930. return (table);
  931. }
  932. PPCI_IRQ_ROUTING_TABLE
  933. HalpGetPCIBIOSTableFromRealMode(
  934. VOID
  935. )
  936. /*++
  937. Routine Description:
  938. Gets the PCI IRQ routing table from PCI BIOS using real-mode
  939. interface. The table is read by ntdetect.com and added to the
  940. ARC tree in the registry.
  941. Input Parameters:
  942. None.
  943. Return Value:
  944. Pointer to the Pci Irq Routing Table if successful.
  945. NULL if there is no valid table.
  946. --*/
  947. {
  948. PPCI_IRQ_ROUTING_TABLE table = NULL;
  949. NTSTATUS status;
  950. HANDLE mf;
  951. HANDLE child = NULL;
  952. UNICODE_STRING unicodeString;
  953. ULONG index;
  954. ULONG length;
  955. ULONG temp;
  956. BOOLEAN done;
  957. BOOLEAN error;
  958. PKEY_BASIC_INFORMATION keyInfo;
  959. PKEY_VALUE_FULL_INFORMATION childInfo;
  960. length = PAGE_SIZE;
  961. keyInfo = ExAllocatePoolWithTag( PagedPool,
  962. length,
  963. HAL_POOL_TAG);
  964. if (keyInfo == NULL)
  965. {
  966. HalPrint(("Could not allocate memory to enumerate keys!"));
  967. return (table);
  968. }
  969. childInfo = ExAllocatePoolWithTag( PagedPool,
  970. length,
  971. HAL_POOL_TAG);
  972. if (childInfo == NULL)
  973. {
  974. ExFreePool(keyInfo);
  975. HalPrint(("Could not allocate memory to query value!"));
  976. return (table);
  977. }
  978. //
  979. // Search for the IRQ routing table under the multifunction branch of the registry.
  980. //
  981. RtlInitUnicodeString( &unicodeString,
  982. L"\\Registry\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter");
  983. status = HalpOpenRegistryKey(&mf, NULL, &unicodeString, MAXIMUM_ALLOWED, FALSE);
  984. if (NT_SUCCESS(status))
  985. {
  986. index = 0;
  987. done = FALSE;
  988. error = FALSE;
  989. while (!done && !error)
  990. {
  991. error = TRUE;
  992. status = ZwEnumerateKey( mf,
  993. index++,
  994. KeyBasicInformation,
  995. keyInfo,
  996. length,
  997. &temp);
  998. if (NT_SUCCESS(status))
  999. {
  1000. keyInfo->Name[keyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  1001. RtlInitUnicodeString(&unicodeString, keyInfo->Name);
  1002. status = HalpOpenRegistryKey( &child,
  1003. mf,
  1004. &unicodeString,
  1005. MAXIMUM_ALLOWED,
  1006. FALSE);
  1007. if (NT_SUCCESS(status))
  1008. {
  1009. //
  1010. // Read the "identifier".
  1011. //
  1012. RtlInitUnicodeString(&unicodeString, L"Identifier");
  1013. status = ZwQueryValueKey( child,
  1014. &unicodeString,
  1015. KeyValueFullInformation,
  1016. childInfo,
  1017. length,
  1018. &temp);
  1019. if (NT_SUCCESS(status))
  1020. {
  1021. error = FALSE;
  1022. if ((8 * sizeof(WCHAR) + sizeof(UNICODE_NULL)) == childInfo->DataLength)
  1023. {
  1024. done = RtlEqualMemory( (PCHAR)childInfo + childInfo->DataOffset,
  1025. L"PCI BIOS",
  1026. childInfo->DataLength);
  1027. }
  1028. }
  1029. else
  1030. {
  1031. HalPrint(("Failed to query value!"));
  1032. }
  1033. }
  1034. else
  1035. {
  1036. HalPrint(("Could not open child key!"));
  1037. }
  1038. }
  1039. else
  1040. {
  1041. HalPrint(("Failed to enumerate keys!"));
  1042. }
  1043. //
  1044. // Close the child key if it was successfully opened.
  1045. //
  1046. if (child)
  1047. {
  1048. ZwClose(child);
  1049. child = NULL;
  1050. }
  1051. }
  1052. //
  1053. // Close the MF adapter key.
  1054. //
  1055. ZwClose(mf);
  1056. if (done && !error)
  1057. {
  1058. unicodeString.Length = 0;
  1059. unicodeString.MaximumLength = (USHORT)(256 * sizeof(WCHAR) + keyInfo->NameLength);
  1060. unicodeString.Buffer = ExAllocatePoolWithTag( PagedPool,
  1061. unicodeString.MaximumLength,
  1062. HAL_POOL_TAG);
  1063. if (unicodeString.Buffer)
  1064. {
  1065. RtlAppendUnicodeToString( &unicodeString,
  1066. L"\\Registry\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter\\");
  1067. RtlAppendUnicodeToString(&unicodeString, keyInfo->Name);
  1068. RtlAppendUnicodeToString(&unicodeString, L"\\RealModeIrqRoutingTable\\0");
  1069. table = HalpGetRegistryTable(unicodeString.Buffer, L"Configuration Data", sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
  1070. if (table == NULL)
  1071. {
  1072. HalPrint(("Could not read table from PCIBIOS using real-mode interface!"));
  1073. }
  1074. ExFreePool(unicodeString.Buffer);
  1075. }
  1076. else
  1077. {
  1078. HalPrint(("Could not allocate memory to read routing table from PCIBIOS real-mode interface!"));
  1079. }
  1080. }
  1081. ExFreePool(keyInfo);
  1082. ExFreePool(childInfo);
  1083. }
  1084. return (table);
  1085. }
  1086. PPCI_IRQ_ROUTING_TABLE
  1087. HalpCopy$PIRTable (
  1088. IN PUCHAR BiosPtr,
  1089. IN PUCHAR BiosEnd
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. Allocates memory and copies the $PIR table if found at the specified
  1094. address.
  1095. Input Parameters:
  1096. BiosPtr is the location that possibly contains the $PIR table.
  1097. BiosEnd is the last possible BIOS ROM address.
  1098. Return Value:
  1099. Pointer to the Pci Irq Routing Table if successful.
  1100. NULL if there is no valid table at the specified address.
  1101. --*/
  1102. {
  1103. PPCI_IRQ_ROUTING_TABLE table = (PPCI_IRQ_ROUTING_TABLE)BiosPtr;
  1104. PVOID buffer = NULL;
  1105. PAGED_CODE();
  1106. //
  1107. // Validate this table.
  1108. //
  1109. if ( (table->Signature == PIRT_SIGNATURE) &&
  1110. (BiosPtr + table->TableSize <= BiosEnd) &&
  1111. (table->Signature == PIRT_SIGNATURE) &&
  1112. (table->TableSize > 0) )
  1113. {
  1114. //
  1115. // Allocate memory for the table.
  1116. //
  1117. buffer = ExAllocatePoolWithTag( PagedPool,
  1118. table->TableSize,
  1119. HAL_POOL_TAG);
  1120. if (buffer != NULL)
  1121. {
  1122. //
  1123. // Copy the table from the ROM into the allocated memory.
  1124. //
  1125. memcpy(buffer, table, table->TableSize);
  1126. if (!HalpSanityCheckTable(buffer, FALSE))
  1127. {
  1128. ExFreePool(buffer);
  1129. buffer = NULL;
  1130. }
  1131. }
  1132. else
  1133. {
  1134. HalPrint(("Failed to allocate memory for $PIR Pci Irq Routing Table!"));
  1135. ASSERT(buffer);
  1136. }
  1137. }
  1138. return (buffer);
  1139. }
  1140. BOOLEAN
  1141. HalpSanityCheckTable (
  1142. IN PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable,
  1143. IN BOOLEAN IgnoreChecksum
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. Validate the Pci Irq Routing Table.
  1148. Input Parameters:
  1149. PciIrqRoutingTable - Pointer to the Pci Irq Routing Table.
  1150. Return Value:
  1151. TRUE if this is a valid table, else FALSE.
  1152. --*/
  1153. {
  1154. CHAR checkSum;
  1155. PUCHAR tablePtr;
  1156. PUCHAR tableEnd;
  1157. PSLOT_INFO slotInfo;
  1158. PSLOT_INFO lastSlot;
  1159. PPIN_INFO pinInfo;
  1160. PPIN_INFO lastPin;
  1161. BOOLEAN hasNonZeroBusEntries = FALSE;
  1162. BOOLEAN valid = TRUE;
  1163. PAGED_CODE();
  1164. //
  1165. // Test1: Should have a valid signature.
  1166. //
  1167. if (PciIrqRoutingTable->Signature != PIRT_SIGNATURE)
  1168. {
  1169. HalPrint(("Pci Irq Routing Table has invalid signature %08X!", PciIrqRoutingTable->Signature));
  1170. valid = FALSE;
  1171. }
  1172. //
  1173. // Test2 - Should have a valid version.
  1174. //
  1175. else if (PciIrqRoutingTable->Version != PIRT_VERSION)
  1176. {
  1177. HalPrint(("Pci Irq Routing Table has invalid version %04X!", PciIrqRoutingTable->Version));
  1178. valid = FALSE;
  1179. }
  1180. //
  1181. // Test3 - Should have a valid size.
  1182. //
  1183. else if ( PciIrqRoutingTable->TableSize % 16 != 0 ||
  1184. PciIrqRoutingTable->TableSize <= sizeof (PCI_IRQ_ROUTING_TABLE))
  1185. {
  1186. HalPrint(("Pci Irq Routing Table has invalid size %04X!", PciIrqRoutingTable->TableSize));
  1187. valid = FALSE;
  1188. }
  1189. else if (!IgnoreChecksum)
  1190. {
  1191. //
  1192. // Test4 - Should have a valid checksum.
  1193. //
  1194. checkSum = 0;
  1195. tablePtr = (PUCHAR)PciIrqRoutingTable;
  1196. for ( tableEnd = tablePtr + PciIrqRoutingTable->TableSize;
  1197. tablePtr < tableEnd;
  1198. tablePtr++)
  1199. {
  1200. checkSum += *tablePtr;
  1201. }
  1202. if (checkSum != 0)
  1203. {
  1204. HalPrint(("Pci Irq Routing Table checksum is invalid!"));
  1205. valid = FALSE;
  1206. }
  1207. }
  1208. if(valid)
  1209. {
  1210. PSLOT_INFO testSlot;
  1211. ULONG pin;
  1212. //
  1213. // First get rid of sutpid entries.
  1214. //
  1215. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + sizeof(PCI_IRQ_ROUTING_TABLE));
  1216. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + PciIrqRoutingTable->TableSize);
  1217. while (slotInfo < lastSlot && valid)
  1218. {
  1219. //
  1220. // Process all pins.
  1221. //
  1222. pinInfo = &slotInfo->PinInfo[0];
  1223. lastPin = &slotInfo->PinInfo[NUM_IRQ_PINS];
  1224. while (pinInfo < lastPin)
  1225. {
  1226. //
  1227. // Check for bad cases.
  1228. //
  1229. if(pinInfo->Link)
  1230. {
  1231. if ( pinInfo->InterruptMap == 0x0000 ||
  1232. pinInfo->InterruptMap == 0x0001)
  1233. {
  1234. 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));
  1235. pinInfo->InterruptMap = 0;
  1236. pinInfo->Link = 0;
  1237. }
  1238. }
  1239. //
  1240. // Next pin.
  1241. //
  1242. pinInfo++;
  1243. }
  1244. //
  1245. // Remove this entry if all pins have NULL links.
  1246. //
  1247. if ( slotInfo->PinInfo[0].Link == 0 &&
  1248. slotInfo->PinInfo[1].Link == 0 &&
  1249. slotInfo->PinInfo[2].Link == 0 &&
  1250. slotInfo->PinInfo[3].Link == 0)
  1251. {
  1252. HalPrint(("Removed redundant entry (b=%02X, d=%02X, s=%02X) from IRQ routing table!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1253. *slotInfo = *(--lastSlot);
  1254. PciIrqRoutingTable->TableSize -= sizeof(SLOT_INFO);
  1255. //
  1256. // Need to test the newly copied entry.
  1257. //
  1258. continue;
  1259. }
  1260. //
  1261. // Merge entries for MF devices.
  1262. //
  1263. testSlot = slotInfo + 1;
  1264. while (testSlot < lastSlot)
  1265. {
  1266. if ( (testSlot->DeviceNumber & 0xF8) == (slotInfo->DeviceNumber & 0xF8) &&
  1267. testSlot->BusNumber == slotInfo->BusNumber)
  1268. {
  1269. //
  1270. // Process all pins.
  1271. //
  1272. for (pin = 0; pin < NUM_IRQ_PINS; pin++)
  1273. {
  1274. if (testSlot->PinInfo[pin].Link)
  1275. {
  1276. if (slotInfo->PinInfo[pin].Link)
  1277. {
  1278. 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));
  1279. valid = FALSE;
  1280. break;
  1281. }
  1282. else
  1283. {
  1284. HalPrint(("Merging multiple entries for same device (b=%02X, d=%02X, s=%02X) in IRQ routing table!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1285. slotInfo->PinInfo[pin] = testSlot->PinInfo[pin];
  1286. }
  1287. }
  1288. }
  1289. if (!valid)
  1290. {
  1291. break;
  1292. }
  1293. *testSlot = *(--lastSlot);
  1294. PciIrqRoutingTable->TableSize -= sizeof(SLOT_INFO);
  1295. //
  1296. // Need to test the newly copied entry.
  1297. //
  1298. continue;
  1299. }
  1300. testSlot++;
  1301. }
  1302. if (slotInfo->BusNumber > 0)
  1303. {
  1304. hasNonZeroBusEntries = TRUE;
  1305. }
  1306. //
  1307. // Next slot.
  1308. //
  1309. slotInfo++;
  1310. }
  1311. if (valid && PciIrqRoutingTable->TableSize == sizeof(PCI_IRQ_ROUTING_TABLE))
  1312. {
  1313. HalPrint(("No IRQ routing table left after sanity checking!"));
  1314. valid = FALSE;
  1315. }
  1316. }
  1317. //
  1318. // Make sure there are entries for all bus 0 devices in the table.
  1319. //
  1320. if (valid)
  1321. {
  1322. PBUS_HANDLER busHandler;
  1323. PCI_SLOT_NUMBER slotNumber;
  1324. ULONG device;
  1325. ULONG function;
  1326. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  1327. PPCI_COMMON_CONFIG pciData = (PPCI_COMMON_CONFIG)&buffer[0];
  1328. busHandler = HalpHandlerForBus(PCIBus, 0);
  1329. if (busHandler)
  1330. {
  1331. slotNumber.u.AsULONG = 0;
  1332. for ( device = 0;
  1333. device < PCI_MAX_DEVICES && valid;
  1334. device++)
  1335. {
  1336. slotNumber.u.bits.DeviceNumber = device;
  1337. for (function = 0; function < PCI_MAX_FUNCTION && valid; function++)
  1338. {
  1339. slotNumber.u.bits.FunctionNumber = function;
  1340. //
  1341. // Read the standard config space.
  1342. //
  1343. HalpReadPCIConfig(busHandler, slotNumber, pciData, 0, PCI_COMMON_HDR_LENGTH);
  1344. //
  1345. // Make sure this is a valid device.
  1346. //
  1347. if (pciData->VendorID != 0xFFFF && pciData->DeviceID != 0xFFFF)
  1348. {
  1349. //
  1350. // Ignore IDE devices.
  1351. //
  1352. if ( (pciData->BaseClass != PCI_CLASS_MASS_STORAGE_CTLR && pciData->SubClass != PCI_SUBCLASS_MSC_IDE_CTLR) ||
  1353. (pciData->ProgIf & 0x05))
  1354. {
  1355. //
  1356. // Handle P-P bridges separately.
  1357. //
  1358. if ( ((pciData->HeaderType & 0x7F) == PCI_BRIDGE_TYPE) &&
  1359. pciData->BaseClass == PCI_CLASS_BRIDGE_DEV && pciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)
  1360. {
  1361. //
  1362. // P-P bridge.
  1363. //
  1364. if (!hasNonZeroBusEntries)
  1365. {
  1366. //
  1367. // Must have the bridge with at least one entry.
  1368. //
  1369. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + sizeof(PCI_IRQ_ROUTING_TABLE));
  1370. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + PciIrqRoutingTable->TableSize);
  1371. valid = FALSE;
  1372. while (slotInfo < lastSlot && !valid)
  1373. {
  1374. if ((slotInfo->DeviceNumber>>3) == (UCHAR)device)
  1375. {
  1376. //
  1377. // Process all pins.
  1378. //
  1379. pinInfo = &slotInfo->PinInfo[0];
  1380. lastPin = &slotInfo->PinInfo[NUM_IRQ_PINS];
  1381. while (pinInfo < lastPin)
  1382. {
  1383. if(pinInfo->Link)
  1384. {
  1385. valid = TRUE;
  1386. break;
  1387. }
  1388. pinInfo++;
  1389. }
  1390. }
  1391. slotInfo++;
  1392. }
  1393. if (!valid)
  1394. {
  1395. HalPrint(("All links missing for bridge (b=%02X, d=%02X, s=%02X)!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1396. }
  1397. }
  1398. }
  1399. else
  1400. {
  1401. UCHAR intLine;
  1402. UCHAR intPin;
  1403. //
  1404. // Normal device.
  1405. //
  1406. if ((pciData->HeaderType & 0x7F) == PCI_CARDBUS_BRIDGE_TYPE)
  1407. {
  1408. intPin = pciData->u.type2.InterruptPin;
  1409. intLine = pciData->u.type2.InterruptLine;
  1410. }
  1411. else
  1412. {
  1413. intPin = pciData->u.type0.InterruptPin;
  1414. intLine = pciData->u.type0.InterruptLine;
  1415. }
  1416. if (intPin && intPin <= NUM_IRQ_PINS)
  1417. {
  1418. if ( !(pciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) ||
  1419. (intLine && intLine <= 0x0F))
  1420. {
  1421. intPin--;
  1422. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + sizeof(PCI_IRQ_ROUTING_TABLE));
  1423. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable + PciIrqRoutingTable->TableSize);
  1424. valid = FALSE;
  1425. while (slotInfo < lastSlot)
  1426. {
  1427. if ( (slotInfo->DeviceNumber>>3) == (UCHAR)device &&
  1428. slotInfo->PinInfo[intPin].Link)
  1429. {
  1430. valid = TRUE;
  1431. break;
  1432. }
  1433. slotInfo++;
  1434. }
  1435. if (!valid)
  1436. {
  1437. HalPrint(("Missing entry for device (b=%02X, d=%02X, s=%02X) in the IRQ routing table!", slotInfo->BusNumber, slotInfo->DeviceNumber>>3, slotInfo->SlotNumber));
  1438. }
  1439. }
  1440. }
  1441. }
  1442. }
  1443. }
  1444. //
  1445. // Dont waste time if this is not a multifunction device or
  1446. // device does not exist.
  1447. //
  1448. if ( (function == 0 && !(pciData->HeaderType & PCI_MULTIFUNCTION)) ||
  1449. pciData->HeaderType == 0xFF)
  1450. {
  1451. break;
  1452. }
  1453. }
  1454. }
  1455. }
  1456. }
  1457. if (!valid) {
  1458. HalPrint (("Failing IRQ routing table. IRQ routing will be disabled"));
  1459. }
  1460. return (valid);
  1461. }
  1462. NTSTATUS
  1463. HalpFindLinkNode (
  1464. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  1465. IN PDEVICE_OBJECT Pdo,
  1466. IN ULONG Bus,
  1467. IN ULONG Slot,
  1468. OUT PLINK_NODE *LinkNode
  1469. )
  1470. {
  1471. PINT_ROUTE_INTERFACE_STANDARD pciInterface;
  1472. NTSTATUS status;
  1473. ULONG dummy;
  1474. UCHAR classCode;
  1475. UCHAR subClassCode;
  1476. ROUTING_TOKEN routingToken;
  1477. PSLOT_INFO slotInfo;
  1478. PLINK_NODE linkNode;
  1479. UCHAR pin;
  1480. PAGED_CODE();
  1481. ASSERT(IsPciIrqRoutingEnabled());
  1482. *LinkNode = NULL;
  1483. pciInterface = PciIrqRoutingInfo->PciInterface;
  1484. //
  1485. // Call Pci driver to get info about the Pdo.
  1486. //
  1487. status = pciInterface->GetInterruptRouting( Pdo,
  1488. &Bus,
  1489. &Slot,
  1490. (PUCHAR)&dummy,
  1491. &pin,
  1492. &classCode,
  1493. &subClassCode,
  1494. (PDEVICE_OBJECT *)&dummy,
  1495. &routingToken,
  1496. (PUCHAR)&dummy);
  1497. //
  1498. // This means that it is not a Pci device.
  1499. //
  1500. if (!NT_SUCCESS(status))
  1501. {
  1502. return (STATUS_NOT_FOUND);
  1503. }
  1504. //
  1505. // Pci Ide Irqs behave differently than other Pci devices.
  1506. //
  1507. if ( classCode == PCI_CLASS_MASS_STORAGE_CTLR &&
  1508. subClassCode == PCI_SUBCLASS_MSC_IDE_CTLR)
  1509. {
  1510. PBUS_HANDLER busHandler;
  1511. PCI_SLOT_NUMBER slot;
  1512. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  1513. PPCI_COMMON_CONFIG pciData = (PPCI_COMMON_CONFIG)&buffer[0];
  1514. BOOLEAN nativeMode = FALSE;
  1515. //
  1516. // Check for native mode IDE controller.
  1517. //
  1518. busHandler = HalpHandlerForBus(PCIBus, Bus);
  1519. if (busHandler)
  1520. {
  1521. slot.u.AsULONG = Slot;
  1522. HalpReadPCIConfig(busHandler, slot, pciData, 0, PCI_COMMON_HDR_LENGTH);
  1523. if ( pciData->VendorID != 0xFFFF &&
  1524. pciData->DeviceID != 0xFFFF &&
  1525. pciData->BaseClass == classCode &&
  1526. pciData->SubClass == subClassCode)
  1527. {
  1528. //
  1529. // Check if either channel is in native mode?
  1530. //
  1531. if (pciData->ProgIf & 0x05)
  1532. {
  1533. nativeMode = TRUE;
  1534. }
  1535. }
  1536. }
  1537. if (!nativeMode)
  1538. {
  1539. return (STATUS_RESOURCE_REQUIREMENTS_CHANGED);
  1540. }
  1541. }
  1542. //
  1543. // Have we cached this before?
  1544. //
  1545. if (routingToken.LinkNode != NULL)
  1546. {
  1547. ASSERT(((PLINK_NODE)routingToken.LinkNode)->Signature == PCI_LINK_SIGNATURE);
  1548. *LinkNode = (PLINK_NODE)routingToken.LinkNode;
  1549. return (STATUS_SUCCESS);
  1550. }
  1551. //
  1552. // Get the slot info for this device.
  1553. //
  1554. slotInfo = HalpBarberPole( PciIrqRoutingInfo,
  1555. Pdo,
  1556. Bus,
  1557. Slot,
  1558. &pin);
  1559. if (slotInfo != NULL)
  1560. {
  1561. ASSERT(pin <4);
  1562. for ( linkNode = PciIrqRoutingInfo->LinkNodeHead;
  1563. linkNode && linkNode->Link != slotInfo->PinInfo[pin].Link;
  1564. linkNode = linkNode->Next);
  1565. if (linkNode != NULL)
  1566. {
  1567. *LinkNode = linkNode;
  1568. //
  1569. // Initialize the routing token.
  1570. //
  1571. routingToken.LinkNode = linkNode;
  1572. routingToken.StaticVector = 0;
  1573. routingToken.Flags = 0;
  1574. //
  1575. // Save the routing token.
  1576. //
  1577. status = pciInterface->SetInterruptRoutingToken( Pdo,
  1578. &routingToken);
  1579. if (!NT_SUCCESS(status))
  1580. {
  1581. HalPrint(("Failed to set Pci routing token!"));
  1582. ASSERT(NT_SUCCESS(status));
  1583. }
  1584. }
  1585. }
  1586. return (STATUS_SUCCESS);
  1587. }
  1588. PSLOT_INFO
  1589. HalpBarberPole (
  1590. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  1591. IN PDEVICE_OBJECT Pdo,
  1592. IN ULONG Bus,
  1593. IN ULONG Slot,
  1594. IN OUT PUCHAR Pin
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. This routine implements the "barber pole" algorithm to determine the interrupt
  1599. pin for Pci devices behind bridges.
  1600. Input Parameters:
  1601. PciIrqRouting - Pci Irq Routing information.
  1602. Pdo - Pci device object for which we barber pole.
  1603. Pin - Interrupt pin for the Pci device entry in the routing table we reached.
  1604. Return Value:
  1605. Slot info for the specified device iff successful.
  1606. --*/
  1607. {
  1608. ULONG dummy;
  1609. UCHAR pin;
  1610. PDEVICE_OBJECT parent;
  1611. ROUTING_TOKEN routingToken;
  1612. BOOLEAN success;
  1613. PSLOT_INFO slotInfo;
  1614. NTSTATUS status;
  1615. PINT_ROUTE_INTERFACE_STANDARD pciInterface;
  1616. PAGED_CODE();
  1617. ASSERT(IsPciIrqRoutingEnabled());
  1618. pciInterface = PciIrqRoutingInfo->PciInterface;
  1619. //
  1620. // This device MUST be a PCI device with a valid interrupt pin.
  1621. //
  1622. status = pciInterface->GetInterruptRouting( Pdo,
  1623. &Bus,
  1624. &Slot,
  1625. (PUCHAR)&dummy,
  1626. &pin,
  1627. (PUCHAR)&dummy,
  1628. (PUCHAR)&dummy,
  1629. &parent,
  1630. &routingToken,
  1631. (PUCHAR)&dummy);
  1632. if (!NT_SUCCESS(status) || pin == 0)
  1633. {
  1634. return (NULL);
  1635. }
  1636. //
  1637. // Normalize the pin.
  1638. //
  1639. pin--;
  1640. success = TRUE;
  1641. while (success)
  1642. {
  1643. slotInfo = HalpGetSlotInfo( PciIrqRoutingInfo->PciIrqRoutingTable,
  1644. (UCHAR)Bus,
  1645. (UCHAR)(Slot & 0x1F));
  1646. if (slotInfo != NULL)
  1647. {
  1648. break;
  1649. }
  1650. //
  1651. // Get barber pole info for the parent.
  1652. //
  1653. success = HalpBarberPolePin( PciIrqRoutingInfo,
  1654. parent,
  1655. Bus,
  1656. Slot & 0x1F,
  1657. &pin);
  1658. Bus = (ULONG)-1;
  1659. Slot = (ULONG)-1;
  1660. //
  1661. // Get parent's info.
  1662. //
  1663. status = pciInterface->GetInterruptRouting( parent,
  1664. &Bus,
  1665. &Slot,
  1666. (PUCHAR)&dummy,
  1667. (PUCHAR)&dummy,
  1668. (PUCHAR)&dummy,
  1669. (PUCHAR)&dummy,
  1670. &parent,
  1671. &routingToken,
  1672. (PUCHAR)&dummy);
  1673. if (!NT_SUCCESS(status))
  1674. {
  1675. success = FALSE;
  1676. break;
  1677. }
  1678. }
  1679. //
  1680. // Return unsuccessfully if we encountered any weird error.
  1681. //
  1682. if (success == FALSE)
  1683. slotInfo = NULL;
  1684. if (slotInfo)
  1685. {
  1686. *Pin = pin;
  1687. }
  1688. return (slotInfo);
  1689. }
  1690. BOOLEAN
  1691. HalpBarberPolePin (
  1692. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  1693. IN PDEVICE_OBJECT Parent,
  1694. IN ULONG Bus,
  1695. IN ULONG Device,
  1696. IN OUT PUCHAR Pin
  1697. )
  1698. /*++
  1699. Routine Description:
  1700. This routine returns the info used for barber poling.
  1701. Input Parameters:
  1702. PciIrqRoutingInfo - Pci Irq Routing information.
  1703. Parent - Parent device object as we barber pole.
  1704. Bus - Child device objects bus number.
  1705. Device - Device number for the child device.
  1706. Pin - Child device objects interrupt pin number (normalized) on entry.
  1707. Return Value:
  1708. TRUE iff successful.
  1709. --*/
  1710. {
  1711. ULONG parentBus;
  1712. ULONG parentSlot;
  1713. ULONG dummy;
  1714. UCHAR parentPin;
  1715. UCHAR classCode;
  1716. UCHAR subClassCode;
  1717. ROUTING_TOKEN routingToken;
  1718. NTSTATUS status;
  1719. PINT_ROUTE_INTERFACE_STANDARD pciInterface;
  1720. PAGED_CODE();
  1721. ASSERT(IsPciIrqRoutingEnabled());
  1722. pciInterface = PciIrqRoutingInfo->PciInterface;
  1723. //
  1724. // Read the registry flags and see if this device supports straight
  1725. // through routing.
  1726. //
  1727. //
  1728. // Check if the pin table is present in the registry.
  1729. //
  1730. parentBus = (ULONG)-1;
  1731. parentSlot = (ULONG)-1;
  1732. //
  1733. // Get info about the parent from Pci.
  1734. //
  1735. status = pciInterface->GetInterruptRouting( Parent,
  1736. &parentBus,
  1737. &parentSlot,
  1738. (PUCHAR)&dummy,
  1739. &parentPin,
  1740. &classCode,
  1741. &subClassCode,
  1742. (PDEVICE_OBJECT *)&dummy,
  1743. &routingToken,
  1744. (PUCHAR)&dummy);
  1745. if (NT_SUCCESS(status) && classCode == PCI_CLASS_BRIDGE_DEV)
  1746. {
  1747. switch (subClassCode)
  1748. {
  1749. case PCI_SUBCLASS_BR_PCI_TO_PCI:
  1750. *Pin = (*Pin + (UCHAR)Device) % 4;
  1751. break;
  1752. case PCI_SUBCLASS_BR_CARDBUS:
  1753. *Pin = parentPin - 1;
  1754. break;
  1755. default:
  1756. HalPrint(("Pci device (bus=%02lx, slot=%02lx) does not have a PCI bridge as its parent!", Bus, Device));
  1757. ASSERT(FALSE);
  1758. return (FALSE);
  1759. }
  1760. }
  1761. return (TRUE);
  1762. }
  1763. PSLOT_INFO
  1764. HalpGetSlotInfo (
  1765. IN PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable,
  1766. IN UCHAR Bus,
  1767. IN UCHAR Device
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. This routine searches the Pci Irq Routing Table for an entry for the specified
  1772. Pci device on the given bus number.
  1773. Input Parameters:
  1774. PciIrqRoutingInfo - Pci Irq Routing information.
  1775. Bus - Bus number of the Pci device.
  1776. Device - Device number of the Pci device.
  1777. Return Value:
  1778. Pointer to the slot info for the specified device iff successful.
  1779. --*/
  1780. {
  1781. PSLOT_INFO slotInfo;
  1782. PSLOT_INFO lastSlot;
  1783. PAGED_CODE();
  1784. ASSERT(IsPciIrqRoutingEnabled());
  1785. //
  1786. // Process all slots in this table.
  1787. //
  1788. slotInfo = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable +
  1789. sizeof(PCI_IRQ_ROUTING_TABLE));
  1790. lastSlot = (PSLOT_INFO)((PUCHAR)PciIrqRoutingTable +
  1791. PciIrqRoutingTable->TableSize);
  1792. while (slotInfo < lastSlot)
  1793. {
  1794. if ( slotInfo->BusNumber == Bus &&
  1795. (slotInfo->DeviceNumber >> 3) == Device)
  1796. {
  1797. return (slotInfo);
  1798. }
  1799. slotInfo++;
  1800. }
  1801. return (NULL);
  1802. }
  1803. NTSTATUS
  1804. HalpReadRegistryValue (
  1805. IN HANDLE Root,
  1806. IN const WCHAR* KeyName,
  1807. IN const WCHAR* ValueName,
  1808. OUT PULONG Data
  1809. )
  1810. /*++
  1811. Routine Description:
  1812. Reads the value for the valuename under the key specified.
  1813. Input Parameters:
  1814. Root is the handle of the root if any.
  1815. KeyName is the name of the key under which this value appears.
  1816. ValueName is the name of the value to be read.
  1817. Data is the variable that receives the value read.
  1818. Return Value:
  1819. Standard NT status value.
  1820. --*/
  1821. {
  1822. UNICODE_STRING valueName;
  1823. HANDLE hKey;
  1824. NTSTATUS status;
  1825. UCHAR buffer[sizeof(KEY_VALUE_FULL_INFORMATION) + MAXIMUM_VALUE_NAME_LENGTH + sizeof(ULONG)];
  1826. ULONG cbData;
  1827. UNICODE_STRING keyName;
  1828. PAGED_CODE();
  1829. RtlInitUnicodeString( &keyName, KeyName);
  1830. status = HalpOpenRegistryKey(&hKey, Root, &keyName, KEY_READ, FALSE);
  1831. if (NT_SUCCESS(status))
  1832. {
  1833. RtlInitUnicodeString(&valueName, ValueName);
  1834. status = ZwQueryValueKey( hKey,
  1835. &valueName,
  1836. KeyValueFullInformation,
  1837. &buffer[0],
  1838. sizeof(buffer),
  1839. &cbData);
  1840. if (NT_SUCCESS(status))
  1841. {
  1842. *Data = *(PULONG)((PUCHAR)&buffer[0] + ((PKEY_VALUE_FULL_INFORMATION)&buffer[0])->DataOffset);
  1843. }
  1844. ZwClose(hKey);
  1845. }
  1846. return (status);
  1847. }
  1848. NTSTATUS
  1849. HalpWriteRegistryValue (
  1850. IN HANDLE Root,
  1851. IN const WCHAR* KeyName,
  1852. IN const WCHAR* ValueName,
  1853. IN ULONG Value
  1854. )
  1855. /*++
  1856. Routine Description:
  1857. Writes the value for the valuename under the key specified.
  1858. Input Parameters:
  1859. Root is the handle of the root if any.
  1860. KeyName is the name of the key under which this value appears.
  1861. ValueName is the name of the value to be written.
  1862. Value is the value to be written.
  1863. Return Value:
  1864. Standard NT status value.
  1865. --*/
  1866. {
  1867. NTSTATUS status;
  1868. UNICODE_STRING valueName;
  1869. HANDLE hKey;
  1870. UNICODE_STRING keyName;
  1871. PAGED_CODE();
  1872. RtlInitUnicodeString(&keyName, KeyName);
  1873. status = HalpOpenRegistryKey(&hKey, Root, &keyName, KEY_ALL_ACCESS, FALSE);
  1874. if (NT_SUCCESS(status))
  1875. {
  1876. RtlInitUnicodeString(&valueName, ValueName);
  1877. status = ZwSetValueKey( hKey,
  1878. &valueName,
  1879. 0,
  1880. REG_DWORD,
  1881. &Value,
  1882. sizeof(Value));
  1883. ZwClose(hKey);
  1884. }
  1885. return (status);
  1886. }
  1887. NTSTATUS
  1888. HalpCommitLink (
  1889. IN PLINK_NODE LinkNode
  1890. )
  1891. {
  1892. NTSTATUS status;
  1893. ULONG interrupt;
  1894. PLINK_STATE temp;
  1895. //
  1896. // Read the current state of this link.
  1897. //
  1898. interrupt = 0;
  1899. status = PciirqmpGetIrq((PUCHAR)&interrupt, (UCHAR)LinkNode->Link);
  1900. if (LinkNode->PossibleAllocation->RefCount)
  1901. {
  1902. //
  1903. // Program the link.
  1904. //
  1905. if (NT_SUCCESS(status) && interrupt != LinkNode->PossibleAllocation->Interrupt)
  1906. {
  1907. PciirqmpSetIrq((UCHAR)LinkNode->PossibleAllocation->Interrupt, (UCHAR)LinkNode->Link);
  1908. }
  1909. }
  1910. else if (LinkNode->Allocation->RefCount)
  1911. {
  1912. //
  1913. // Disable the link.
  1914. //
  1915. if (NT_SUCCESS(status) && interrupt)
  1916. {
  1917. PciirqmpSetIrq((UCHAR)0, (UCHAR)LinkNode->Link);
  1918. }
  1919. }
  1920. #if defined(NEC_98)
  1921. else if (!(LinkNode->PossibleAllocation->Interrupt))
  1922. {
  1923. //
  1924. // Disable the link.
  1925. //
  1926. PciirqmpSetIrq((UCHAR)0, (UCHAR)LinkNode->Link);
  1927. }
  1928. #endif
  1929. //
  1930. // Swap the possible with the allocation.
  1931. //
  1932. temp = LinkNode->Allocation;
  1933. LinkNode->Allocation = LinkNode->PossibleAllocation;
  1934. LinkNode->PossibleAllocation = temp;
  1935. return (STATUS_SUCCESS);
  1936. }
  1937. VOID
  1938. HalpProgramInterruptLine (
  1939. IN PPCI_IRQ_ROUTING_INFO PciIrqRoutingInfo,
  1940. IN PDEVICE_OBJECT Pdo,
  1941. IN ULONG Interrupt
  1942. )
  1943. {
  1944. PAGED_CODE();
  1945. //
  1946. // We should never be here if Pci Irq routing is not enabled.
  1947. //
  1948. ASSERT(IsPciIrqRoutingEnabled());
  1949. PciIrqRoutingInfo->PciInterface->UpdateInterruptLine(Pdo, (UCHAR)Interrupt);
  1950. }