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.

900 lines
21 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. routintf.c
  5. Abstract:
  6. This module implements the "Pci Interrupt Routing" interfaces supported
  7. by the PCI driver.
  8. Author:
  9. Jake Oshins (jakeo) 19-Jul-1997
  10. Revision History:
  11. Elliot Shmukler (t-ellios) 7-15-1998 Modified the PCI routing interface to support
  12. MSI capable devices.
  13. --*/
  14. #include "pcip.h"
  15. #define MSI_SIMULATE 0
  16. //
  17. // Prototypes for routines exposed only thru the "interface"
  18. // mechanism.
  19. //
  20. NTSTATUS
  21. routeintrf_Constructor(
  22. PVOID DeviceExtension,
  23. PVOID PciInterface,
  24. PVOID InterfaceSpecificData,
  25. USHORT Version,
  26. USHORT Size,
  27. PINTERFACE InterfaceReturn
  28. );
  29. NTSTATUS
  30. routeintrf_Initializer(
  31. IN PPCI_ARBITER_INSTANCE Instance
  32. );
  33. VOID
  34. routeintrf_Reference(
  35. IN PVOID Context
  36. );
  37. VOID
  38. routeintrf_Dereference(
  39. IN PVOID Context
  40. );
  41. NTSTATUS
  42. PciGetInterruptRoutingInfoEx(
  43. IN PDEVICE_OBJECT Pdo,
  44. OUT ULONG *Bus,
  45. OUT ULONG *PciSlot,
  46. OUT UCHAR *InterruptLine,
  47. OUT UCHAR *InterruptPin,
  48. OUT UCHAR *ClassCode,
  49. OUT UCHAR *SubClassCode,
  50. OUT PDEVICE_OBJECT *ParentPdo,
  51. OUT ROUTING_TOKEN *RoutingToken,
  52. OUT UCHAR *Flags
  53. );
  54. NTSTATUS
  55. PciSetRoutingToken(
  56. IN PDEVICE_OBJECT Pdo,
  57. IN PROUTING_TOKEN RoutingToken
  58. );
  59. NTSTATUS
  60. PciSetRoutingTokenEx(
  61. IN PDEVICE_OBJECT Pdo,
  62. IN PROUTING_TOKEN RoutingToken
  63. );
  64. VOID
  65. PciUpdateInterruptLine(
  66. IN PDEVICE_OBJECT Pdo,
  67. IN UCHAR Line
  68. );
  69. NTSTATUS
  70. PciGetInterruptRoutingInfo(
  71. IN PDEVICE_OBJECT Pdo,
  72. OUT ULONG *Bus,
  73. OUT ULONG *PciSlot,
  74. OUT UCHAR *InterruptLine,
  75. OUT UCHAR *InterruptPin,
  76. OUT UCHAR *ClassCode,
  77. OUT UCHAR *SubClassCode,
  78. OUT PDEVICE_OBJECT *ParentPdo,
  79. OUT ROUTING_TOKEN *RoutingToken
  80. );
  81. NTSTATUS
  82. PciSetLegacyDeviceToken(
  83. IN PDEVICE_OBJECT LegacyDO,
  84. IN PROUTING_TOKEN RoutingToken
  85. );
  86. NTSTATUS
  87. PciFindLegacyDevice(
  88. IN PDEVICE_OBJECT LegacyDO,
  89. OUT ULONG *Bus,
  90. OUT ULONG *PciSlot,
  91. OUT UCHAR *InterruptLine,
  92. OUT UCHAR *InterruptPin,
  93. OUT UCHAR *ClassCode,
  94. OUT UCHAR *SubClassCode,
  95. OUT PDEVICE_OBJECT *ParentPdo,
  96. OUT ROUTING_TOKEN *RoutingToken
  97. );
  98. typedef struct {
  99. PCI_SECONDARY_EXTENSION ExtensionHeader;
  100. ROUTING_TOKEN RoutingToken;
  101. } ROUTING_EXTENSION, *PROUTING_EXTENSION;
  102. //
  103. // Define the Pci Routing interface "Interface" structure.
  104. //
  105. PCI_INTERFACE PciRoutingInterface = {
  106. &GUID_INT_ROUTE_INTERFACE_STANDARD, // InterfaceType
  107. sizeof(INT_ROUTE_INTERFACE_STANDARD), // MinSize
  108. PCI_INT_ROUTE_INTRF_STANDARD_VER, // MinVersion
  109. PCI_INT_ROUTE_INTRF_STANDARD_VER, // MaxVersion
  110. PCIIF_FDO, // Flags
  111. 0, // ReferenceCount
  112. PciInterface_IntRouteHandler, // Signature
  113. routeintrf_Constructor, // Constructor
  114. routeintrf_Initializer // Instance Initializer
  115. };
  116. PLEGACY_DEVICE PciLegacyDeviceHead = NULL;
  117. #ifdef ALLOC_PRAGMA
  118. #pragma alloc_text(PAGE, routeintrf_Constructor)
  119. #pragma alloc_text(PAGE, routeintrf_Initializer)
  120. #pragma alloc_text(PAGE, routeintrf_Reference)
  121. #pragma alloc_text(PAGE, PciGetInterruptRoutingInfo)
  122. #pragma alloc_text(PAGE, PciGetInterruptRoutingInfoEx)
  123. #pragma alloc_text(PAGE, PciSetRoutingToken)
  124. #pragma alloc_text(PAGE, PciSetRoutingTokenEx)
  125. #pragma alloc_text(PAGE, PciFindLegacyDevice)
  126. #pragma alloc_text(PAGE, PciCacheLegacyDeviceRouting)
  127. #pragma alloc_text(PAGE, PciUpdateInterruptLine)
  128. #endif
  129. VOID
  130. routeintrf_Reference(
  131. IN PVOID Context
  132. )
  133. {
  134. return;
  135. }
  136. NTSTATUS
  137. routeintrf_Constructor(
  138. PVOID DeviceExtension,
  139. PVOID PciInterface,
  140. PVOID InterfaceSpecificData,
  141. USHORT Version,
  142. USHORT Size,
  143. PINTERFACE InterfaceReturn
  144. )
  145. /*++
  146. Routine Description:
  147. Initialize the BUS_INTERFACE_STANDARD fields.
  148. Arguments:
  149. PciInterface Pointer to the PciInterface record for this
  150. interface type.
  151. InterfaceSpecificData
  152. InterfaceReturn
  153. Return Value:
  154. Status
  155. --*/
  156. {
  157. PINT_ROUTE_INTERFACE_STANDARD standard = (PINT_ROUTE_INTERFACE_STANDARD)InterfaceReturn;
  158. switch(Version)
  159. {
  160. case PCI_INT_ROUTE_INTRF_STANDARD_VER:
  161. standard->GetInterruptRouting = PciGetInterruptRoutingInfoEx;
  162. standard->SetInterruptRoutingToken = PciSetRoutingTokenEx;
  163. standard->UpdateInterruptLine = PciUpdateInterruptLine;
  164. break;
  165. default:
  166. return STATUS_NOINTERFACE;
  167. }
  168. standard->Size = sizeof( INT_ROUTE_INTERFACE_STANDARD );
  169. standard->Version = Version;
  170. standard->Context = DeviceExtension;
  171. standard->InterfaceReference = routeintrf_Reference;
  172. standard->InterfaceDereference = routeintrf_Reference;
  173. return STATUS_SUCCESS;
  174. }
  175. NTSTATUS
  176. routeintrf_Initializer(
  177. IN PPCI_ARBITER_INSTANCE Instance
  178. )
  179. /*++
  180. Routine Description:
  181. For bus interface, does nothing, shouldn't actually be called.
  182. Arguments:
  183. Instance Pointer to the PDO extension.
  184. Return Value:
  185. Returns the status of this operation.
  186. --*/
  187. {
  188. ASSERTMSG("PCI routeintrf_Initializer, unexpected call.", 0);
  189. return STATUS_UNSUCCESSFUL;
  190. }
  191. NTSTATUS
  192. PciGetInterruptRoutingInfo(
  193. IN PDEVICE_OBJECT Pdo,
  194. OUT ULONG *Bus,
  195. OUT ULONG *PciSlot,
  196. OUT UCHAR *InterruptLine,
  197. OUT UCHAR *InterruptPin,
  198. OUT UCHAR *ClassCode,
  199. OUT UCHAR *SubClassCode,
  200. OUT PDEVICE_OBJECT *ParentPdo,
  201. OUT ROUTING_TOKEN *RoutingToken
  202. )
  203. /*++
  204. Routine Description:
  205. Each PCI device in the system is connected to some
  206. interrupt pin. And in order to figure out which interrupt
  207. that device may trigger, an IRQ arbiter must have this
  208. information. This interface gathers all such information
  209. for the arbiter.
  210. Arguments:
  211. Pdo - Device object that the arbiter needs to inquire about
  212. Bus - Number of the PCI bus in question
  213. PciSlot - Slot/Function that corresponds to this device
  214. InterruptLine - Contents of the device's interrupt line register
  215. InterruptPin - Contents of the device's interrupt pin register
  216. ClassCode - type of device
  217. SubClassCode - sub-type of device
  218. ParentPdo - PDO of parent PCI bus
  219. RoutingToken - blob of data
  220. Return Value:
  221. STATUS_SUCCESS - this is a PCI device and all the fields have been filled
  222. STATUS_NOT_FOUND - to the knowledge of the PCI driver, this is not a PCI device
  223. --*/
  224. {
  225. PROUTING_EXTENSION RoutingExtension;
  226. PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
  227. NTSTATUS status;
  228. ASSERT(Bus);
  229. ASSERT(PciSlot);
  230. ASSERT(InterruptLine);
  231. ASSERT(InterruptPin);
  232. ASSERT(ClassCode);
  233. ASSERT(SubClassCode);
  234. ASSERT(ParentPdo);
  235. ASSERT(RoutingToken);
  236. //
  237. // Check to see if this is a legacy PCI device that
  238. // we are tracking.
  239. //
  240. status = PciFindLegacyDevice(Pdo,
  241. Bus,
  242. PciSlot,
  243. InterruptLine,
  244. InterruptPin,
  245. ClassCode,
  246. SubClassCode,
  247. ParentPdo,
  248. RoutingToken);
  249. if (NT_SUCCESS(status)) {
  250. //
  251. // If so, the fields have been filled in already.
  252. //
  253. return status;
  254. }
  255. //
  256. // Verify that this PDO actually belongs to us.
  257. //
  258. if (!PdoExt) {
  259. return STATUS_NOT_FOUND;
  260. }
  261. //
  262. // Verify that it is actually a PDO.
  263. //
  264. if (PdoExt->ExtensionType != PciPdoExtensionType) {
  265. return STATUS_NOT_FOUND;
  266. }
  267. *Bus = PCI_PARENT_FDOX(PdoExt)->BaseBus;
  268. *PciSlot = PdoExt->Slot.u.AsULONG;
  269. *InterruptLine = PdoExt->RawInterruptLine;
  270. *InterruptPin = PdoExt->InterruptPin;
  271. *ClassCode = PdoExt->BaseClass;
  272. *SubClassCode = PdoExt->SubClass;
  273. *ParentPdo = PCI_PARENT_PDO(PdoExt);
  274. RoutingExtension = PciFindSecondaryExtension(PdoExt,
  275. PciInterface_IntRouteHandler);
  276. if (RoutingExtension) {
  277. *RoutingToken = RoutingExtension->RoutingToken;
  278. } else {
  279. RoutingToken->LinkNode = 0;
  280. RoutingToken->StaticVector = 0;
  281. RoutingToken->Flags = 0;
  282. }
  283. return STATUS_SUCCESS;
  284. }
  285. NTSTATUS
  286. PciGetInterruptRoutingInfoEx(
  287. IN PDEVICE_OBJECT Pdo,
  288. OUT ULONG *Bus,
  289. OUT ULONG *PciSlot,
  290. OUT UCHAR *InterruptLine,
  291. OUT UCHAR *InterruptPin,
  292. OUT UCHAR *ClassCode,
  293. OUT UCHAR *SubClassCode,
  294. OUT PDEVICE_OBJECT *ParentPdo,
  295. OUT ROUTING_TOKEN *RoutingToken,
  296. OUT UCHAR *Flags
  297. )
  298. /*++
  299. Routine Description:
  300. Wrapper for PciGetInterruptroutingInfo that sets
  301. the Flags parameter to indicate MSI-capable PCI devices.
  302. Arguments:
  303. Mostly, same as PciGetInterruptRoutingInfo.
  304. Flags receives device-specific flags such as whether the device
  305. supports MSI.
  306. Return Value:
  307. Same as PciGetInterruptRoutingInfo.
  308. --*/
  309. {
  310. NTSTATUS status;
  311. PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
  312. // Call the real function
  313. status = PciGetInterruptRoutingInfo(Pdo,
  314. Bus,
  315. PciSlot,
  316. InterruptLine,
  317. InterruptPin,
  318. ClassCode,
  319. SubClassCode,
  320. ParentPdo,
  321. RoutingToken);
  322. *Flags = 0;
  323. #if MSI_SUPPORTED
  324. if (NT_SUCCESS(status)
  325. #if !MSI_SIMULATE
  326. && PdoExt->CapableMSI
  327. #endif
  328. ) {
  329. // MSI device?
  330. *Flags = PCI_MSI_ROUTING;
  331. }
  332. #endif // MSI_SUPPORTED
  333. return status;
  334. }
  335. NTSTATUS
  336. PciSetRoutingToken(
  337. IN PDEVICE_OBJECT Pdo,
  338. IN PROUTING_TOKEN RoutingToken
  339. )
  340. /*++
  341. Routine Description:
  342. This routine stores a blob of data associated with this
  343. PCI device. This job is foisted off on the PCI driver because
  344. the PCI driver has a one-to-one correspondence between useful
  345. data structures and PCI devices.
  346. Arguments:
  347. Pdo - Device object that the IRQ arbiter is working with
  348. RoutingToken - Blob of data that the IRQ arbiter wants to associate with
  349. the PCI device.
  350. Return Value:
  351. Returns the status of this operation.
  352. --*/
  353. {
  354. PROUTING_EXTENSION RoutingExtension;
  355. PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
  356. NTSTATUS status;
  357. //
  358. // Check first to see if this is a legacy PCI device.
  359. //
  360. status = PciSetLegacyDeviceToken(Pdo, RoutingToken);
  361. if (NT_SUCCESS(status)) {
  362. return STATUS_SUCCESS;
  363. }
  364. //
  365. // This isn't in our list of legacy devices. So it must be
  366. // a PCI PDO.
  367. //
  368. #if DBG
  369. RoutingExtension = PciFindSecondaryExtension(PdoExt,
  370. PciInterface_IntRouteHandler);
  371. if (RoutingExtension != NULL) {
  372. DbgPrint("PCI: *** redundant PCI routing extesion being created ***\n");
  373. }
  374. ASSERT(RoutingExtension == NULL);
  375. #endif
  376. RoutingExtension = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION,
  377. sizeof(ROUTING_EXTENSION));
  378. if (!RoutingExtension) {
  379. return STATUS_INSUFFICIENT_RESOURCES;
  380. }
  381. RoutingExtension->RoutingToken = *RoutingToken;
  382. PciLinkSecondaryExtension(PdoExt,
  383. RoutingExtension,
  384. PciInterface_IntRouteHandler,
  385. NULL);
  386. return STATUS_SUCCESS;
  387. }
  388. NTSTATUS
  389. PciSetRoutingTokenEx(
  390. IN PDEVICE_OBJECT Pdo,
  391. IN PROUTING_TOKEN RoutingToken
  392. )
  393. /*++
  394. Routine Description:
  395. MSI-aware wrapper for PciSetRoutingToken.
  396. This function will intercept MSI routing tokens (as indicated by
  397. the PCI_MSI_ROUTING flag) and store the MSI routing information
  398. in the PDO extension without caching the token in a secondary extension.
  399. Non-MSI routing tokens will be passed to PciSetRoutingToken.
  400. Arguments:
  401. Same as PciSetRoutingToken.
  402. Return Value:
  403. Same as PciSetRoutingToken.
  404. --*/
  405. {
  406. PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
  407. NTSTATUS status = STATUS_SUCCESS;
  408. #if MSI_SUPPORTED
  409. if(
  410. #if !MSI_SIMULATE
  411. PdoExt->CapableMSI &&
  412. #endif
  413. (RoutingToken->Flags & PCI_MSI_ROUTING))
  414. {
  415. // MSI token
  416. PciDebugPrint(PciDbgInformative,"PCI: MSI Resources Received for Device %08x\n", Pdo);
  417. #ifdef DBG
  418. // have we received a new resource assignment?
  419. if ((PdoExt->MsiInfo.MessageAddress != (ULONG_PTR)RoutingToken->LinkNode)
  420. || (PdoExt->MsiInfo.MessageData != (USHORT)RoutingToken->StaticVector)) {
  421. PciDebugPrint(PciDbgPrattling,"PCI: Device %08x will be reprogrammed with Message = %ld @%p\n",
  422. Pdo, RoutingToken->StaticVector, RoutingToken->LinkNode);
  423. }
  424. #endif
  425. // Store MSI info in PdoExt.
  426. PdoExt->MsiInfo.MessageAddress = (ULONG_PTR)RoutingToken->LinkNode;
  427. PdoExt->MsiInfo.MessageData = (USHORT)RoutingToken->StaticVector;
  428. }
  429. else
  430. #endif // MSI_SUPPORTED
  431. {
  432. // Call the original function on non-MSI tokens.
  433. status = PciSetRoutingToken(Pdo, RoutingToken);
  434. }
  435. return status;
  436. }
  437. //
  438. // NT 5.0 has to support non-PnP 4.0-style device drivers. And
  439. // this driver doesn't create the device objects associated with
  440. // a PCI device when its driver is 4.0-style. It does, however
  441. // get a chance to look at those objects when the driver calls
  442. // HalAssignSlotResources. This collection of functions tracks
  443. // these foreign device objects.
  444. //
  445. NTSTATUS
  446. PciFindLegacyDevice(
  447. IN PDEVICE_OBJECT LegacyDO,
  448. OUT ULONG *Bus,
  449. OUT ULONG *PciSlot,
  450. OUT UCHAR *InterruptLine,
  451. OUT UCHAR *InterruptPin,
  452. OUT UCHAR *ClassCode,
  453. OUT UCHAR *SubClassCode,
  454. OUT PDEVICE_OBJECT *ParentPdo,
  455. OUT ROUTING_TOKEN *RoutingToken
  456. )
  457. /*++
  458. Routine Description:
  459. This function returns all the routing data for a legacy
  460. device object.
  461. Arguments:
  462. Return Value:
  463. Returns the status of this operation.
  464. --*/
  465. {
  466. PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
  467. NTSTATUS status = STATUS_NOT_FOUND;
  468. PAGED_CODE();
  469. while (legacyDev) {
  470. if (legacyDev->LegacyDeviceObject == LegacyDO) {
  471. break;
  472. } else if (legacyDev->Bus == *Bus && legacyDev->PciSlot == *PciSlot) {
  473. if (legacyDev->LegacyDeviceObject == NULL) {
  474. //
  475. // Cache the LegacyDO in case we matched on the bus and slot info.
  476. //
  477. legacyDev->LegacyDeviceObject = LegacyDO;
  478. break;
  479. } else {
  480. PciDebugPrint(PciDbgAlways, "Two PDOs (Legacy = %08x, Pnp = %08x) for device on bus %08x, slot %08x\n", legacyDev->LegacyDeviceObject, LegacyDO, *Bus, *PciSlot);
  481. ASSERT(legacyDev->LegacyDeviceObject != NULL);
  482. legacyDev = NULL;
  483. break;
  484. }
  485. }
  486. legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
  487. }
  488. if (legacyDev) {
  489. *Bus = legacyDev->Bus;
  490. *PciSlot = legacyDev->PciSlot;
  491. *InterruptLine = legacyDev->InterruptLine;
  492. *InterruptPin = legacyDev->InterruptPin;
  493. *ClassCode = legacyDev->ClassCode;
  494. *SubClassCode = legacyDev->SubClassCode;
  495. *ParentPdo = legacyDev->ParentPdo;
  496. *RoutingToken = legacyDev->RoutingToken;
  497. status = STATUS_SUCCESS;
  498. }
  499. return status;
  500. }
  501. NTSTATUS
  502. PciCacheLegacyDeviceRouting(
  503. IN PDEVICE_OBJECT LegacyDO,
  504. IN ULONG Bus,
  505. IN ULONG PciSlot,
  506. IN UCHAR InterruptLine,
  507. IN UCHAR InterruptPin,
  508. IN UCHAR ClassCode,
  509. IN UCHAR SubClassCode,
  510. IN PDEVICE_OBJECT ParentPdo,
  511. IN PPCI_PDO_EXTENSION PdoExtension,
  512. OUT PDEVICE_OBJECT *OldLegacyDO
  513. )
  514. /*++
  515. Routine Description:
  516. This function stores all the routing data for a legacy
  517. device object, except the RoutingToken. Caller needs to acquire
  518. PciGlobalLock before calling this function.
  519. Arguments:
  520. Return Value:
  521. Returns the status of this operation.
  522. --*/
  523. {
  524. PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
  525. PAGED_CODE();
  526. while (legacyDev) {
  527. if (Bus == legacyDev->Bus && PciSlot == legacyDev->PciSlot) {
  528. if (legacyDev->LegacyDeviceObject == LegacyDO) {
  529. //
  530. // This device is already in the list.
  531. //
  532. if (OldLegacyDO) {
  533. *OldLegacyDO = LegacyDO;
  534. }
  535. return STATUS_SUCCESS;
  536. } else {
  537. PDEVICE_OBJECT oldDO;
  538. //
  539. // We are overwriting an existing entry.
  540. //
  541. oldDO = legacyDev->LegacyDeviceObject;
  542. legacyDev->LegacyDeviceObject = LegacyDO;
  543. if (OldLegacyDO) {
  544. *OldLegacyDO = oldDO;
  545. }
  546. return STATUS_SUCCESS;
  547. }
  548. }
  549. legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
  550. }
  551. legacyDev = ExAllocatePool(PagedPool,
  552. sizeof(LEGACY_DEVICE));
  553. if (!legacyDev) {
  554. return STATUS_INSUFFICIENT_RESOURCES;
  555. }
  556. RtlZeroMemory(legacyDev, sizeof(LEGACY_DEVICE));
  557. legacyDev->LegacyDeviceObject = LegacyDO;
  558. legacyDev->Bus = Bus;
  559. legacyDev->PciSlot = PciSlot;
  560. legacyDev->InterruptLine = InterruptLine;
  561. legacyDev->InterruptPin = InterruptPin;
  562. legacyDev->ClassCode = ClassCode;
  563. legacyDev->SubClassCode = SubClassCode;
  564. legacyDev->ParentPdo = ParentPdo;
  565. legacyDev->PdoExtension = PdoExtension;
  566. //
  567. // Push this one onto the list.
  568. //
  569. legacyDev->List.Next = (PSINGLE_LIST_ENTRY)PciLegacyDeviceHead;
  570. PciLegacyDeviceHead = legacyDev;
  571. if (OldLegacyDO) {
  572. *OldLegacyDO = LegacyDO;
  573. }
  574. return STATUS_SUCCESS;
  575. }
  576. NTSTATUS
  577. PciSetLegacyDeviceToken(
  578. IN PDEVICE_OBJECT LegacyDO,
  579. IN PROUTING_TOKEN RoutingToken
  580. )
  581. /*++
  582. Routine Description:
  583. This function stores the RoutingToken.
  584. Arguments:
  585. Return Value:
  586. Returns the status of this operation.
  587. --*/
  588. {
  589. PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
  590. PAGED_CODE();
  591. while (legacyDev) {
  592. if (legacyDev->LegacyDeviceObject == LegacyDO) {
  593. //
  594. // Found it. Copy the token into the structure.
  595. //
  596. legacyDev->RoutingToken = *RoutingToken;
  597. return STATUS_SUCCESS;
  598. }
  599. legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
  600. }
  601. return STATUS_NOT_FOUND;
  602. }
  603. VOID
  604. PciUpdateInterruptLine(
  605. IN PDEVICE_OBJECT Pdo,
  606. IN UCHAR Line
  607. )
  608. {
  609. NTSTATUS status;
  610. PPCI_PDO_EXTENSION pdoExt;
  611. PLEGACY_DEVICE legacyDev = PciLegacyDeviceHead;
  612. PCI_COMMON_HEADER header;
  613. PPCI_COMMON_CONFIG biosConfig = (PPCI_COMMON_CONFIG) &header;
  614. PAGED_CODE();
  615. //
  616. // Work out if this is a legacy PDO or not
  617. //
  618. while (legacyDev) {
  619. if (legacyDev->LegacyDeviceObject == Pdo) {
  620. //
  621. // Found it.
  622. //
  623. pdoExt = legacyDev->PdoExtension;
  624. break;
  625. }
  626. legacyDev = (PLEGACY_DEVICE)legacyDev->List.Next;
  627. }
  628. if (legacyDev == NULL) {
  629. //
  630. // Oh well it must be a PCI pdo
  631. //
  632. pdoExt = Pdo->DeviceExtension;
  633. }
  634. ASSERT_PCI_PDO_EXTENSION(pdoExt);
  635. //
  636. // Now we can update the hardware and our internal state!
  637. //
  638. pdoExt->RawInterruptLine = pdoExt->AdjustedInterruptLine = Line;
  639. PciWriteDeviceConfig(pdoExt,
  640. &Line,
  641. FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.InterruptLine),
  642. sizeof(Line)
  643. );
  644. //
  645. // Finally refresh the config space stored in the registry
  646. //
  647. status = PciGetBiosConfig(pdoExt, biosConfig);
  648. ASSERT(NT_SUCCESS(status));
  649. if (NT_SUCCESS(status)
  650. && biosConfig->u.type0.InterruptLine != Line) {
  651. biosConfig->u.type0.InterruptLine = Line;
  652. status = PciSaveBiosConfig(pdoExt, biosConfig);
  653. ASSERT(NT_SUCCESS(status));
  654. }
  655. }