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.

5146 lines
136 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. utils.c
  5. Abstract:
  6. This module contains assorted utility functions for PCI.SYS.
  7. Author:
  8. Peter Johnston (peterj) 20-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "pcip.h"
  12. typedef struct _LIST_CONTEXT {
  13. PCM_PARTIAL_RESOURCE_LIST List;
  14. CM_RESOURCE_TYPE DesiredType;
  15. ULONG Remaining;
  16. PCM_PARTIAL_RESOURCE_DESCRIPTOR Next;
  17. CM_PARTIAL_RESOURCE_DESCRIPTOR Alias;
  18. } LIST_CONTEXT, *PLIST_CONTEXT;
  19. extern PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable;
  20. VOID
  21. PcipInitializePartialListContext(
  22. IN PLIST_CONTEXT ListContext,
  23. IN PCM_PARTIAL_RESOURCE_LIST PartialList,
  24. IN CM_RESOURCE_TYPE DesiredType
  25. );
  26. PCM_PARTIAL_RESOURCE_DESCRIPTOR
  27. PcipGetNextRangeFromList(
  28. PLIST_CONTEXT ListContext
  29. );
  30. NTSTATUS
  31. PciGetDeviceCapabilities(
  32. IN PDEVICE_OBJECT DeviceObject,
  33. IN PDEVICE_CAPABILITIES DeviceCapabilities
  34. );
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(PAGE, PcipDestroySecondaryExtension)
  37. #pragma alloc_text(PAGE, PciFindDescriptorInCmResourceList)
  38. #pragma alloc_text(PAGE, PciFindParentPciFdoExtension)
  39. #pragma alloc_text(PAGE, PciGetDeviceCapabilities)
  40. #pragma alloc_text(PAGE, PciGetDeviceProperty)
  41. #pragma alloc_text(PAGE, PcipGetNextRangeFromList)
  42. #pragma alloc_text(PAGE, PciGetRegistryValue)
  43. #pragma alloc_text(PAGE, PcipInitializePartialListContext)
  44. #pragma alloc_text(PAGE, PciInsertEntryAtHead)
  45. #pragma alloc_text(PAGE, PciInsertEntryAtTail)
  46. #pragma alloc_text(PAGE, PcipLinkSecondaryExtension)
  47. #pragma alloc_text(PAGE, PciOpenKey)
  48. #pragma alloc_text(PAGE, PciQueryBusInformation)
  49. #pragma alloc_text(PAGE, PciQueryLegacyBusInformation)
  50. #pragma alloc_text(PAGE, PciQueryCapabilities)
  51. #pragma alloc_text(PAGE, PciRangeListFromResourceList)
  52. #pragma alloc_text(PAGE, PciSaveBiosConfig)
  53. #pragma alloc_text(PAGE, PciGetBiosConfig)
  54. #pragma alloc_text(PAGE, PciStringToUSHORT)
  55. #pragma alloc_text(PAGE, PciSendIoctl)
  56. #pragma alloc_text(INIT, PciBuildDefaultExclusionLists)
  57. #pragma alloc_text(PAGE, PciIsDeviceOnDebugPath)
  58. #endif
  59. //
  60. // Range lists indicating the ranges excluded from decode when the ISA and/or
  61. // VGA bits are set on a bridge. Initialized by PciBuildDefaultExclusionLists
  62. // from DriverEntry.
  63. //
  64. RTL_RANGE_LIST PciIsaBitExclusionList;
  65. RTL_RANGE_LIST PciVgaAndIsaBitExclusionList;
  66. PCM_PARTIAL_RESOURCE_DESCRIPTOR
  67. PciFindDescriptorInCmResourceList(
  68. IN CM_RESOURCE_TYPE DescriptorType,
  69. IN PCM_RESOURCE_LIST ResourceList,
  70. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR PreviousHit
  71. )
  72. {
  73. ULONG numlists;
  74. PCM_FULL_RESOURCE_DESCRIPTOR full;
  75. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
  76. if (ResourceList == NULL) {
  77. return NULL;
  78. }
  79. numlists = ResourceList->Count;
  80. full = ResourceList->List;
  81. while (numlists--) {
  82. PCM_PARTIAL_RESOURCE_LIST partial = &full->PartialResourceList;
  83. ULONG count = partial->Count;
  84. descriptor = partial->PartialDescriptors;
  85. while (count--) {
  86. if (descriptor->Type == DescriptorType) {
  87. //
  88. // We have a hit on the type. If we we are doing a
  89. // find next, check to see if we're back where we got
  90. // to last time yet.
  91. //
  92. if (PreviousHit != NULL) {
  93. if (PreviousHit == descriptor) {
  94. //
  95. // We found it again, now we can search for real.
  96. //
  97. PreviousHit = NULL;
  98. }
  99. } else {
  100. //
  101. // It's the one.
  102. //
  103. return descriptor;
  104. }
  105. }
  106. descriptor = PciNextPartialDescriptor(descriptor);
  107. }
  108. full = (PCM_FULL_RESOURCE_DESCRIPTOR)descriptor;
  109. }
  110. return NULL;
  111. }
  112. PVOID
  113. PciFindNextSecondaryExtension(
  114. IN PSINGLE_LIST_ENTRY ListEntry,
  115. IN PCI_SIGNATURE DesiredType
  116. )
  117. {
  118. PPCI_SECONDARY_EXTENSION extension;
  119. while (ListEntry != NULL) {
  120. extension = CONTAINING_RECORD(ListEntry,
  121. PCI_SECONDARY_EXTENSION,
  122. List);
  123. if (extension->ExtensionType == DesiredType) {
  124. //
  125. // This extension is the right type, get out.
  126. //
  127. return extension;
  128. }
  129. ListEntry = extension->List.Next;
  130. }
  131. //
  132. // Didn't find it, fail.
  133. //
  134. return NULL;
  135. }
  136. VOID
  137. PcipLinkSecondaryExtension(
  138. IN PSINGLE_LIST_ENTRY ListHead,
  139. IN PFAST_MUTEX Mutex,
  140. IN PVOID NewExtension,
  141. IN PCI_SIGNATURE Type,
  142. IN PSECONDARYEXTENSIONDESTRUCTOR Destructor
  143. )
  144. /*++
  145. Routine Description:
  146. Add a secondary extension to the secondary extension list for
  147. a PDO/FDO and fill in the header fields.
  148. NOTE: Use the macro PciLinkSecondaryExtension which takes a
  149. PDO extension or FDO extension instead of the list header and
  150. mutex fields.
  151. Arguments:
  152. ListHead &SecondaryExtension.Next from the FDO/PDO extension.
  153. Mutex FDO/PDO Mutex.
  154. NewExtension Extension being added to the list.
  155. Type Member of the enum PCI_SIGNATURE.
  156. Destructor Routine to call when this entry is being torn down.
  157. (Optional).
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. PPCI_SECONDARY_EXTENSION Header;
  163. PAGED_CODE();
  164. Header = (PPCI_SECONDARY_EXTENSION)NewExtension;
  165. Header->ExtensionType = Type;
  166. Header->Destructor = Destructor;
  167. PciInsertEntryAtHead(ListHead, &Header->List, Mutex);
  168. }
  169. VOID
  170. PcipDestroySecondaryExtension(
  171. IN PSINGLE_LIST_ENTRY ListHead,
  172. IN PFAST_MUTEX Mutex,
  173. IN PVOID Extension
  174. )
  175. /*++
  176. Routine Description:
  177. Remove this secondary extension from the list of secondary
  178. extensions, call its destructor routine and free the memory
  179. allocated to it. The destructor is responsible for deleting
  180. any associated allocations.
  181. Failure is not an option.
  182. Note: Use the macro PciDestroySecondaryExtension instead of
  183. calling this routine directly.
  184. Arguments:
  185. ListHead Pointer to the list this extension is on.
  186. Mutex Mutex for synchronization of list manipulation.
  187. Extension The Secondary extension being destroyed.
  188. Return Value:
  189. None.
  190. --*/
  191. {
  192. PPCI_SECONDARY_EXTENSION Header;
  193. PAGED_CODE();
  194. Header = (PPCI_SECONDARY_EXTENSION)Extension;
  195. PciRemoveEntryFromList(ListHead, &Header->List, Mutex);
  196. //
  197. // Call the extension's destructor if one was specified.
  198. //
  199. if (Header->Destructor != NULL) {
  200. Header->Destructor(Extension);
  201. }
  202. //
  203. // Free the memory allocated for this extension.
  204. //
  205. ExFreePool(Extension);
  206. }
  207. VOID
  208. PciInsertEntryAtTail(
  209. IN PSINGLE_LIST_ENTRY ListHead,
  210. IN PSINGLE_LIST_ENTRY NewEntry,
  211. IN PFAST_MUTEX Mutex
  212. )
  213. {
  214. PSINGLE_LIST_ENTRY Previous;
  215. PAGED_CODE();
  216. if (Mutex) {
  217. ExAcquireFastMutex(Mutex);
  218. }
  219. //
  220. // Find the end of the list.
  221. //
  222. Previous = ListHead;
  223. while (Previous->Next) {
  224. Previous = Previous->Next;
  225. }
  226. //
  227. // Append the entry.
  228. //
  229. Previous->Next = NewEntry;
  230. if (Mutex) {
  231. ExReleaseFastMutex(Mutex);
  232. }
  233. }
  234. VOID
  235. PciInsertEntryAtHead(
  236. IN PSINGLE_LIST_ENTRY ListHead,
  237. IN PSINGLE_LIST_ENTRY NewEntry,
  238. IN PFAST_MUTEX Mutex
  239. )
  240. {
  241. PAGED_CODE();
  242. if (Mutex) {
  243. ExAcquireFastMutex(Mutex);
  244. }
  245. NewEntry->Next = ListHead->Next;
  246. ListHead->Next = NewEntry;
  247. if (Mutex) {
  248. ExReleaseFastMutex(Mutex);
  249. }
  250. }
  251. VOID
  252. PciRemoveEntryFromList(
  253. IN PSINGLE_LIST_ENTRY ListHead,
  254. IN PSINGLE_LIST_ENTRY OldEntry,
  255. IN PFAST_MUTEX Mutex
  256. )
  257. /*++
  258. Routine Description:
  259. Remove an entry from a singly linked list.
  260. It is the caller's responsibility to have locked the list if
  261. there is danger of multiple updates.
  262. Arguments:
  263. ListHead - Address of the first entry in the list.
  264. OldEntry - Address of the entry to be removed from the
  265. list.
  266. Return Value:
  267. None.
  268. --*/
  269. {
  270. PSINGLE_LIST_ENTRY Previous;
  271. //
  272. // Sanity check, the list head can't be removed.
  273. //
  274. PCI_ASSERT(ListHead != OldEntry);
  275. if (Mutex) {
  276. ExAcquireFastMutex(Mutex);
  277. }
  278. //
  279. // Locate the entry that points to this entry.
  280. //
  281. for (Previous = ListHead; Previous; Previous = Previous->Next) {
  282. if (Previous->Next == OldEntry) {
  283. break;
  284. }
  285. }
  286. //
  287. // The entry is not in the list - this is bad but fail gracefully...
  288. //
  289. if (!Previous) {
  290. PCI_ASSERT(Previous);
  291. goto exit;
  292. }
  293. //
  294. // Pull it off the list.
  295. //
  296. Previous->Next = OldEntry->Next;
  297. OldEntry->Next = NULL;
  298. exit:
  299. if (Mutex) {
  300. ExReleaseFastMutex(Mutex);
  301. }
  302. }
  303. PCM_PARTIAL_RESOURCE_DESCRIPTOR
  304. PciNextPartialDescriptor(
  305. PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
  306. )
  307. /*++
  308. Routine Description:
  309. Given a pointer to a CmPartialResourceDescriptor, return a pointer
  310. to the next descriptor in the same list.
  311. This is only done in a routine (rather than a simple descriptor++)
  312. because if the variable length resource CmResourceTypeDeviceSpecific.
  313. Arguments:
  314. Descriptor - Pointer to the descriptor being advanced over.
  315. Return Value:
  316. Pointer to the next descriptor in the same list (or byte beyond
  317. end of list).
  318. --*/
  319. {
  320. PCM_PARTIAL_RESOURCE_DESCRIPTOR nextDescriptor;
  321. nextDescriptor = Descriptor + 1;
  322. if (Descriptor->Type == CmResourceTypeDeviceSpecific) {
  323. //
  324. // This (old) descriptor is followed by DataSize bytes
  325. // of device specific data, ie, not immediatelly by the
  326. // next descriptor. Adjust nextDescriptor by this amount.
  327. //
  328. nextDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  329. ((ULONG_PTR)nextDescriptor + Descriptor->u.DeviceSpecificData.DataSize);
  330. }
  331. return nextDescriptor;
  332. }
  333. VOID
  334. PcipInitializePartialListContext(
  335. IN PLIST_CONTEXT ListContext,
  336. IN PCM_PARTIAL_RESOURCE_LIST PartialList,
  337. IN CM_RESOURCE_TYPE DesiredType
  338. )
  339. {
  340. PCI_ASSERT(DesiredType != CmResourceTypeNull);
  341. ListContext->List = PartialList;
  342. ListContext->DesiredType = DesiredType;
  343. ListContext->Remaining = PartialList->Count;
  344. ListContext->Next = PartialList->PartialDescriptors;
  345. ListContext->Alias.Type = CmResourceTypeNull;
  346. }
  347. PCM_PARTIAL_RESOURCE_DESCRIPTOR
  348. PcipGetNextRangeFromList(
  349. PLIST_CONTEXT ListContext
  350. )
  351. {
  352. ULONG Addend;
  353. PCM_PARTIAL_RESOURCE_DESCRIPTOR current;
  354. //
  355. // See if we should be generating an alias to the current
  356. // descriptor.
  357. //
  358. if (ListContext->Alias.Type == ListContext->DesiredType) {
  359. //
  360. // Yes, advance to alias by adding offset to next 10 bit or
  361. // 12 bit alias (only allowable values).
  362. //
  363. if (ListContext->Alias.Flags & CM_RESOURCE_PORT_10_BIT_DECODE) {
  364. Addend = 1 << 10;
  365. } else {
  366. Addend = 1 << 12;
  367. }
  368. Addend += ListContext->Alias.u.Generic.Start.LowPart;
  369. if (Addend < (1 << 16)) {
  370. //
  371. // This is a valid alias, return it.
  372. //
  373. ListContext->Alias.u.Generic.Start.LowPart = Addend;
  374. return &ListContext->Alias;
  375. }
  376. //
  377. // Out of aliases to this resource.
  378. //
  379. ListContext->Alias.Type = CmResourceTypeNull;
  380. }
  381. //
  382. // We get here if there are no aliases or it is time to advance
  383. // to the next descriptor of the desired type.
  384. //
  385. while (ListContext->Remaining != 0) {
  386. current = ListContext->Next;
  387. //
  388. // Advance context to next before examining and possibly
  389. // returning current.
  390. //
  391. ListContext->Next = PciNextPartialDescriptor(current);
  392. ListContext->Remaining--;
  393. //
  394. // Is this current descriptor a candidate?
  395. //
  396. if (current->Type == ListContext->DesiredType) {
  397. //
  398. // Return this one to caller. If this descriptor has
  399. // aliases, setup so the next call will return an alias.
  400. //
  401. if (current->Flags & (CM_RESOURCE_PORT_10_BIT_DECODE |
  402. CM_RESOURCE_PORT_12_BIT_DECODE)) {
  403. ListContext->Alias = *current;
  404. }
  405. return current;
  406. }
  407. }
  408. //
  409. // No aliases and no new descriptors of the desired type.
  410. //
  411. return NULL;
  412. }
  413. NTSTATUS
  414. PciQueryPowerCapabilities(
  415. IN PPCI_PDO_EXTENSION PdoExtension,
  416. IN PDEVICE_CAPABILITIES Capabilities
  417. )
  418. /*++
  419. Routine Description:
  420. determine a device's power capabilites by using its parent capabilities
  421. It should be noted that there two ways that the code calculates the system
  422. and device wake levels. The first method, which is preferred, biases toward
  423. the deepest possible system state, and the second, which gets used if the
  424. first fails to find something legal, is biased towards finding the deepest
  425. possible device wake state
  426. Arguments:
  427. PdoExtension - The PDO whose capabilities we will provide
  428. Capablities - Where we will store the device capabilities
  429. Return Value:
  430. NTSTATUS
  431. --*/
  432. {
  433. NTSTATUS status;
  434. DEVICE_CAPABILITIES parentCapabilities;
  435. DEVICE_POWER_STATE deviceState;
  436. DEVICE_POWER_STATE validDeviceWakeState = PowerDeviceUnspecified;
  437. SYSTEM_POWER_STATE index;
  438. SYSTEM_POWER_STATE highestSupportedSleepState = PowerSystemUnspecified;
  439. SYSTEM_POWER_STATE validSystemWakeState = PowerSystemUnspecified;
  440. //
  441. // Get the device capabilities of the parent
  442. //
  443. status = PciGetDeviceCapabilities(
  444. PdoExtension->ParentFdoExtension->PhysicalDeviceObject,
  445. &parentCapabilities
  446. );
  447. if (!NT_SUCCESS(status)) {
  448. return status;
  449. }
  450. //
  451. // Make sure that we have sane device capabilities to start with...
  452. //
  453. if (parentCapabilities.DeviceState[PowerSystemWorking] == PowerDeviceUnspecified) {
  454. parentCapabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
  455. }
  456. if (parentCapabilities.DeviceState[PowerSystemShutdown] == PowerDeviceUnspecified) {
  457. parentCapabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
  458. }
  459. //
  460. // Does the device have any PCI power capabilities?
  461. //
  462. if ( (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)) {
  463. //
  464. // Use the parent's mapping as our own
  465. //
  466. RtlCopyMemory(
  467. Capabilities->DeviceState,
  468. parentCapabilities.DeviceState,
  469. (PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE)
  470. );
  471. //
  472. // As D1 and D2 are not supported here, round down to D3.
  473. //
  474. // This code is not enabled so that a hack becomes available for
  475. // older PCI video cards. Basically, older video cards can do D3 hot
  476. // but not D3 cold (in which case they need reposting). ACPI supplies
  477. // a hack by which all PCI-to-PCI bridges are said to map S1->D1. The
  478. // code below lets the parent's D1 "appear" as a state the child
  479. // supports, regardless of it's real capabilities. Video drivers for
  480. // such cards fail D3 (which may be D3-cold), but succeed D1 (which is
  481. // really D3-hot).
  482. //
  483. // Also note that this is not targetted at video cards but rather is
  484. // targetted at any non-PCI power managed device. That means drivers
  485. // for older devices need to either map D1&D2 to D3 themselves, or
  486. // treat unexpected D1&D2 IRPs as if D3. Folklore says that there is
  487. // also a net card or two that also takes advantage of this hack.
  488. //
  489. #if 0
  490. for (index = PowerSystemWorking; index < PowerSystemMaximum; index++) {
  491. //
  492. // This is the device state that the parent supports
  493. //
  494. deviceState = parentCapabilities.DeviceState[index];
  495. //
  496. // Round down if D1 or D2
  497. //
  498. if ((deviceState == PowerDeviceD1) || (deviceState == PowerDeviceD2)) {
  499. Capabilities->DeviceState[index] = PowerDeviceD3;
  500. }
  501. }
  502. #endif
  503. //
  504. // The device has no wake capabilities
  505. //
  506. Capabilities->DeviceWake = PowerDeviceUnspecified;
  507. Capabilities->SystemWake = PowerSystemUnspecified;
  508. //
  509. // Set these bits explicitly
  510. //
  511. Capabilities->DeviceD1 = FALSE;
  512. Capabilities->DeviceD2 = FALSE;
  513. Capabilities->WakeFromD0 = FALSE;
  514. Capabilities->WakeFromD1 = FALSE;
  515. Capabilities->WakeFromD2 = FALSE;
  516. Capabilities->WakeFromD3 = FALSE;
  517. //
  518. // Done
  519. //
  520. return STATUS_SUCCESS;
  521. }
  522. //
  523. // Set all the capabilities bits
  524. //
  525. Capabilities->DeviceD1 = PdoExtension->PowerCapabilities.Support.D1;
  526. Capabilities->DeviceD2 = PdoExtension->PowerCapabilities.Support.D2;
  527. Capabilities->WakeFromD0 = PdoExtension->PowerCapabilities.Support.PMED0;
  528. Capabilities->WakeFromD1 = PdoExtension->PowerCapabilities.Support.PMED1;
  529. Capabilities->WakeFromD2 = PdoExtension->PowerCapabilities.Support.PMED2;
  530. if (parentCapabilities.DeviceWake == PowerDeviceD3) {
  531. //
  532. // If our parent can wake from the D3 state, than we must support
  533. // PM3 From D3 Cold. The (obvious) exception to this is if the
  534. // parent is a root bus...
  535. //
  536. if (PCI_PDO_ON_ROOT(PdoExtension)) {
  537. Capabilities->WakeFromD3 =
  538. PdoExtension->PowerCapabilities.Support.PMED3Hot;
  539. } else {
  540. Capabilities->WakeFromD3 =
  541. PdoExtension->PowerCapabilities.Support.PMED3Cold;
  542. }
  543. } else {
  544. //
  545. // If our parent cannot wake from the D3 state, then we support
  546. // the D3 state if we support PME3Hot
  547. //
  548. Capabilities->WakeFromD3 =
  549. PdoExtension->PowerCapabilities.Support.PMED3Hot;
  550. }
  551. //
  552. // First step is to make sure that all the S-states that we got from
  553. // out parent map to valid D-states for this device
  554. //
  555. // ADRIAO N.B. 08/18/1999 -
  556. // This algorithm works but it's overly aggressive. It is in fact legal
  557. // for a bridge to be in D2 with a card behind it in D1.
  558. //
  559. for (index = PowerSystemWorking; index < PowerSystemMaximum; index++) {
  560. //
  561. // This is the device state that the parent supports
  562. //
  563. deviceState = parentCapabilities.DeviceState[index];
  564. //
  565. // If the device state is D1 and we don't support D1, then
  566. // consider D2 instead
  567. //
  568. if (deviceState == PowerDeviceD1 &&
  569. PdoExtension->PowerCapabilities.Support.D1 == FALSE) {
  570. deviceState++;
  571. }
  572. //
  573. // If the device state is D2 and we don't support D2, then
  574. // consider D3 instead
  575. //
  576. if (deviceState == PowerDeviceD2 &&
  577. PdoExtension->PowerCapabilities.Support.D2 == FALSE) {
  578. deviceState++;
  579. }
  580. //
  581. // We should be able to support this deviceState
  582. //
  583. Capabilities->DeviceState[index] = deviceState;
  584. //
  585. // If this S-state is less than PowerSystemHibernate, and the
  586. // S-State doesn't map to PowerDeviceUnspecified, then consider
  587. // this to be the highest supported SleepState
  588. //
  589. if (index < PowerSystemHibernate &&
  590. Capabilities->DeviceState[index] != PowerDeviceUnspecified) {
  591. highestSupportedSleepState = index;
  592. }
  593. //
  594. // Can we support this as a wake state?
  595. //
  596. if (index < parentCapabilities.SystemWake &&
  597. deviceState >= parentCapabilities.DeviceState[index] &&
  598. parentCapabilities.DeviceState[index] != PowerDeviceUnspecified) {
  599. //
  600. // Consider using this as a valid wake state
  601. //
  602. if ( (deviceState == PowerDeviceD0 && Capabilities->WakeFromD0) ||
  603. (deviceState == PowerDeviceD1 && Capabilities->WakeFromD1) ||
  604. (deviceState == PowerDeviceD2 && Capabilities->WakeFromD2) ) {
  605. validSystemWakeState = index;
  606. validDeviceWakeState = deviceState;
  607. } else if (deviceState == PowerDeviceD3 &&
  608. PdoExtension->PowerCapabilities.Support.PMED3Hot) {
  609. //
  610. // This is a special case logic (which is why it is seperate from
  611. // the above logic
  612. //
  613. if (parentCapabilities.DeviceState[index] < PowerDeviceD3 ||
  614. PdoExtension->PowerCapabilities.Support.PMED3Cold) {
  615. validSystemWakeState = index;
  616. validDeviceWakeState = deviceState;
  617. }
  618. }
  619. }
  620. }
  621. //
  622. // Does the parent device have power management capabilities?
  623. // Does the device have power management capabilities?
  624. // Can we wake up from the same D-states that our parent can? or better?
  625. //
  626. if (parentCapabilities.SystemWake == PowerSystemUnspecified ||
  627. parentCapabilities.DeviceWake == PowerDeviceUnspecified ||
  628. PdoExtension->PowerState.DeviceWakeLevel == PowerDeviceUnspecified ||
  629. PdoExtension->PowerState.DeviceWakeLevel < parentCapabilities.DeviceWake) {
  630. //
  631. // The device doesn't support any kind of wakeup (that we know about)
  632. // or the device doesn't support wakeup from supported D-states, so
  633. // set the latency and return
  634. //
  635. Capabilities->D1Latency = 0;
  636. Capabilities->D2Latency = 0;
  637. Capabilities->D3Latency = 0;
  638. return STATUS_SUCCESS;
  639. }
  640. //
  641. // We should be able to wake the device from the same state
  642. // that our parent can wake from
  643. //
  644. Capabilities->SystemWake = parentCapabilities.SystemWake;
  645. Capabilities->DeviceWake = PdoExtension->PowerState.DeviceWakeLevel;
  646. //
  647. // Change our device wake level to include a state that we support
  648. //
  649. if (Capabilities->DeviceWake == PowerDeviceD0 && !Capabilities->WakeFromD0) {
  650. Capabilities->DeviceWake++;
  651. }
  652. if (Capabilities->DeviceWake == PowerDeviceD1 && !Capabilities->WakeFromD1) {
  653. Capabilities->DeviceWake++;
  654. }
  655. if (Capabilities->DeviceWake == PowerDeviceD2 && !Capabilities->WakeFromD2) {
  656. Capabilities->DeviceWake++;
  657. }
  658. if (Capabilities->DeviceWake == PowerDeviceD3 && !Capabilities->WakeFromD3) {
  659. Capabilities->DeviceWake = PowerDeviceUnspecified;
  660. Capabilities->SystemWake = PowerSystemUnspecified;
  661. }
  662. //
  663. // This is our fallback position. If we got here and there is no wake
  664. // capability using the above method of calcuation, then we should
  665. // check to see if we noticed a valid wake combination while scanning
  666. // the S to D mapping information
  667. //
  668. if ( (Capabilities->DeviceWake == PowerDeviceUnspecified ||
  669. Capabilities->SystemWake == PowerSystemUnspecified) &&
  670. (validSystemWakeState != PowerSystemUnspecified &&
  671. validDeviceWakeState != PowerSystemUnspecified) ) {
  672. Capabilities->DeviceWake = validDeviceWakeState;
  673. Capabilities->SystemWake = validSystemWakeState;
  674. //
  675. // Note that in this case, we might have set DeviceWake to D3, without
  676. // having set the bit, so "correct" that situation.
  677. //
  678. if (validDeviceWakeState == PowerDeviceD3) {
  679. Capabilities->WakeFromD3 = TRUE;
  680. }
  681. }
  682. //
  683. // We shouldn't allow Wake From S4, S5, unless the supports the D3 state
  684. // Even then, we really shouldn't allow S4, S5 unless the device supports
  685. // the D3Cold PME state
  686. //
  687. if (Capabilities->SystemWake > PowerSystemSleeping3) {
  688. //
  689. // Does the device support wake from D3?
  690. //
  691. if (Capabilities->DeviceWake != PowerDeviceD3) {
  692. //
  693. // Reduce the systemwake level to something more realistic
  694. //
  695. Capabilities->SystemWake = highestSupportedSleepState;
  696. }
  697. //
  698. // This is in a seperate if statement so that the code can be easily
  699. // commented out
  700. //
  701. if (!PdoExtension->PowerCapabilities.Support.PMED3Cold) {
  702. //
  703. // Reduce the systemwake level to something more realistic
  704. //
  705. Capabilities->SystemWake = highestSupportedSleepState;
  706. }
  707. }
  708. //
  709. // From the PCI Power Management spec V1.0, table 18
  710. // "PCI Function State Transition Delays".
  711. //
  712. // D1 -> D0 0
  713. // D2 -> D0 200 us
  714. // D3 -> D0 10 ms
  715. //
  716. // The latency entries are in units of 100 us.
  717. //
  718. Capabilities->D1Latency = 0;
  719. Capabilities->D2Latency = 2;
  720. Capabilities->D3Latency = 100;
  721. //
  722. // Make sure that S0 maps to D0
  723. //
  724. PCI_ASSERT( Capabilities->DeviceState[PowerSystemWorking] == PowerDeviceD0);
  725. //
  726. // Done
  727. //
  728. return STATUS_SUCCESS;
  729. }
  730. NTSTATUS
  731. PciDetermineSlotNumber(
  732. IN PPCI_PDO_EXTENSION PdoExtension,
  733. IN OUT PULONG SlotNumber
  734. )
  735. /*++
  736. Description:
  737. Determine the slot number associated with a PCI device (if any)
  738. through use of the PCI IRQ routing table information we may have
  739. stored earlier.
  740. If the previous mechanism fails to retrieve a slot number, see if
  741. we can inherit our parent's slot number.
  742. This result may be filtered further by ACPI and other bus filters..
  743. Arguments:
  744. PdoExtension - PDO extension of device in question.
  745. SlotNumber - Pointer to slot number to update
  746. Return Value:
  747. STATUS_SUCCESS if slot # found
  748. --*/
  749. {
  750. PSLOT_INFO slotInfo, lastSlot;
  751. ULONG length;
  752. //
  753. // If we have a legacy PCI routing table and our Pdo isn't orphaned search
  754. // the table for our physical slot number. If this is an ACPI machine then ACPI
  755. // will overwrite this with the value from the _SUN if it exists.
  756. //
  757. if (PciIrqRoutingTable && PCI_PARENT_FDOX(PdoExtension)) {
  758. slotInfo = (PSLOT_INFO)((PUCHAR) PciIrqRoutingTable +
  759. sizeof(PCI_IRQ_ROUTING_TABLE));
  760. lastSlot = (PSLOT_INFO)((PUCHAR) PciIrqRoutingTable +
  761. PciIrqRoutingTable->TableSize);
  762. // Search for a entry in the routing table that matches this device
  763. while (slotInfo < lastSlot) {
  764. if ((PCI_PARENT_FDOX(PdoExtension)->BaseBus == slotInfo->BusNumber) &&
  765. ((UCHAR)PdoExtension->Slot.u.bits.DeviceNumber == (slotInfo->DeviceNumber >> 3)) &&
  766. (slotInfo->SlotNumber != 0)) {
  767. *SlotNumber = slotInfo->SlotNumber;
  768. return STATUS_SUCCESS;
  769. }
  770. slotInfo++;
  771. }
  772. }
  773. //
  774. // Maybe our parent has a UI Number that we could 'inherit'.
  775. // but only if we're not a PDO off a root bus otherwise we pick up
  776. // the UI number from the PNPA03 node (likely 0)
  777. //
  778. if (PCI_PDO_ON_ROOT(PdoExtension)) {
  779. return STATUS_UNSUCCESSFUL;
  780. }
  781. return IoGetDeviceProperty(PCI_PARENT_PDO(PdoExtension),
  782. DevicePropertyUINumber,
  783. sizeof(*SlotNumber),
  784. SlotNumber,
  785. &length);
  786. }
  787. NTSTATUS
  788. PciQueryCapabilities(
  789. IN PPCI_PDO_EXTENSION PdoExtension,
  790. IN PDEVICE_CAPABILITIES Capabilities
  791. )
  792. /*++
  793. Routine Description:
  794. return a subset of our parent's capabilities.
  795. Arguments:
  796. Capabilities - pointer to a DEVICE_CAPABILITIES structured supplied
  797. by the caller.
  798. Return Value:
  799. Status.
  800. --*/
  801. {
  802. NTSTATUS status = STATUS_SUCCESS;
  803. #ifndef HANDLE_BOGUS_CAPS
  804. if (Capabilities->Version < 1) {
  805. //
  806. // do not touch irp!
  807. //
  808. return STATUS_NOT_SUPPORTED;
  809. }
  810. #endif
  811. //
  812. // For PCI devices, the Capabilities Address field contains
  813. // the Device Number in the upper 16 bits and the function
  814. // number in the lower.
  815. //
  816. Capabilities->Address =
  817. PdoExtension->Slot.u.bits.DeviceNumber << 16 |
  818. PdoExtension->Slot.u.bits.FunctionNumber;
  819. //
  820. // The PCI bus driver does not generate Unique IDs for its children.
  821. //
  822. Capabilities->UniqueID = FALSE;
  823. //
  824. // If this PDO is for a HOST BRIDGE, claim that it supports
  825. // being handled Raw. This is so the device controller will
  826. // allow installation of the NULL device on this puppy.
  827. //
  828. if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
  829. (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST)) {
  830. Capabilities->RawDeviceOK = TRUE;
  831. } else {
  832. Capabilities->RawDeviceOK = FALSE;
  833. }
  834. //
  835. // The following values should be fixed by filters or function
  836. // drivers that actually know the answer.
  837. //
  838. Capabilities->LockSupported = FALSE;
  839. Capabilities->EjectSupported = FALSE;
  840. Capabilities->Removable = FALSE;
  841. Capabilities->DockDevice = FALSE;
  842. PciDetermineSlotNumber(PdoExtension, &Capabilities->UINumber);
  843. //
  844. // Get the device power capabilities
  845. //
  846. status = PciQueryPowerCapabilities( PdoExtension, Capabilities );
  847. if (!NT_SUCCESS(status)) {
  848. return status;
  849. }
  850. #if DBG
  851. if (PciDebug & PciDbgQueryCap) {
  852. PciDebugDumpQueryCapabilities(Capabilities);
  853. }
  854. #endif
  855. //
  856. // Done
  857. //
  858. return status;
  859. }
  860. NTSTATUS
  861. PciQueryBusInformation(
  862. IN PPCI_PDO_EXTENSION PdoExtension,
  863. IN PPNP_BUS_INFORMATION *BusInformation
  864. )
  865. /*++
  866. Routine Description:
  867. Tell PnP that it's talking to a PCI bus.
  868. Arguments:
  869. BusInformation - Pointer to a PPNP_BUS_INFORMATION. We create
  870. a PNP_BUS_INFORMATION and pass its address
  871. back thru here.
  872. Return Value:
  873. Status.
  874. --*/
  875. {
  876. PPNP_BUS_INFORMATION information;
  877. information = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, sizeof(PNP_BUS_INFORMATION));
  878. if (information == NULL) {
  879. return STATUS_INSUFFICIENT_RESOURCES;
  880. }
  881. RtlCopyMemory(&information->BusTypeGuid, &GUID_BUS_TYPE_PCI, sizeof(GUID));
  882. information->LegacyBusType = PCIBus;
  883. information->BusNumber = PCI_PARENT_FDOX(PdoExtension)->BaseBus;
  884. *BusInformation = information;
  885. return STATUS_SUCCESS;
  886. }
  887. NTSTATUS
  888. PciQueryLegacyBusInformation(
  889. IN PPCI_FDO_EXTENSION FdoExtension,
  890. IN PLEGACY_BUS_INFORMATION *BusInformation
  891. )
  892. /*++
  893. Routine Description:
  894. Tell PnP that it's talking to a PCI bus.
  895. Arguments:
  896. BusInformation - Pointer to a PLEGACY_BUS_INFORMATION. We create
  897. a LEGACY_BUS_INFORMATION and pass its address
  898. back thru here.
  899. Return Value:
  900. Status.
  901. --*/
  902. {
  903. PLEGACY_BUS_INFORMATION information;
  904. information = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, sizeof(LEGACY_BUS_INFORMATION));
  905. if (information == NULL) {
  906. PCI_ASSERT(information != NULL);
  907. return STATUS_INSUFFICIENT_RESOURCES;
  908. }
  909. RtlCopyMemory(&information->BusTypeGuid, &GUID_BUS_TYPE_PCI, sizeof(GUID));
  910. information->LegacyBusType = PCIBus;
  911. information->BusNumber = FdoExtension->BaseBus;
  912. *BusInformation = information;
  913. return STATUS_SUCCESS;
  914. }
  915. NTSTATUS
  916. PciGetInterruptAssignment(
  917. IN PPCI_PDO_EXTENSION PdoExtension,
  918. OUT ULONG *Minimum,
  919. OUT ULONG *Maximum
  920. )
  921. {
  922. UCHAR pin = PdoExtension->InterruptPin;
  923. //
  924. // Using HAL for interrupts.
  925. //
  926. PIO_RESOURCE_REQUIREMENTS_LIST reqList;
  927. PIO_RESOURCE_DESCRIPTOR resource;
  928. NTSTATUS status = STATUS_RESOURCE_TYPE_NOT_FOUND;
  929. if (pin != 0) {
  930. //
  931. // This hardware uses an interrupt.
  932. //
  933. // Depend on the HAL to understand how IRQ routing is
  934. // really done.
  935. //
  936. reqList = PciAllocateIoRequirementsList(
  937. 1, // number of resources
  938. PCI_PARENT_FDOX(PdoExtension)->BaseBus,
  939. PdoExtension->Slot.u.AsULONG
  940. );
  941. if (reqList == NULL) {
  942. //
  943. // Out of system resources? Bad things are happening.
  944. //
  945. return STATUS_INSUFFICIENT_RESOURCES;
  946. }
  947. resource = reqList->List[0].Descriptors;
  948. resource->Type = CmResourceTypeInterrupt;
  949. resource->ShareDisposition = CmResourceShareShared;
  950. resource->Option = 0;
  951. resource->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  952. resource->u.Interrupt.MinimumVector = 0x00;
  953. //
  954. // Historically the maximum allowable interrupt vector for a PCI
  955. // device was FF, since that is the largest value that can be written
  956. // into the interrupt line register. However, the interrupt line
  957. // register is largely irrelevant now, and large machines may contain
  958. // enough interrupt controllers to kick the number of interrupt vectors
  959. // in the machine above FF. To support devices connected to these vectors
  960. // the maximum vector in the requirement must be as large as possible.
  961. // For now this change is only made on the Datacenter SKU as drivers may
  962. // rely on the interrupt line register, which is now bogus. When more
  963. // complete testing is available, this change will be made global.
  964. //
  965. if (PciRunningDatacenter) {
  966. resource->u.Interrupt.MaximumVector = MAXULONG;
  967. } else {
  968. resource->u.Interrupt.MaximumVector = 0xff;
  969. }
  970. #if defined(NO_LEGACY_DRIVERS)
  971. *Minimum = 0;
  972. if (PciRunningDatacenter) {
  973. *Maximum = MAXULONG;
  974. } else {
  975. *Maximum = 0xFF;
  976. }
  977. status = STATUS_SUCCESS;
  978. #else
  979. status = HalAdjustResourceList(&reqList);
  980. //
  981. // If the HAL succeeded it will have reallocated the list.
  982. //
  983. resource = reqList->List[0].Descriptors;
  984. if (!NT_SUCCESS(status)) {
  985. PciDebugPrint(
  986. PciDbgInformative,
  987. " PIN %02x, HAL FAILED Interrupt Assignment, status %08x\n",
  988. pin,
  989. status
  990. );
  991. status = STATUS_UNSUCCESSFUL;
  992. } else if (resource->u.Interrupt.MinimumVector >
  993. resource->u.Interrupt.MaximumVector) {
  994. UCHAR line;
  995. //
  996. // The HAL succeeded but returned an invalid range. This
  997. // is the HALs way of telling us that, sorry, it doesn't
  998. // know either.
  999. //
  1000. //
  1001. // We have a bug in that we restore the interrupt line to
  1002. // config space before we power up the device and thus if
  1003. // the device is in D>0 and the interrupt line register
  1004. // isn't sticky it doesn't stick. It doesn't matter unless
  1005. // we are on a machine that doesn't support interrupt
  1006. // routing in which case we are toast. The correct fix is
  1007. // to move the restore code after we power managed the device
  1008. // but that changes things too much for Whistler Beta2 and this
  1009. // is totally rewritten for Blackcomb so, now that you know
  1010. // the right way to fix this, the hack is if the HAL fails
  1011. // the call use what we would have restored into the interrupt
  1012. // line.
  1013. //
  1014. //
  1015. // Get the current int line (this is in the same place for all header types)
  1016. //
  1017. PciReadDeviceConfig(PdoExtension,
  1018. &line,
  1019. FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.InterruptLine),
  1020. sizeof(line)
  1021. );
  1022. //
  1023. // If this is 0 and it was something when we first saw the device then use
  1024. // what we first saw
  1025. //
  1026. if (line == 0 && PdoExtension->RawInterruptLine != 0) {
  1027. *Minimum = *Maximum = (ULONG)PdoExtension->RawInterruptLine;
  1028. status = STATUS_SUCCESS;
  1029. } else {
  1030. PciDebugPrint(
  1031. PciDbgInformative,
  1032. " PIN %02x, HAL could not assign interrupt.\n",
  1033. pin
  1034. );
  1035. status = STATUS_UNSUCCESSFUL;
  1036. }
  1037. } else {
  1038. *Minimum = resource->u.Interrupt.MinimumVector;
  1039. *Maximum = resource->u.Interrupt.MaximumVector;
  1040. PciDebugPrint(
  1041. PciDbgObnoxious,
  1042. " Interrupt assigned = 0x%x through 0x%x\n",
  1043. *Minimum,
  1044. *Maximum
  1045. );
  1046. status = STATUS_SUCCESS;
  1047. }
  1048. ExFreePool(reqList);
  1049. #endif // NO_LEGACY_DRIVERS
  1050. } else {
  1051. #if MSI_SUPPORTED
  1052. if (PdoExtension->CapableMSI) {
  1053. //
  1054. // MSI Only device - we need to return a success here so that
  1055. // this device gets resource requests passed to a (hopefully)
  1056. // MSI-aware arbiter. If the arbiter is not MSI aware, we will
  1057. // simply get extraneous/unusable resources allocated for this
  1058. // device - not to mention the fact that the device will not work.
  1059. //
  1060. // The below could be anything, they are only limited by message
  1061. // size and the available APIC ranges which only the arbiter
  1062. // knows about.
  1063. //
  1064. *Minimum = 0x00;
  1065. *Maximum = 0xFF;
  1066. status = STATUS_SUCCESS;
  1067. }
  1068. #endif // MSI_SUPPORTED
  1069. }
  1070. return status;
  1071. }
  1072. PPCI_PDO_EXTENSION
  1073. PciFindPdoByFunction(
  1074. IN PPCI_FDO_EXTENSION FdoExtension,
  1075. IN PCI_SLOT_NUMBER Slot,
  1076. IN PPCI_COMMON_CONFIG Config
  1077. )
  1078. {
  1079. PPCI_PDO_EXTENSION pdoExtension;
  1080. KIRQL currentIrql;
  1081. //
  1082. // This can be called at >= DISPATCH_LEVEL when we scan the bus on returning
  1083. // from hibernate. Don't try to acquire the locks because (1) it'll crash
  1084. // and (2) it is guaranteed to be single threaded
  1085. //
  1086. currentIrql = KeGetCurrentIrql();
  1087. if (currentIrql < DISPATCH_LEVEL) {
  1088. ExAcquireFastMutex(&FdoExtension->ChildListMutex);
  1089. };
  1090. //
  1091. // Seach each PDO hanging off of the given FDO until we find a matching
  1092. // PCI function or fall off the end of the list.
  1093. //
  1094. for (pdoExtension = FdoExtension->ChildPdoList;
  1095. pdoExtension;
  1096. pdoExtension = pdoExtension->Next) {
  1097. if ((!pdoExtension->ReportedMissing) &&
  1098. (pdoExtension->Slot.u.bits.DeviceNumber == Slot.u.bits.DeviceNumber) &&
  1099. (pdoExtension->Slot.u.bits.FunctionNumber == Slot.u.bits.FunctionNumber)) {
  1100. //
  1101. // Check that the device in this slot hasn't changed. (as best
  1102. // we can).
  1103. //
  1104. if ( (pdoExtension->VendorId == Config->VendorID)
  1105. && (pdoExtension->DeviceId == Config->DeviceID)
  1106. && (pdoExtension->RevisionId == Config->RevisionID)
  1107. #if 0
  1108. //
  1109. // NTRAID #62668 - 4/25/2000
  1110. //
  1111. // These do not contribute towards the device ID itself, and
  1112. // as they are unfortunately volatile on some cards (SubClass
  1113. // changes on the ATIRage, Programming interface on IDE cards).
  1114. // Therefore a change in these fields does not mean a change in
  1115. // the presence of the card.
  1116. //
  1117. // What about the SSVID?
  1118. //
  1119. && (pdoExtension->ProgIf == Config->ProgIf)
  1120. && (pdoExtension->SubClass == Config->SubClass)
  1121. && (pdoExtension->BaseClass == Config->BaseClass)
  1122. #endif
  1123. ) {
  1124. break;
  1125. }
  1126. }
  1127. }
  1128. if (currentIrql < DISPATCH_LEVEL) {
  1129. ExReleaseFastMutex(&FdoExtension->ChildListMutex);
  1130. }
  1131. return pdoExtension;
  1132. }
  1133. PPCI_FDO_EXTENSION
  1134. PciFindParentPciFdoExtension(
  1135. PDEVICE_OBJECT PhysicalDeviceObject,
  1136. IN PFAST_MUTEX Mutex
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. For each Parent PCI FDO, search the child Pdo lists for the supplied
  1141. PhysicalDeviceObject.
  1142. Arguments:
  1143. PhysicalDeviceObject Pdo to find.
  1144. Mutex Mutex list is protected by.
  1145. Return Value:
  1146. If Pdo is found as a child, returns a pointer to the root Fdo's
  1147. device extension, otherwise returns NULL.
  1148. --*/
  1149. {
  1150. PPCI_FDO_EXTENSION fdoExtension;
  1151. PPCI_PDO_EXTENSION pdoExtension;
  1152. PPCI_PDO_EXTENSION target;
  1153. PSINGLE_LIST_ENTRY nextEntry;
  1154. if (Mutex) {
  1155. ExAcquireFastMutex(Mutex);
  1156. }
  1157. target = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
  1158. //
  1159. // For each root
  1160. //
  1161. for ( nextEntry = PciFdoExtensionListHead.Next;
  1162. nextEntry != NULL;
  1163. nextEntry = nextEntry->Next ) {
  1164. fdoExtension = CONTAINING_RECORD(nextEntry,
  1165. PCI_FDO_EXTENSION,
  1166. List);
  1167. //
  1168. // Search the child Pdo list.
  1169. //
  1170. ExAcquireFastMutex(&fdoExtension->ChildListMutex);
  1171. for ( pdoExtension = fdoExtension->ChildPdoList;
  1172. pdoExtension;
  1173. pdoExtension = pdoExtension->Next ) {
  1174. //
  1175. // Is this the one we're looking for?
  1176. //
  1177. if ( pdoExtension == target ) {
  1178. ExReleaseFastMutex(&fdoExtension->ChildListMutex);
  1179. //
  1180. // Yes, return it.
  1181. //
  1182. if (Mutex) {
  1183. ExReleaseFastMutex(Mutex);
  1184. }
  1185. return fdoExtension;
  1186. }
  1187. }
  1188. ExReleaseFastMutex(&fdoExtension->ChildListMutex);
  1189. }
  1190. //
  1191. // Did not find match.
  1192. //
  1193. if (Mutex) {
  1194. ExReleaseFastMutex(Mutex);
  1195. }
  1196. return NULL;
  1197. }
  1198. PCI_OBJECT_TYPE
  1199. PciClassifyDeviceType(
  1200. PPCI_PDO_EXTENSION PdoExtension
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. Examine the Configuration Header BaseClass and SubClass fields
  1205. and classify the device into a simple enumerated type.
  1206. Arguments:
  1207. PdoExtension Pointer to the Physical Device Object extension
  1208. into which the above fields have been previously
  1209. been copied from PCI config space.
  1210. Return Value:
  1211. Returns a device type from the PCI_OBJECT_TYPE enumeration.
  1212. --*/
  1213. {
  1214. ASSERT_PCI_PDO_EXTENSION(PdoExtension);
  1215. switch (PdoExtension->BaseClass) {
  1216. case PCI_CLASS_BRIDGE_DEV:
  1217. //
  1218. // It's a bridge, subdivide it into the kind of bridge.
  1219. //
  1220. switch (PdoExtension->SubClass) {
  1221. case PCI_SUBCLASS_BR_HOST:
  1222. return PciTypeHostBridge;
  1223. case PCI_SUBCLASS_BR_PCI_TO_PCI:
  1224. return PciTypePciBridge;
  1225. case PCI_SUBCLASS_BR_CARDBUS:
  1226. return PciTypeCardbusBridge;
  1227. default:
  1228. //
  1229. // Anything else is just a device.
  1230. //
  1231. break;
  1232. }
  1233. default:
  1234. //
  1235. // Anything else is just another device.
  1236. //
  1237. break;
  1238. }
  1239. return PciTypeDevice;
  1240. }
  1241. ULONG
  1242. PciGetLengthFromBar(
  1243. ULONG BaseAddressRegister
  1244. )
  1245. /*++
  1246. Routine Description:
  1247. Given the contents of a PCI Base Address Register, after it
  1248. has been written with all ones, this routine calculates the
  1249. length (and alignment) requirement for this BAR.
  1250. This method for determining requirements is described in
  1251. section 6.2.5.1 of the PCI Specification (Rev 2.1).
  1252. NTRAID #62631 - 4/25/2000 - andrewth
  1253. The length is a power of two, given only a ULONG to
  1254. contain it, we are restricted to a maximum resource size of
  1255. 2GB.
  1256. Arguments:
  1257. BaseAddressRegister contains something.
  1258. Return Value:
  1259. Returns the length of the resource requirement. This will be a number
  1260. in the range 0 thru 0x80000000.
  1261. --*/
  1262. {
  1263. ULONG Length;
  1264. //
  1265. // A number of least significant bits should be ignored in the
  1266. // determination of the length. These are flag bits, the number
  1267. // of bits is dependent on the type of the resource.
  1268. //
  1269. if (BaseAddressRegister & PCI_ADDRESS_IO_SPACE) {
  1270. //
  1271. // PCI IO space.
  1272. //
  1273. BaseAddressRegister &= PCI_ADDRESS_IO_ADDRESS_MASK;
  1274. } else {
  1275. //
  1276. // PCI Memory space.
  1277. //
  1278. BaseAddressRegister &= PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  1279. }
  1280. //
  1281. // BaseAddressRegister now contains the maximum base address
  1282. // this device can reside at and still exist below the top of
  1283. // memory.
  1284. //
  1285. // The value 0xffffffff was written to the BAR. The device will
  1286. // have adjusted this value to the maximum it can really use.
  1287. //
  1288. // Length MUST be a power of 2.
  1289. //
  1290. // For most devices, h/w will simply have cleared bits from the
  1291. // least significant bit positions so that the address 0xffffffff
  1292. // is adjusted to accomodate the length. eg: if the new value is
  1293. // 0xffffff00, the device requires 256 bytes.
  1294. //
  1295. // The difference between the original and new values is the length (-1).
  1296. //
  1297. // For example, if the value fead back from the BAR is 0xffff0000,
  1298. // the length of this resource is
  1299. //
  1300. // 0xffffffff - 0xffff0000 + 1
  1301. // = 0x0000ffff + 1
  1302. // = 0x00010000
  1303. //
  1304. // ie 16KB.
  1305. //
  1306. // Some devices cannot reside at the top of PCI address space. These
  1307. // devices will have adjusted the value such that length bytes are
  1308. // accomodated below the highest address. For example, if a device
  1309. // must reside below 1MB, and occupies 256 bytes, the value will now
  1310. // be 0x000fff00.
  1311. //
  1312. // In the first case, length can be calculated as-
  1313. //
  1314. Length = (0xffffffff - BaseAddressRegister) + 1;
  1315. if (((Length - 1) & Length) != 0) {
  1316. //
  1317. // We didn't end up with a power of two, must be the latter
  1318. // case, we will have to scan for it.
  1319. //
  1320. Length = 4; // start with minimum possible
  1321. while ((Length | BaseAddressRegister) != BaseAddressRegister) {
  1322. //
  1323. // Length *= 2, note we will eventually drop out of this
  1324. // loop for one of two reasons (a) because we found the
  1325. // length, or (b) because Length left shifted off the end
  1326. // and became 0.
  1327. //
  1328. Length <<= 1;
  1329. }
  1330. }
  1331. //
  1332. // Check that we got something - if this is a 64bit bar then nothing is ok as
  1333. // we might be asking for a range >= 4GB (not that that's going to work any time soon)
  1334. //
  1335. if (!((BaseAddressRegister & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) {
  1336. PCI_ASSERT(Length);
  1337. }
  1338. return Length;
  1339. }
  1340. BOOLEAN
  1341. PciCreateIoDescriptorFromBarLimit(
  1342. IN PIO_RESOURCE_DESCRIPTOR Descriptor,
  1343. IN PULONG BaseAddress,
  1344. IN BOOLEAN Rom
  1345. )
  1346. /*++
  1347. Description:
  1348. Generate an IO resource descriptor to describe the settings
  1349. a Base Address Register can take.
  1350. Arguments:
  1351. Descriptor -
  1352. BaseAddress - Pointer to the value read from a base address register
  1353. immediately after writing all ones to it.
  1354. Rom - If true, this is a base address register for ROM.
  1355. Return Value:
  1356. Returns TRUE if this address register was a 64 bit address register,
  1357. FALSE otherwise.
  1358. --*/
  1359. {
  1360. ULONG bar = *BaseAddress;
  1361. ULONG length;
  1362. ULONG addressMask;
  1363. BOOLEAN returnValue = FALSE;
  1364. //
  1365. // If the Base Address Register contains zero after being written
  1366. // with all ones, it is not implemented. Set the resource type to
  1367. // NULL, no further processing is required.
  1368. //
  1369. // Note: We ignore the I/O bit in the BAR due to HARDWARE BUGS
  1370. // in some people's hardware.
  1371. //
  1372. if ((bar & ~1) == 0) {
  1373. Descriptor->Type = CmResourceTypeNull;
  1374. return FALSE;
  1375. }
  1376. //
  1377. // Default to ordinary (32 bit) memory.
  1378. //
  1379. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  1380. Descriptor->u.Memory.MaximumAddress.HighPart = 0;
  1381. Descriptor->u.Memory.MinimumAddress.QuadPart = 0;
  1382. if (Rom == TRUE) {
  1383. //
  1384. // Mask out unused bits and indicate in the descriptor that
  1385. // this entry describes ROM.
  1386. //
  1387. bar &= PCI_ADDRESS_ROM_ADDRESS_MASK;
  1388. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  1389. }
  1390. //
  1391. // Ranges described by PCI Base Address Registers must be a
  1392. // power of 2 in length and naturally aligned. Get the length
  1393. // and set the length and alignment in the descriptor.
  1394. //
  1395. length = PciGetLengthFromBar(bar);
  1396. Descriptor->u.Generic.Length = length;
  1397. Descriptor->u.Generic.Alignment = length;
  1398. if ((bar & PCI_ADDRESS_IO_SPACE) != 0) {
  1399. //
  1400. // This BAR describes I/O space.
  1401. //
  1402. addressMask = PCI_ADDRESS_IO_ADDRESS_MASK;
  1403. Descriptor->Type = CmResourceTypePort;
  1404. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  1405. } else {
  1406. //
  1407. // This BAR describes PCI memory space.
  1408. //
  1409. addressMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  1410. Descriptor->Type = CmResourceTypeMemory;
  1411. if ((bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT) {
  1412. //
  1413. // This is a 64 bit PCI device. Get the high 32 bits
  1414. // from the next BAR.
  1415. //
  1416. Descriptor->u.Memory.MaximumAddress.HighPart = *(BaseAddress+1);
  1417. returnValue = TRUE;
  1418. } else if ((bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) {
  1419. //
  1420. // This device must locate below 1MB, the BAR shouldn't
  1421. // have any top bits set but this isn't clear from the
  1422. // spec. Enforce it by clearing the top bits.
  1423. //
  1424. addressMask &= 0x000fffff;
  1425. }
  1426. if (bar & PCI_ADDRESS_MEMORY_PREFETCHABLE) {
  1427. Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
  1428. }
  1429. }
  1430. Descriptor->u.Generic.MaximumAddress.LowPart = bar & addressMask;
  1431. Descriptor->u.Generic.MaximumAddress.QuadPart += (length - 1);
  1432. return returnValue;
  1433. }
  1434. BOOLEAN
  1435. PciOpenKey(
  1436. IN PWSTR KeyName,
  1437. IN HANDLE ParentHandle,
  1438. IN ACCESS_MASK Access,
  1439. OUT PHANDLE Handle,
  1440. OUT PNTSTATUS Status
  1441. )
  1442. /*++
  1443. Description:
  1444. Open a registry key.
  1445. Arguments:
  1446. KeyName Name of the key to be opened.
  1447. ParentHandle Pointer to the parent handle (OPTIONAL)
  1448. Handle Pointer to a handle to recieve the opened key.
  1449. Return Value:
  1450. TRUE is key successfully opened, FALSE otherwise.
  1451. --*/
  1452. {
  1453. UNICODE_STRING nameString;
  1454. OBJECT_ATTRIBUTES nameAttributes;
  1455. NTSTATUS localStatus;
  1456. PAGED_CODE();
  1457. RtlInitUnicodeString(&nameString, KeyName);
  1458. InitializeObjectAttributes(&nameAttributes,
  1459. &nameString,
  1460. OBJ_CASE_INSENSITIVE,
  1461. ParentHandle,
  1462. (PSECURITY_DESCRIPTOR)NULL
  1463. );
  1464. localStatus = ZwOpenKey(Handle,
  1465. Access,
  1466. &nameAttributes
  1467. );
  1468. if (Status != NULL) {
  1469. //
  1470. // Caller wants underlying status.
  1471. //
  1472. *Status = localStatus;
  1473. }
  1474. //
  1475. // Return status converted to a boolean, TRUE if
  1476. // successful.
  1477. //
  1478. return NT_SUCCESS(localStatus);
  1479. }
  1480. NTSTATUS
  1481. PciGetRegistryValue(
  1482. IN PWSTR ValueName,
  1483. IN PWSTR KeyName,
  1484. IN HANDLE ParentHandle,
  1485. IN ULONG Type,
  1486. OUT PVOID *Buffer,
  1487. OUT PULONG Length
  1488. )
  1489. {
  1490. NTSTATUS status;
  1491. HANDLE keyHandle = NULL;
  1492. ULONG neededLength;
  1493. ULONG actualLength;
  1494. UNICODE_STRING unicodeValueName;
  1495. PKEY_VALUE_PARTIAL_INFORMATION info = NULL;
  1496. if (!PciOpenKey(KeyName, ParentHandle, KEY_READ, &keyHandle, &status)) {
  1497. goto exit;
  1498. }
  1499. RtlInitUnicodeString(&unicodeValueName, ValueName);
  1500. //
  1501. // Find out how much memory we need for this.
  1502. //
  1503. status = ZwQueryValueKey(
  1504. keyHandle,
  1505. &unicodeValueName,
  1506. KeyValuePartialInformation,
  1507. NULL,
  1508. 0,
  1509. &neededLength
  1510. );
  1511. if (status != STATUS_BUFFER_TOO_SMALL) {
  1512. //
  1513. // Either the value doesn't exist or something else went wrong but this
  1514. // should never succeed
  1515. //
  1516. ASSERT(!(NT_SUCCESS(status)));
  1517. goto exit;
  1518. }
  1519. ASSERT(neededLength != 0);
  1520. //
  1521. // Get memory to return the data in. Note this includes
  1522. // a header that we really don't want.
  1523. //
  1524. info = ExAllocatePool(
  1525. PagedPool | POOL_COLD_ALLOCATION,
  1526. neededLength);
  1527. if (info == NULL) {
  1528. status = STATUS_INSUFFICIENT_RESOURCES;
  1529. goto exit;
  1530. }
  1531. //
  1532. // Get the data.
  1533. //
  1534. status = ZwQueryValueKey(
  1535. keyHandle,
  1536. &unicodeValueName,
  1537. KeyValuePartialInformation,
  1538. info,
  1539. neededLength,
  1540. &actualLength
  1541. );
  1542. if (!NT_SUCCESS(status)) {
  1543. goto exit;
  1544. }
  1545. //
  1546. // Make sure the data is the correcty type
  1547. //
  1548. if (info->Type != Type) {
  1549. status = STATUS_INVALID_PARAMETER;
  1550. goto exit;
  1551. }
  1552. ASSERT(neededLength == actualLength);
  1553. //
  1554. // Subtract out the header size and get memory for just
  1555. // the data we want.
  1556. //
  1557. neededLength -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  1558. *Buffer = ExAllocatePool(
  1559. PagedPool | POOL_COLD_ALLOCATION,
  1560. neededLength
  1561. );
  1562. if (*Buffer == NULL) {
  1563. status = STATUS_INSUFFICIENT_RESOURCES;
  1564. goto exit;
  1565. }
  1566. //
  1567. // Copy data sans header.
  1568. //
  1569. RtlCopyMemory(*Buffer, info->Data, neededLength);
  1570. if (Length) {
  1571. *Length = neededLength;
  1572. }
  1573. exit:
  1574. if (keyHandle) {
  1575. ZwClose(keyHandle);
  1576. }
  1577. if (info) {
  1578. ExFreePool(info);
  1579. }
  1580. return status;
  1581. }
  1582. NTSTATUS
  1583. PciGetDeviceCapabilities(
  1584. IN PDEVICE_OBJECT DeviceObject,
  1585. IN PDEVICE_CAPABILITIES DeviceCapabilities
  1586. )
  1587. /*++
  1588. Routine Description:
  1589. This routine sends the get capabilities irp to the given stack
  1590. Arguments:
  1591. DeviceObject A device object in the stack whose capabilities we want
  1592. DeviceCapabilites Where to store the answer
  1593. Return Value:
  1594. NTSTATUS
  1595. --*/
  1596. {
  1597. IO_STATUS_BLOCK ioStatus;
  1598. KEVENT pnpEvent;
  1599. NTSTATUS status;
  1600. PDEVICE_OBJECT targetObject;
  1601. PIO_STACK_LOCATION irpStack;
  1602. PIRP pnpIrp;
  1603. PAGED_CODE();
  1604. //
  1605. // Initialize the capabilities that we will send down
  1606. //
  1607. RtlZeroMemory( DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) );
  1608. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  1609. DeviceCapabilities->Version = 1;
  1610. DeviceCapabilities->Address = MAXULONG;
  1611. DeviceCapabilities->UINumber = MAXULONG;
  1612. //
  1613. // Initialize the event
  1614. //
  1615. KeInitializeEvent( &pnpEvent, SynchronizationEvent, FALSE );
  1616. //
  1617. // Get the irp that we will send the request to
  1618. //
  1619. targetObject = IoGetAttachedDeviceReference( DeviceObject );
  1620. //
  1621. // Build an Irp
  1622. //
  1623. pnpIrp = IoBuildSynchronousFsdRequest(
  1624. IRP_MJ_PNP,
  1625. targetObject,
  1626. NULL,
  1627. 0,
  1628. NULL,
  1629. &pnpEvent,
  1630. &ioStatus
  1631. );
  1632. if (pnpIrp == NULL) {
  1633. status = STATUS_INSUFFICIENT_RESOURCES;
  1634. goto PciGetDeviceCapabilitiesExit;
  1635. }
  1636. //
  1637. // Pnp Irps all begin life as STATUS_NOT_SUPPORTED;
  1638. //
  1639. pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1640. pnpIrp->IoStatus.Information = 0;
  1641. //
  1642. // Get the top of stack
  1643. //
  1644. irpStack = IoGetNextIrpStackLocation( pnpIrp );
  1645. if (irpStack == NULL) {
  1646. status = STATUS_INVALID_PARAMETER;
  1647. goto PciGetDeviceCapabilitiesExit;
  1648. }
  1649. //
  1650. // Set the top of stack
  1651. //
  1652. RtlZeroMemory( irpStack, sizeof(IO_STACK_LOCATION ) );
  1653. irpStack->MajorFunction = IRP_MJ_PNP;
  1654. irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  1655. irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;
  1656. //
  1657. // Make sure that there are no completion routines set
  1658. //
  1659. IoSetCompletionRoutine(
  1660. pnpIrp,
  1661. NULL,
  1662. NULL,
  1663. FALSE,
  1664. FALSE,
  1665. FALSE
  1666. );
  1667. //
  1668. // Call the driver
  1669. //
  1670. status = IoCallDriver( targetObject, pnpIrp );
  1671. if (status == STATUS_PENDING) {
  1672. //
  1673. // Block until the irp comes back
  1674. //
  1675. KeWaitForSingleObject(
  1676. &pnpEvent,
  1677. Executive,
  1678. KernelMode,
  1679. FALSE,
  1680. NULL
  1681. );
  1682. status = ioStatus.Status;
  1683. }
  1684. PciGetDeviceCapabilitiesExit:
  1685. //
  1686. // Done with reference
  1687. //
  1688. ObDereferenceObject( targetObject );
  1689. //
  1690. // Done
  1691. //
  1692. return status;
  1693. }
  1694. ULONGLONG
  1695. PciGetHackFlags(
  1696. IN USHORT VendorID,
  1697. IN USHORT DeviceID,
  1698. IN USHORT SubVendorID,
  1699. IN USHORT SubSystemID,
  1700. IN UCHAR RevisionID
  1701. )
  1702. /*++
  1703. Description:
  1704. Look in the registry for any flags for this VendorId/DeviceId.
  1705. Arguments:
  1706. VendorId PCI Vendor ID (16 bits) of the manufacturer of the
  1707. device.
  1708. DeviceId PCI Device ID (16 bits) of the device.
  1709. SubVendorID PCI SubVendorID representing the manufacturer of the
  1710. subsystem
  1711. SubSystemID PCI SubSystemID representing subsystem
  1712. RevisionID PCI Revision denoting the revision of the device
  1713. Return Value:
  1714. 64 bit flags value or 0 if not found.
  1715. --*/
  1716. {
  1717. PPCI_HACK_TABLE_ENTRY current;
  1718. ULONGLONG hackFlags = 0;
  1719. ULONG match, bestMatch = 0;
  1720. PCI_ASSERT(PciHackTable);
  1721. //
  1722. // We want to do a best-case match:
  1723. // VVVVDDDDSSSSssssRR
  1724. // VVVVDDDDSSSSssss
  1725. // VVVVDDDDRR
  1726. // VVVVDDDD
  1727. //
  1728. // List is currently unsorted, so keep updating current best match.
  1729. //
  1730. for (current = PciHackTable; current->VendorID != 0xFFFF; current++) {
  1731. match = 0;
  1732. //
  1733. // Must at least match vendor/dev
  1734. //
  1735. if ((current->DeviceID != DeviceID) ||
  1736. (current->VendorID != VendorID)) {
  1737. continue;
  1738. }
  1739. match = 1;
  1740. //
  1741. // If this entry specifies a revision, check that it is consistent.
  1742. //
  1743. if (current->Flags & PCI_HACK_FLAG_REVISION) {
  1744. if (current->RevisionID == RevisionID) {
  1745. match += 2;
  1746. } else {
  1747. continue;
  1748. }
  1749. }
  1750. //
  1751. // If this entry specifies subsystems, check that they are consistent
  1752. //
  1753. if (current->Flags & PCI_HACK_FLAG_SUBSYSTEM) {
  1754. if (current->SubVendorID == SubVendorID &&
  1755. current->SubSystemID == SubSystemID) {
  1756. match += 4;
  1757. } else {
  1758. continue;
  1759. }
  1760. }
  1761. if (match > bestMatch) {
  1762. bestMatch = match;
  1763. hackFlags = current->HackFlags;
  1764. }
  1765. }
  1766. return hackFlags;
  1767. }
  1768. NTSTATUS
  1769. PciGetDeviceProperty(
  1770. IN PDEVICE_OBJECT PhysicalDeviceObject,
  1771. IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
  1772. OUT PVOID *PropertyBuffer
  1773. )
  1774. {
  1775. NTSTATUS status;
  1776. NTSTATUS expected;
  1777. ULONG length;
  1778. ULONG length2;
  1779. PVOID buffer;
  1780. //
  1781. // Two passes, first pass, find out what size buffer
  1782. // is needed.
  1783. //
  1784. status = IoGetDeviceProperty(
  1785. PhysicalDeviceObject,
  1786. DeviceProperty,
  1787. 0,
  1788. NULL,
  1789. &length
  1790. );
  1791. expected = STATUS_BUFFER_TOO_SMALL;
  1792. if (status == expected) {
  1793. //
  1794. // Good, now get a buffer.
  1795. //
  1796. buffer = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, length);
  1797. if (buffer == NULL) {
  1798. PciDebugPrint(
  1799. PciDbgAlways,
  1800. "PCI - Failed to allocate DeviceProperty buffer (%d bytes).\n",
  1801. length
  1802. );
  1803. status = STATUS_INSUFFICIENT_RESOURCES;
  1804. } else {
  1805. //
  1806. // This time, do it for real.
  1807. //
  1808. status = IoGetDeviceProperty(
  1809. PhysicalDeviceObject,
  1810. DeviceProperty,
  1811. length,
  1812. buffer,
  1813. &length2
  1814. );
  1815. if (NT_SUCCESS(status)) {
  1816. PCI_ASSERT(length == length2);
  1817. //
  1818. // Return the buffer containing the requested device
  1819. // property to the caller.
  1820. //
  1821. *PropertyBuffer = buffer;
  1822. return STATUS_SUCCESS;
  1823. }
  1824. expected = STATUS_SUCCESS;
  1825. }
  1826. }
  1827. PciDebugPrint(
  1828. PciDbgAlways,
  1829. "PCI - Unexpected status from GetDeviceProperty, saw %08X, expected %08X.\n",
  1830. status,
  1831. expected
  1832. );
  1833. //
  1834. // Clear the caller's buffer pointer, and, if the unexpected status
  1835. // is success (from the first call to IoGetDeviceProperty) change it
  1836. // to STATUS_UNSUCCESSFUL (N.B. This is if course impossible).
  1837. //
  1838. *PropertyBuffer = NULL;
  1839. if (status == STATUS_SUCCESS) {
  1840. PCI_ASSERTMSG("PCI Successfully did the impossible!", 0);
  1841. status = STATUS_UNSUCCESSFUL;
  1842. }
  1843. return status;
  1844. }
  1845. NTSTATUS
  1846. PciRangeListFromResourceList(
  1847. IN PPCI_FDO_EXTENSION FdoExtension,
  1848. IN PCM_RESOURCE_LIST ResourceList,
  1849. IN CM_RESOURCE_TYPE DesiredType,
  1850. IN BOOLEAN Complement,
  1851. IN PRTL_RANGE_LIST ResultRange
  1852. )
  1853. /*++
  1854. Description:
  1855. Generates a range list for the resources of a given type
  1856. from a resource list.
  1857. Note: This routine supports only Memory or Io resources.
  1858. Overlapping ranges in the incoming list will be combined.
  1859. Arguments:
  1860. FdoExtension Bus particulars. NOTE: This is only needed for the
  1861. gross X86 hack for A0000 due to buggy MPS BIOS
  1862. implementations. Otherwise this routine is more
  1863. generalized.
  1864. ResourceList Incoming CM Resource List.
  1865. DesiredType Type of resource to be included in the range list.
  1866. Complement Specifies wether or not the range list should be
  1867. the "complement" of the incoming data.
  1868. ResultRange Output range list.
  1869. Return Value:
  1870. TRUE is key successfully opened, FALSE otherwise.
  1871. --*/
  1872. {
  1873. #define EXIT_IF_ERROR(status) \
  1874. if (!NT_SUCCESS(status)) { \
  1875. PCI_ASSERT(NT_SUCCESS(status)); \
  1876. goto exitPoint; \
  1877. }
  1878. #if DBG
  1879. #define ADD_RANGE(range, start, end, status) \
  1880. PciDebugPrint( \
  1881. PciDbgObnoxious, \
  1882. " Adding to RtlRange %I64x thru %I64x\n", \
  1883. (ULONGLONG)start, \
  1884. (ULONGLONG)end \
  1885. ); \
  1886. status = RtlAddRange(range, start, end, 0, 0, NULL, NULL); \
  1887. if (!NT_SUCCESS(status)) { \
  1888. PCI_ASSERT(NT_SUCCESS(status)); \
  1889. goto exitPoint; \
  1890. }
  1891. #else
  1892. #define ADD_RANGE(range, start, end, status) \
  1893. status = RtlAddRange(range, start, end, 0, 0, NULL, NULL); \
  1894. if (!NT_SUCCESS(status)) { \
  1895. PCI_ASSERT(NT_SUCCESS(status)); \
  1896. goto exitPoint; \
  1897. }
  1898. #endif
  1899. NTSTATUS status;
  1900. ULONG elementCount;
  1901. ULONG count;
  1902. ULONG numlists;
  1903. PCM_FULL_RESOURCE_DESCRIPTOR full = NULL;
  1904. PCM_PARTIAL_RESOURCE_LIST partial = NULL;
  1905. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor = NULL;
  1906. typedef struct {
  1907. LIST_ENTRY list;
  1908. ULONGLONG start;
  1909. ULONGLONG end;
  1910. BOOLEAN valid;
  1911. } PCI_RANGE_LIST_ELEMENT, *PPCI_RANGE_LIST_ELEMENT;
  1912. PPCI_RANGE_LIST_ELEMENT elementBuffer;
  1913. PPCI_RANGE_LIST_ELEMENT upper;
  1914. PPCI_RANGE_LIST_ELEMENT lower = NULL;
  1915. PPCI_RANGE_LIST_ELEMENT current;
  1916. ULONG allocatedElement;
  1917. ULONGLONG start;
  1918. ULONGLONG end;
  1919. #if defined(_X86_) && defined(PCI_NT50_BETA1_HACKS)
  1920. //
  1921. // BETA1_HACKS - Remove this when the problem is fixed.
  1922. //
  1923. // HACK HACK some MPS BIOS implementations don't report the
  1924. // memory range 0xA0000 thru 0xBFFFF. They should. HACK
  1925. // them into the memory list. Gross.
  1926. // Even grosser, assume this applies only to bus 0.
  1927. //
  1928. // The 400 hack is because some cards (Matrox MGA) want access
  1929. // to the SYSTEM BIOS DATA area which is in memory at address
  1930. // 0x400 thru 0x4ff. It's not on the BUS so why are we making
  1931. // it appear here?
  1932. //
  1933. // Note, there is TWO hacks here but we do both under the
  1934. // exact same condition so we have only one boolean. If the
  1935. // two are seperated (or one removed) this needs to be split.
  1936. //
  1937. BOOLEAN doA0000Hack = (DesiredType == CmResourceTypeMemory) &&
  1938. (FdoExtension && (FdoExtension->BaseBus == 0));
  1939. #else
  1940. #endif
  1941. PAGED_CODE();
  1942. PCI_ASSERT((DesiredType == CmResourceTypeMemory) ||
  1943. (DesiredType == CmResourceTypePort));
  1944. //
  1945. // First, get a count of the number of resources of the desired
  1946. // type in the list. This gives us the maximum number of entries
  1947. // in the resulting list.
  1948. //
  1949. // Plus 1 in case we're complementing it. 2 actually, we start
  1950. // with a beginning and end entry.
  1951. //
  1952. elementCount = 2;
  1953. numlists = 0;
  1954. if (ResourceList != NULL) {
  1955. numlists = ResourceList->Count;
  1956. full = ResourceList->List;
  1957. }
  1958. while (numlists--) {
  1959. partial = &full->PartialResourceList;
  1960. count = partial->Count;
  1961. descriptor = partial->PartialDescriptors;
  1962. while (count--) {
  1963. if (descriptor->Type == DesiredType) {
  1964. if (DesiredType == CmResourceTypePort) {
  1965. if (descriptor->Flags & CM_RESOURCE_PORT_10_BIT_DECODE) {
  1966. elementCount += ((1 << 16) / (1 << 10)) - 1;
  1967. } else if (descriptor->Flags & CM_RESOURCE_PORT_12_BIT_DECODE) {
  1968. elementCount += ((1 << 16) / (1 << 12)) - 1;
  1969. }
  1970. }
  1971. elementCount++;
  1972. }
  1973. descriptor = PciNextPartialDescriptor(descriptor);
  1974. }
  1975. full = (PCM_FULL_RESOURCE_DESCRIPTOR)descriptor;
  1976. }
  1977. PciDebugPrint(
  1978. PciDbgObnoxious,
  1979. "PCI - PciRangeListFromResourceList processing %d elements.\n",
  1980. elementCount - 2
  1981. );
  1982. #if defined(_X86_) && defined(PCI_NT50_BETA1_HACKS)
  1983. if (doA0000Hack) {
  1984. elementCount += 3; // one for A0000 hack, one for 400 hack. + 1 for 70
  1985. }
  1986. #endif
  1987. //
  1988. // Allocate list entries and initialize the list.
  1989. //
  1990. elementBuffer = ExAllocatePool(
  1991. PagedPool | POOL_COLD_ALLOCATION,
  1992. elementCount * sizeof(PCI_RANGE_LIST_ELEMENT)
  1993. );
  1994. if (elementBuffer == NULL) {
  1995. return STATUS_INSUFFICIENT_RESOURCES;
  1996. }
  1997. //
  1998. // Take the first two entries and set them to the absolute minimum
  1999. // and absolute maximum possible values. Everything else will
  2000. // either end up between these or be combined with them.
  2001. //
  2002. // Setting the terminators this way should avoid us having to check
  2003. // for end conditions.
  2004. //
  2005. allocatedElement = 2;
  2006. current = &elementBuffer[1];
  2007. // first element (list min terminator)
  2008. elementBuffer[1].start = elementBuffer[1].end = 0;
  2009. elementBuffer[1].list.Flink = &elementBuffer[0].list;
  2010. elementBuffer[1].list.Blink = &elementBuffer[0].list;
  2011. elementBuffer[1].valid = FALSE;
  2012. // last element (list max terminator)
  2013. elementBuffer[0].start = elementBuffer[0].end = MAXULONGLONG;
  2014. elementBuffer[0].list.Flink = &elementBuffer[1].list;
  2015. elementBuffer[0].list.Blink = &elementBuffer[1].list;
  2016. elementBuffer[0].valid = FALSE;
  2017. #if defined(_X86_) && defined(PCI_NT50_BETA1_HACKS)
  2018. if (doA0000Hack) {
  2019. //
  2020. // Hack in A0000 thru FFFFF by just adding an entry for it
  2021. // to the otherwise empty list.
  2022. //
  2023. // Hack in 400 thru 4ff too.
  2024. //
  2025. PLIST_ENTRY minEntry = &elementBuffer[1].list;
  2026. PLIST_ENTRY maxEntry = &elementBuffer[0].list;
  2027. allocatedElement = 5;
  2028. elementBuffer[2].start = 0x70; // HACK Trident
  2029. elementBuffer[2].end = 0x70;
  2030. elementBuffer[2].valid = TRUE;
  2031. elementBuffer[3].start = 0x400; // HACK Matrox MGA
  2032. elementBuffer[3].end = 0x4FF;
  2033. elementBuffer[3].valid = TRUE;
  2034. elementBuffer[4].start = 0xA0000; // HACK broken MPS BIOS
  2035. elementBuffer[4].end = 0xBFFFF;
  2036. elementBuffer[4].valid = TRUE;
  2037. // set the flinks
  2038. minEntry->Flink = &elementBuffer[2].list;
  2039. elementBuffer[2].list.Flink = &elementBuffer[3].list;
  2040. elementBuffer[3].list.Flink = &elementBuffer[4].list;
  2041. elementBuffer[4].list.Flink = maxEntry;
  2042. // set the blinks
  2043. elementBuffer[2].list.Blink = minEntry;
  2044. elementBuffer[3].list.Blink = &elementBuffer[2].list;
  2045. elementBuffer[4].list.Blink = &elementBuffer[3].list;
  2046. maxEntry->Blink = &elementBuffer[4].list;
  2047. #if DBG
  2048. {
  2049. PPCI_RANGE_LIST_ELEMENT tempElement;
  2050. tempElement = CONTAINING_RECORD(
  2051. minEntry,
  2052. PCI_RANGE_LIST_ELEMENT,
  2053. list
  2054. );
  2055. PciDebugPrint(
  2056. PciDbgObnoxious,
  2057. " === PCI added default initial ranges ===\n"
  2058. );
  2059. do {
  2060. //
  2061. // Print this entry if it is valid.
  2062. //
  2063. if (tempElement->valid == TRUE) {
  2064. PciDebugPrint(
  2065. PciDbgObnoxious,
  2066. " %I64x .. %I64x\n",
  2067. tempElement->start,
  2068. tempElement->end
  2069. );
  2070. }
  2071. //
  2072. // Next entry.
  2073. //
  2074. if (tempElement->list.Flink == minEntry) {
  2075. break;
  2076. }
  2077. tempElement = CONTAINING_RECORD(
  2078. tempElement->list.Flink,
  2079. PCI_RANGE_LIST_ELEMENT,
  2080. list
  2081. );
  2082. } while (TRUE);
  2083. PciDebugPrint(
  2084. PciDbgObnoxious,
  2085. " === end added default initial ranges ===\n"
  2086. );
  2087. }
  2088. #endif
  2089. }
  2090. #endif
  2091. //
  2092. // Starting again at the beginning of the resource list, extract
  2093. // the desired resources and insert them in our new list.
  2094. //
  2095. numlists = 0;
  2096. if (ResourceList != NULL) {
  2097. full = ResourceList->List;
  2098. numlists = ResourceList->Count;
  2099. }
  2100. while (numlists--) {
  2101. LIST_CONTEXT listContext;
  2102. PcipInitializePartialListContext(
  2103. &listContext,
  2104. &full->PartialResourceList,
  2105. DesiredType
  2106. );
  2107. while ((descriptor = PcipGetNextRangeFromList(&listContext)) != NULL) {
  2108. PCI_ASSERT(descriptor->Type == DesiredType);
  2109. //
  2110. // insert this element into the list.
  2111. //
  2112. start = (ULONGLONG)descriptor->u.Generic.Start.QuadPart;
  2113. end = start - 1 + descriptor->u.Generic.Length;
  2114. //
  2115. // First find the element to the left of this one
  2116. // (below it).
  2117. //
  2118. lower = current;
  2119. //
  2120. // Just in case we actually need to go right,...
  2121. //
  2122. while (start > lower->end) {
  2123. lower = CONTAINING_RECORD(
  2124. lower->list.Flink,
  2125. PCI_RANGE_LIST_ELEMENT,
  2126. list
  2127. );
  2128. }
  2129. //
  2130. // Search left.
  2131. //
  2132. while (start <= lower->end) {
  2133. if (start >= lower->start) {
  2134. break;
  2135. }
  2136. //
  2137. // Go left.
  2138. //
  2139. lower = CONTAINING_RECORD(
  2140. lower->list.Blink,
  2141. PCI_RANGE_LIST_ELEMENT,
  2142. list
  2143. );
  2144. }
  2145. //
  2146. // Early out if the lower entry completely
  2147. // covers the new entry.
  2148. //
  2149. if ((start >= lower->start) && (end <= lower->end)) {
  2150. //
  2151. // It does, just skip it.
  2152. //
  2153. PciDebugPrint(
  2154. PciDbgObnoxious,
  2155. " -- (%I64x .. %I64x) swallows (%I64x .. %I64x)\n",
  2156. lower->start,
  2157. lower->end,
  2158. start,
  2159. end
  2160. );
  2161. current = lower;
  2162. current->valid = TRUE;
  2163. continue;
  2164. }
  2165. //
  2166. // Then, the one above it.
  2167. //
  2168. upper = lower;
  2169. while (end > upper->start) {
  2170. if (end <= upper->end) {
  2171. break;
  2172. }
  2173. //
  2174. // Go right.
  2175. //
  2176. upper = CONTAINING_RECORD(
  2177. upper->list.Flink,
  2178. PCI_RANGE_LIST_ELEMENT,
  2179. list
  2180. );
  2181. }
  2182. current = &elementBuffer[allocatedElement++];
  2183. current->start = start;
  2184. current->end = end;
  2185. current->valid = TRUE;
  2186. PciDebugPrint(
  2187. PciDbgObnoxious,
  2188. " (%I64x .. %I64x) <= (%I64x .. %I64x) <= (%I64x .. %I64x)\n",
  2189. lower->start,
  2190. lower->end,
  2191. start,
  2192. end,
  2193. upper->start,
  2194. upper->end
  2195. );
  2196. //
  2197. // We now have, the element below this one, possibly
  2198. // overlapping, the element above this one, possibly
  2199. // overlapping, and a new one.
  2200. //
  2201. // The easiest way to deal with this is to create
  2202. // the new entry, link it in, then unlink the overlaps
  2203. // if they exist.
  2204. //
  2205. //
  2206. // Note: The new entry may overlap several entries,
  2207. // these are orphaned.
  2208. //
  2209. // Link it in.
  2210. //
  2211. current->list.Flink = &upper->list;
  2212. current->list.Blink = &lower->list;
  2213. upper->list.Blink = &current->list;
  2214. lower->list.Flink = &current->list;
  2215. //
  2216. // Check for lower overlap.
  2217. //
  2218. if ((lower->valid == TRUE) && (start > 0)) {
  2219. start--;
  2220. }
  2221. if (lower->end >= start) {
  2222. //
  2223. // Overlaps from below,...
  2224. //
  2225. // Merge lower into current.
  2226. //
  2227. current->start = lower->start;
  2228. current->list.Blink = lower->list.Blink;
  2229. //
  2230. //
  2231. // lower is being orphaned, reuse it to get to
  2232. // our new lower neighbor.
  2233. //
  2234. lower = CONTAINING_RECORD(
  2235. lower->list.Blink,
  2236. PCI_RANGE_LIST_ELEMENT,
  2237. list
  2238. );
  2239. lower->list.Flink = &current->list;
  2240. PciDebugPrint(
  2241. PciDbgObnoxious,
  2242. " -- Overlaps lower, merged to (%I64x .. %I64x)\n",
  2243. current->start,
  2244. current->end
  2245. );
  2246. }
  2247. //
  2248. // Check for upper overlap.
  2249. //
  2250. if ((upper->valid == TRUE) && (end < MAXULONGLONG)) {
  2251. end++;
  2252. }
  2253. if ((end >= upper->start) && (current != upper)) {
  2254. //
  2255. // Overlaps above,... merge upper into current.
  2256. //
  2257. current->end = upper->end;
  2258. current->list.Flink = upper->list.Flink;
  2259. //
  2260. // upper is being orphaned, reuse it to get to
  2261. // our new upper neighbor.
  2262. //
  2263. upper = CONTAINING_RECORD(
  2264. upper->list.Flink,
  2265. PCI_RANGE_LIST_ELEMENT,
  2266. list
  2267. );
  2268. upper->list.Blink = &current->list;
  2269. PciDebugPrint(
  2270. PciDbgObnoxious,
  2271. " -- Overlaps upper, merged to (%I64x .. %I64x)\n",
  2272. current->start,
  2273. current->end
  2274. );
  2275. }
  2276. }
  2277. full = (PCM_FULL_RESOURCE_DESCRIPTOR)listContext.Next;
  2278. }
  2279. //
  2280. // Find the lowest value.
  2281. //
  2282. while (current->valid == TRUE) {
  2283. lower = CONTAINING_RECORD(
  2284. current->list.Blink,
  2285. PCI_RANGE_LIST_ELEMENT,
  2286. list
  2287. );
  2288. if ((lower->valid == FALSE) ||
  2289. (lower->start > current->start)) {
  2290. break;
  2291. }
  2292. current = lower;
  2293. }
  2294. #if DBG
  2295. lower = current;
  2296. if (current->valid == FALSE) {
  2297. PciDebugPrint(
  2298. PciDbgObnoxious,
  2299. " ==== No ranges in results list. ====\n"
  2300. );
  2301. } else {
  2302. PciDebugPrint(
  2303. PciDbgObnoxious,
  2304. " === ranges ===\n"
  2305. );
  2306. do {
  2307. if (current->valid == TRUE) {
  2308. PciDebugPrint(
  2309. PciDbgObnoxious,
  2310. " %I64x .. %I64x\n",
  2311. current->start,
  2312. current->end
  2313. );
  2314. }
  2315. //
  2316. // Next entry.
  2317. //
  2318. current = CONTAINING_RECORD(
  2319. current->list.Flink,
  2320. PCI_RANGE_LIST_ELEMENT,
  2321. list
  2322. );
  2323. } while (current != lower);
  2324. }
  2325. #endif
  2326. if (Complement == TRUE) {
  2327. //
  2328. // Invert the list.
  2329. //
  2330. // The generation of the list always results in the orphaning
  2331. // of elementBuffer[1] (which was the original start point),
  2332. // we can use that one for the first element of the new
  2333. // inverted list.
  2334. //
  2335. if (current->valid == FALSE) {
  2336. //
  2337. // Empty list, complement it you get everything.
  2338. //
  2339. ADD_RANGE(ResultRange, 0, MAXULONGLONG, status);
  2340. } else {
  2341. //
  2342. // If the original range doesn't start at zero we must
  2343. // generate an entry from 0 to the start of that range.
  2344. //
  2345. if (current->start != 0) {
  2346. ADD_RANGE(ResultRange, 0, current->start - 1, status);
  2347. }
  2348. //
  2349. // Run the list greating range list entries for the
  2350. // gaps between entries in this list.
  2351. //
  2352. do {
  2353. PPCI_RANGE_LIST_ELEMENT next = CONTAINING_RECORD(
  2354. current->list.Flink,
  2355. PCI_RANGE_LIST_ELEMENT,
  2356. list
  2357. );
  2358. if (current->valid == TRUE) {
  2359. start = current->end + 1;
  2360. end = next->start - 1;
  2361. if ((end < start) || (next == elementBuffer)) {
  2362. end = MAXULONGLONG;
  2363. }
  2364. ADD_RANGE(ResultRange, start, end, status);
  2365. }
  2366. //
  2367. // Next entry.
  2368. //
  2369. current = next;
  2370. } while (current != lower);
  2371. }
  2372. } else {
  2373. //
  2374. // Not complementing,... add a range for each member of the
  2375. // list.
  2376. //
  2377. if (current->valid == TRUE) {
  2378. do {
  2379. ADD_RANGE(ResultRange, current->start, current->end, status);
  2380. //
  2381. // Next entry.
  2382. //
  2383. current = CONTAINING_RECORD(
  2384. current->list.Flink,
  2385. PCI_RANGE_LIST_ELEMENT,
  2386. list
  2387. );
  2388. } while (current != lower);
  2389. }
  2390. }
  2391. status = STATUS_SUCCESS;
  2392. exitPoint:
  2393. ExFreePool(elementBuffer);
  2394. return status;
  2395. #undef EXIT_IF_ERROR
  2396. }
  2397. UCHAR
  2398. PciReadDeviceCapability(
  2399. IN PPCI_PDO_EXTENSION PdoExtension,
  2400. IN UCHAR Offset,
  2401. IN UCHAR Id,
  2402. IN OUT PVOID Buffer,
  2403. IN ULONG Length
  2404. )
  2405. /*++
  2406. Description:
  2407. Searches configuration space for the PCI Capabilities structure
  2408. identified by Id. Begins at offset Offset in PCI config space.
  2409. Arguments:
  2410. PdoExtension Pointer to the PDO Extension for this device.
  2411. Offset Offset into PCI config space to begin traversing
  2412. the capabilities list.
  2413. Id Capabilities ID. (0 if want to match any).
  2414. Buffer Pointer to the buffer where the capabilities
  2415. structure is to be returned (includes capabilities
  2416. header).
  2417. Length Number of bytes wanted (must be at least large
  2418. enough to contain the header).
  2419. Return Value:
  2420. Returns the Offset in PCI config space at which the capability
  2421. was found or 0 if not found.
  2422. --*/
  2423. {
  2424. PPCI_CAPABILITIES_HEADER capHeader;
  2425. UCHAR loopCount = 0;
  2426. capHeader = (PPCI_CAPABILITIES_HEADER)Buffer;
  2427. //
  2428. // In case the caller is running the list, check if we got
  2429. // handed the list end.
  2430. //
  2431. if (Offset == 0) {
  2432. return 0;
  2433. }
  2434. ASSERT_PCI_PDO_EXTENSION(PdoExtension);
  2435. PCI_ASSERT(PdoExtension->CapabilitiesPtr != 0);
  2436. PCI_ASSERT(Buffer);
  2437. PCI_ASSERT(Length >= sizeof(PCI_CAPABILITIES_HEADER));
  2438. do {
  2439. //
  2440. // Catch case where the device has been powered off. (Reads
  2441. // from a powered off device return FF,... allowing also for
  2442. // the case where the device is just broken).
  2443. //
  2444. if ((Offset < PCI_COMMON_HDR_LENGTH) ||
  2445. ((Offset & 0x3) != 0)) {
  2446. PCI_ASSERT((Offset >= PCI_COMMON_HDR_LENGTH) && ((Offset & 0x3) == 0));
  2447. return 0;
  2448. }
  2449. PciReadDeviceConfig(
  2450. PdoExtension,
  2451. Buffer,
  2452. Offset,
  2453. sizeof(PCI_CAPABILITIES_HEADER)
  2454. );
  2455. //
  2456. // Check if this capability is the one we want (or if we want
  2457. // ALL capability structures).
  2458. //
  2459. // NOTE: Intel 21554 non-transparent P2P bridge has a VPD
  2460. // capability that has the Chassis capability id. Needs to be
  2461. // handled here in the future. Maybe fixed in later revisions.
  2462. //
  2463. if ((capHeader->CapabilityID == Id) || (Id == 0)) {
  2464. break;
  2465. }
  2466. Offset = capHeader->Next;
  2467. //
  2468. // One more check for broken h/w. Make sure we're not
  2469. // traversing a circular list. A Capabilities header
  2470. // cannot be in the common header and must be DWORD aligned
  2471. // in config space so there can only be (256-64)/4 of them.
  2472. //
  2473. if (++loopCount > ((256-64)/4)) {
  2474. PciDebugPrint(
  2475. PciDbgAlways,
  2476. "PCI device %p capabilities list is broken.\n",
  2477. PdoExtension
  2478. );
  2479. return 0;
  2480. }
  2481. } while (Offset != 0);
  2482. //
  2483. // If we found a match and we haven't read all the data, get the
  2484. // remainder.
  2485. //
  2486. if ((Offset != 0) && (Length > sizeof(PCI_CAPABILITIES_HEADER))) {
  2487. if (Length > (sizeof(PCI_COMMON_CONFIG) - Offset)) {
  2488. //
  2489. // If we are too close to the end of config space to
  2490. // return the amount of data the caller requested,
  2491. // truncate.
  2492. //
  2493. // Worst case truncation will be to 4 bytes so no need
  2494. // to check we have data to read (again).
  2495. //
  2496. PCI_ASSERT(Length <= (sizeof(PCI_COMMON_CONFIG) - Offset));
  2497. Length = sizeof(PCI_COMMON_CONFIG) - Offset;
  2498. }
  2499. //
  2500. // Read remainder.
  2501. //
  2502. Length -= sizeof(PCI_CAPABILITIES_HEADER);
  2503. PciReadDeviceConfig(
  2504. PdoExtension,
  2505. capHeader + 1,
  2506. Offset + sizeof(PCI_CAPABILITIES_HEADER),
  2507. Length
  2508. );
  2509. }
  2510. return Offset;
  2511. }
  2512. BOOLEAN
  2513. PciIsCriticalDeviceClass(
  2514. IN UCHAR BaseClass,
  2515. IN UCHAR SubClass
  2516. )
  2517. /*++
  2518. Routine Description:
  2519. Checks to see if a given class/subclass pair identifies a
  2520. "critical" device class, that is, a class of devices that
  2521. cannot be turned off at any time during boot (not to probe
  2522. the BARs, etc) without risking a crash.
  2523. Arguments:
  2524. BaseClass - the PCI class code to check.
  2525. SubClass - the subclass within BaseClass to check.
  2526. Return Value:
  2527. TRUE if the class/subclass pair is critical
  2528. FALSE otherwise
  2529. --*/
  2530. {
  2531. //
  2532. // Interrupt controllers are critical system devices and
  2533. // must be treated very specially. They cannot be turned
  2534. // off without stopping all traffic in the system, but
  2535. // they can't be left alone either.
  2536. //
  2537. if ((BaseClass == PCI_CLASS_BASE_SYSTEM_DEV) &&
  2538. (SubClass == PCI_SUBCLASS_SYS_INTERRUPT_CTLR)) {
  2539. return TRUE;
  2540. }
  2541. //
  2542. // Video cards are critical because vga writes to the
  2543. // video card during boot in parallel with PnP enumeration
  2544. // of the video card. It doesn't know if/when PnP tries
  2545. // to turn off the card for enumeration.
  2546. //
  2547. if (BaseClass == PCI_CLASS_DISPLAY_CTLR) {
  2548. return TRUE;
  2549. }
  2550. return FALSE;
  2551. }
  2552. BOOLEAN
  2553. PciCanDisableDecodes(
  2554. IN PPCI_PDO_EXTENSION PdoExtension OPTIONAL,
  2555. IN PPCI_COMMON_CONFIG Config OPTIONAL,
  2556. IN ULONGLONG HackFlags,
  2557. IN ULONG Flags
  2558. )
  2559. // N.B. - not paged so we can power down at dispatch level
  2560. {
  2561. UCHAR baseClass;
  2562. UCHAR subClass;
  2563. BOOLEAN canDisableVideoDecodes;
  2564. canDisableVideoDecodes = (Flags & PCI_CAN_DISABLE_VIDEO_DECODES) == PCI_CAN_DISABLE_VIDEO_DECODES;
  2565. if (ARGUMENT_PRESENT(PdoExtension)) {
  2566. PCI_ASSERT(HackFlags == 0);
  2567. HackFlags = PdoExtension->HackFlags;
  2568. baseClass = PdoExtension->BaseClass;
  2569. subClass = PdoExtension->SubClass;
  2570. } else {
  2571. PCI_ASSERT(ARGUMENT_PRESENT(Config));
  2572. baseClass = Config->BaseClass;
  2573. subClass = Config->SubClass;
  2574. }
  2575. if (HackFlags & PCI_HACK_PRESERVE_COMMAND) {
  2576. //
  2577. // Bad things happen if we touch this device's command
  2578. // register, leave it alone.
  2579. //
  2580. return FALSE;
  2581. }
  2582. if (HackFlags & PCI_HACK_CB_SHARE_CMD_BITS) {
  2583. //
  2584. // This is a multifunction cardbus controller with a shared
  2585. // command register. Never turn of any of the functions because it has
  2586. // the unfortunate side effect of turning of all of them!
  2587. //
  2588. // NTRAID #62672 - 4/25/2000 - andrewth
  2589. // We should probably ensure that the windows for all functions
  2590. // are closed on all functions before enabling any of them...
  2591. //
  2592. //
  2593. return FALSE;
  2594. }
  2595. if (HackFlags & PCI_HACK_NO_DISABLE_DECODES) {
  2596. //
  2597. // If we disable the decodes on this device bad things happen
  2598. //
  2599. return FALSE;
  2600. }
  2601. //
  2602. // If this is a video device then don't allow the decodes to be disabled unless
  2603. // we are allowed to...
  2604. //
  2605. if ((baseClass == PCI_CLASS_DISPLAY_CTLR && subClass == PCI_SUBCLASS_VID_VGA_CTLR)
  2606. || (baseClass == PCI_CLASS_PRE_20 && subClass == PCI_SUBCLASS_PRE_20_VGA)) {
  2607. return canDisableVideoDecodes;
  2608. }
  2609. //
  2610. // There are various things in the world we shouldn't turn off.
  2611. // The system is quite possibly unable to recover if we do, so
  2612. // don't (just pretend).
  2613. //
  2614. switch (baseClass) {
  2615. case PCI_CLASS_BRIDGE_DEV:
  2616. //
  2617. // Bad things happen if we turn off the HOST bridge (the
  2618. // system doesn't understand that this device, which is
  2619. // on a PCI bus, is actually the parent of that PCI bus),
  2620. // or ISA/EISA/MCA bridges under which are devices we still
  2621. // need to have working but are legacy detected so not in
  2622. // the heirachy in any way we understand.
  2623. //
  2624. if ((subClass == PCI_SUBCLASS_BR_ISA ) ||
  2625. (subClass == PCI_SUBCLASS_BR_EISA) ||
  2626. (subClass == PCI_SUBCLASS_BR_MCA) ||
  2627. (subClass == PCI_SUBCLASS_BR_HOST) ||
  2628. (subClass == PCI_SUBCLASS_BR_OTHER)) {
  2629. return FALSE;
  2630. }
  2631. //
  2632. // We don't want to turn off bridges that might have the VGA card behind
  2633. // then otherwise video stops working. Seeing as we can't actually tell
  2634. // where the VGA card is use the hint that if the bridge is passing VGA
  2635. // ranges the video card is probably somewhere down there.
  2636. //
  2637. if (subClass == PCI_SUBCLASS_BR_PCI_TO_PCI
  2638. || subClass == PCI_SUBCLASS_BR_CARDBUS) {
  2639. BOOLEAN vgaBitSet;
  2640. if (ARGUMENT_PRESENT(PdoExtension)) {
  2641. vgaBitSet = PdoExtension->Dependent.type1.VgaBitSet;
  2642. } else {
  2643. vgaBitSet = (Config->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) != 0;
  2644. }
  2645. if (vgaBitSet) {
  2646. //
  2647. // We can disable the video path if we are powering down the machine
  2648. //
  2649. return canDisableVideoDecodes;
  2650. }
  2651. }
  2652. break;
  2653. case PCI_CLASS_DISPLAY_CTLR:
  2654. //
  2655. // If a video driver fails to start, the device reverts back to being
  2656. // VGA if it is the VGA device. Don't disable the decodes on VGA
  2657. // devices.
  2658. //
  2659. if (subClass == PCI_SUBCLASS_VID_VGA_CTLR) {
  2660. //
  2661. // We can disable the video path if we are powering down the machine
  2662. //
  2663. return canDisableVideoDecodes;
  2664. }
  2665. break;
  2666. case PCI_CLASS_PRE_20:
  2667. //
  2668. // Same as above.
  2669. //
  2670. if (subClass == PCI_SUBCLASS_PRE_20_VGA) {
  2671. //
  2672. // We can disable the video path if we are powering down the machine
  2673. //
  2674. return canDisableVideoDecodes;
  2675. }
  2676. break;
  2677. }
  2678. //
  2679. // NB - The check to see if this device is a critical device is done
  2680. // AFTER the check to see if this device is the video device. This
  2681. // is done so that video devices, which are normally critical, can
  2682. // be turned off when the caller specifies the PCI_CAN_DISABLE_VIDEO_DECODES
  2683. // flag (eg when going into a sleep state)
  2684. //
  2685. if (HackFlags & PCI_HACK_CRITICAL_DEVICE) {
  2686. //
  2687. // This device performs a critical system function,
  2688. // like processing interrupts. Turning it off is
  2689. // likely to cause the machine to crash.
  2690. //
  2691. return FALSE;
  2692. }
  2693. return TRUE;
  2694. }
  2695. VOID
  2696. PciDecodeEnable(
  2697. IN PPCI_PDO_EXTENSION PdoExtension,
  2698. IN BOOLEAN Enable,
  2699. IN PUSHORT ExistingCommand OPTIONAL
  2700. )
  2701. /*++
  2702. Description:
  2703. Either sets the decodes to match the extension (misnomered Enable) or zeros
  2704. the decodes entirely.
  2705. N.B. - not paged so we can power down at dispatch level
  2706. Arguments:
  2707. PdoExtension Pointer to the PDO Extension for this device.
  2708. Enable If TRUE, decodes are set to match the extension (on or off).
  2709. If FALSE, decodes are disabled.
  2710. ExistingCommand Optional saved command to prevent a reread of the config
  2711. space command field.
  2712. Return Value:
  2713. Nothing.
  2714. --*/
  2715. {
  2716. USHORT cmd;
  2717. //
  2718. // Can we disable it if so ordered?
  2719. //
  2720. if (!Enable && !PciCanDisableDecodes(PdoExtension, NULL, 0, 0)) {
  2721. return;
  2722. }
  2723. if (PdoExtension->HackFlags & PCI_HACK_PRESERVE_COMMAND) {
  2724. //
  2725. // Bad things happen if we touch this device's command
  2726. // register, leave it alone.
  2727. //
  2728. return;
  2729. }
  2730. if (ARGUMENT_PRESENT(ExistingCommand)) {
  2731. //
  2732. // The caller has supplied the current contents of the
  2733. // device's config space.
  2734. //
  2735. cmd = *ExistingCommand;
  2736. } else {
  2737. //
  2738. // Get the current command register from the device.
  2739. //
  2740. PciGetCommandRegister(PdoExtension, &cmd);
  2741. }
  2742. cmd &= ~(PCI_ENABLE_IO_SPACE |
  2743. PCI_ENABLE_MEMORY_SPACE |
  2744. PCI_ENABLE_BUS_MASTER);
  2745. if (Enable) {
  2746. //
  2747. // Set enables
  2748. //
  2749. cmd |= PdoExtension->CommandEnables & (PCI_ENABLE_IO_SPACE
  2750. | PCI_ENABLE_MEMORY_SPACE
  2751. | PCI_ENABLE_BUS_MASTER);
  2752. }
  2753. //
  2754. // Set the new command register into the device.
  2755. //
  2756. PciSetCommandRegister(PdoExtension, cmd);
  2757. }
  2758. NTSTATUS
  2759. PciExcludeRangesFromWindow(
  2760. IN ULONGLONG Start,
  2761. IN ULONGLONG End,
  2762. IN PRTL_RANGE_LIST ArbiterRanges,
  2763. IN PRTL_RANGE_LIST ExclusionRanges
  2764. )
  2765. {
  2766. NTSTATUS status;
  2767. RTL_RANGE_LIST_ITERATOR iterator;
  2768. PRTL_RANGE current;
  2769. FOR_ALL_RANGES(ExclusionRanges, &iterator, current) {
  2770. if (current->Owner == NULL
  2771. && INTERSECT(current->Start, current->End, Start, End)) {
  2772. status = RtlAddRange(ArbiterRanges,
  2773. current->Start,
  2774. current->End,
  2775. 0,
  2776. RTL_RANGE_LIST_ADD_IF_CONFLICT,
  2777. NULL,
  2778. NULL // this range is not on the bus
  2779. );
  2780. if (!NT_SUCCESS(status)) {
  2781. PCI_ASSERT(NT_SUCCESS(status));
  2782. return status;
  2783. }
  2784. }
  2785. }
  2786. return STATUS_SUCCESS;
  2787. }
  2788. NTSTATUS
  2789. PciBuildDefaultExclusionLists(
  2790. VOID
  2791. )
  2792. {
  2793. NTSTATUS status;
  2794. ULONG windowBase;
  2795. PCI_ASSERT(PciIsaBitExclusionList.Count == 0);
  2796. PCI_ASSERT(PciVgaAndIsaBitExclusionList.Count == 0);
  2797. RtlInitializeRangeList(&PciIsaBitExclusionList);
  2798. RtlInitializeRangeList(&PciVgaAndIsaBitExclusionList);
  2799. for (windowBase = 0; windowBase <= 0xFFFF; windowBase += 0x400) {
  2800. //
  2801. // Add the x100-x3ff range to the ISA list
  2802. //
  2803. status = RtlAddRange(&PciIsaBitExclusionList,
  2804. windowBase + 0x100,
  2805. windowBase + 0x3FF,
  2806. 0,
  2807. RTL_RANGE_LIST_ADD_IF_CONFLICT,
  2808. NULL,
  2809. NULL // this range is not on the bus
  2810. );
  2811. if (!NT_SUCCESS(status)) {
  2812. goto cleanup;
  2813. }
  2814. //
  2815. // Add the x100-x3af, x3bc-x3bf and x3e0-x3ff ranges to the VGA/ISA list
  2816. //
  2817. status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
  2818. windowBase + 0x100,
  2819. windowBase + 0x3AF,
  2820. 0,
  2821. RTL_RANGE_LIST_ADD_IF_CONFLICT,
  2822. NULL,
  2823. NULL // this range is not on the bus
  2824. );
  2825. if (!NT_SUCCESS(status)) {
  2826. goto cleanup;
  2827. }
  2828. status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
  2829. windowBase + 0x3BC,
  2830. windowBase + 0x3BF,
  2831. 0,
  2832. RTL_RANGE_LIST_ADD_IF_CONFLICT,
  2833. NULL,
  2834. NULL // this range is not on the bus
  2835. );
  2836. if (!NT_SUCCESS(status)) {
  2837. goto cleanup;
  2838. }
  2839. status = RtlAddRange(&PciVgaAndIsaBitExclusionList,
  2840. windowBase + 0x3E0,
  2841. windowBase + 0x3FF,
  2842. 0,
  2843. RTL_RANGE_LIST_ADD_IF_CONFLICT,
  2844. NULL,
  2845. NULL // this range is not on the bus
  2846. );
  2847. if (!NT_SUCCESS(status)) {
  2848. goto cleanup;
  2849. }
  2850. }
  2851. return STATUS_SUCCESS;
  2852. cleanup:
  2853. RtlFreeRangeList(&PciIsaBitExclusionList);
  2854. RtlFreeRangeList(&PciVgaAndIsaBitExclusionList);
  2855. return status;
  2856. }
  2857. NTSTATUS
  2858. PciSaveBiosConfig(
  2859. IN PPCI_PDO_EXTENSION PdoExtension,
  2860. IN PPCI_COMMON_CONFIG Config
  2861. )
  2862. /*++
  2863. Description:
  2864. This saves the original configuration of a device in the registry
  2865. Arguments:
  2866. PdoExtension Pointer to the PDO Extension for this device.
  2867. Config The config space as the BIOS initialized it
  2868. Return Value:
  2869. Status
  2870. --*/
  2871. {
  2872. NTSTATUS status;
  2873. OBJECT_ATTRIBUTES attributes;
  2874. UNICODE_STRING unicodeString;
  2875. HANDLE deviceHandle, configHandle;
  2876. WCHAR buffer[sizeof("DEV_xx&FUN_xx")];
  2877. PAGED_CODE();
  2878. status = IoOpenDeviceRegistryKey(PCI_PARENT_PDO(PdoExtension),
  2879. PLUGPLAY_REGKEY_DEVICE,
  2880. KEY_WRITE,
  2881. &deviceHandle
  2882. );
  2883. if (!NT_SUCCESS(status)) {
  2884. goto cleanup;
  2885. }
  2886. PciConstStringToUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
  2887. InitializeObjectAttributes(&attributes,
  2888. &unicodeString,
  2889. OBJ_KERNEL_HANDLE,
  2890. deviceHandle,
  2891. NULL
  2892. );
  2893. status = ZwCreateKey(&configHandle,
  2894. KEY_WRITE,
  2895. &attributes,
  2896. 0,
  2897. NULL,
  2898. REG_OPTION_VOLATILE,
  2899. NULL
  2900. );
  2901. ZwClose(deviceHandle);
  2902. if (!NT_SUCCESS(status)) {
  2903. goto cleanup;
  2904. }
  2905. if (FAILED(StringCbPrintfW(buffer,
  2906. sizeof(buffer),
  2907. L"DEV_%02x&FUN_%02x",
  2908. PdoExtension->Slot.u.bits.DeviceNumber,
  2909. PdoExtension->Slot.u.bits.FunctionNumber
  2910. ))) {
  2911. status = STATUS_INVALID_PARAMETER;
  2912. goto cleanup;
  2913. }
  2914. RtlInitUnicodeString(&unicodeString, buffer);
  2915. status = ZwSetValueKey(configHandle,
  2916. &unicodeString,
  2917. 0,
  2918. REG_BINARY,
  2919. Config,
  2920. PCI_COMMON_HDR_LENGTH
  2921. );
  2922. ZwClose(configHandle);
  2923. return status;
  2924. cleanup:
  2925. return status;
  2926. }
  2927. NTSTATUS
  2928. PciGetBiosConfig(
  2929. IN PPCI_PDO_EXTENSION PdoExtension,
  2930. IN PPCI_COMMON_CONFIG Config
  2931. )
  2932. /*++
  2933. Description:
  2934. This retrieves the original configuration of a device from the registry
  2935. Arguments:
  2936. PdoExtension Pointer to the PDO Extension for this device.
  2937. Config The config space as the BIOS initialized it
  2938. Return Value:
  2939. Status
  2940. --*/
  2941. {
  2942. NTSTATUS status;
  2943. OBJECT_ATTRIBUTES attributes;
  2944. UNICODE_STRING unicodeString;
  2945. HANDLE deviceHandle, configHandle;
  2946. WCHAR buffer[sizeof("DEV_xx&FUN_xx")];
  2947. CHAR returnBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + PCI_COMMON_HDR_LENGTH - 1];
  2948. PKEY_VALUE_PARTIAL_INFORMATION info;
  2949. ULONG resultLength;
  2950. PAGED_CODE();
  2951. status = IoOpenDeviceRegistryKey(PCI_PARENT_PDO(PdoExtension),
  2952. PLUGPLAY_REGKEY_DEVICE,
  2953. KEY_READ | KEY_WRITE,
  2954. &deviceHandle
  2955. );
  2956. if (!NT_SUCCESS(status)) {
  2957. goto cleanup;
  2958. }
  2959. PciConstStringToUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
  2960. InitializeObjectAttributes(&attributes,
  2961. &unicodeString,
  2962. OBJ_KERNEL_HANDLE,
  2963. deviceHandle,
  2964. NULL
  2965. );
  2966. status = ZwOpenKey(&configHandle,
  2967. KEY_READ,
  2968. &attributes
  2969. );
  2970. ZwClose(deviceHandle);
  2971. if (!NT_SUCCESS(status)) {
  2972. goto cleanup;
  2973. }
  2974. if (FAILED(StringCbPrintfW(buffer,
  2975. sizeof(buffer),
  2976. L"DEV_%02x&FUN_%02x",
  2977. PdoExtension->Slot.u.bits.DeviceNumber,
  2978. PdoExtension->Slot.u.bits.FunctionNumber
  2979. ))) {
  2980. status = STATUS_INVALID_PARAMETER;
  2981. goto cleanup;
  2982. }
  2983. RtlInitUnicodeString(&unicodeString, buffer);
  2984. status = ZwQueryValueKey(configHandle,
  2985. &unicodeString,
  2986. KeyValuePartialInformation,
  2987. returnBuffer,
  2988. sizeof(returnBuffer),
  2989. &resultLength
  2990. );
  2991. ZwClose(configHandle);
  2992. if (NT_SUCCESS(status)) {
  2993. info = (PKEY_VALUE_PARTIAL_INFORMATION) returnBuffer;
  2994. PCI_ASSERT(info->DataLength == PCI_COMMON_HDR_LENGTH);
  2995. RtlCopyMemory(Config, info->Data, PCI_COMMON_HDR_LENGTH);
  2996. }
  2997. return status;
  2998. cleanup:
  2999. return status;
  3000. }
  3001. #if 0
  3002. BOOLEAN
  3003. PciPresenceCheck(
  3004. IN PPCI_PDO_EXTENSION PdoExtension
  3005. )
  3006. {
  3007. UCHAR configSpaceBuffer[PCI_COMMON_HDR_LENGTH];
  3008. PPCI_COMMON_CONFIG cardConfig = (PPCI_COMMON_CONFIG) configSpaceBuffer;
  3009. PAGED_CODE();
  3010. //
  3011. // If the card is already missing, don't bother reexamining it.
  3012. //
  3013. if (PdoExtension->NotPresent) {
  3014. return FALSE;
  3015. }
  3016. if (PciIsSameDevice(PdoExtension)) {
  3017. //
  3018. // Still here.
  3019. //
  3020. return TRUE;
  3021. }
  3022. //
  3023. // Mark it not present, then tell the OS it's gone.
  3024. //
  3025. PdoExtension->NotPresent = 1;
  3026. IoInvalidateDeviceState(PdoExtension->PhysicalDeviceObject);
  3027. return FALSE;
  3028. }
  3029. #endif
  3030. BOOLEAN
  3031. PciStringToUSHORT(
  3032. IN PWCHAR String,
  3033. OUT PUSHORT Result
  3034. )
  3035. /*++
  3036. Description:
  3037. Takes a 4 character hexidecimal sting and converts it into a USHORT.
  3038. Arguments:
  3039. String - the string
  3040. Result - the USHORT
  3041. Return Value:
  3042. TRUE is success, FASLE otherwise
  3043. --*/
  3044. {
  3045. ULONG count;
  3046. USHORT number = 0;
  3047. PWCHAR current;
  3048. current = String;
  3049. for (count = 0; count < 4; count++) {
  3050. number <<= 4;
  3051. if (*current >= L'0' && *current <= L'9') {
  3052. number |= *current - L'0';
  3053. } else if (*current >= L'A' && *current <= L'F') {
  3054. number |= *current + 10 - L'A';
  3055. } else if (*current >= L'a' && *current <= L'f') {
  3056. number |= *current + 10 - L'a';
  3057. } else {
  3058. return FALSE;
  3059. }
  3060. current++;
  3061. }
  3062. *Result = number;
  3063. return TRUE;
  3064. }
  3065. NTSTATUS
  3066. PciSendIoctl(
  3067. IN PDEVICE_OBJECT Device,
  3068. IN ULONG IoctlCode,
  3069. IN PVOID InputBuffer OPTIONAL,
  3070. IN ULONG InputBufferLength,
  3071. IN PVOID OutputBuffer OPTIONAL,
  3072. IN ULONG OutputBufferLength
  3073. )
  3074. /*++
  3075. Description:
  3076. Builds and send an IOCTL to a device and return the results
  3077. Arguments:
  3078. Device - a device on the device stack to receive the IOCTL - the
  3079. irp is always sent to the top of the stack
  3080. IoctlCode - the IOCTL to run
  3081. InputBuffer - arguments to the IOCTL
  3082. InputBufferLength - length in bytes of the InputBuffer
  3083. OutputBuffer - data returned by the IOCTL
  3084. OnputBufferLength - the size in bytes of the OutputBuffer
  3085. Return Value:
  3086. Status
  3087. --*/
  3088. {
  3089. NTSTATUS status;
  3090. IO_STATUS_BLOCK ioStatus;
  3091. KEVENT event;
  3092. PIRP irp;
  3093. PDEVICE_OBJECT targetDevice = NULL;
  3094. PAGED_CODE();
  3095. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  3096. //
  3097. // Get the top of the stack to send the IRP to
  3098. //
  3099. targetDevice = IoGetAttachedDeviceReference(Device);
  3100. if (!targetDevice) {
  3101. status = STATUS_INVALID_PARAMETER;
  3102. goto exit;
  3103. }
  3104. //
  3105. // Get Io to build the IRP for us
  3106. //
  3107. irp = IoBuildDeviceIoControlRequest(IoctlCode,
  3108. targetDevice,
  3109. InputBuffer,
  3110. InputBufferLength,
  3111. OutputBuffer,
  3112. OutputBufferLength,
  3113. FALSE, // InternalDeviceIoControl
  3114. &event,
  3115. &ioStatus
  3116. );
  3117. if (!irp) {
  3118. status = STATUS_INSUFFICIENT_RESOURCES;
  3119. goto exit;
  3120. }
  3121. //
  3122. // Send the IRP and wait for it to complete
  3123. //
  3124. status = IoCallDriver(targetDevice, irp);
  3125. if (status == STATUS_PENDING) {
  3126. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3127. status = ioStatus.Status;
  3128. }
  3129. exit:
  3130. if (targetDevice) {
  3131. ObDereferenceObject(targetDevice);
  3132. }
  3133. return status;
  3134. }
  3135. BOOLEAN
  3136. PciIsOnVGAPath(
  3137. IN PPCI_PDO_EXTENSION Pdo
  3138. )
  3139. /*++
  3140. Description:
  3141. Guesses if we are on the VGA path or not!
  3142. Arguments:
  3143. Pdo - The PDO for the device in question
  3144. Return Value:
  3145. TRUE if we are on the VGA path, TRUE otherwise
  3146. --*/
  3147. {
  3148. switch (Pdo->BaseClass) {
  3149. case PCI_CLASS_BRIDGE_DEV:
  3150. //
  3151. // We don't want to turn off bridges that might have the VGA card behind
  3152. // then otherwise video stops working. Seeing as we can't actually tell
  3153. // where the VGA card is use the hint that if the bridge is passing VGA
  3154. // ranges the video card is probably somewhere down there.
  3155. //
  3156. if (Pdo->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI
  3157. || Pdo->SubClass == PCI_SUBCLASS_BR_CARDBUS) {
  3158. if (Pdo->Dependent.type1.VgaBitSet) {
  3159. return TRUE;
  3160. }
  3161. }
  3162. break;
  3163. case PCI_CLASS_DISPLAY_CTLR:
  3164. if (Pdo->SubClass == PCI_SUBCLASS_VID_VGA_CTLR) {
  3165. return TRUE;
  3166. }
  3167. break;
  3168. case PCI_CLASS_PRE_20:
  3169. if (Pdo->SubClass == PCI_SUBCLASS_PRE_20_VGA) {
  3170. return TRUE;
  3171. }
  3172. break;
  3173. }
  3174. return FALSE;
  3175. }
  3176. BOOLEAN
  3177. PciIsSlotPresentInParentMethod(
  3178. IN PPCI_PDO_EXTENSION Pdo,
  3179. IN ULONG Method
  3180. )
  3181. /*++
  3182. Description:
  3183. This function checks if the slot this device is in is present in a
  3184. Method named package on the parent of this device.
  3185. Arguments:
  3186. Pdo - The PDO extension for the device
  3187. Method - The Parents method to examine
  3188. Return Value:
  3189. TRUE if present, FALSE otherwise
  3190. --*/
  3191. {
  3192. NTSTATUS status;
  3193. ACPI_EVAL_INPUT_BUFFER input;
  3194. PACPI_EVAL_OUTPUT_BUFFER output = NULL;
  3195. ULONG count, adr;
  3196. PACPI_METHOD_ARGUMENT argument;
  3197. BOOLEAN result = FALSE;
  3198. //
  3199. // Allocate a buffer big enough for all possible slots
  3200. //
  3201. ULONG outputSize = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + sizeof(ACPI_METHOD_ARGUMENT) * (PCI_MAX_DEVICES * PCI_MAX_FUNCTION);
  3202. PAGED_CODE();
  3203. output = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, outputSize);
  3204. if (!output) {
  3205. status = STATUS_INSUFFICIENT_RESOURCES;
  3206. goto exit;
  3207. }
  3208. RtlZeroMemory(&input, sizeof(ACPI_EVAL_INPUT_BUFFER));
  3209. RtlZeroMemory(output, outputSize);
  3210. //
  3211. // Send a IOCTL to ACPI to request it to run the method on this device's
  3212. // parent if the method it is present
  3213. //
  3214. input.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
  3215. input.MethodNameAsUlong = Method;
  3216. status = PciSendIoctl(PCI_PARENT_FDOX(Pdo)->PhysicalDeviceObject,
  3217. IOCTL_ACPI_EVAL_METHOD,
  3218. &input,
  3219. sizeof(ACPI_EVAL_INPUT_BUFFER),
  3220. output,
  3221. outputSize
  3222. );
  3223. if (!NT_SUCCESS(status)) {
  3224. goto exit;
  3225. }
  3226. //
  3227. // Format my slot number as an _ADR style integer
  3228. //
  3229. adr = (Pdo->Slot.u.bits.DeviceNumber << 16) | Pdo->Slot.u.bits.FunctionNumber;
  3230. for (count = 0; count < output->Count; count++) {
  3231. //
  3232. // Walking the arguments works like this because we are a package of
  3233. // integers
  3234. //
  3235. argument = &output->Argument[count];
  3236. if (argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  3237. status = STATUS_INVALID_PARAMETER;
  3238. goto exit;
  3239. }
  3240. if (argument->Argument == adr) {
  3241. //
  3242. // Jackpot!
  3243. //
  3244. result = TRUE;
  3245. break;
  3246. }
  3247. }
  3248. exit:
  3249. if (output) {
  3250. ExFreePool(output);
  3251. }
  3252. return result;
  3253. }
  3254. BOOLEAN
  3255. PciIsDeviceOnDebugPath(
  3256. IN PPCI_PDO_EXTENSION Pdo
  3257. )
  3258. /*++
  3259. Description:
  3260. This function checks if device is on the path to the debugging device
  3261. NOTE: PDO is only partially initialized at this point. Take care to insure
  3262. that fields touched here are valid.
  3263. Arguments:
  3264. Pdo - The PDO extension for the device
  3265. Return Value:
  3266. TRUE if on the debug path, FALSE otherwise
  3267. --*/
  3268. {
  3269. NTSTATUS status;
  3270. PPCI_DEBUG_PORT current;
  3271. PCI_COMMON_HEADER header;
  3272. PPCI_COMMON_CONFIG config = (PPCI_COMMON_CONFIG) &header;
  3273. PAGED_CODE();
  3274. PCI_ASSERT(PciDebugPortsCount <= MAX_DEBUGGING_DEVICES_SUPPORTED);
  3275. //
  3276. // We can't be on the debug path if we aren't using a PCI debug port!
  3277. //
  3278. if (PciDebugPortsCount == 0) {
  3279. return FALSE;
  3280. }
  3281. RtlZeroMemory(&header, sizeof(header));
  3282. //
  3283. // If its a bridge check if one of its subordinate buses has the debugger
  3284. // port on it
  3285. //
  3286. if (Pdo->HeaderType == PCI_BRIDGE_TYPE
  3287. || Pdo->HeaderType == PCI_CARDBUS_BRIDGE_TYPE) {
  3288. //
  3289. // Use the configuration that the firmware left the device in
  3290. //
  3291. status = PciGetBiosConfig(Pdo, config);
  3292. PCI_ASSERT(NT_SUCCESS(status));
  3293. FOR_ALL_IN_ARRAY(PciDebugPorts, PciDebugPortsCount, current) {
  3294. if (current->Bus >= config->u.type1.SecondaryBus
  3295. && current->Bus <= config->u.type1.SubordinateBus
  3296. && config->u.type1.SecondaryBus != 0
  3297. && config->u.type1.SubordinateBus != 0) {
  3298. return TRUE;
  3299. }
  3300. }
  3301. } else {
  3302. UCHAR parentBus;
  3303. if (PCI_PDO_ON_ROOT(Pdo)) {
  3304. parentBus = PCI_PARENT_FDOX(Pdo)->BaseBus;
  3305. } else {
  3306. //
  3307. // Get the BIOS config of the parent so we can get its initial bus
  3308. // number
  3309. //
  3310. status = PciGetBiosConfig(PCI_BRIDGE_PDO(PCI_PARENT_FDOX(Pdo)),
  3311. config
  3312. );
  3313. PCI_ASSERT(NT_SUCCESS(status));
  3314. if (config->u.type1.SecondaryBus == 0
  3315. || config->u.type1.SubordinateBus == 0) {
  3316. //
  3317. // This is a bridge that wasn't configured by the firmware so this
  3318. // child can't be on the debug path.
  3319. //
  3320. return FALSE;
  3321. } else {
  3322. parentBus = config->u.type1.SecondaryBus;
  3323. }
  3324. }
  3325. //
  3326. // Check if we are the device on the correct bus in the correct slot
  3327. //
  3328. FOR_ALL_IN_ARRAY(PciDebugPorts, PciDebugPortsCount, current) {
  3329. if (current->Bus == parentBus
  3330. && current->Slot.u.AsULONG == Pdo->Slot.u.AsULONG) {
  3331. return TRUE;
  3332. }
  3333. }
  3334. }
  3335. return FALSE;
  3336. }
  3337. NTSTATUS
  3338. PciUpdateLegacyHardwareDescription(
  3339. IN PPCI_FDO_EXTENSION Fdo
  3340. )
  3341. {
  3342. NTSTATUS status;
  3343. HANDLE multifunctionHandle = NULL, indexHandle = NULL;
  3344. WCHAR indexStringBuffer[10];
  3345. UNICODE_STRING indexString, tempString, pciString;
  3346. OBJECT_ATTRIBUTES attributes;
  3347. UCHAR infoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50];
  3348. PKEY_VALUE_PARTIAL_INFORMATION info = (PKEY_VALUE_PARTIAL_INFORMATION) infoBuffer;
  3349. ULONG infoLength;
  3350. ULONG disposition;
  3351. CM_FULL_RESOURCE_DESCRIPTOR descriptor;
  3352. PCM_FULL_RESOURCE_DESCRIPTOR full;
  3353. CONFIGURATION_COMPONENT component;
  3354. ULONG index;
  3355. BOOLEAN createdNewKey = FALSE;
  3356. if (!PciOpenKey(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter",
  3357. NULL,
  3358. KEY_READ | KEY_WRITE,
  3359. &multifunctionHandle,
  3360. &status)) {
  3361. goto exit;
  3362. }
  3363. //
  3364. // HKML\Hardware\Description\System\MultifunctionAdapter is structured as
  3365. // a set of 0 base consecutive numbered keys.
  3366. // Run through all the subkeys and check that we haven't already reported
  3367. // this bus
  3368. //
  3369. RtlInitEmptyUnicodeString(&indexString,
  3370. indexStringBuffer,
  3371. sizeof(indexStringBuffer)
  3372. );
  3373. for (index = 0;;index++) {
  3374. status = RtlIntegerToUnicodeString(index, 10, &indexString);
  3375. if (!NT_SUCCESS(status)) {
  3376. goto exit;
  3377. }
  3378. InitializeObjectAttributes(&attributes,
  3379. &indexString,
  3380. OBJ_CASE_INSENSITIVE,
  3381. multifunctionHandle,
  3382. NULL
  3383. );
  3384. status = ZwCreateKey(&indexHandle,
  3385. KEY_READ | KEY_WRITE,
  3386. &attributes,
  3387. 0,
  3388. NULL,
  3389. REG_OPTION_VOLATILE,
  3390. &disposition
  3391. );
  3392. if (!NT_SUCCESS(status)) {
  3393. goto exit;
  3394. }
  3395. //
  3396. // As the keys are all consecutive then if we created this key we have
  3397. // enumerated then all and we can get on with registering out data
  3398. //
  3399. if (disposition == REG_CREATED_NEW_KEY) {
  3400. createdNewKey = TRUE;
  3401. break;
  3402. }
  3403. PciConstStringToUnicodeString(&tempString, L"Identifier");
  3404. status = ZwQueryValueKey(indexHandle,
  3405. &tempString,
  3406. KeyValuePartialInformation,
  3407. info,
  3408. sizeof(infoBuffer),
  3409. &infoLength
  3410. );
  3411. if (NT_SUCCESS(status) && info->Type == REG_SZ) {
  3412. //
  3413. // Build counted strings of the REG_SZ which we assume has been
  3414. // NULL terminated and then compare knowing we can't overrun
  3415. // as everything is counted. If the string is longer than MAXUSHORT
  3416. // we truncate it.
  3417. //
  3418. PciConstStringToUnicodeString(&pciString, L"PCI");
  3419. tempString.Buffer = (PWSTR)&info->Data;
  3420. tempString.MaximumLength = (USHORT)info->DataLength;
  3421. tempString.Length = tempString.MaximumLength - sizeof(UNICODE_NULL);
  3422. if (RtlEqualUnicodeString(&pciString, &tempString, FALSE)) {
  3423. //
  3424. // This is a PCI bus, now check if its our bus number
  3425. //
  3426. PciConstStringToUnicodeString(&tempString, L"Configuration Data");
  3427. status = ZwQueryValueKey(indexHandle,
  3428. &tempString,
  3429. KeyValuePartialInformation,
  3430. info,
  3431. sizeof(infoBuffer),
  3432. &infoLength
  3433. );
  3434. if (NT_SUCCESS(status)) {
  3435. if (info->Type == REG_FULL_RESOURCE_DESCRIPTOR) {
  3436. full = (PCM_FULL_RESOURCE_DESCRIPTOR) &info->Data;
  3437. PCI_ASSERT(full->InterfaceType == PCIBus);
  3438. if (full->BusNumber == Fdo->BaseBus) {
  3439. //
  3440. // We're already reported this so we don't need to
  3441. // do anything.
  3442. //
  3443. status = STATUS_SUCCESS;
  3444. //
  3445. // indexHandle will be closed by the exit path.
  3446. //
  3447. goto exit;
  3448. }
  3449. }
  3450. }
  3451. }
  3452. }
  3453. ZwClose(indexHandle);
  3454. indexHandle = NULL;
  3455. }
  3456. //
  3457. // if we created a new key then indexHandle is it
  3458. //
  3459. if (createdNewKey) {
  3460. //
  3461. // Fill in the Identifier entry. This is a PCI bus.
  3462. //
  3463. PciConstStringToUnicodeString(&tempString, L"Identifier");
  3464. status = ZwSetValueKey(indexHandle,
  3465. &tempString,
  3466. 0,
  3467. REG_SZ,
  3468. L"PCI",
  3469. sizeof(L"PCI")
  3470. );
  3471. if (!NT_SUCCESS(status)) {
  3472. goto exit;
  3473. }
  3474. //
  3475. // Fill in the Configuration Data entry.
  3476. //
  3477. // Note that the complete descriptor is not written to the registry just
  3478. // enough data to indicate that this is an empty list (the first 16 bytes).
  3479. // This is a bit gross but it is what happens on x86 machines today and
  3480. // after all we're only doing this for backward compatibility.
  3481. //
  3482. RtlZeroMemory(&descriptor, sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
  3483. descriptor.InterfaceType = PCIBus;
  3484. descriptor.BusNumber = Fdo->BaseBus;
  3485. PciConstStringToUnicodeString(&tempString, L"Configuration Data");
  3486. status = ZwSetValueKey(indexHandle,
  3487. &tempString,
  3488. 0,
  3489. REG_FULL_RESOURCE_DESCRIPTOR,
  3490. &descriptor,
  3491. 16
  3492. );
  3493. if (!NT_SUCCESS(status)) {
  3494. goto exit;
  3495. }
  3496. //
  3497. // Fill in the Component Information entry. This is the Flags, Revision, Version,
  3498. // Key and AffinityMask members from the CONFIGURATION_COMPONENT structure.
  3499. //
  3500. // For PCI buses the affinity is set to all processors (0xFFFFFFFF) and
  3501. // everything else is 0.
  3502. //
  3503. RtlZeroMemory(&component, sizeof(CONFIGURATION_COMPONENT));
  3504. component.AffinityMask = 0xFFFFFFFF;
  3505. PciConstStringToUnicodeString(&tempString, L"Component Information");
  3506. status = ZwSetValueKey(indexHandle,
  3507. &tempString,
  3508. 0,
  3509. REG_BINARY,
  3510. &component.Flags,
  3511. FIELD_OFFSET(CONFIGURATION_COMPONENT, ConfigurationDataLength) -
  3512. FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags)
  3513. );
  3514. if (!NT_SUCCESS(status)) {
  3515. goto exit;
  3516. }
  3517. }
  3518. status = STATUS_SUCCESS;
  3519. exit:
  3520. if (indexHandle) {
  3521. //
  3522. // If we are failing attempt to cleanup by deleting the key we tried
  3523. // to create.
  3524. //
  3525. if (!NT_SUCCESS(status) && createdNewKey) {
  3526. ZwDeleteKey(indexHandle);
  3527. }
  3528. ZwClose(indexHandle);
  3529. }
  3530. if (multifunctionHandle) {
  3531. ZwClose(multifunctionHandle);
  3532. }
  3533. return status;
  3534. }
  3535. NTSTATUS
  3536. PciReadDeviceSpace(
  3537. IN PPCI_PDO_EXTENSION PdoExtension,
  3538. IN ULONG WhichSpace,
  3539. IN PVOID Buffer,
  3540. IN ULONG Offset,
  3541. IN ULONG Length,
  3542. OUT PULONG LengthRead
  3543. )
  3544. /*++
  3545. Routine Description:
  3546. This function handles reading from PCI device spaces and is called for both
  3547. the IRP_MN_READ_CONFIG and the BUS_INTERFACE_STANDARD.GetBusData cases.
  3548. Arguments:
  3549. PdoExtension - the PDO for the device we want to read from
  3550. WhichSpace - what type of space we want to read - of the form PCI_WHICHSPACE_*
  3551. Buffer - Supplies a pointer to where the data is to be returned
  3552. Offset - Indicates the offset into the space where the reading should begin.
  3553. Length - Indicates the count of bytes which should be read.
  3554. LengthRead - Indicates the count of bytes which was actually read.
  3555. Return Value:
  3556. Status
  3557. --*/
  3558. {
  3559. // NOT PAGED
  3560. NTSTATUS status;
  3561. PVERIFIER_DATA verifierData;
  3562. *LengthRead = 0;
  3563. switch (WhichSpace) {
  3564. default:
  3565. //
  3566. // Many people hand in the wrong WhichSpace parameters slap them around if we are verifing...
  3567. //
  3568. verifierData = PciVerifierRetrieveFailureData(PCI_VERIFIER_INVALID_WHICHSPACE);
  3569. PCI_ASSERT(verifierData);
  3570. VfFailDeviceNode(
  3571. PdoExtension->PhysicalDeviceObject,
  3572. PCI_VERIFIER_DETECTED_VIOLATION,
  3573. PCI_VERIFIER_INVALID_WHICHSPACE,
  3574. verifierData->FailureClass,
  3575. &verifierData->Flags,
  3576. verifierData->FailureText,
  3577. "%DevObj%Ulong",
  3578. PdoExtension->PhysicalDeviceObject,
  3579. WhichSpace
  3580. );
  3581. // fall through
  3582. case PCI_WHICHSPACE_CONFIG:
  3583. status = PciExternalReadDeviceConfig(
  3584. PdoExtension,
  3585. Buffer,
  3586. Offset,
  3587. Length
  3588. );
  3589. if(NT_SUCCESS(status)){
  3590. *LengthRead = Length;
  3591. }
  3592. break;
  3593. case PCI_WHICHSPACE_ROM:
  3594. //
  3595. // Read ROM.
  3596. //
  3597. *LengthRead = Length;
  3598. status = PciReadRomImage(
  3599. PdoExtension,
  3600. WhichSpace,
  3601. Buffer,
  3602. Offset,
  3603. LengthRead
  3604. );
  3605. break;
  3606. }
  3607. return status;
  3608. }
  3609. NTSTATUS
  3610. PciWriteDeviceSpace(
  3611. IN PPCI_PDO_EXTENSION PdoExtension,
  3612. IN ULONG WhichSpace,
  3613. IN PVOID Buffer,
  3614. IN ULONG Offset,
  3615. IN ULONG Length,
  3616. OUT PULONG LengthWritten
  3617. )
  3618. /*++
  3619. Routine Description:
  3620. This function handles reading from PCI device spaces and is called for both
  3621. the IRP_MN_WRITE_CONFIG and the BUS_INTERFACE_STANDARD.SetBusData cases.
  3622. Arguments:
  3623. PdoExtension - the PDO for the device we want to write to
  3624. WhichSpace - what type of space we want to write - of the form PCI_WHICHSPACE_*
  3625. Buffer - Supplies a pointer to where the data is to be written resides
  3626. Offset - Indicates the offset into the space where the writing should begin.
  3627. Length - Indicates the count of bytes which should be written.
  3628. LengthWritten - Indicates the count of bytes which was actually written.
  3629. Return Value:
  3630. Status
  3631. --*/
  3632. {
  3633. NTSTATUS status;
  3634. PVERIFIER_DATA verifierData;
  3635. *LengthWritten = 0;
  3636. switch (WhichSpace) {
  3637. default:
  3638. //
  3639. // Many people hand in the wrong WhichSpace parameters slap them around if we are verifing...
  3640. //
  3641. verifierData = PciVerifierRetrieveFailureData(PCI_VERIFIER_INVALID_WHICHSPACE);
  3642. PCI_ASSERT(verifierData);
  3643. VfFailDeviceNode(
  3644. PdoExtension->PhysicalDeviceObject,
  3645. PCI_VERIFIER_DETECTED_VIOLATION,
  3646. PCI_VERIFIER_INVALID_WHICHSPACE,
  3647. verifierData->FailureClass,
  3648. &verifierData->Flags,
  3649. verifierData->FailureText,
  3650. "%DevObj%Ulong",
  3651. PdoExtension->PhysicalDeviceObject,
  3652. WhichSpace
  3653. );
  3654. // fall through
  3655. case PCI_WHICHSPACE_CONFIG:
  3656. status = PciExternalWriteDeviceConfig(
  3657. PdoExtension,
  3658. Buffer,
  3659. Offset,
  3660. Length
  3661. );
  3662. if( NT_SUCCESS(status)){
  3663. *LengthWritten = Length;
  3664. }
  3665. break;
  3666. case PCI_WHICHSPACE_ROM:
  3667. //
  3668. // You can't write ROM
  3669. //
  3670. PciDebugPrint(
  3671. PciDbgAlways,
  3672. "PCI (%08x) WRITE_CONFIG IRP for ROM, failing.\n",
  3673. PdoExtension
  3674. );
  3675. status = STATUS_INVALID_DEVICE_REQUEST;
  3676. *LengthWritten = 0;
  3677. break;
  3678. }
  3679. return status;
  3680. }
  3681. BOOLEAN
  3682. PciIsSuiteVersion(
  3683. IN USHORT Version
  3684. )
  3685. /*++
  3686. Routine Description:
  3687. This routine checks to see if the system is currently running the given
  3688. product suite.
  3689. Arguments:
  3690. Version - a USHORT representing the suite to check for.
  3691. Return Value:
  3692. TRUE if the currently running system matches the suite.
  3693. FALSE otherwise.
  3694. --*/
  3695. {
  3696. OSVERSIONINFOEXW versionInfo;
  3697. ULONGLONG conditionMask = 0;
  3698. RtlZeroMemory(&versionInfo,sizeof(OSVERSIONINFOEX));
  3699. versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  3700. versionInfo.wSuiteMask = Version;
  3701. VER_SET_CONDITION(conditionMask, VER_SUITENAME, VER_AND);
  3702. return NT_SUCCESS(RtlVerifyVersionInfo(&versionInfo, VER_SUITENAME, conditionMask));
  3703. }
  3704. BOOLEAN
  3705. PciIsDatacenter(
  3706. )
  3707. /*++
  3708. Routine Description:
  3709. This routine checks to see if the system is currently running the datacenter SKU.
  3710. PciIsSuiteVersion is the supported system API to do this, but it does not work
  3711. in text mode setup, when only a value under the setupdd registry key contains
  3712. the information. The setupdd key only exists in text mode setup, so if it doesn't
  3713. exist, the normal API is used.
  3714. Return Value:
  3715. TRUE if the system is currently running datacenter.
  3716. FALSE otherwise.
  3717. --*/
  3718. {
  3719. PVOID valueBuffer = NULL;
  3720. ULONG valueLength = 0;
  3721. ULONG suiteVersion;
  3722. BOOLEAN returnValue = FALSE;
  3723. //
  3724. // Look for an unnamed value under CCS\Services\setupdd
  3725. // If it exists, we are in text mode setup and need to get the information out of this
  3726. // unnamed value.
  3727. //
  3728. if (NT_SUCCESS(PciGetRegistryValue(L"",
  3729. L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\setupdd",
  3730. NULL,
  3731. REG_BINARY,
  3732. &valueBuffer,
  3733. &valueLength
  3734. ))) {
  3735. if (valueLength == 16) {
  3736. //
  3737. // The unnamed value is 4 DWORDs long, and the fourth is the Suite version.
  3738. // 130 is the encoding for Datacenter.
  3739. //
  3740. suiteVersion = *((PULONG)valueBuffer + 3);
  3741. if (suiteVersion == 130) {
  3742. returnValue = TRUE;
  3743. }
  3744. }
  3745. ExFreePool(valueBuffer);
  3746. return returnValue;
  3747. } else {
  3748. //
  3749. // Not in text mode setup. The normal APIs will work.
  3750. //
  3751. return PciIsSuiteVersion(VER_SUITE_DATACENTER);
  3752. }
  3753. }
  3754. ULONG_PTR
  3755. PciExecuteCriticalSystemRoutine(
  3756. IN ULONG_PTR Context
  3757. )
  3758. /*++
  3759. Routine Description:
  3760. This routine is called in the context of KeIpiGenericCall, which
  3761. executes it on all processors. It is used to execute
  3762. a critical routine which needs all processors synchronized, such
  3763. as probing the BARs of a device that could not otherwise be turned off.
  3764. Only one context parameter is allowed in this routine, so it must
  3765. contain both the routine to execute and any context that routine
  3766. requires.
  3767. When this routine is entered, it is guaranteed that all processors will
  3768. already have been targeted with an IPI, and will be running at IPI_LEVEL.
  3769. All processors will either be running this routine, or will be about to
  3770. enter the routine. No arbitrary threads can possibly be running. No
  3771. devices can interrupt the execution of this routine, since IPI_LEVEL is
  3772. above all device IRQLs.
  3773. Because this routine runs at IPI_LEVEL, no debug prints, asserts or other
  3774. debugging can occur in this function without hanging MP machines.
  3775. Arguments:
  3776. Context - the context passed into the call to KeIpiGenericCall.
  3777. It contains the critical routine to execute, any context required
  3778. in that routine and a gate and a barrier to ensure that the critical routine
  3779. is executed on only one processor, even though this function is
  3780. executed on all processors.
  3781. Return Value:
  3782. VOID
  3783. --*/
  3784. {
  3785. PPCI_CRITICAL_ROUTINE_CONTEXT routineContext = (PPCI_CRITICAL_ROUTINE_CONTEXT)Context;
  3786. //
  3787. // The Gate parameter in the routineContext is preinitialized
  3788. // to 1, meaning that the first processor to reach this point
  3789. // in the routine will decrement it to 0, and succeed the if
  3790. // statement.
  3791. //
  3792. if (InterlockedDecrement(&routineContext->Gate) == 0) {
  3793. //
  3794. // This is only executed on one processor.
  3795. //
  3796. routineContext->Routine(routineContext->Extension,
  3797. routineContext->Context
  3798. );
  3799. //
  3800. // Free other processors.
  3801. //
  3802. routineContext->Barrier = 0;
  3803. } else {
  3804. //
  3805. // Wait for gated function to complete.
  3806. //
  3807. do {
  3808. } while (routineContext->Barrier != 0);
  3809. }
  3810. return (ULONG_PTR)0;
  3811. }
  3812. BOOLEAN
  3813. PciUnicodeStringStrStr(
  3814. IN PUNICODE_STRING SearchString,
  3815. IN PUNICODE_STRING SubString,
  3816. IN BOOLEAN CaseInsensitive
  3817. )
  3818. /*++
  3819. Routine Description:
  3820. This routine is a counted string version of strstr and searchs for any
  3821. instance of SubString within SearchString.
  3822. Arguments:
  3823. SearchString - String to search within
  3824. SubString - String to search for
  3825. CaseInsensitive - If TRUE indicates that a the comparison should be case
  3826. insensitive
  3827. Return Value:
  3828. TRUE if SubString is contained within SearchString, FALSE otherwise.
  3829. --*/
  3830. {
  3831. USHORT searchIndex, searchCount, subCount;
  3832. UNICODE_STRING currentSearchString;
  3833. searchCount = SearchString->Length / sizeof(WCHAR);
  3834. subCount = SubString->Length / sizeof(WCHAR);
  3835. currentSearchString.Buffer = SearchString->Buffer;
  3836. currentSearchString.MaximumLength = SearchString->MaximumLength;
  3837. //
  3838. // Set the length of the potential match string to the same length as
  3839. // SubString so we can use RtlEqualUnicodeString to compare them.
  3840. //
  3841. currentSearchString.Length = SubString->Length;
  3842. //
  3843. // Iterate through the search string until we are less than searchCount
  3844. // characters from the end since the SubString can't possibly fit.
  3845. //
  3846. for (searchIndex = 0;
  3847. searchIndex <= searchCount - subCount;
  3848. searchIndex++) {
  3849. //
  3850. // Now see if our substring is located at this position.
  3851. //
  3852. if(RtlEqualUnicodeString(SubString, &currentSearchString, CaseInsensitive)) {
  3853. return TRUE;
  3854. }
  3855. //
  3856. // Advance one character in the currentSearchString and decrement maximum
  3857. // length accordingly
  3858. //
  3859. currentSearchString.Buffer++;
  3860. currentSearchString.MaximumLength -= sizeof(WCHAR);
  3861. }
  3862. return FALSE;
  3863. }