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.

2343 lines
60 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pciopregion.c
  5. Abstract:
  6. This module implements PCI Operational Region
  7. support, which allows AML code to read and
  8. write PCI configuration space.
  9. Author:
  10. Jake Oshins (jakeo) 7-14-97
  11. Environment:
  12. NT Kernel Model Driver only
  13. --*/
  14. #include "pch.h"
  15. NTSTATUS
  16. AcpiRegisterPciRegionSupport(
  17. PDEVICE_OBJECT PciDeviceFilter
  18. );
  19. NTSTATUS
  20. GetPciAddress(
  21. IN PNSOBJ PciObj,
  22. IN PFNACB CompletionRoutine,
  23. IN PVOID Context,
  24. IN OUT PUCHAR Bus,
  25. IN OUT PPCI_SLOT_NUMBER Slot
  26. );
  27. NTSTATUS
  28. EXPORT
  29. GetPciAddressWorker(
  30. IN PNSOBJ AcpiObject,
  31. IN NTSTATUS Status,
  32. IN POBJDATA Result,
  33. IN PVOID Context
  34. );
  35. NTSTATUS
  36. GetOpRegionScope(
  37. IN PNSOBJ OpRegion,
  38. IN PFNACB CompletionHandler,
  39. IN PVOID CompletionContext,
  40. OUT PNSOBJ *PciObj
  41. );
  42. NTSTATUS
  43. EXPORT
  44. GetOpRegionScopeWorker(
  45. IN PNSOBJ AcpiObject,
  46. IN NTSTATUS Status,
  47. IN POBJDATA Result,
  48. IN PVOID Context
  49. );
  50. UCHAR
  51. GetBusNumberFromCRS(
  52. IN PDEVICE_EXTENSION DeviceExtension,
  53. IN PUCHAR CRS
  54. );
  55. #define MAX(a, b) \
  56. ((a) > (b) ? (a) : (b))
  57. #define MIN(a, b) \
  58. ((a) < (b) ? (a) : (b))
  59. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text(PAGE, AcpiRegisterPciRegionSupport)
  61. #pragma alloc_text(PAGE, ACPIInitBusInterfaces)
  62. #pragma alloc_text(PAGE, ACPIDeleteFilterInterfaceReferences)
  63. #pragma alloc_text(PAGE, IsPciBus)
  64. #pragma alloc_text(PAGE, IsNsobjPciBus)
  65. #pragma alloc_text(PAGE, EnableDisableRegions)
  66. #endif
  67. VOID
  68. ACPIInitBusInterfaces(
  69. PDEVICE_OBJECT Filter
  70. )
  71. /*++
  72. Routine Description:
  73. This routine determines whether this filter is for a PCI
  74. device. If it is, then we call AcpiRegisterPciRegionSupport.
  75. Arguments:
  76. Filter - device object for the filter we are looking at
  77. Return Value:
  78. Status
  79. Notes:
  80. --*/
  81. {
  82. PDEVICE_EXTENSION filterExt = Filter->DeviceExtension;
  83. PDEVICE_EXTENSION parentExt;
  84. NTSTATUS status;
  85. PAGED_CODE();
  86. parentExt = filterExt->ParentExtension;
  87. if (!IsPciBus(parentExt->DeviceObject)) {
  88. return;
  89. }
  90. AcpiRegisterPciRegionSupport(Filter);
  91. }
  92. VOID
  93. ACPIDeleteFilterInterfaceReferences(
  94. IN PDEVICE_EXTENSION DeviceExtension
  95. )
  96. /*++
  97. Routine Description:
  98. This routine is called for all filters when they are removed to see if
  99. we need to free some interfaces
  100. Arguments:
  101. DeviceExtension - The device whose extension we have to dereference
  102. Return Value:
  103. NTSTATUS
  104. --*/
  105. {
  106. AMLISUPP_CONTEXT_PASSIVE isPciDeviceContext;
  107. BOOLEAN pciDevice;
  108. NTSTATUS status;
  109. PAGED_CODE();
  110. if ( (DeviceExtension->Flags & DEV_PROP_NO_OBJECT) ) {
  111. return;
  112. }
  113. KeInitializeEvent(&isPciDeviceContext.Event, SynchronizationEvent, FALSE);
  114. isPciDeviceContext.Status = STATUS_NOT_FOUND;
  115. status = IsPciDevice(
  116. DeviceExtension->AcpiObject,
  117. AmlisuppCompletePassive,
  118. (PVOID)&isPciDeviceContext,
  119. &pciDevice);
  120. if (status == STATUS_PENDING) {
  121. KeWaitForSingleObject(
  122. &isPciDeviceContext.Event,
  123. Executive,
  124. KernelMode,
  125. FALSE,
  126. NULL);
  127. status = isPciDeviceContext.Status;
  128. }
  129. if (!NT_SUCCESS(status) || !pciDevice) {
  130. return;
  131. }
  132. //
  133. // This is a PCI device, so we need to relinquish
  134. // the interfaces that we got from the PCI driver.
  135. //
  136. if (!DeviceExtension->Filter.Interface) {
  137. //
  138. // There were no interfaces to release.
  139. //
  140. return;
  141. }
  142. //
  143. // Dereference it.
  144. //
  145. DeviceExtension->Filter.Interface->InterfaceDereference(
  146. DeviceExtension->Filter.Interface->Context
  147. );
  148. ExFreePool(DeviceExtension->Filter.Interface);
  149. DeviceExtension->Filter.Interface = NULL;
  150. }
  151. NTSTATUS
  152. AcpiRegisterPciRegionSupport(
  153. PDEVICE_OBJECT PciDeviceFilter
  154. )
  155. /*++
  156. Routine Description:
  157. This routine queries the PCI driver for read and write functions
  158. for PCI config space. It then attaches these interfaces to the
  159. device extension for this filter. Then, if it hasn't been done
  160. already, it registers PCI Operational Region support with the
  161. AML interpretter.
  162. Arguments:
  163. PciDeviceFilter - A filter for a PCI device
  164. Return Value:
  165. Status
  166. Notes:
  167. --*/
  168. {
  169. PBUS_INTERFACE_STANDARD interface;
  170. PCI_COMMON_CONFIG pciData;
  171. NTSTATUS status;
  172. IO_STACK_LOCATION irpSp;
  173. PWSTR buffer;
  174. PDEVICE_EXTENSION pciFilterExt;
  175. PDEVICE_OBJECT topDeviceInStack;
  176. ULONG bytes;
  177. PAGED_CODE();
  178. RtlZeroMemory( &irpSp, sizeof(IO_STACK_LOCATION) );
  179. //
  180. // If we have already registered a handler for this
  181. // device, then we don't need to do it again.
  182. //
  183. pciFilterExt = PciDeviceFilter->DeviceExtension;
  184. if (pciFilterExt->Filter.Interface) {
  185. return STATUS_SUCCESS;
  186. }
  187. interface = ExAllocatePoolWithTag(NonPagedPool, sizeof(BUS_INTERFACE_STANDARD), ACPI_INTERFACE_POOLTAG);
  188. if (!interface) {
  189. return STATUS_INSUFFICIENT_RESOURCES;
  190. }
  191. topDeviceInStack = IoGetAttachedDeviceReference(pciFilterExt->TargetDeviceObject);
  192. //
  193. // Set the function codes and parameters.
  194. //
  195. irpSp.MajorFunction = IRP_MJ_PNP;
  196. irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
  197. irpSp.Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_INTERFACE_STANDARD;
  198. irpSp.Parameters.QueryInterface.Version = 1;
  199. irpSp.Parameters.QueryInterface.Size = sizeof (BUS_INTERFACE_STANDARD);
  200. irpSp.Parameters.QueryInterface.Interface = (PINTERFACE) interface;
  201. irpSp.Parameters.QueryInterface.InterfaceSpecificData = NULL;
  202. //
  203. // Call the PCI driver.
  204. //
  205. status = ACPIInternalSendSynchronousIrp(topDeviceInStack,
  206. &irpSp,
  207. &buffer);
  208. if (NT_SUCCESS(status)) {
  209. //
  210. // Attach this interface to the PCI bus PDO.
  211. //
  212. pciFilterExt->Filter.Interface = interface;
  213. //
  214. // Reference it.
  215. //
  216. pciFilterExt->Filter.Interface->InterfaceReference(pciFilterExt->Filter.Interface->Context);
  217. //
  218. // HACKHACK. The ACPI HAL doesn't really know much about busses. But
  219. // it needs to maintain legacy HAL behavior. And to do that, it needs to
  220. // know how many PCI busses are in the system. Since we are now looking
  221. // at a PCI bus that we are filtering, we now give the HAL a heads-up that
  222. // this bus exists.
  223. //
  224. bytes = interface->GetBusData(interface->Context,
  225. 0,
  226. &pciData,
  227. 0,
  228. PCI_COMMON_HDR_LENGTH);
  229. ASSERT(bytes != 0);
  230. if ((PCI_CONFIGURATION_TYPE((&pciData)) == PCI_BRIDGE_TYPE) ||
  231. (PCI_CONFIGURATION_TYPE((&pciData)) == PCI_CARDBUS_BRIDGE_TYPE)) {
  232. //
  233. // This is actually a PCI to PCI bridge.
  234. //
  235. if (pciData.u.type1.SecondaryBus != 0) {
  236. //
  237. // And it has a bus number. So notify the HAL.
  238. //
  239. HalSetMaxLegacyPciBusNumber(pciData.u.type1.SecondaryBus);
  240. }
  241. }
  242. } else {
  243. ExFreePool(interface);
  244. }
  245. ObDereferenceObject(topDeviceInStack);
  246. return status;
  247. }
  248. typedef struct {
  249. //
  250. // Arguments to PciConfigSpaceHandler
  251. //
  252. ULONG AccessType;
  253. PNSOBJ OpRegion;
  254. ULONG Address;
  255. ULONG Size;
  256. PULONG Data;
  257. ULONG Context;
  258. PVOID CompletionHandler;
  259. PVOID CompletionContext;
  260. //
  261. // Function state
  262. //
  263. PNSOBJ PciObj;
  264. PNSOBJ ParentObj;
  265. ULONG CompletionHandlerType;
  266. ULONG Flags;
  267. LONG RunCompletion;
  268. PCI_SLOT_NUMBER Slot;
  269. UCHAR Bus;
  270. BOOLEAN IsPciDeviceResult;
  271. } PCI_CONFIG_STATE, *PPCI_CONFIG_STATE;
  272. NTSTATUS
  273. EXPORT
  274. PciConfigSpaceHandler (
  275. ULONG AccessType,
  276. PNSOBJ OpRegion,
  277. ULONG Address,
  278. ULONG Size,
  279. PULONG Data,
  280. ULONG Context,
  281. PFNAA CompletionHandler,
  282. PVOID CompletionContext
  283. )
  284. /*++
  285. Routine Description:
  286. This routine handles requests to service the PCI operation region
  287. Arguments:
  288. AccessType - Read or Write data
  289. OpRegion - Operation region object
  290. Address - Address within PCI Configuration space
  291. Size - Number of bytes to transfer
  292. Data - Data buffer to transfer to/from
  293. Context - unused
  294. CompletionHandler - AMLI handler to call when operation is complete
  295. CompletionContext - Context to pass to the AMLI handler
  296. Return Value:
  297. Status
  298. Notes:
  299. --*/
  300. {
  301. PPCI_CONFIG_STATE state;
  302. state = ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_CONFIG_STATE), ACPI_INTERFACE_POOLTAG);
  303. if (!state) {
  304. return STATUS_INSUFFICIENT_RESOURCES;
  305. }
  306. RtlZeroMemory(state, sizeof(PCI_CONFIG_STATE));
  307. state->AccessType = AccessType;
  308. state->OpRegion = OpRegion;
  309. state->Address = Address;
  310. state->Size = Size;
  311. state->Data = Data;
  312. state->Context = Context;
  313. state->CompletionHandler = CompletionHandler;
  314. state->CompletionContext = CompletionContext;
  315. state->PciObj = OpRegion->pnsParent;
  316. state->RunCompletion = INITIAL_RUN_COMPLETION;
  317. return PciConfigSpaceHandlerWorker(state->PciObj,
  318. STATUS_SUCCESS,
  319. NULL,
  320. (PVOID)state);
  321. }
  322. typedef struct {
  323. PCI_CONFIG_STATE HandlerState;
  324. NSOBJ FakeOpRegion;
  325. } PCI_INTERNAL_STATE, *PPCI_INTERNAL_STATE;
  326. NTSTATUS
  327. PciConfigInternal(
  328. IN ULONG AccessType,
  329. IN PNSOBJ PciObject,
  330. IN ULONG Offset,
  331. IN ULONG Length,
  332. IN PFNACB CompletionHandler,
  333. IN PVOID CompletionContext,
  334. IN OUT PUCHAR Data
  335. )
  336. /*++
  337. Routine Description:
  338. This routine does PCI configuration space reads or writes.
  339. It does the same thing as PciConfigSpaceHandler, except
  340. that it takes an arbitrary PNSOBJ instead of an OpRegion.
  341. Arguments:
  342. AccessType - Read or Write data
  343. PciObject - name space object for the PCI device
  344. Offset - Address within PCI Configuration space
  345. Length - Number of bytes to transfer
  346. Context - unused
  347. CompletionHandler - AMLI handler to call when operation is complete
  348. CompletionContext - Context to pass to the AMLI handler
  349. Data - Data buffer to transfer to/from
  350. Return Value:
  351. Status
  352. Notes:
  353. (1) This function is intended to be used only internally. It does
  354. not check to see if the PNSOBJ actually represents a PCI device.
  355. (2) This function will not allow writes to the first 0x40 bytes of
  356. any device's PCI configuration space. This is the common area
  357. and it is owned by the PCI driver.
  358. --*/
  359. {
  360. PPCI_INTERNAL_STATE internal;
  361. PPCI_CONFIG_STATE state;
  362. PNSOBJ opRegion;
  363. internal = ExAllocatePoolWithTag(NonPagedPool, sizeof(PCI_INTERNAL_STATE), ACPI_INTERFACE_POOLTAG);
  364. if (!internal) {
  365. return STATUS_INSUFFICIENT_RESOURCES;
  366. }
  367. RtlZeroMemory(internal, sizeof(PCI_INTERNAL_STATE));
  368. internal->FakeOpRegion.Context = PciObject;
  369. state = (PPCI_CONFIG_STATE)internal;
  370. state->AccessType = AccessType;
  371. state->OpRegion = &internal->FakeOpRegion;
  372. state->Address = Offset;
  373. state->Size = Length;
  374. state->Data = (PULONG)Data;
  375. state->Context = 0;
  376. state->CompletionHandler = CompletionHandler;
  377. state->CompletionContext = CompletionContext;
  378. state->PciObj = PciObject;
  379. state->CompletionHandlerType = PCISUPP_COMPLETION_HANDLER_PFNACB;
  380. state->RunCompletion = INITIAL_RUN_COMPLETION;
  381. return PciConfigSpaceHandlerWorker(PciObject,
  382. STATUS_SUCCESS,
  383. NULL,
  384. (PVOID)state);
  385. }
  386. //
  387. // This structure defines ranges in PCI configuration
  388. // space that AML may not write. This list must be
  389. // monotonic increasing.
  390. //
  391. USHORT PciOpRegionDisallowedRanges[4][2] =
  392. { //
  393. // Everything below the subsystem ID registers
  394. //
  395. {0,0x2b},
  396. //
  397. // Everthing between the subsystem ID registers and
  398. // the Max_Lat register
  399. //
  400. {0x30, 0x3b},
  401. //
  402. // Disallow anything above MAXUCHAR
  403. //
  404. {0x100, 0xffff},
  405. // End tag.
  406. {0,0}
  407. };
  408. NTSTATUS
  409. EXPORT
  410. PciConfigSpaceHandlerWorker(
  411. IN PNSOBJ AcpiObject,
  412. IN NTSTATUS CompletionStatus,
  413. IN POBJDATA Result,
  414. IN PVOID Context
  415. )
  416. {
  417. PBUS_INTERFACE_STANDARD interface;
  418. PDEVICE_EXTENSION pciDeviceFilter;
  419. PPCI_CONFIG_STATE state;
  420. NTSTATUS status;
  421. ULONG range, offset, length, bytes = 0;
  422. ULONG bytesWritten;
  423. PFNAA simpleCompletion;
  424. PFNACB lessSimpleCompletion;
  425. KIRQL oldIrql;
  426. #if DBG
  427. BOOLEAN Complain = FALSE;
  428. #endif
  429. state = (PPCI_CONFIG_STATE)Context;
  430. status = CompletionStatus;
  431. //
  432. // Entering this function twice with the same state
  433. // means that we need to run the completion routine.
  434. //
  435. InterlockedIncrement(&state->RunCompletion);
  436. //
  437. // If the interpretter failed, just bail.
  438. //
  439. if (!NT_SUCCESS(CompletionStatus)) {
  440. status = STATUS_SUCCESS;
  441. #if DBG
  442. Complain = TRUE;
  443. #endif
  444. goto PciConfigSpaceHandlerWorkerDone;
  445. }
  446. //
  447. // If we have not seen this OpRegion before, we need to
  448. // fill in the dwContext with the PNSOBJ of the
  449. // PCI device which the OpRegion relates to.
  450. //
  451. if (!state->OpRegion->Context) {
  452. if (!(state->Flags & PCISUPP_GOT_SCOPE)) {
  453. state->Flags |= PCISUPP_GOT_SCOPE;
  454. status = GetOpRegionScope(state->OpRegion,
  455. PciConfigSpaceHandlerWorker,
  456. (PVOID)state,
  457. &((PNSOBJ)(state->OpRegion->Context)));
  458. if (status == STATUS_PENDING) {
  459. return status;
  460. }
  461. if (!NT_SUCCESS(status)) {
  462. status = STATUS_SUCCESS;
  463. goto PciConfigSpaceHandlerWorkerDone;
  464. }
  465. }
  466. }
  467. //
  468. // Identify the PCI device, that device's extension,
  469. // and the pointer to the interface within the PCI
  470. // driver that does PCI config space reads and writes.
  471. //
  472. state->PciObj = (PNSOBJ)state->OpRegion->Context;
  473. pciDeviceFilter = (PDEVICE_EXTENSION)state->PciObj->Context;
  474. if (pciDeviceFilter == NULL) {
  475. //
  476. // The device has not been initialized yet, we cannot perform
  477. // PCI config cycles to it. Fail gracefully and return all 0xFF
  478. //
  479. bytes = 0;
  480. status = STATUS_SUCCESS;
  481. goto PciConfigSpaceHandlerWorkerDone;
  482. }
  483. ASSERT(pciDeviceFilter);
  484. interface = pciDeviceFilter->Filter.Interface;
  485. ASSERT(interface ? (interface->Size == sizeof(BUS_INTERFACE_STANDARD)) : TRUE);
  486. //
  487. // If interface is non-zero, we have enumerated this PCI
  488. // device. So use the PCI driver to do config ops.
  489. // If it is zero, make some attempt to figure out what
  490. // device this request is for. The result will be
  491. // used in calls to the HAL.
  492. //
  493. if (!interface) {
  494. if (!(state->Flags & PCISUPP_GOT_SLOT_INFO)) {
  495. state->Flags |= PCISUPP_GOT_SLOT_INFO;
  496. status = GetPciAddress(state->PciObj,
  497. PciConfigSpaceHandlerWorker,
  498. (PVOID)state,
  499. &state->Bus,
  500. &state->Slot);
  501. if (status == STATUS_PENDING) {
  502. return status;
  503. }
  504. if (!NT_SUCCESS(status)) {
  505. status = STATUS_SUCCESS;
  506. goto PciConfigSpaceHandlerWorkerDone;
  507. }
  508. }
  509. }
  510. status = STATUS_SUCCESS;
  511. oldIrql = KeGetCurrentIrql();
  512. switch (state->AccessType) {
  513. case RSACCESS_READ:
  514. if (interface) {
  515. //
  516. // Do config space op through PCI driver. Do it
  517. // at DISPATCH_LEVEL because the PCI driver expects
  518. // that, if we are running at passive level, it can
  519. // do things that page. Which may not be true here
  520. // after we have powered off the disk.
  521. //
  522. if (oldIrql < DISPATCH_LEVEL) {
  523. KeRaiseIrql(DISPATCH_LEVEL,
  524. &oldIrql);
  525. }
  526. bytes = interface->GetBusData(interface->Context,
  527. 0,
  528. state->Data,
  529. state->Address,
  530. state->Size);
  531. if (oldIrql < DISPATCH_LEVEL) {
  532. KeLowerIrql(oldIrql);
  533. }
  534. } else {
  535. //
  536. // Do config space op through HAL
  537. //
  538. bytes = HalGetBusDataByOffset(PCIConfiguration,
  539. state->Bus,
  540. state->Slot.u.AsULONG,
  541. state->Data,
  542. state->Address,
  543. state->Size);
  544. }
  545. break;
  546. case RSACCESS_WRITE:
  547. {
  548. static BOOLEAN ErrorLogged = FALSE;
  549. offset = state->Address;
  550. length = state->Size;
  551. bytesWritten = 0;
  552. //
  553. // Crop any writes down to the regions that are allowed.
  554. //
  555. range = 0;
  556. while (PciOpRegionDisallowedRanges[range][1] != 0) {
  557. if (offset < PciOpRegionDisallowedRanges[range][0]) {
  558. //
  559. // At least part of this write falls below this
  560. // disallowed range. Write all the data up to
  561. // the beggining of the next allowed range.
  562. //
  563. length = MIN(state->Address + state->Size - offset,
  564. PciOpRegionDisallowedRanges[range][0] - offset);
  565. if (interface) {
  566. if (oldIrql < DISPATCH_LEVEL) {
  567. KeRaiseIrql(DISPATCH_LEVEL,
  568. &oldIrql);
  569. }
  570. bytes = interface->SetBusData(interface->Context,
  571. 0,
  572. (PUCHAR)(state->Data + offset - state->Address),
  573. offset,
  574. length);
  575. if (oldIrql < DISPATCH_LEVEL) {
  576. KeLowerIrql(oldIrql);
  577. }
  578. } else {
  579. bytes = HalSetBusDataByOffset(PCIConfiguration,
  580. state->Bus,
  581. state->Slot.u.AsULONG,
  582. (PUCHAR)(state->Data + offset - state->Address),
  583. offset,
  584. length);
  585. }
  586. //
  587. // Keep track of what we wrote.
  588. //
  589. bytesWritten += length;
  590. }
  591. //
  592. // Now advance offset past the end of the disallowed range.
  593. //
  594. offset = MAX(state->Address,
  595. (ULONG)(PciOpRegionDisallowedRanges[range][1] + 1));
  596. if (offset >= state->Address + state->Size) {
  597. //
  598. // The current possible write is beyond the end
  599. // of the requested buffer. So we are done.
  600. //
  601. break;
  602. }
  603. range++;
  604. }
  605. if (bytesWritten == 0) {
  606. if(!ErrorLogged) {
  607. PWCHAR IllegalPCIOpRegionAddress[2];
  608. WCHAR ACPIName[] = L"ACPI";
  609. WCHAR addressBuffer[13];
  610. //
  611. // None of this write was possible. Log the problem.
  612. //
  613. //
  614. // Turn the address into a string
  615. //
  616. swprintf( addressBuffer, L"0x%x", state->Address );
  617. //
  618. // Build the list of arguments to pass to the function that will write the
  619. // error log to the registry
  620. //
  621. IllegalPCIOpRegionAddress[0] = ACPIName;
  622. IllegalPCIOpRegionAddress[1] = addressBuffer;
  623. //
  624. // Log error to event log
  625. //
  626. ACPIWriteEventLogEntry(ACPI_ERR_ILLEGAL_PCIOPREGION_WRITE,
  627. IllegalPCIOpRegionAddress,
  628. 2,
  629. NULL,
  630. 0
  631. );
  632. ErrorLogged = TRUE;
  633. }
  634. #if DBG
  635. Complain = TRUE;
  636. #endif
  637. goto PciConfigSpaceHandlerWorkerExit;
  638. }
  639. bytes = bytesWritten;
  640. break;
  641. }
  642. default:
  643. status = STATUS_NOT_IMPLEMENTED;
  644. }
  645. PciConfigSpaceHandlerWorkerDone:
  646. if (bytes == 0) {
  647. //
  648. // The handler from the HAL or the PCI driver didn't
  649. // succeed for some reason. Fill the buffer with 0xff,
  650. // which is what the AML will expect on failure.
  651. //
  652. RtlFillMemory(state->Data, state->Size, 0xff);
  653. }
  654. PciConfigSpaceHandlerWorkerExit:
  655. if (state->RunCompletion) {
  656. if (state->CompletionHandlerType ==
  657. PCISUPP_COMPLETION_HANDLER_PFNAA) {
  658. simpleCompletion = (PFNAA)state->CompletionHandler;
  659. simpleCompletion(state->CompletionContext);
  660. } else {
  661. lessSimpleCompletion = (PFNACB)state->CompletionHandler;
  662. lessSimpleCompletion(state->PciObj,
  663. status,
  664. NULL,
  665. state->CompletionContext);
  666. }
  667. }
  668. #if DBG
  669. if ((!NT_SUCCESS(status)) || Complain) {
  670. UCHAR opRegion[5] = {0};
  671. UCHAR parent[5] = {0};
  672. RtlCopyMemory(opRegion, ACPIAmliNameObject(state->OpRegion), 4);
  673. if (state->PciObj) {
  674. RtlCopyMemory(parent, ACPIAmliNameObject(state->PciObj), 4);
  675. }
  676. ACPIPrint( (
  677. ACPI_PRINT_WARNING,
  678. "Op Region %s failed (parent PCI device was %s)\n",
  679. opRegion, parent
  680. ) );
  681. }
  682. #endif
  683. ExFreePool(state);
  684. return status;
  685. }
  686. typedef struct {
  687. PNSOBJ PciObject;
  688. PUCHAR Bus;
  689. PPCI_SLOT_NUMBER Slot;
  690. UCHAR ParentBus;
  691. PCI_SLOT_NUMBER ParentSlot;
  692. ULONG Flags;
  693. ULONG Address;
  694. ULONG BaseBusNumber;
  695. LONG RunCompletion;
  696. PFNACB CompletionRoutine;
  697. PVOID CompletionContext;
  698. } GET_ADDRESS_CONTEXT, *PGET_ADDRESS_CONTEXT;
  699. NTSTATUS
  700. GetPciAddress(
  701. IN PNSOBJ PciObj,
  702. IN PFNACB CompletionRoutine,
  703. IN PVOID Context,
  704. IN OUT PUCHAR Bus,
  705. IN OUT PPCI_SLOT_NUMBER Slot
  706. )
  707. /*++
  708. Routine Description:
  709. This routine takes a PNSOBJ that represents a PCI device
  710. and returns the Bus/Slot information for that device.
  711. Arguments:
  712. PciObj - PNSOBJ that represents a PCI device
  713. CompletionRoutine - funtion to call after a STATUS_PENDING
  714. Context - argument to the CompletionRoutine
  715. Bus - pointer to fill in with the bus number
  716. Slot - pointer to fill in with the slot information
  717. Return Value:
  718. Status
  719. Notes:
  720. N.B. This is not guaranteed to produce correct results.
  721. It is intended to be used only when before the PCI
  722. driver takes control of a device. It is a best-effort
  723. function that will almost always work early in the
  724. boot process.
  725. --*/
  726. {
  727. PGET_ADDRESS_CONTEXT state;
  728. ASSERT(CompletionRoutine);
  729. state = ExAllocatePoolWithTag(NonPagedPool, sizeof(GET_ADDRESS_CONTEXT), ACPI_INTERFACE_POOLTAG);
  730. if (!state) {
  731. return STATUS_INSUFFICIENT_RESOURCES;
  732. }
  733. RtlZeroMemory(state, sizeof(GET_ADDRESS_CONTEXT));
  734. state->PciObject = PciObj;
  735. state->CompletionRoutine = CompletionRoutine;
  736. state->CompletionContext = Context;
  737. state->Bus = Bus;
  738. state->Slot = Slot;
  739. state->RunCompletion = INITIAL_RUN_COMPLETION;
  740. return GetPciAddressWorker(PciObj,
  741. STATUS_SUCCESS,
  742. NULL,
  743. (PVOID)state);
  744. }
  745. NTSTATUS
  746. EXPORT
  747. GetPciAddressWorker(
  748. IN PNSOBJ AcpiObject,
  749. IN NTSTATUS Status,
  750. IN POBJDATA Result,
  751. IN PVOID Context
  752. )
  753. {
  754. PIO_RESOURCE_REQUIREMENTS_LIST resources;
  755. PGET_ADDRESS_CONTEXT state;
  756. PPCI_COMMON_CONFIG pciConfig;
  757. NTSTATUS status;
  758. PNSOBJ bus;
  759. PNSOBJ tempObj;
  760. ULONG bytesRead, i;
  761. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  762. ASSERT(Context);
  763. state = (PGET_ADDRESS_CONTEXT)Context;
  764. status = Status;
  765. //
  766. // Entering this function twice with the same state
  767. // means that we need to run the completion routine.
  768. //
  769. InterlockedIncrement(&state->RunCompletion);
  770. //
  771. // If Status isn't success, then one of the worker
  772. // functions we called puked. Bail.
  773. //
  774. if (!NT_SUCCESS(Status)) {
  775. goto GetPciAddressWorkerExit;
  776. }
  777. //
  778. // First, determine the slot number.
  779. //
  780. if (!(state->Flags & PCISUPP_CHECKED_ADR)) {
  781. //
  782. // Get the _ADR.
  783. //
  784. state->Flags |= PCISUPP_CHECKED_ADR;
  785. status = ACPIGetNSAddressAsync(
  786. state->PciObject,
  787. GetPciAddressWorker,
  788. (PVOID)state,
  789. &(state->Address),
  790. NULL
  791. );
  792. if (status == STATUS_PENDING) {
  793. return status;
  794. }
  795. if (!NT_SUCCESS(status)) {
  796. goto GetPciAddressWorkerExit;
  797. }
  798. }
  799. if (!(state->Flags & PCISUPP_GOT_SLOT_INFO)) {
  800. //
  801. // Build a PCI_SLOT_NUMBER out of the integer returned
  802. // from the interpretter.
  803. //
  804. state->Slot->u.bits.FunctionNumber = (state->Address) & 0x7;
  805. state->Slot->u.bits.DeviceNumber = ( (state->Address) >> 16) & 0x1f;
  806. state->Flags |= PCISUPP_GOT_SLOT_INFO;
  807. }
  808. //
  809. // Next, get the bus number, if possible.
  810. //
  811. *state->Bus = 0; // default value, in case we have to guess
  812. //
  813. // Check first to see if this bus has a _HID.
  814. // (It might be a root PCI bridge.)
  815. //
  816. bus = state->PciObject;
  817. tempObj = ACPIAmliGetNamedChild(bus, PACKED_HID);
  818. if (!tempObj) {
  819. //
  820. // This device had no _HID. So look up
  821. // to the parent and see if it is a
  822. // root PCI bridge.
  823. //
  824. bus = state->PciObject->pnsParent;
  825. tempObj = ACPIAmliGetNamedChild(bus, PACKED_HID);
  826. }
  827. if (!tempObj) {
  828. //
  829. // This PCI device is on a PCI bus that
  830. // is created by a PCI-PCI bridge.
  831. //
  832. if (!(state->Flags & PCISUPP_CHECKED_PARENT)) {
  833. state->Flags |= PCISUPP_CHECKED_PARENT;
  834. status = GetPciAddress(
  835. bus,
  836. GetPciAddressWorker,
  837. (PVOID)state,
  838. &state->ParentBus,
  839. &state->ParentSlot
  840. );
  841. if (status == STATUS_PENDING) {
  842. return status;
  843. }
  844. if (!NT_SUCCESS(status)) {
  845. goto GetPciAddressWorkerExit;
  846. }
  847. }
  848. //
  849. // Read the config space for this device.
  850. //
  851. bytesRead = HalGetBusDataByOffset(PCIConfiguration,
  852. state->ParentBus,
  853. state->ParentSlot.u.AsULONG,
  854. buffer,
  855. 0,
  856. PCI_COMMON_HDR_LENGTH);
  857. if (bytesRead == 0) {
  858. //
  859. // Make a guess that the bus number was 0.
  860. //
  861. status = STATUS_SUCCESS;
  862. goto GetPciAddressWorkerExit;
  863. }
  864. pciConfig = (PPCI_COMMON_CONFIG)buffer;
  865. if (pciConfig->HeaderType != PCI_BRIDGE_TYPE) {
  866. //
  867. // Make a guess that the bus number was 0.
  868. //
  869. status = STATUS_SUCCESS;
  870. goto GetPciAddressWorkerExit;
  871. }
  872. //
  873. // Success. Record the actual bus number of
  874. // the secondary PCI bus and exit.
  875. //
  876. *state->Bus = pciConfig->u.type1.SecondaryBus;
  877. status = STATUS_SUCCESS;
  878. goto GetPciAddressWorkerExit;
  879. }
  880. //
  881. // Is there a _BBN to run?
  882. //
  883. tempObj = ACPIAmliGetNamedChild(bus, PACKED_BBN);
  884. if (tempObj) {
  885. //
  886. // This device must be the child of a root PCI bus.
  887. //
  888. if (!(state->Flags & PCISUPP_CHECKED_BBN)) {
  889. state->Flags |= PCISUPP_CHECKED_BBN;
  890. status = ACPIGetNSIntegerAsync(
  891. bus,
  892. PACKED_BBN,
  893. GetPciAddressWorker,
  894. (PVOID)state,
  895. &(state->BaseBusNumber),
  896. NULL
  897. );
  898. if (status == STATUS_PENDING) {
  899. return(status);
  900. }
  901. if (!NT_SUCCESS(status)) {
  902. goto GetPciAddressWorkerExit;
  903. }
  904. }
  905. //
  906. // At this point, we must have a Boot Bus Number. This is the correct
  907. // number for this bus
  908. //
  909. ASSERT( state->BaseBusNumber <= 0xFF );
  910. *(state->Bus) = (UCHAR) (state->BaseBusNumber);
  911. //
  912. // HACKHACK. The ACPI HAL doesn't really know much about busses. But
  913. // it needs to maintain legacy HAL behavior. And to do that, it needs to
  914. // know how many PCI busses are in the system. Since we just looked at
  915. // a root PCI bus, we now give the HAL a heads-up that this bus exists.
  916. //
  917. HalSetMaxLegacyPciBusNumber(state->BaseBusNumber);
  918. status = STATUS_SUCCESS;
  919. } else {
  920. //
  921. // There is a no _BBN, so the bus number MUST be Zero
  922. //
  923. *(state->Bus) = 0;
  924. status = STATUS_SUCCESS;
  925. }
  926. GetPciAddressWorkerExit:
  927. if (state->RunCompletion) {
  928. state->CompletionRoutine(AcpiObject,
  929. status,
  930. NULL,
  931. state->CompletionContext);
  932. }
  933. ExFreePool(state);
  934. return status;
  935. }
  936. typedef struct {
  937. PNSOBJ AcpiObject;
  938. ULONG Flags;
  939. ULONG Adr;
  940. PUCHAR Hid;
  941. PUCHAR Cid;
  942. BOOLEAN IsPciDeviceResult;
  943. LONG RunCompletion;
  944. PFNACB CompletionHandler;
  945. PVOID CompletionContext;
  946. BOOLEAN *Result;
  947. } IS_PCI_DEVICE_STATE, *PIS_PCI_DEVICE_STATE;
  948. NTSTATUS
  949. IsPciDevice(
  950. IN PNSOBJ AcpiObject,
  951. IN PFNACB CompletionHandler,
  952. IN PVOID CompletionContext,
  953. OUT BOOLEAN *Result
  954. )
  955. /*++
  956. Routine Description:
  957. This checks to see if the PNSOBJ is a PCI device.
  958. Arguments:
  959. AcpiObject - the object to be checked
  960. Result - pointer to a boolean for the result
  961. Return Value:
  962. Status
  963. Notes:
  964. --*/
  965. {
  966. PIS_PCI_DEVICE_STATE state;
  967. NTSTATUS status;
  968. state = ExAllocatePoolWithTag(NonPagedPool, sizeof(IS_PCI_DEVICE_STATE), ACPI_INTERFACE_POOLTAG);
  969. if (!state) {
  970. return STATUS_INSUFFICIENT_RESOURCES;
  971. }
  972. RtlZeroMemory(state, sizeof(IS_PCI_DEVICE_STATE));
  973. state->AcpiObject = AcpiObject;
  974. state->CompletionHandler = CompletionHandler;
  975. state->CompletionContext = CompletionContext;
  976. state->Result = Result;
  977. state->RunCompletion = INITIAL_RUN_COMPLETION;
  978. return IsPciDeviceWorker(AcpiObject,
  979. STATUS_SUCCESS,
  980. NULL,
  981. (PVOID)state);
  982. }
  983. NTSTATUS
  984. EXPORT
  985. IsPciDeviceWorker(
  986. IN PNSOBJ AcpiObject,
  987. IN NTSTATUS Status,
  988. IN POBJDATA Result,
  989. IN PVOID Context
  990. )
  991. /*++
  992. Routine Description:
  993. This is the worker function for determining whether
  994. or not a namespace object represents a PCI device.
  995. The algorithm is as follows:
  996. 1) Does this device have a _HID of PNP0A03? If
  997. so, it is a PCI device.
  998. 2) Does this device have a _CID of PNP0A03? If
  999. so, it is a PCI device.
  1000. 3) Does this device have an _ADR?
  1001. a) No, not a PCI device.
  1002. b) Yes, check to see if the parent qualifies
  1003. as a PCI device. If it does, this must
  1004. also be a PCI device. If not, then it is not.
  1005. Arguments:
  1006. AcpiObject - the object most recently under scrutiny
  1007. Status - current status
  1008. Result - OBJDATA structure necessary for worker functions
  1009. Context - pointer to the context structure
  1010. Return Value:
  1011. Status
  1012. Notes:
  1013. This function is re-entrant. It may block at any time and
  1014. return. All state is in the Context structure.
  1015. --*/
  1016. {
  1017. PIS_PCI_DEVICE_STATE state;
  1018. NTSTATUS status;
  1019. PNSOBJ hidObj;
  1020. PNSOBJ cidObj;
  1021. state = (PIS_PCI_DEVICE_STATE)Context;
  1022. status = Status;
  1023. //
  1024. // Entering this function twice with the same state
  1025. // means that we need to run the completion routine.
  1026. //
  1027. InterlockedIncrement(&state->RunCompletion);
  1028. //
  1029. // If Status isn't success, then one of the worker
  1030. // functions we called puked. Bail.
  1031. //
  1032. if (!NT_SUCCESS(status)) {
  1033. *state->Result = FALSE;
  1034. goto IsPciDeviceExit;
  1035. }
  1036. //
  1037. // Step 0), check to see if this is actually a "device" type
  1038. // namespace object.
  1039. //
  1040. if (NSGETOBJTYPE(state->AcpiObject) != OBJTYPE_DEVICE) {
  1041. *state->Result = FALSE;
  1042. goto IsPciDeviceExit;
  1043. }
  1044. //
  1045. // Step 1), check the _HID.
  1046. //
  1047. if (!(state->Flags & PCISUPP_CHECKED_HID)) {
  1048. state->Flags |= PCISUPP_CHECKED_HID;
  1049. state->Hid = NULL;
  1050. hidObj = ACPIAmliGetNamedChild( state->AcpiObject, PACKED_HID );
  1051. if (hidObj) {
  1052. status = ACPIGetNSPnpIDAsync(
  1053. state->AcpiObject,
  1054. IsPciDeviceWorker,
  1055. (PVOID)state,
  1056. &state->Hid,
  1057. NULL);
  1058. if (status == STATUS_PENDING) {
  1059. return status;
  1060. }
  1061. if (!NT_SUCCESS(status)) {
  1062. *state->Result = FALSE;
  1063. goto IsPciDeviceExit;
  1064. }
  1065. }
  1066. }
  1067. if (state->Hid) {
  1068. if (strstr(state->Hid, PCI_PNP_ID)) {
  1069. //
  1070. // Was PCI.
  1071. //
  1072. *state->Result = TRUE;
  1073. goto IsPciDeviceExit;
  1074. }
  1075. ExFreePool(state->Hid);
  1076. state->Hid = NULL;
  1077. }
  1078. //
  1079. // Step 2), check the _CID.
  1080. //
  1081. if (!(state->Flags & PCISUPP_CHECKED_CID)) {
  1082. state->Flags |= PCISUPP_CHECKED_CID;
  1083. state->Cid = NULL;
  1084. cidObj = ACPIAmliGetNamedChild( state->AcpiObject, PACKED_CID );
  1085. if (cidObj) {
  1086. status = ACPIGetNSCompatibleIDAsync(
  1087. state->AcpiObject,
  1088. IsPciDeviceWorker,
  1089. (PVOID)state,
  1090. &state->Cid,
  1091. NULL);
  1092. if (status == STATUS_PENDING) {
  1093. return status;
  1094. }
  1095. if (!NT_SUCCESS(status)) {
  1096. *state->Result = FALSE;
  1097. goto IsPciDeviceExit;
  1098. }
  1099. }
  1100. }
  1101. if (state->Cid) {
  1102. if (strstr(state->Cid, PCI_PNP_ID)) {
  1103. //
  1104. // Was PCI.
  1105. //
  1106. *state->Result = TRUE;
  1107. goto IsPciDeviceExit;
  1108. }
  1109. ExFreePool(state->Cid);
  1110. state->Cid = NULL;
  1111. }
  1112. //
  1113. // Step 3), check the _ADR.
  1114. //
  1115. if (!(state->Flags & PCISUPP_CHECKED_ADR)) {
  1116. state->Flags |= PCISUPP_CHECKED_ADR;
  1117. status = ACPIGetNSAddressAsync(
  1118. state->AcpiObject,
  1119. IsPciDeviceWorker,
  1120. (PVOID)state,
  1121. &(state->Adr),
  1122. NULL);
  1123. if (status == STATUS_PENDING) {
  1124. return status;
  1125. }
  1126. if (!NT_SUCCESS(status)) {
  1127. *state->Result = FALSE;
  1128. goto IsPciDeviceExit;
  1129. }
  1130. }
  1131. //
  1132. // If we got here, it has an _ADR. Check to see if the
  1133. // parent device is a PCI device.
  1134. //
  1135. if (!(state->Flags & PCISUPP_CHECKED_PARENT)) {
  1136. state->Flags |= PCISUPP_CHECKED_PARENT;
  1137. state->IsPciDeviceResult = FALSE;
  1138. status = IsPciDevice(state->AcpiObject->pnsParent,
  1139. IsPciDeviceWorker,
  1140. (PVOID)state,
  1141. &state->IsPciDeviceResult);
  1142. if (status == STATUS_PENDING) {
  1143. return status;
  1144. }
  1145. if (!NT_SUCCESS(status)) {
  1146. *state->Result = FALSE;
  1147. goto IsPciDeviceExit;
  1148. }
  1149. }
  1150. //
  1151. // Fall through to the result. If the parent was a PCI
  1152. // device, IsPciDeviceResult will now be TRUE.
  1153. //
  1154. IsPciDeviceExit:
  1155. if (state->IsPciDeviceResult) {
  1156. //
  1157. // Record the result.
  1158. //
  1159. *state->Result = state->IsPciDeviceResult;
  1160. }
  1161. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1162. status = STATUS_SUCCESS;
  1163. }
  1164. if (state->RunCompletion) {
  1165. state->CompletionHandler(state->AcpiObject,
  1166. status,
  1167. NULL,
  1168. state->CompletionContext);
  1169. }
  1170. if (state->Hid) ExFreePool(state->Hid);
  1171. if (state->Cid) ExFreePool(state->Cid);
  1172. ExFreePool(state);
  1173. return status;
  1174. }
  1175. typedef struct {
  1176. PNSOBJ AcpiObject;
  1177. ULONG Flags;
  1178. PUCHAR Hid;
  1179. PUCHAR Cid;
  1180. ULONG Adr;
  1181. BOOLEAN IsPciDevice;
  1182. LONG RunCompletion;
  1183. PFNACB CompletionHandler;
  1184. PVOID CompletionContext;
  1185. BOOLEAN *Result;
  1186. UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
  1187. } IS_PCI_BUS_STATE, *PIS_PCI_BUS_STATE;
  1188. NTSTATUS
  1189. IsPciBusAsync(
  1190. IN PNSOBJ AcpiObject,
  1191. IN PFNACB CompletionHandler,
  1192. IN PVOID CompletionContext,
  1193. OUT BOOLEAN *Result
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. This checks to see if the PNSOBJ represents a PCI bus.
  1198. Arguments:
  1199. AcpiObject - the object to be checked
  1200. Result - pointer to a boolean for the result
  1201. Return Value:
  1202. Status
  1203. Notes:
  1204. The PNSOBJ may also be a PCI device, in which case
  1205. it is a PCI to PCI bridge.
  1206. --*/
  1207. {
  1208. PIS_PCI_BUS_STATE state;
  1209. state = ExAllocatePoolWithTag(NonPagedPool, sizeof(IS_PCI_BUS_STATE), ACPI_INTERFACE_POOLTAG);
  1210. if (!state) {
  1211. return STATUS_INSUFFICIENT_RESOURCES;
  1212. }
  1213. RtlZeroMemory(state, sizeof(IS_PCI_BUS_STATE));
  1214. state->AcpiObject = AcpiObject;
  1215. state->CompletionHandler = CompletionHandler;
  1216. state->CompletionContext = CompletionContext;
  1217. state->Result = Result;
  1218. state->RunCompletion = INITIAL_RUN_COMPLETION;
  1219. *Result = FALSE;
  1220. return IsPciBusAsyncWorker(AcpiObject,
  1221. STATUS_SUCCESS,
  1222. NULL,
  1223. (PVOID)state);
  1224. }
  1225. NTSTATUS
  1226. EXPORT
  1227. IsPciBusAsyncWorker(
  1228. IN PNSOBJ AcpiObject,
  1229. IN NTSTATUS Status,
  1230. IN POBJDATA Result,
  1231. IN PVOID Context
  1232. )
  1233. {
  1234. PIS_PCI_BUS_STATE state;
  1235. PNSOBJ hidObj;
  1236. PNSOBJ cidObj;
  1237. PPCI_COMMON_CONFIG pciData;
  1238. NTSTATUS status;
  1239. ASSERT(Context);
  1240. state = (PIS_PCI_BUS_STATE)Context;
  1241. status = Status;
  1242. //
  1243. // Entering this function twice with the same state
  1244. // means that we need to run the completion routine.
  1245. //
  1246. InterlockedIncrement(&state->RunCompletion);
  1247. //
  1248. // Definitely not a PCI bus...
  1249. //
  1250. if (state->AcpiObject == NULL) {
  1251. *state->Result = FALSE;
  1252. goto IsPciBusAsyncExit;
  1253. }
  1254. //
  1255. // If Status isn't success, then one of the worker
  1256. // functions we called puked. Bail.
  1257. //
  1258. if (!NT_SUCCESS(status)) {
  1259. *state->Result = FALSE;
  1260. goto IsPciBusAsyncExit;
  1261. }
  1262. if (!(state->Flags & PCISUPP_CHECKED_HID)) {
  1263. state->Flags |= PCISUPP_CHECKED_HID;
  1264. state->Hid = NULL;
  1265. //
  1266. // Is there an _HID?
  1267. //
  1268. hidObj = ACPIAmliGetNamedChild( state->AcpiObject, PACKED_HID );
  1269. if (hidObj) {
  1270. status = ACPIGetNSPnpIDAsync(
  1271. state->AcpiObject,
  1272. IsPciBusAsyncWorker,
  1273. (PVOID)state,
  1274. &(state->Hid),
  1275. NULL);
  1276. if (status == STATUS_PENDING) {
  1277. return status;
  1278. }
  1279. if (!NT_SUCCESS(status)) {
  1280. *state->Result = FALSE;
  1281. goto IsPciBusAsyncExit;
  1282. }
  1283. }
  1284. }
  1285. if (state->Hid) {
  1286. if (strstr(state->Hid, PCI_PNP_ID)) {
  1287. //
  1288. // Was PCI.
  1289. //
  1290. *state->Result = TRUE;
  1291. goto IsPciBusAsyncExit;
  1292. }
  1293. ExFreePool(state->Hid);
  1294. state->Hid = NULL;
  1295. }
  1296. if (!(state->Flags & PCISUPP_CHECKED_CID)) {
  1297. state->Flags |= PCISUPP_CHECKED_CID;
  1298. state->Cid = NULL;
  1299. //
  1300. // Is there a _CID?
  1301. //
  1302. cidObj = ACPIAmliGetNamedChild( state->AcpiObject, PACKED_CID );
  1303. if (cidObj) {
  1304. status = ACPIGetNSCompatibleIDAsync(
  1305. state->AcpiObject,
  1306. IsPciBusAsyncWorker,
  1307. (PVOID)state,
  1308. &(state->Cid),
  1309. NULL);
  1310. if (status == STATUS_PENDING) {
  1311. return status;
  1312. }
  1313. if (!NT_SUCCESS(status)) {
  1314. *state->Result = FALSE;
  1315. goto IsPciBusAsyncExit;
  1316. }
  1317. }
  1318. }
  1319. if (state->Cid) {
  1320. if (strstr(state->Cid, PCI_PNP_ID)) {
  1321. //
  1322. // Was PCI.
  1323. //
  1324. *state->Result = TRUE;
  1325. goto IsPciBusAsyncExit;
  1326. }
  1327. ExFreePool(state->Cid);
  1328. state->Cid = NULL;
  1329. }
  1330. if (!(state->Flags & PCISUPP_CHECKED_PCI_DEVICE)) {
  1331. state->Flags |= PCISUPP_CHECKED_PCI_DEVICE;
  1332. status = IsPciDevice(state->AcpiObject,
  1333. IsPciBusAsyncWorker,
  1334. (PVOID)state,
  1335. &state->IsPciDevice);
  1336. if (status == STATUS_PENDING) {
  1337. return status;
  1338. }
  1339. if (!NT_SUCCESS(status)) {
  1340. *state->Result = FALSE;
  1341. goto IsPciBusAsyncExit;
  1342. }
  1343. }
  1344. if (state->IsPciDevice) {
  1345. if (!(state->Flags & PCISUPP_CHECKED_ADR)) {
  1346. state->Flags |= PCISUPP_CHECKED_ADR;
  1347. status = ACPIGetNSAddressAsync(
  1348. state->AcpiObject,
  1349. IsPciBusAsyncWorker,
  1350. (PVOID)state,
  1351. &(state->Adr),
  1352. NULL
  1353. );
  1354. if (status == STATUS_PENDING) {
  1355. return status;
  1356. }
  1357. if (!NT_SUCCESS(status)) {
  1358. *state->Result = FALSE;
  1359. goto IsPciBusAsyncExit;
  1360. }
  1361. }
  1362. if (!(state->Flags & PCISUPP_CHECKED_PCI_BRIDGE)) {
  1363. //
  1364. // Now read PCI config space to see if this is a bridge.
  1365. //
  1366. state->Flags |= PCISUPP_CHECKED_PCI_BRIDGE;
  1367. status = PciConfigInternal(RSACCESS_READ,
  1368. state->AcpiObject,
  1369. 0,
  1370. PCI_COMMON_HDR_LENGTH,
  1371. IsPciBusAsyncWorker,
  1372. (PVOID)state,
  1373. state->Buffer);
  1374. if (status == STATUS_PENDING) {
  1375. return status;
  1376. }
  1377. if (!NT_SUCCESS(status)) {
  1378. *state->Result = FALSE;
  1379. goto IsPciBusAsyncExit;
  1380. }
  1381. }
  1382. pciData = (PPCI_COMMON_CONFIG)state->Buffer;
  1383. if ((PCI_CONFIGURATION_TYPE(pciData) == PCI_BRIDGE_TYPE) ||
  1384. (PCI_CONFIGURATION_TYPE(pciData) == PCI_CARDBUS_BRIDGE_TYPE)) {
  1385. *state->Result = TRUE;
  1386. } else {
  1387. *state->Result = FALSE;
  1388. }
  1389. }
  1390. IsPciBusAsyncExit:
  1391. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1392. status = STATUS_SUCCESS;
  1393. }
  1394. if (state->RunCompletion) {
  1395. state->CompletionHandler(state->AcpiObject,
  1396. status,
  1397. NULL,
  1398. state->CompletionContext);
  1399. }
  1400. if (state->Hid) ExFreePool(state->Hid);
  1401. if (state->Cid) ExFreePool(state->Cid);
  1402. ExFreePool(state);
  1403. return status;
  1404. }
  1405. BOOLEAN
  1406. IsPciBus(
  1407. IN PDEVICE_OBJECT DeviceObject
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This checks to see if the DeviceObject represents a PCI bus.
  1412. Arguments:
  1413. AcpiObject - the object to be checked
  1414. Result - pointer to a boolean for the result
  1415. Return Value:
  1416. Status
  1417. Notes:
  1418. --*/
  1419. {
  1420. AMLISUPP_CONTEXT_PASSIVE getDataContext;
  1421. PDEVICE_EXTENSION devExt = ACPIInternalGetDeviceExtension(DeviceObject);
  1422. NTSTATUS status;
  1423. BOOLEAN result = FALSE;
  1424. PAGED_CODE();
  1425. ASSERT(devExt->Signature == ACPI_SIGNATURE);
  1426. KeInitializeEvent(&getDataContext.Event, SynchronizationEvent, FALSE);
  1427. getDataContext.Status = STATUS_NOT_FOUND;
  1428. if (!(devExt->Flags & DEV_PROP_NO_OBJECT) ) {
  1429. status = IsPciBusAsync( devExt->AcpiObject,
  1430. AmlisuppCompletePassive,
  1431. (PVOID)&getDataContext,
  1432. &result );
  1433. if (status == STATUS_PENDING) {
  1434. KeWaitForSingleObject(&getDataContext.Event,
  1435. Executive,
  1436. KernelMode,
  1437. FALSE,
  1438. NULL);
  1439. }
  1440. }
  1441. return result;
  1442. }
  1443. BOOLEAN
  1444. IsPciBusExtension(
  1445. IN PDEVICE_EXTENSION DeviceExtension
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. This checks to see if the DeviceExtension represents a PCI bus.
  1450. Arguments:
  1451. AcpiObject - the object to be checked
  1452. Result - pointer to a boolean for the result
  1453. Return Value:
  1454. Status
  1455. Notes:
  1456. --*/
  1457. {
  1458. AMLISUPP_CONTEXT_PASSIVE getDataContext;
  1459. NTSTATUS status;
  1460. BOOLEAN result = FALSE;
  1461. PAGED_CODE();
  1462. ASSERT(DeviceExtension->Signature == ACPI_SIGNATURE);
  1463. KeInitializeEvent(&getDataContext.Event, SynchronizationEvent, FALSE);
  1464. getDataContext.Status = STATUS_NOT_FOUND;
  1465. if ( (DeviceExtension->Flags & DEV_PROP_NO_OBJECT) ) {
  1466. return result;
  1467. }
  1468. status = IsPciBusAsync(
  1469. DeviceExtension->AcpiObject,
  1470. AmlisuppCompletePassive,
  1471. (PVOID)&getDataContext,
  1472. &result
  1473. );
  1474. if (status == STATUS_PENDING) {
  1475. KeWaitForSingleObject(
  1476. &getDataContext.Event,
  1477. Executive,
  1478. KernelMode,
  1479. FALSE,
  1480. NULL
  1481. );
  1482. }
  1483. return result;
  1484. }
  1485. BOOLEAN
  1486. IsNsobjPciBus(
  1487. IN PNSOBJ Device
  1488. )
  1489. /*++
  1490. Routine Description:
  1491. This checks to see if the DeviceObject represents a PCI bus.
  1492. Arguments:
  1493. AcpiObject - the object to be checked
  1494. Result - pointer to a boolean for the result
  1495. Return Value:
  1496. Status
  1497. Notes:
  1498. --*/
  1499. {
  1500. AMLISUPP_CONTEXT_PASSIVE getDataContext;
  1501. NTSTATUS status;
  1502. BOOLEAN result = FALSE;
  1503. PAGED_CODE();
  1504. KeInitializeEvent(&getDataContext.Event, SynchronizationEvent, FALSE);
  1505. getDataContext.Status = STATUS_NOT_FOUND;
  1506. status = IsPciBusAsync( Device,
  1507. AmlisuppCompletePassive,
  1508. (PVOID)&getDataContext,
  1509. &result );
  1510. if (status == STATUS_PENDING) {
  1511. KeWaitForSingleObject(&getDataContext.Event,
  1512. Executive,
  1513. KernelMode,
  1514. FALSE,
  1515. NULL);
  1516. status = getDataContext.Status;
  1517. }
  1518. return result;
  1519. }
  1520. typedef struct {
  1521. PNSOBJ OpRegion;
  1522. PNSOBJ Parent;
  1523. ULONG Flags;
  1524. BOOLEAN IsPciDeviceResult;
  1525. LONG RunCompletion;
  1526. PFNACB CompletionHandler;
  1527. PVOID CompletionContext;
  1528. PNSOBJ *PciObj;
  1529. } OP_REGION_SCOPE_STATE, *POP_REGION_SCOPE_STATE;
  1530. NTSTATUS
  1531. GetOpRegionScope(
  1532. IN PNSOBJ OpRegion,
  1533. IN PFNACB CompletionHandler,
  1534. IN PVOID CompletionContext,
  1535. OUT PNSOBJ *PciObj
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. This routine takes a pointer to an OpRegion and
  1540. returns a pointer to the PCI device that it operates
  1541. on.
  1542. Arguments:
  1543. OpRegion - the operational region
  1544. PciObj - the object the region operates on
  1545. Return Value:
  1546. Status
  1547. Notes:
  1548. --*/
  1549. {
  1550. POP_REGION_SCOPE_STATE state;
  1551. state = ExAllocatePoolWithTag(NonPagedPool, sizeof(OP_REGION_SCOPE_STATE), ACPI_INTERFACE_POOLTAG);
  1552. if (!state) {
  1553. return STATUS_INSUFFICIENT_RESOURCES;
  1554. }
  1555. RtlZeroMemory(state, sizeof(OP_REGION_SCOPE_STATE));
  1556. state->OpRegion = OpRegion;
  1557. state->Parent = OpRegion->pnsParent;
  1558. state->CompletionHandler = CompletionHandler;
  1559. state->CompletionContext = CompletionContext;
  1560. state->PciObj = PciObj;
  1561. state->RunCompletion = INITIAL_RUN_COMPLETION;
  1562. return GetOpRegionScopeWorker(OpRegion,
  1563. STATUS_SUCCESS,
  1564. NULL,
  1565. (PVOID)state);
  1566. }
  1567. NTSTATUS
  1568. EXPORT
  1569. GetOpRegionScopeWorker(
  1570. IN PNSOBJ AcpiObject,
  1571. IN NTSTATUS Status,
  1572. IN POBJDATA Result,
  1573. IN PVOID Context
  1574. )
  1575. {
  1576. POP_REGION_SCOPE_STATE state;
  1577. NTSTATUS status;
  1578. BOOLEAN found = FALSE;
  1579. ASSERT(Context);
  1580. state = (POP_REGION_SCOPE_STATE)Context;
  1581. status = Status;
  1582. //
  1583. // Entering this function twice with the same state
  1584. // means that we need to run the completion routine.
  1585. //
  1586. InterlockedIncrement(&state->RunCompletion);
  1587. if (!NT_SUCCESS(Status)) {
  1588. goto GetOpRegionScopeWorkerExit;
  1589. }
  1590. //
  1591. // Need to find the PNSOBJ for the PCI device. Do it by
  1592. // looking up the tree.
  1593. //
  1594. while ((state->Parent != NULL) &&
  1595. (state->Parent->pnsParent != state->Parent)) {
  1596. if ( !(state->Flags & PCISUPP_COMPLETING_IS_PCI) ) {
  1597. state->Flags |= PCISUPP_COMPLETING_IS_PCI;
  1598. status = IsPciDevice(state->Parent,
  1599. GetOpRegionScopeWorker,
  1600. (PVOID)state,
  1601. &state->IsPciDeviceResult);
  1602. if (status == STATUS_PENDING) {
  1603. return status;
  1604. }
  1605. if (!NT_SUCCESS(status)) {
  1606. goto GetOpRegionScopeWorkerExit;
  1607. }
  1608. }
  1609. state->Flags &= ~PCISUPP_COMPLETING_IS_PCI;
  1610. if (state->IsPciDeviceResult) {
  1611. found = TRUE;
  1612. break;
  1613. }
  1614. //
  1615. // Look one step higher.
  1616. //
  1617. state->Parent = state->Parent->pnsParent;
  1618. }
  1619. if (found) {
  1620. *state->PciObj = state->Parent;
  1621. status = STATUS_SUCCESS;
  1622. } else {
  1623. status = STATUS_NOT_FOUND;
  1624. }
  1625. GetOpRegionScopeWorkerExit:
  1626. if (state->RunCompletion) {
  1627. state->CompletionHandler(state->OpRegion,
  1628. status,
  1629. NULL,
  1630. state->CompletionContext);
  1631. }
  1632. ExFreePool(state);
  1633. return status;
  1634. }
  1635. NTSTATUS
  1636. EnableDisableRegions(
  1637. IN PNSOBJ NameSpaceObj,
  1638. IN BOOLEAN Enable
  1639. )
  1640. /*++
  1641. Routine Description:
  1642. This routine runs the _REG method for all PCI op-regions
  1643. underneath NameSpaceObj and all its children, except
  1644. additional PCI to PCI bridges.
  1645. Arguments:
  1646. NameSpaceObj - A device in the namespace
  1647. Enable - boolean specifying whether this function should
  1648. enable or disable the regions
  1649. Return Value:
  1650. Status
  1651. Notes:
  1652. --*/
  1653. #define CONNECT_HANDLER 1
  1654. #define DISCONNECT_HANDLER 0
  1655. {
  1656. PNSOBJ sibling;
  1657. PNSOBJ regMethod = NULL;
  1658. OBJDATA objdata[2];
  1659. NTSTATUS status, returnStatus;
  1660. PAGED_CODE();
  1661. ASSERT(NameSpaceObj->dwNameSeg);
  1662. //
  1663. // Find a _REG that is a child of this device.
  1664. //
  1665. regMethod = ACPIAmliGetNamedChild( NameSpaceObj, PACKED_REG );
  1666. if (regMethod != NULL) {
  1667. //
  1668. // Construct arguments for _REG method.
  1669. //
  1670. RtlZeroMemory(objdata, sizeof(objdata));
  1671. objdata[0].dwDataType = OBJTYPE_INTDATA;
  1672. objdata[0].uipDataValue = REGSPACE_PCICFG;
  1673. objdata[1].dwDataType = OBJTYPE_INTDATA;
  1674. objdata[1].uipDataValue = (Enable ? CONNECT_HANDLER : DISCONNECT_HANDLER );
  1675. status = AMLIEvalNameSpaceObject(
  1676. regMethod,
  1677. NULL,
  1678. 2,
  1679. objdata
  1680. );
  1681. }
  1682. //
  1683. // Recurse to all of the children. Propagate any errors,
  1684. // but don't stop for them.
  1685. //
  1686. returnStatus = STATUS_SUCCESS;
  1687. sibling = NSGETFIRSTCHILD(NameSpaceObj);
  1688. if (!sibling) {
  1689. return returnStatus;
  1690. }
  1691. do {
  1692. switch (NSGETOBJTYPE(sibling)) {
  1693. case OBJTYPE_DEVICE:
  1694. if (IsNsobjPciBus(sibling)) {
  1695. //
  1696. // Don't recurse past a child PCI to PCI bridge.
  1697. //
  1698. break;
  1699. }
  1700. status = EnableDisableRegions(sibling, Enable);
  1701. if (!NT_SUCCESS(status)) {
  1702. returnStatus = status;
  1703. }
  1704. break;
  1705. default:
  1706. break;
  1707. }
  1708. } while (sibling = NSGETNEXTSIBLING(sibling));
  1709. return returnStatus;
  1710. }
  1711. UCHAR
  1712. GetBusNumberFromCRS(
  1713. IN PDEVICE_EXTENSION DeviceExtension,
  1714. IN PUCHAR CRS
  1715. )
  1716. /*++
  1717. Routine Description:
  1718. Grovels through the _CRS buffer looking for an address
  1719. descriptor for the bus number
  1720. Arguments:
  1721. DeviceExtension - Pointer to the PCI root bus
  1722. CRS - Supplies the CRS.
  1723. Return Value:
  1724. NTSTATUS
  1725. --*/
  1726. {
  1727. PPNP_DWORD_ADDRESS_DESCRIPTOR DwordAddress;
  1728. PPNP_QWORD_ADDRESS_DESCRIPTOR QwordAddress;
  1729. PPNP_WORD_ADDRESS_DESCRIPTOR WordAddress;
  1730. PUCHAR Current;
  1731. UCHAR TagName;
  1732. USHORT Increment;
  1733. Current = CRS;
  1734. while ( *Current ) {
  1735. TagName = *Current;
  1736. if ( !(TagName & LARGE_RESOURCE_TAG)) {
  1737. Increment = (USHORT) (TagName & SMALL_TAG_SIZE_MASK) + 1;
  1738. TagName &= SMALL_TAG_MASK;
  1739. } else {
  1740. Increment = ( *(USHORT UNALIGNED *)(Current + 1) ) + 3;
  1741. }
  1742. if (TagName == TAG_END) {
  1743. break;
  1744. }
  1745. switch(TagName) {
  1746. case TAG_DOUBLE_ADDRESS:
  1747. DwordAddress = (PPNP_DWORD_ADDRESS_DESCRIPTOR) Current;
  1748. if (DwordAddress->RFlag == PNP_ADDRESS_BUS_NUMBER_TYPE) {
  1749. ASSERT(DwordAddress->MinimumAddress <= 0xFF);
  1750. return (UCHAR) DwordAddress->MinimumAddress;
  1751. }
  1752. break;
  1753. case TAG_QUAD_ADDRESS:
  1754. QwordAddress = (PPNP_QWORD_ADDRESS_DESCRIPTOR) Current;
  1755. if (QwordAddress->RFlag == PNP_ADDRESS_BUS_NUMBER_TYPE) {
  1756. ASSERT(QwordAddress->MinimumAddress <= 0xFF);
  1757. return (UCHAR) QwordAddress->MinimumAddress;
  1758. }
  1759. break;
  1760. case TAG_WORD_ADDRESS:
  1761. WordAddress = (PPNP_WORD_ADDRESS_DESCRIPTOR) Current;
  1762. if (WordAddress->RFlag == PNP_ADDRESS_BUS_NUMBER_TYPE) {
  1763. ASSERT(WordAddress->MinimumAddress <= 0xFF);
  1764. return (UCHAR) WordAddress->MinimumAddress;
  1765. }
  1766. break;
  1767. }
  1768. Current += Increment;
  1769. }
  1770. //
  1771. // No Bus address was found. This is an error in the BIOS.
  1772. //
  1773. KeBugCheckEx(
  1774. ACPI_BIOS_ERROR,
  1775. ACPI_ROOT_PCI_RESOURCE_FAILURE,
  1776. (ULONG_PTR) DeviceExtension,
  1777. 3,
  1778. (ULONG_PTR) CRS
  1779. );
  1780. return((UCHAR)-1);
  1781. }