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

1688 lines
47 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. i64pcibus.c
  5. Abstract:
  6. Get/Set bus data routines for the PCI bus
  7. Author:
  8. Ken Reneris (kenr) 14-June-1994
  9. Chris Hyser (chrish@fc.hp.com) 1-Feb-98
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "halp.h"
  15. #include "pci.h"
  16. #include "pcip.h"
  17. #include "i64fw.h"
  18. extern WCHAR rgzMultiFunctionAdapter[];
  19. extern WCHAR rgzConfigurationData[];
  20. extern WCHAR rgzIdentifier[];
  21. extern WCHAR rgzPCIIdentifier[];
  22. extern WCHAR rgzPCICardList[];
  23. //
  24. // Prototypes
  25. //
  26. ULONG
  27. HalpGetPCIData(
  28. IN PBUS_HANDLER BusHandler,
  29. IN PBUS_HANDLER RootHandler,
  30. IN PCI_SLOT_NUMBER SlotNumber,
  31. IN PVOID Buffer,
  32. IN ULONG Offset,
  33. IN ULONG Length
  34. );
  35. ULONG
  36. HalpSetPCIData(
  37. IN PBUS_HANDLER BusHandler,
  38. IN PBUS_HANDLER RootHandler,
  39. IN PCI_SLOT_NUMBER SlotNumber,
  40. IN PVOID Buffer,
  41. IN ULONG Offset,
  42. IN ULONG Length
  43. );
  44. NTSTATUS
  45. HalpAssignPCISlotResources(
  46. IN PBUS_HANDLER BusHandler,
  47. IN PBUS_HANDLER RootHandler,
  48. IN PUNICODE_STRING RegistryPath,
  49. IN PUNICODE_STRING DriverClassName OPTIONAL,
  50. IN PDRIVER_OBJECT DriverObject,
  51. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  52. IN ULONG SlotNumber,
  53. IN OUT PCM_RESOURCE_LIST *AllocatedResources
  54. );
  55. VOID
  56. HalpInitializePciBus(
  57. VOID
  58. );
  59. BOOLEAN
  60. HalpIsValidPCIDevice(
  61. IN PBUS_HANDLER BusHandler,
  62. IN PCI_SLOT_NUMBER Slot
  63. );
  64. BOOLEAN
  65. HalpValidPCISlot(
  66. IN PBUS_HANDLER BusHandler,
  67. IN PCI_SLOT_NUMBER Slot
  68. );
  69. //
  70. // Globals
  71. //
  72. KSPIN_LOCK HalpPCIConfigLock;
  73. BOOLEAN HalpDoingCrashDump = FALSE;
  74. //
  75. // Used to prevent attempts at synchronizing on locks which might have been held
  76. // before the crash.
  77. //
  78. extern BOOLEAN HalpDoingCrashDump;
  79. //
  80. // PCI Configuration Space Accessor types
  81. //
  82. typedef enum {
  83. PCI_READ,
  84. PCI_WRITE
  85. } PCI_ACCESS_TYPE;
  86. VOID
  87. HalpPCIConfig(
  88. IN PBUS_HANDLER BusHandler,
  89. IN PCI_SLOT_NUMBER Slot,
  90. IN PUCHAR Buffer,
  91. IN ULONG Offset,
  92. IN ULONG Length,
  93. IN PCI_ACCESS_TYPE Acctype
  94. );
  95. #if DBG
  96. #if !defined(NO_LEGACY_DRIVERS)
  97. VOID
  98. HalpTestPci(
  99. ULONG
  100. );
  101. #endif
  102. #endif
  103. #ifdef ALLOC_PRAGMA
  104. #pragma alloc_text(INIT,HalpInitializePciBus)
  105. #pragma alloc_text(INIT,HalpAllocateAndInitPciBusHandler)
  106. #pragma alloc_text(INIT,HalpIsValidPCIDevice)
  107. #pragma alloc_text(PAGE,HalpAssignPCISlotResources)
  108. #endif
  109. ULONG
  110. HalpGetPCIData(
  111. IN PBUS_HANDLER BusHandler,
  112. IN PBUS_HANDLER RootHandler,
  113. IN PCI_SLOT_NUMBER Slot,
  114. IN PUCHAR Buffer,
  115. IN ULONG Offset,
  116. IN ULONG Length
  117. )
  118. /*++
  119. Routine Description:
  120. The function returns the PCI bus data for a specified PCI "slot". This
  121. function is called on behalf of
  122. Arguments:
  123. BusHandler - An encapsulation of data and manipulation functions specific to
  124. this bus.
  125. RootHandler - ???
  126. Slot - A PCI "slot" description (ie bus number, device number and function
  127. number.)
  128. Buffer - A pointer to the space to store the data.
  129. Offset - The byte offset into the configuration space for this PCI "slot".
  130. Length - Supplies a count in bytes of the maximum amount to return. (ie
  131. equal or less than the size of the Buffer.)
  132. Return Value:
  133. Returns the amount of data stored into the buffer.
  134. If this PCI slot has never been set, then the configuration information
  135. returned is zeroed.
  136. --*/
  137. {
  138. PPCI_COMMON_CONFIG PciData;
  139. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  140. PPCIPBUSDATA BusData;
  141. ULONG Len;
  142. ULONG i, bit;
  143. if (Length > sizeof(PCI_COMMON_CONFIG))
  144. Length = sizeof(PCI_COMMON_CONFIG);
  145. Len = 0;
  146. PciData = (PPCI_COMMON_CONFIG)iBuffer;
  147. //
  148. // If the requested offset does not lie in the PCI onfiguration space common
  149. // header, we will read the vendor ID from the common header to ensure this
  150. // is a valid device. Note: The common header is from 0 to
  151. // PCI_COMMON_HEADER_LENGTH inclusive. We know Offset is > 0 because it is
  152. // unsigned.
  153. //
  154. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  155. //
  156. // No data was requested from the common header. Verify the PCI device
  157. // exists, then continue in the device specific area.
  158. //
  159. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, sizeof(ULONG));
  160. if (PciData->VendorID == PCI_INVALID_VENDORID)
  161. return(0);
  162. } else {
  163. //
  164. // Caller requested at least some data within the common header. Read
  165. // the whole header, effect the fields we need to and then copy the
  166. // user's requested bytes from the header
  167. //
  168. BusData = (PPCIPBUSDATA)BusHandler->BusData;
  169. //
  170. // Read this PCI devices slot data
  171. //
  172. Len = PCI_COMMON_HDR_LENGTH;
  173. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, Len);
  174. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  175. PciData->VendorID = PCI_INVALID_VENDORID;
  176. Len = 2; // only return invalid id
  177. } else {
  178. BusData->CommonData.Pin2Line(BusHandler, RootHandler, Slot, PciData);
  179. }
  180. //
  181. // Copy whatever data overlaps into the callers buffer
  182. //
  183. if (Len < Offset)
  184. return(0);
  185. Len -= Offset;
  186. if (Len > Length)
  187. Len = Length;
  188. RtlMoveMemory(Buffer, iBuffer + Offset, Len);
  189. Offset += Len;
  190. Buffer += Len;
  191. Length -= Len;
  192. }
  193. if (Length) {
  194. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  195. //
  196. // The remaining Buffer comes from the Device Specific
  197. // area - put on the kitten gloves and read from it.
  198. //
  199. // Specific read/writes to the PCI device specific area
  200. // are guarenteed:
  201. //
  202. // Not to read/write any byte outside the area specified
  203. // by the caller. (this may cause WORD or BYTE references
  204. // to the area in order to read the non-dword aligned
  205. // ends of the request)
  206. //
  207. // To use a WORD access if the requested length is exactly
  208. // a WORD long.
  209. //
  210. // To use a BYTE access if the requested length is exactly
  211. // a BYTE long.
  212. //
  213. HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length);
  214. Len += Length;
  215. }
  216. }
  217. return(Len);
  218. }
  219. ULONG
  220. HalpSetPCIData(
  221. IN PBUS_HANDLER BusHandler,
  222. IN PBUS_HANDLER RootHandler,
  223. IN PCI_SLOT_NUMBER Slot,
  224. IN PUCHAR Buffer,
  225. IN ULONG Offset,
  226. IN ULONG Length
  227. )
  228. /*++
  229. Routine Description:
  230. The function sets the PCI bus data for a specified PCI "slot".
  231. Arguments:
  232. BusHandler - An encapsulation of data and manipulation functions specific to
  233. this bus.
  234. RootHandler - ???
  235. Slot - A PCI "slot" description (ie bus number, device number and function
  236. number.)
  237. Buffer - Supplies the space to store the data.
  238. Length - Supplies a count in bytes of the maximum amount to return.
  239. Return Value:
  240. Returns the amount of data stored into the buffer. ???
  241. --*/
  242. {
  243. PPCI_COMMON_CONFIG PciData, PciData2;
  244. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  245. UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
  246. PPCIPBUSDATA BusData;
  247. ULONG Len, cnt;
  248. if (Length > sizeof(PCI_COMMON_CONFIG))
  249. Length = sizeof(PCI_COMMON_CONFIG);
  250. Len = 0;
  251. PciData = (PPCI_COMMON_CONFIG)iBuffer;
  252. PciData2 = (PPCI_COMMON_CONFIG)iBuffer2;
  253. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  254. //
  255. // The user did not request any data from the common
  256. // header. Verify the PCI device exists, then continue in
  257. // the device specific area.
  258. //
  259. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, sizeof(ULONG));
  260. if (PciData->VendorID == PCI_INVALID_VENDORID)
  261. return(0);
  262. } else {
  263. //
  264. // Caller requested to set at least some data within the
  265. // common header.
  266. //
  267. Len = PCI_COMMON_HDR_LENGTH;
  268. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, Len);
  269. //
  270. // return error if no device or header type unknown
  271. //
  272. if (PciData->VendorID == PCI_INVALID_VENDORID ||
  273. PCI_CONFIG_TYPE(PciData) != PCI_DEVICE_TYPE)
  274. return(0);
  275. //
  276. // Set this device as configured
  277. //
  278. BusData = (PPCIPBUSDATA)BusHandler->BusData;
  279. #if DBG1
  280. cnt = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
  281. RtlSetBits(&BusData->DeviceConfigured, cnt, 1);
  282. #endif
  283. //
  284. // Copy COMMON_HDR values to buffer2, then overlay callers changes.
  285. //
  286. RtlMoveMemory(iBuffer2, iBuffer, Len);
  287. BusData->CommonData.Pin2Line(BusHandler, RootHandler, Slot, PciData2);
  288. Len -= Offset;
  289. if (Len > Length)
  290. Len = Length;
  291. RtlMoveMemory(iBuffer2+Offset, Buffer, Len);
  292. //
  293. // in case interrupt line or pin was edited
  294. //
  295. BusData->CommonData.Line2Pin(BusHandler, RootHandler, Slot, PciData2, PciData);
  296. #if DBG1
  297. //
  298. // Verify R/O fields haven't changed
  299. //
  300. if (PciData2->VendorID != PciData->VendorID ||
  301. PciData2->DeviceID != PciData->DeviceID ||
  302. PciData2->RevisionID != PciData->RevisionID ||
  303. PciData2->ProgIf != PciData->ProgIf ||
  304. PciData2->SubClass != PciData->SubClass ||
  305. PciData2->BaseClass != PciData->BaseClass ||
  306. PciData2->HeaderType != PciData->HeaderType ||
  307. PciData2->BaseClass != PciData->BaseClass ||
  308. PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant ||
  309. PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) {
  310. HalDebugPrint(( HAL_INFO, "HAL: PCI SetBusData - Read-Only configuration value changed\n" ));
  311. }
  312. #endif
  313. //
  314. // Set new PCI configuration
  315. //
  316. HalpWritePCIConfig(BusHandler, Slot, iBuffer2+Offset, Offset, Len);
  317. Offset += Len;
  318. Buffer += Len;
  319. Length -= Len;
  320. }
  321. if (Length) {
  322. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  323. //
  324. // The remaining Buffer comes from the Device Specific
  325. // area - put on the kitten gloves and write it
  326. //
  327. // Specific read/writes to the PCI device specific area
  328. // are guarenteed:
  329. //
  330. // Not to read/write any byte outside the area specified
  331. // by the caller. (this may cause WORD or BYTE references
  332. // to the area in order to read the non-dword aligned
  333. // ends of the request)
  334. //
  335. // To use a WORD access if the requested length is exactly
  336. // a WORD long.
  337. //
  338. // To use a BYTE access if the requested length is exactly
  339. // a BYTE long.
  340. //
  341. HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length);
  342. Len += Length;
  343. }
  344. }
  345. return(Len);
  346. }
  347. NTSTATUS
  348. HalpAssignPCISlotResources(
  349. IN PBUS_HANDLER BusHandler,
  350. IN PBUS_HANDLER RootHandler,
  351. IN PUNICODE_STRING RegistryPath,
  352. IN PUNICODE_STRING DriverClassName OPTIONAL,
  353. IN PDRIVER_OBJECT DriverObject,
  354. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  355. IN ULONG Slot,
  356. IN OUT PCM_RESOURCE_LIST *pAllocatedResources
  357. )
  358. /*++
  359. Routine Description:
  360. Reads the targeted device to determine it's required resources.
  361. Calls IoAssignResources to allocate them.
  362. Sets the targeted device with it's assigned resoruces
  363. and returns the assignments to the caller.
  364. Note: This function assumes all of a PCI "slots" resources as indicated by
  365. it's configuration space are REQUIRED.
  366. Arguments:
  367. Return Value:
  368. STATUS_SUCCESS or error
  369. --*/
  370. {
  371. NTSTATUS status;
  372. PUCHAR WorkingPool;
  373. PPCI_COMMON_CONFIG PciData, PciOrigData, PciData2;
  374. PCI_SLOT_NUMBER PciSlot;
  375. PPCIPBUSDATA BusData;
  376. PIO_RESOURCE_REQUIREMENTS_LIST CompleteList;
  377. PIO_RESOURCE_DESCRIPTOR Descriptor;
  378. PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
  379. ULONG BusNumber;
  380. ULONG i, j, m, length, memtype;
  381. ULONG NoBaseAddress, RomIndex, Option;
  382. PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
  383. PULONG OrigAddress[PCI_TYPE0_ADDRESSES + 1];
  384. BOOLEAN Match, EnableRomBase, RequestedInterrupt;
  385. *pAllocatedResources = NULL;
  386. PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
  387. BusNumber = BusHandler->BusNumber;
  388. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  389. //
  390. // Allocate some pool for working space
  391. //
  392. i = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  393. sizeof(IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 +
  394. PCI_COMMON_HDR_LENGTH * 3;
  395. WorkingPool = (PUCHAR)ExAllocatePool(PagedPool, i);
  396. if (!WorkingPool)
  397. return(STATUS_INSUFFICIENT_RESOURCES);
  398. //
  399. // Zero initialize pool, and get pointers into memory
  400. //
  401. RtlZeroMemory(WorkingPool, i);
  402. CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST)WorkingPool;
  403. PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 3);
  404. PciData2 = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2);
  405. PciOrigData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH * 1);
  406. //
  407. // Read the PCI device's configuration
  408. //
  409. HalpReadPCIConfig(BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  410. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  411. ExFreePool(WorkingPool);
  412. return(STATUS_NO_SUCH_DEVICE);
  413. }
  414. //
  415. // For now since there's not PnP support in the OS, if the BIOS hasn't
  416. // enable a VGA device don't allow it to get enabled via this interface.
  417. //
  418. if ((PciData->BaseClass == 0 && PciData->SubClass == 1) ||
  419. (PciData->BaseClass == 3 && PciData->SubClass == 0)) {
  420. if ((PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) == 0) {
  421. ExFreePool (WorkingPool);
  422. return(STATUS_DEVICE_NOT_CONNECTED);
  423. }
  424. }
  425. //
  426. // Make a copy of the device's current settings
  427. //
  428. RtlMoveMemory(PciOrigData, PciData, PCI_COMMON_HDR_LENGTH);
  429. //
  430. // Initialize base addresses base on configuration data type
  431. //
  432. switch (PCI_CONFIG_TYPE(PciData)) {
  433. case 0 :
  434. NoBaseAddress = PCI_TYPE0_ADDRESSES+1;
  435. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  436. BaseAddress[j] = &PciData->u.type0.BaseAddresses[j];
  437. OrigAddress[j] = &PciOrigData->u.type0.BaseAddresses[j];
  438. }
  439. BaseAddress[j] = &PciData->u.type0.ROMBaseAddress;
  440. OrigAddress[j] = &PciOrigData->u.type0.ROMBaseAddress;
  441. RomIndex = j;
  442. break;
  443. case 1:
  444. NoBaseAddress = PCI_TYPE1_ADDRESSES+1;
  445. for (j=0; j < PCI_TYPE1_ADDRESSES; j++) {
  446. BaseAddress[j] = &PciData->u.type1.BaseAddresses[j];
  447. OrigAddress[j] = &PciOrigData->u.type1.BaseAddresses[j];
  448. }
  449. BaseAddress[j] = &PciData->u.type1.ROMBaseAddress;
  450. OrigAddress[j] = &PciOrigData->u.type1.ROMBaseAddress;
  451. RomIndex = j;
  452. break;
  453. default:
  454. ExFreePool (WorkingPool);
  455. return(STATUS_NO_SUCH_DEVICE);
  456. }
  457. //
  458. // If the BIOS doesn't have the device's ROM enabled, then we won't enable
  459. // it either. Remove it from the list.
  460. //
  461. EnableRomBase = TRUE;
  462. if (!(*BaseAddress[RomIndex] & PCI_ROMADDRESS_ENABLED)) {
  463. ASSERT (RomIndex+1 == NoBaseAddress);
  464. EnableRomBase = FALSE;
  465. NoBaseAddress -= 1;
  466. }
  467. //
  468. // Set resources to all bits on to see what type of resources are required.
  469. //
  470. for (j=0; j < NoBaseAddress; j++)
  471. *BaseAddress[j] = 0xFFFFFFFF;
  472. PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
  473. *BaseAddress[RomIndex] &= ~PCI_ROMADDRESS_ENABLED;
  474. HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  475. HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  476. //
  477. // note type0 & type1 overlay ROMBaseAddress, InterruptPin, and InterruptLine
  478. //
  479. BusData->CommonData.Pin2Line (BusHandler, RootHandler, PciSlot, PciData);
  480. //
  481. // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device
  482. //
  483. CompleteList->InterfaceType = PCIBus;
  484. CompleteList->BusNumber = BusNumber;
  485. CompleteList->SlotNumber = Slot;
  486. CompleteList->AlternativeLists = 1;
  487. CompleteList->List[0].Version = 1;
  488. CompleteList->List[0].Revision = 1;
  489. Descriptor = CompleteList->List[0].Descriptors;
  490. //
  491. // If PCI device has an interrupt resource, add it
  492. //
  493. RequestedInterrupt = FALSE;
  494. if (PciData->u.type0.InterruptPin &&
  495. PciData->u.type0.InterruptLine != (0 ^ IRQXOR) &&
  496. PciData->u.type0.InterruptLine != (0xFF ^ IRQXOR)) {
  497. RequestedInterrupt = TRUE;
  498. CompleteList->List[0].Count++;
  499. Descriptor->Option = 0;
  500. Descriptor->Type = CmResourceTypeInterrupt;
  501. Descriptor->ShareDisposition = CmResourceShareShared;
  502. Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  503. // Fill in any vector here - we'll pick it back up in
  504. // HalAdjustResourceList and adjust it to it's allowed settings
  505. Descriptor->u.Interrupt.MinimumVector = 0;
  506. Descriptor->u.Interrupt.MaximumVector = 0xff;
  507. Descriptor++;
  508. }
  509. //
  510. // Add a memory/port resoruce for each PCI resource
  511. //
  512. // Clear ROM reserved bits
  513. *BaseAddress[RomIndex] &= ~0x7FF;
  514. for (j=0; j < NoBaseAddress; j++) {
  515. if (*BaseAddress[j]) {
  516. i = *BaseAddress[j];
  517. //
  518. // scan for first set bit, that's the length & alignment
  519. //
  520. length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4);
  521. while (!(i & length) && length)
  522. length <<= 1;
  523. //
  524. // scan for last set bit, that's the maxaddress + 1
  525. //
  526. for (m = length; i & m; m <<= 1) ;
  527. m--;
  528. //
  529. // check for hosed PCI configuration requirements
  530. //
  531. if (length & ~m) {
  532. #if DBG
  533. HalDebugPrint(( HAL_INFO, "HAL: PCI - defective device! Bus %d, Slot %d, Function %d\n",
  534. BusNumber,
  535. PciSlot.u.bits.DeviceNumber,
  536. PciSlot.u.bits.FunctionNumber
  537. ));
  538. HalDebugPrint(( HAL_INFO, "HAL: PCI - BaseAddress[%d] = %08lx\n", j, i ));
  539. #endif
  540. //
  541. // The device is in error - punt. don't allow this
  542. // resource any option - it either gets set to whatever
  543. // bits it was able to return, or it doesn't get set.
  544. //
  545. if (i & PCI_ADDRESS_IO_SPACE) {
  546. m = i & ~0x3;
  547. Descriptor->u.Port.MinimumAddress.LowPart = m;
  548. } else {
  549. m = i & ~0xf;
  550. Descriptor->u.Memory.MinimumAddress.LowPart = m;
  551. }
  552. m += length; // max address is min address + length
  553. }
  554. //
  555. // Add requested resource
  556. //
  557. Descriptor->Option = 0;
  558. if (i & PCI_ADDRESS_IO_SPACE) {
  559. memtype = 0;
  560. if (!Is64BitBaseAddress(i) &&
  561. PciOrigData->Command & PCI_ENABLE_IO_SPACE) {
  562. //
  563. // The IO range is/was already enabled at some location, add that
  564. // as it's preferred setting.
  565. //
  566. Descriptor->Type = CmResourceTypePort;
  567. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  568. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  569. Descriptor->Option = IO_RESOURCE_PREFERRED;
  570. Descriptor->u.Port.Length = length;
  571. Descriptor->u.Port.Alignment = length;
  572. Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0x3;
  573. Descriptor->u.Port.MaximumAddress.LowPart =
  574. Descriptor->u.Port.MinimumAddress.LowPart + length - 1;
  575. CompleteList->List[0].Count++;
  576. Descriptor++;
  577. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  578. }
  579. //
  580. // Add this IO range
  581. //
  582. Descriptor->Type = CmResourceTypePort;
  583. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  584. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  585. Descriptor->u.Port.Length = length;
  586. Descriptor->u.Port.Alignment = length;
  587. Descriptor->u.Port.MaximumAddress.LowPart = m;
  588. } else {
  589. memtype = i & PCI_ADDRESS_MEMORY_TYPE_MASK;
  590. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  591. if (j == RomIndex) {
  592. // this is a ROM address
  593. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  594. }
  595. if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) {
  596. Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
  597. }
  598. if (!Is64BitBaseAddress(i) &&
  599. (j == RomIndex ||
  600. PciOrigData->Command & PCI_ENABLE_MEMORY_SPACE)) {
  601. //
  602. // The memory range is/was already enabled at some location, add that
  603. // as it's preferred setting.
  604. //
  605. Descriptor->Type = CmResourceTypeMemory;
  606. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  607. Descriptor->Option = IO_RESOURCE_PREFERRED;
  608. Descriptor->u.Port.Length = length;
  609. Descriptor->u.Port.Alignment = length;
  610. Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0xF;
  611. Descriptor->u.Port.MaximumAddress.LowPart =
  612. Descriptor->u.Port.MinimumAddress.LowPart + length - 1;
  613. CompleteList->List[0].Count++;
  614. Descriptor++;
  615. Descriptor->Flags = Descriptor[-1].Flags;
  616. Descriptor->Option = IO_RESOURCE_ALTERNATIVE;
  617. }
  618. //
  619. // Add this memory range
  620. //
  621. Descriptor->Type = CmResourceTypeMemory;
  622. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  623. Descriptor->u.Memory.Length = length;
  624. Descriptor->u.Memory.Alignment = length;
  625. Descriptor->u.Memory.MaximumAddress.LowPart = m;
  626. if (memtype == PCI_TYPE_20BIT && m > 0xFFFFF) {
  627. // limit to 20 bit address
  628. Descriptor->u.Memory.MaximumAddress.LowPart = 0xFFFFF;
  629. }
  630. }
  631. CompleteList->List[0].Count++;
  632. Descriptor++;
  633. if (Is64BitBaseAddress(i)) {
  634. //
  635. // Eventually we may want to do some work here for 64-bit
  636. // configs...
  637. //
  638. // skip upper half of 64 bit address since this processor
  639. // only supports 32 bits of address space
  640. //
  641. j++;
  642. }
  643. }
  644. }
  645. CompleteList->ListSize = (ULONG)
  646. ((PUCHAR) Descriptor - (PUCHAR) CompleteList);
  647. //
  648. // Restore the device settings as we found them, enable memory
  649. // and io decode after setting base addresses. This is done in
  650. // case HalAdjustResourceList wants to read the current settings
  651. // in the device.
  652. //
  653. HalpWritePCIConfig (
  654. BusHandler,
  655. PciSlot,
  656. &PciOrigData->Status,
  657. FIELD_OFFSET (PCI_COMMON_CONFIG, Status),
  658. PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  659. );
  660. HalpWritePCIConfig (
  661. BusHandler,
  662. PciSlot,
  663. PciOrigData,
  664. 0,
  665. FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  666. );
  667. //
  668. // Have the IO system allocate resource assignments
  669. //
  670. status = IoAssignResources (
  671. RegistryPath,
  672. DriverClassName,
  673. DriverObject,
  674. DeviceObject,
  675. CompleteList,
  676. pAllocatedResources
  677. );
  678. if (!NT_SUCCESS(status)) {
  679. goto CleanUp;
  680. }
  681. //
  682. // Slurp the assigments back into the PciData structure and perform them
  683. //
  684. CmDescriptor = (*pAllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
  685. //
  686. // If PCI device has an interrupt resource then that was passed in as the
  687. // first requested resource
  688. //
  689. if (RequestedInterrupt) {
  690. PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector;
  691. BusData->CommonData.Line2Pin (BusHandler, RootHandler, PciSlot, PciData, PciOrigData);
  692. CmDescriptor++;
  693. }
  694. //
  695. // Pull out resources in the order they were passed to IoAssignResources
  696. //
  697. for (j=0; j < NoBaseAddress; j++) {
  698. i = *BaseAddress[j];
  699. if (i) {
  700. if (i & PCI_ADDRESS_IO_SPACE) {
  701. *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart;
  702. } else {
  703. *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart;
  704. }
  705. CmDescriptor++;
  706. }
  707. if (Is64BitBaseAddress(i)) {
  708. // skip upper 32 bits
  709. j++;
  710. }
  711. }
  712. //
  713. // Turn off decodes, then set new addresses
  714. //
  715. HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  716. //
  717. // Read configuration back and verify address settings took
  718. //
  719. HalpReadPCIConfig(BusHandler, PciSlot, PciData2, 0, PCI_COMMON_HDR_LENGTH);
  720. Match = TRUE;
  721. if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine ||
  722. PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin ||
  723. PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) {
  724. Match = FALSE;
  725. }
  726. for (j=0; j < NoBaseAddress; j++) {
  727. if (*BaseAddress[j]) {
  728. if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) {
  729. i = (ULONG) ~0x3;
  730. } else {
  731. i = (ULONG) ~0xF;
  732. }
  733. if (( (*BaseAddress[j]) & i) !=
  734. (*((PULONG) ((PUCHAR) BaseAddress[j] -
  735. (PUCHAR) PciData +
  736. (PUCHAR) PciData2)) & i)) {
  737. Match = FALSE;
  738. }
  739. if (Is64BitBaseAddress(*BaseAddress[j])) {
  740. //
  741. // Eventually we may want to do something with the upper
  742. // 32 bits
  743. //
  744. j++;
  745. }
  746. }
  747. }
  748. if (!Match) {
  749. HalDebugPrint(( HAL_INFO, "HAL: PCI - defective device! Bus %d, Slot %d, Function %d\n",
  750. BusNumber,
  751. PciSlot.u.bits.DeviceNumber,
  752. PciSlot.u.bits.FunctionNumber
  753. ));
  754. status = STATUS_DEVICE_PROTOCOL_ERROR;
  755. goto CleanUp;
  756. }
  757. //
  758. // Settings took - turn on the appropiate decodes
  759. //
  760. if (EnableRomBase && *BaseAddress[RomIndex]) {
  761. //
  762. // A rom address was allocated and should be enabled
  763. //
  764. *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED;
  765. HalpWritePCIConfig(
  766. BusHandler,
  767. PciSlot,
  768. BaseAddress[RomIndex],
  769. (ULONG) ((PUCHAR) BaseAddress[RomIndex] - (PUCHAR) PciData),
  770. sizeof (ULONG)
  771. );
  772. }
  773. //
  774. // Enable IO, Memory, and BUS_MASTER decodes
  775. // (use HalSetBusData since valid settings now set)
  776. //
  777. PciData->Command |= PCI_ENABLE_IO_SPACE |
  778. PCI_ENABLE_MEMORY_SPACE |
  779. PCI_ENABLE_BUS_MASTER;
  780. HalSetBusDataByOffset(
  781. PCIConfiguration,
  782. BusHandler->BusNumber,
  783. PciSlot.u.AsULONG,
  784. &PciData->Command,
  785. FIELD_OFFSET (PCI_COMMON_CONFIG, Command),
  786. sizeof (PciData->Command)
  787. );
  788. CleanUp:
  789. if (!NT_SUCCESS(status)) {
  790. //
  791. // Failure, if there are any allocated resources free them
  792. //
  793. if (*pAllocatedResources) {
  794. IoAssignResources(
  795. RegistryPath,
  796. DriverClassName,
  797. DriverObject,
  798. DeviceObject,
  799. NULL,
  800. NULL
  801. );
  802. ExFreePool(*pAllocatedResources);
  803. *pAllocatedResources = NULL;
  804. }
  805. //
  806. // Restore the device settings as we found them, enable memory
  807. // and io decode after setting base addresses
  808. //
  809. HalpWritePCIConfig(
  810. BusHandler,
  811. PciSlot,
  812. &PciOrigData->Status,
  813. FIELD_OFFSET(PCI_COMMON_CONFIG, Status),
  814. PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
  815. );
  816. HalpWritePCIConfig(
  817. BusHandler,
  818. PciSlot,
  819. PciOrigData,
  820. 0,
  821. FIELD_OFFSET(PCI_COMMON_CONFIG, Status)
  822. );
  823. }
  824. ExFreePool(WorkingPool);
  825. return(status);
  826. }
  827. BOOLEAN
  828. HalpValidPCISlot(
  829. IN PBUS_HANDLER BusHandler,
  830. IN PCI_SLOT_NUMBER Slot
  831. )
  832. /*++
  833. Routine Description:
  834. The function validates the information specifying a PCI "slot".
  835. Arguments:
  836. BusHandler - An encapsulation of data and manipulation functions specific to
  837. this bus.
  838. Slot - A PCI "slot" description (ie bus number, device number and function
  839. number.)
  840. Return Value:
  841. Returns TRUE if "slot" valid, otherwise FALSE.
  842. --*/
  843. {
  844. PCI_SLOT_NUMBER Slot2;
  845. PPCIPBUSDATA BusData;
  846. UCHAR HeaderType;
  847. ULONG i;
  848. BusData = (PPCIPBUSDATA)BusHandler->BusData;
  849. if (Slot.u.bits.Reserved != 0)
  850. return(FALSE);
  851. if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice)
  852. return(FALSE);
  853. if (Slot.u.bits.FunctionNumber == 0)
  854. return(TRUE);
  855. //
  856. // Read DeviceNumber, Function zero, to determine if the
  857. // PCI supports multifunction devices
  858. //
  859. Slot.u.bits.FunctionNumber = 0;
  860. HalpPCIConfig(
  861. BusHandler,
  862. Slot,
  863. &HeaderType,
  864. FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType),
  865. sizeof(UCHAR),
  866. PCI_READ
  867. );
  868. //
  869. // FALSE if this device doesn't exist or doesn't support MULTIFUNCTION types
  870. //
  871. if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF)
  872. return(FALSE);
  873. return(TRUE);
  874. }
  875. //
  876. // This table is used to determine correct access size to PCI configuration
  877. // space given (offset % 4) and (length % 4).
  878. //
  879. // usage: PCIDeref[offset%4][length%4];
  880. //
  881. // Key:
  882. // 4 - implies a ULONG access and is the number of bytes returned
  883. // 1 - implies a UCHAR access and is the number of bytes returned
  884. // 2 - implies a USHORT access and is the number of bytes returned
  885. //
  886. UCHAR PCIDeref[4][4] = {{4,1,2,2}, {1,1,1,1}, {2,1,2,2}, {1,1,1,1}};
  887. #define SIZEOF_PARTIAL_INFO_HEADER FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)
  888. VOID
  889. HalpPCIConfig(
  890. IN PBUS_HANDLER BusHandler,
  891. IN PCI_SLOT_NUMBER Slot,
  892. IN OUT PUCHAR Buffer,
  893. IN ULONG Offset,
  894. IN ULONG Length,
  895. IN PCI_ACCESS_TYPE AccType
  896. )
  897. {
  898. KIRQL Irql;
  899. ULONG Size;
  900. ULONG SALFunc;
  901. ULONG CfgAddr;
  902. ULONG WriteVal;
  903. SAL_PAL_RETURN_VALUES RetVals;
  904. SAL_STATUS Stat;
  905. //
  906. // Generate a PCI configuration address
  907. //
  908. CfgAddr = (BusHandler->BusNumber << 16) |
  909. (Slot.u.bits.DeviceNumber << 11) |
  910. (Slot.u.bits.FunctionNumber << 8);
  911. //
  912. // As an optimization we could have a separate spinlock for each
  913. // host adapter
  914. // SAL should do whatever locking required.
  915. //
  916. if (!HalpDoingCrashDump) {
  917. Irql = KeAcquireSpinLockRaiseToSynch(&HalpPCIConfigLock);
  918. }
  919. while (Length) {
  920. Size = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
  921. //
  922. // Set up input parameters
  923. //
  924. if (AccType == PCI_READ) {
  925. SALFunc = SAL_PCI_CONFIG_READ;
  926. WriteVal = 0;
  927. } else {
  928. switch (Size) {
  929. case 4: WriteVal = *((PULONG)Buffer); break;
  930. case 2: WriteVal = *((PUSHORT)Buffer); break;
  931. case 1: WriteVal = *Buffer; break;
  932. }
  933. SALFunc = SAL_PCI_CONFIG_WRITE;
  934. }
  935. //
  936. // Make SAL call
  937. //
  938. Stat = HalpSalCall(SALFunc, CfgAddr | Offset, Size, WriteVal, 0, 0, 0, 0, &RetVals);
  939. //
  940. // Retrieve SAL return data
  941. //
  942. if (AccType == PCI_READ) {
  943. switch (Size) {
  944. case 4: *((PULONG)Buffer) = (ULONG)RetVals.ReturnValues[1]; break;
  945. case 2: *((PUSHORT)Buffer) = (USHORT)RetVals.ReturnValues[1]; break;
  946. case 1: *Buffer = (UCHAR)RetVals.ReturnValues[1]; break;
  947. }
  948. }
  949. Offset += Size;
  950. Buffer += Size;
  951. Length -= Size;
  952. }
  953. //
  954. // Release spinlock
  955. //
  956. if (!HalpDoingCrashDump) {
  957. KeReleaseSpinLock(&HalpPCIConfigLock, Irql);
  958. }
  959. }
  960. VOID
  961. HalpReadPCIConfig(
  962. IN PBUS_HANDLER BusHandler,
  963. IN PCI_SLOT_NUMBER Slot,
  964. OUT PVOID Buffer,
  965. IN ULONG Offset,
  966. IN ULONG Length
  967. )
  968. {
  969. //
  970. // If request for an invalid slot, fill return buffer with -1
  971. //
  972. if (!HalpValidPCISlot(BusHandler, Slot)) {
  973. RtlFillMemory(Buffer, Length, (UCHAR)-1);
  974. return;
  975. }
  976. HalpPCIConfig(BusHandler, Slot, Buffer, Offset, Length, PCI_READ);
  977. }
  978. VOID
  979. HalpWritePCIConfig(
  980. IN PBUS_HANDLER BusHandler,
  981. IN PCI_SLOT_NUMBER Slot,
  982. IN PVOID Buffer,
  983. IN ULONG Offset,
  984. IN ULONG Length
  985. )
  986. {
  987. //
  988. // If request for an invalid slot, do nothing
  989. //
  990. if (!HalpValidPCISlot(BusHandler, Slot))
  991. return;
  992. HalpPCIConfig(BusHandler, Slot, Buffer, Offset, Length, PCI_WRITE);
  993. }
  994. BOOLEAN
  995. HalpIsValidPCIDevice(
  996. IN PBUS_HANDLER BusHandler,
  997. IN PCI_SLOT_NUMBER Slot
  998. )
  999. /*++
  1000. Routine Description:
  1001. Reads the device configuration data for the given slot and
  1002. returns TRUE if the configuration data appears to be valid for
  1003. a PCI device; otherwise returns FALSE.
  1004. Arguments:
  1005. BusHandler - Bus to check
  1006. Slot - Slot to check
  1007. --*/
  1008. {
  1009. PPCI_COMMON_CONFIG PciData;
  1010. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  1011. ULONG i, j;
  1012. PciData = (PPCI_COMMON_CONFIG)iBuffer;
  1013. //
  1014. // Read device common header.
  1015. //
  1016. HalpReadPCIConfig(BusHandler, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1017. //
  1018. // Valid device header?
  1019. //
  1020. if (PciData->VendorID == PCI_INVALID_VENDORID ||
  1021. PCI_CONFIG_TYPE(PciData) != PCI_DEVICE_TYPE) {
  1022. return(FALSE);
  1023. }
  1024. //
  1025. // Check fields for reasonable values.
  1026. //
  1027. //
  1028. // Do these values make sense for IA64
  1029. //
  1030. if ((PciData->u.type0.InterruptPin && PciData->u.type0.InterruptPin > 4) ||
  1031. (PciData->u.type0.InterruptLine & 0x70)) {
  1032. return(FALSE);
  1033. }
  1034. for (i=0; i < PCI_TYPE0_ADDRESSES; i++) {
  1035. j = PciData->u.type0.BaseAddresses[i];
  1036. if (j & PCI_ADDRESS_IO_SPACE) {
  1037. if (j > 0xffff) {
  1038. // IO port > 64k?
  1039. return(FALSE);
  1040. }
  1041. } else {
  1042. if (j > 0xf && j < 0x80000) {
  1043. // Mem address < 0x8000h?
  1044. return(FALSE);
  1045. }
  1046. }
  1047. if (Is64BitBaseAddress(j))
  1048. i++;
  1049. }
  1050. //
  1051. // Guess it's a valid device..
  1052. //
  1053. return(TRUE);
  1054. }
  1055. #if !defined(NO_LEGACY_DRIVERS)
  1056. #if DBG
  1057. VOID
  1058. HalpTestPci (ULONG flag2)
  1059. {
  1060. PCI_SLOT_NUMBER SlotNumber;
  1061. PCI_COMMON_CONFIG PciData, OrigData;
  1062. ULONG i, f, j, k, bus;
  1063. BOOLEAN flag;
  1064. if (!flag2) {
  1065. return ;
  1066. }
  1067. DbgBreakPoint ();
  1068. SlotNumber.u.bits.Reserved = 0;
  1069. //
  1070. // Read every possible PCI Device/Function and display it's
  1071. // default info.
  1072. //
  1073. // (note this destories it's current settings)
  1074. //
  1075. flag = TRUE;
  1076. for (bus = 0; flag; bus++) {
  1077. for (i = 0; i < PCI_MAX_DEVICES; i++) {
  1078. SlotNumber.u.bits.DeviceNumber = i;
  1079. for (f = 0; f < PCI_MAX_FUNCTION; f++) {
  1080. SlotNumber.u.bits.FunctionNumber = f;
  1081. //
  1082. // Note: This is reading the DeviceSpecific area of
  1083. // the device's configuration - normally this should
  1084. // only be done on device for which the caller understands.
  1085. // I'm doing it here only for debugging.
  1086. //
  1087. j = HalGetBusData (
  1088. PCIConfiguration,
  1089. bus,
  1090. SlotNumber.u.AsULONG,
  1091. &PciData,
  1092. sizeof (PciData)
  1093. );
  1094. if (j == 0) {
  1095. // out of buses
  1096. flag = FALSE;
  1097. break;
  1098. }
  1099. if (j < PCI_COMMON_HDR_LENGTH) {
  1100. continue;
  1101. }
  1102. HalSetBusData (
  1103. PCIConfiguration,
  1104. bus,
  1105. SlotNumber.u.AsULONG,
  1106. &PciData,
  1107. 1
  1108. );
  1109. HalGetBusData (
  1110. PCIConfiguration,
  1111. bus,
  1112. SlotNumber.u.AsULONG,
  1113. &PciData,
  1114. sizeof (PciData)
  1115. );
  1116. HalDebugPrint(( HAL_INFO, "HAL: PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx",
  1117. bus, i, f, PciData.VendorID, PciData.DeviceID,
  1118. PciData.RevisionID ));
  1119. if (PciData.u.type0.InterruptPin) {
  1120. HalDebugPrint(( HAL_INFO, " IntPin:%x", PciData.u.type0.InterruptPin ));
  1121. }
  1122. if (PciData.u.type0.InterruptLine) {
  1123. HalDebugPrint(( HAL_INFO, " IntLine:%x", PciData.u.type0.InterruptLine ));
  1124. }
  1125. if (PciData.u.type0.ROMBaseAddress) {
  1126. HalDebugPrint(( HAL_INFO, " ROM:%08lx", PciData.u.type0.ROMBaseAddress ));
  1127. }
  1128. HalDebugPrint(( HAL_INFO, "\nHAL: Cmd:%04x Status:%04x ProgIf:%04x SubClass:%04x BaseClass:%04lx\n",
  1129. PciData.Command, PciData.Status, PciData.ProgIf,
  1130. PciData.SubClass, PciData.BaseClass ));
  1131. k = 0;
  1132. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  1133. if (PciData.u.type0.BaseAddresses[j]) {
  1134. HalDebugPrint(( HAL_INFO, " Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j] ));
  1135. k = 1;
  1136. }
  1137. }
  1138. if (k) {
  1139. HalDebugPrint(( HAL_INFO, "\n" ));
  1140. }
  1141. if (PciData.VendorID == 0x8086) {
  1142. // dump complete buffer
  1143. HalDebugPrint(( HAL_INFO, "HAL: Command %x, Status %x, BIST %x\n",
  1144. PciData.Command, PciData.Status,
  1145. PciData.BIST
  1146. ));
  1147. HalDebugPrint(( HAL_INFO, "HAL: CacheLineSz %x, LatencyTimer %x",
  1148. PciData.CacheLineSize, PciData.LatencyTimer
  1149. ));
  1150. for (j=0; j < 192; j++) {
  1151. if ((j & 0xf) == 0) {
  1152. HalDebugPrint(( HAL_INFO, "\n%02x: ", j + 0x40 ));
  1153. }
  1154. HalDebugPrint(( HAL_INFO, "%02x ", PciData.DeviceSpecific[j] ));
  1155. }
  1156. HalDebugPrint(( HAL_INFO, "\n" ));
  1157. }
  1158. //
  1159. // Next
  1160. //
  1161. if (k) {
  1162. HalDebugPrint(( HAL_INFO, "\n\n" ));
  1163. }
  1164. }
  1165. }
  1166. }
  1167. DbgBreakPoint ();
  1168. }
  1169. #endif
  1170. #endif // NO_LEGACY_DRIVERS
  1171. //------------------------------------------------------------------------------
  1172. PPCI_REGISTRY_INFO_INTERNAL
  1173. HalpQueryPciRegistryInfo (
  1174. VOID
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. Reads information from the registry concerning PCI, including the number
  1179. of buses and the hardware access mechanism.
  1180. Arguments:
  1181. None.
  1182. Returns:
  1183. Buffer that must be freed by the caller, NULL if insufficient memory exists
  1184. to complete the request, or the information cannot be located.
  1185. --*/
  1186. {
  1187. PPCI_REGISTRY_INFO_INTERNAL PCIRegInfo = NULL;
  1188. PPCI_REGISTRY_INFO PCIRegInfoHeader = NULL;
  1189. UNICODE_STRING unicodeString, ConfigName, IdentName;
  1190. HANDLE hMFunc, hBus, hCardList;
  1191. OBJECT_ATTRIBUTES objectAttributes;
  1192. NTSTATUS status;
  1193. static UCHAR buffer [sizeof(PPCI_REGISTRY_INFO) + 99];
  1194. PWSTR p;
  1195. WCHAR wstr[8];
  1196. ULONG i, junk;
  1197. ULONG cardListIndex, cardCount, cardMax;
  1198. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  1199. PCM_FULL_RESOURCE_DESCRIPTOR Desc;
  1200. PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
  1201. UCHAR partialInfo[SIZEOF_PARTIAL_INFO_HEADER +
  1202. sizeof(PCI_CARD_DESCRIPTOR)];
  1203. PKEY_VALUE_PARTIAL_INFORMATION partialInfoHeader;
  1204. KEY_FULL_INFORMATION keyFullInfo;
  1205. //
  1206. // Search the hardware description looking for any reported
  1207. // PCI bus. The first ARC entry for a PCI bus will contain
  1208. // the PCI_REGISTRY_INFO.
  1209. RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
  1210. InitializeObjectAttributes (
  1211. &objectAttributes,
  1212. &unicodeString,
  1213. OBJ_CASE_INSENSITIVE,
  1214. NULL, // handle
  1215. NULL);
  1216. status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
  1217. if (!NT_SUCCESS(status)) {
  1218. return NULL;
  1219. }
  1220. unicodeString.Buffer = wstr;
  1221. unicodeString.MaximumLength = sizeof (wstr);
  1222. RtlInitUnicodeString (&ConfigName, rgzConfigurationData);
  1223. RtlInitUnicodeString (&IdentName, rgzIdentifier);
  1224. ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer;
  1225. for (i=0; TRUE; i++) {
  1226. RtlIntegerToUnicodeString (i, 10, &unicodeString);
  1227. InitializeObjectAttributes (
  1228. &objectAttributes,
  1229. &unicodeString,
  1230. OBJ_CASE_INSENSITIVE,
  1231. hMFunc,
  1232. NULL);
  1233. status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
  1234. if (!NT_SUCCESS(status)) {
  1235. //
  1236. // Out of Multifunction adapter entries...
  1237. //
  1238. ZwClose (hMFunc);
  1239. return NULL;
  1240. }
  1241. //
  1242. // Check the Identifier to see if this is a PCI entry
  1243. //
  1244. status = ZwQueryValueKey (
  1245. hBus,
  1246. &IdentName,
  1247. KeyValueFullInformation,
  1248. ValueInfo,
  1249. sizeof (buffer),
  1250. &junk
  1251. );
  1252. if (!NT_SUCCESS (status)) {
  1253. ZwClose (hBus);
  1254. continue;
  1255. }
  1256. p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset);
  1257. if (p[0] != L'P' || p[1] != L'C' || p[2] != L'I' || p[3] != 0) {
  1258. ZwClose (hBus);
  1259. continue;
  1260. }
  1261. //
  1262. // The first PCI entry has the PCI_REGISTRY_INFO structure
  1263. // attached to it.
  1264. //
  1265. status = ZwQueryValueKey (
  1266. hBus,
  1267. &ConfigName,
  1268. KeyValueFullInformation,
  1269. ValueInfo,
  1270. sizeof (buffer),
  1271. &junk
  1272. );
  1273. ZwClose (hBus);
  1274. if (!NT_SUCCESS(status)) {
  1275. continue ;
  1276. }
  1277. Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  1278. ValueInfo + ValueInfo->DataOffset);
  1279. PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  1280. Desc->PartialResourceList.PartialDescriptors);
  1281. if (PDesc->Type == CmResourceTypeDeviceSpecific) {
  1282. // got it..
  1283. PCIRegInfoHeader = (PPCI_REGISTRY_INFO) (PDesc+1);
  1284. break;
  1285. }
  1286. }
  1287. if (!PCIRegInfoHeader) {
  1288. return NULL;
  1289. }
  1290. //
  1291. // Retrieve the list of interesting cards.
  1292. //
  1293. RtlInitUnicodeString (&unicodeString, rgzPCICardList);
  1294. InitializeObjectAttributes (
  1295. &objectAttributes,
  1296. &unicodeString,
  1297. OBJ_CASE_INSENSITIVE,
  1298. NULL, // handle
  1299. NULL
  1300. );
  1301. status = ZwOpenKey (&hCardList, KEY_READ, &objectAttributes);
  1302. if (NT_SUCCESS(status)) {
  1303. status = ZwQueryKey( hCardList,
  1304. KeyFullInformation,
  1305. &keyFullInfo,
  1306. sizeof(keyFullInfo),
  1307. &junk );
  1308. if ( NT_SUCCESS(status) ) {
  1309. cardMax = keyFullInfo.Values;
  1310. PCIRegInfo = (PPCI_REGISTRY_INFO_INTERNAL) ExAllocatePoolWithTag(
  1311. NonPagedPool,
  1312. sizeof(PCI_REGISTRY_INFO_INTERNAL) +
  1313. cardMax * sizeof(PCI_CARD_DESCRIPTOR),
  1314. HAL_POOL_TAG
  1315. );
  1316. if (PCIRegInfo) {
  1317. //
  1318. // Now that we've allocated enough room, enumerate again.
  1319. //
  1320. partialInfoHeader = (PKEY_VALUE_PARTIAL_INFORMATION) partialInfo;
  1321. for(cardListIndex = cardCount = 0;
  1322. cardListIndex < cardMax;
  1323. cardListIndex++) {
  1324. status = ZwEnumerateValueKey(
  1325. hCardList,
  1326. cardListIndex,
  1327. KeyValuePartialInformation,
  1328. partialInfo,
  1329. sizeof(partialInfo),
  1330. &junk
  1331. );
  1332. //
  1333. // Note that STATUS_NO_MORE_ENTRIES is a failure code
  1334. //
  1335. if (!NT_SUCCESS( status )) {
  1336. break;
  1337. }
  1338. if (partialInfoHeader->DataLength != sizeof(PCI_CARD_DESCRIPTOR)) {
  1339. continue;
  1340. }
  1341. RtlCopyMemory(
  1342. PCIRegInfo->CardList + cardCount,
  1343. partialInfoHeader->Data,
  1344. sizeof(PCI_CARD_DESCRIPTOR)
  1345. );
  1346. cardCount++;
  1347. } // next cardListIndex
  1348. }
  1349. }
  1350. ZwClose (hCardList);
  1351. }
  1352. if (!PCIRegInfo) {
  1353. PCIRegInfo = (PPCI_REGISTRY_INFO_INTERNAL) ExAllocatePoolWithTag(
  1354. NonPagedPool,
  1355. sizeof(PCI_REGISTRY_INFO_INTERNAL),
  1356. HAL_POOL_TAG
  1357. );
  1358. if (!PCIRegInfo) {
  1359. return NULL;
  1360. }
  1361. cardCount = 0;
  1362. }
  1363. RtlCopyMemory(
  1364. PCIRegInfo,
  1365. PCIRegInfoHeader,
  1366. sizeof(PCI_REGISTRY_INFO)
  1367. );
  1368. PCIRegInfo->ElementCount = cardCount;
  1369. return PCIRegInfo;
  1370. }