2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/enum.c
5 * PURPOSE: PCI Bus/Device Enumeration
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 PCI_CONFIGURATOR PciConfigurators
[] =
20 Device_MassageHeaderForLimitsDetermination
,
21 Device_RestoreCurrent
,
23 Device_SaveCurrentSettings
,
24 Device_ChangeResourceSettings
,
25 Device_GetAdditionalResourceDescriptors
,
29 PPBridge_MassageHeaderForLimitsDetermination
,
30 PPBridge_RestoreCurrent
,
32 PPBridge_SaveCurrentSettings
,
33 PPBridge_ChangeResourceSettings
,
34 PPBridge_GetAdditionalResourceDescriptors
,
38 Cardbus_MassageHeaderForLimitsDetermination
,
39 Cardbus_RestoreCurrent
,
41 Cardbus_SaveCurrentSettings
,
42 Cardbus_ChangeResourceSettings
,
43 Cardbus_GetAdditionalResourceDescriptors
,
48 /* FUNCTIONS ******************************************************************/
51 * 7. The IO/MEM/Busmaster decodes are disabled for the device.
52 * 8. The PCI bus driver sets the operating mode bits of the Programming
53 * Interface byte to switch the controller to native mode.
55 * Important: When the controller is set to native mode, it must quiet itself
56 * and must not decode I/O resources or generate interrupts until the operating
57 * system has enabled the ports in the PCI configuration header.
58 * The IO/MEM/BusMaster bits will be disabled before the mode change, but it
59 * is not possible to disable interrupts on the device. The device must not
60 * generate interrupts (either legacy or native mode) while the decodes are
61 * disabled in the command register.
63 * This operation is expected to be instantaneous and the operating system does
64 * not stall afterward. It is also expected that the interrupt pin register in
65 * the PCI Configuration space for this device is accurate. The operating system
66 * re-reads this data after previously ignoring it.
70 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension
,
71 IN PPCI_COMMON_HEADER PciData
,
74 UCHAR MasterMode
, SlaveMode
, MasterFixed
, SlaveFixed
, ProgIf
, NewProgIf
;
78 /* Assume it won't work */
81 /* Get master and slave current settings, and programmability flag */
82 ProgIf
= PciData
->ProgIf
;
83 MasterMode
= (ProgIf
& 1) == 1;
84 MasterFixed
= (ProgIf
& 2) == 0;
85 SlaveMode
= (ProgIf
& 4) == 4;
86 SlaveFixed
= (ProgIf
& 8) == 0;
89 * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
90 * ATA controller from compatible mode to native mode, the following must be
93 * - The controller must indicate in its programming interface that both channels
94 * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
95 * not support switching only one IDE channel to native mode. See the PCI IDE
96 * Controller Specification Revision 1.0 for details.
98 if ((MasterMode
!= SlaveMode
) || (MasterFixed
!= SlaveFixed
))
100 /* Windows does not support this configuration, fail */
101 DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
102 PdoExtension
->VendorId
,
103 PdoExtension
->DeviceId
);
107 /* Check if the controller is already in native mode */
108 if ((MasterMode
) && (SlaveMode
))
110 /* Check if I/O decodes should be disabled */
111 if ((Initial
) || (PdoExtension
->IoSpaceUnderNativeIdeControl
))
113 /* Read the current command */
114 PciReadDeviceConfig(PdoExtension
,
116 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
119 /* Disable I/O space decode */
120 Command
&= ~PCI_ENABLE_IO_SPACE
;
122 /* Update new command in PCI IDE controller */
123 PciWriteDeviceConfig(PdoExtension
,
125 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
128 /* Save updated command value */
129 PciData
->Command
= Command
;
132 /* The controller is now in native mode */
135 else if (!(MasterFixed
) &&
137 (PdoExtension
->BIOSAllowsIDESwitchToNativeMode
) &&
138 !(PdoExtension
->HackFlags
& PCI_HACK_DISABLE_IDE_NATIVE_MODE
))
140 /* Turn off decodes */
141 PciDecodeEnable(PdoExtension
, FALSE
, NULL
);
143 /* Update the current command */
144 PciReadDeviceConfig(PdoExtension
,
146 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
149 /* Enable native mode */
150 ProgIf
= PciData
->ProgIf
| 5;
151 PciWriteDeviceConfig(PdoExtension
,
153 FIELD_OFFSET(PCI_COMMON_HEADER
, ProgIf
),
156 /* Verify the setting "stuck" */
157 PciReadDeviceConfig(PdoExtension
,
159 FIELD_OFFSET(PCI_COMMON_HEADER
, ProgIf
),
161 if (NewProgIf
== ProgIf
)
163 /* Update the header and PDO data with the new programming mode */
164 PciData
->ProgIf
= ProgIf
;
165 PdoExtension
->ProgIf
= NewProgIf
;
167 /* Clear the first four BARs to reset current BAR setttings */
168 PciData
->u
.type0
.BaseAddresses
[0] = 0;
169 PciData
->u
.type0
.BaseAddresses
[1] = 0;
170 PciData
->u
.type0
.BaseAddresses
[2] = 0;
171 PciData
->u
.type0
.BaseAddresses
[3] = 0;
172 PciWriteDeviceConfig(PdoExtension
,
173 PciData
->u
.type0
.BaseAddresses
,
174 FIELD_OFFSET(PCI_COMMON_HEADER
,
175 u
.type0
.BaseAddresses
),
178 /* Re-read the BARs to have the latest data for native mode IDE */
179 PciReadDeviceConfig(PdoExtension
,
180 PciData
->u
.type0
.BaseAddresses
,
181 FIELD_OFFSET(PCI_COMMON_HEADER
,
182 u
.type0
.BaseAddresses
),
185 /* Re-read the interrupt pin used for native mode IDE */
186 PciReadDeviceConfig(PdoExtension
,
187 &PciData
->u
.type0
.InterruptPin
,
188 FIELD_OFFSET(PCI_COMMON_HEADER
,
189 u
.type0
.InterruptPin
),
192 /* The IDE Controller is now in native mode */
197 /* Settings did not work, fail */
198 DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
204 /* Return whether or not native mode was enabled on the IDE controller */
210 PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension
,
211 IN PPCI_COMMON_HEADER PciData
,
212 IN PCI_SLOT_NUMBER SlotNumber
,
213 IN ULONG OperationType
,
214 PPCI_PDO_EXTENSION PdoExtension
)
216 ULONG LegacyBaseAddress
;
220 /* Check what kind of hack operation this is */
221 switch (OperationType
)
224 * This is mostly concerned with fixing up incorrect class data that can
225 * exist on certain PCI hardware before the 2.0 spec was ratified.
227 case PCI_HACK_FIXUP_BEFORE_CONFIGURATION
:
229 /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
230 * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
231 * and appear as non-classified, so their correct class/subclass data
232 * is written here instead.
234 if ((PciData
->VendorID
== 0x8086) &&
235 ((PciData
->DeviceID
== 0x482) || (PciData
->DeviceID
== 0x484)))
237 /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
238 PciData
->SubClass
= PciData
->DeviceID
== 0x482 ?
239 PCI_SUBCLASS_BR_EISA
: PCI_SUBCLASS_BR_ISA
;
240 PciData
->BaseClass
= PCI_CLASS_BRIDGE_DEV
;
243 * Because the software is modifying the actual header data from
244 * the BIOS, this flag tells the driver to ignore failures when
245 * comparing the original BIOS data with the PCI data.
247 if (PdoExtension
) PdoExtension
->ExpectedWritebackFailure
= TRUE
;
250 /* Note that in this case, an immediate return is issued */
254 * This is concerned with setting up interrupts correctly for native IDE
255 * mode, but will also handle broken VGA decoding on older bridges as
256 * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
258 case PCI_HACK_FIXUP_AFTER_CONFIGURATION
:
260 /* There should always be a PDO extension passed in */
261 ASSERT(PdoExtension
);
264 * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
265 * and FreeBSD bug reports indicate that the system crashes when the
266 * feature is enabled (so it's disabled on that OS as well). In the
267 * NT PCI Bus Driver, it seems Microsoft too, completely disables
268 * Native IDE functionality on this controller, so it would seem OPTi
269 * simply frelled up this controller.
271 if ((PciData
->VendorID
== 0x1045) && (PciData
->DeviceID
!= 0xC621))
273 /* Disable native mode */
274 PciData
->ProgIf
&= ~5;
275 PciData
->u
.type0
.InterruptPin
= 0;
278 * Because the software is modifying the actual header data from
279 * the BIOS, this flag tells the driver to ignore failures when
280 * comparing the original BIOS data with the PCI data.
282 PdoExtension
->ExpectedWritebackFailure
= TRUE
;
284 else if ((PciData
->BaseClass
== PCI_CLASS_MASS_STORAGE_CTLR
) &&
285 (PciData
->SubClass
== PCI_SUBCLASS_MSC_IDE_CTLR
))
287 /* For other IDE controllers, start out in compatible mode */
288 PdoExtension
->BIOSAllowsIDESwitchToNativeMode
= FALSE
;
291 * Registry must have enabled native mode (typically as a result
292 * of an INF file directive part of the IDE controller's driver)
293 * and the system must not be booted in Safe Mode. If that checks
294 * out, then evaluate the ACPI NATA method to see if the platform
295 * supports this. See the section "BIOS and Platform Prerequisites
296 * for Switching a Native-Mode-Capable Controller" in the Storage
297 * section of the Windows Driver Kit for more details:
299 * 5. For each ATA controller enumerated, the PCI bus driver checks
300 * the Programming Interface register of the IDE controller to
301 * see if it supports switching both channels to native mode.
302 * 6. The PCI bus driver checks whether the BIOS/platform supports
303 * switching the controller by checking the NATA method described
304 * earlier in this article.
306 * If an ATA controller does not indicate that it is native
307 * mode-capable, or if the BIOS NATA control method is missing
308 * or does not list that device, the PCI bus driver does not
309 * switch the controller and it is assigned legacy resources.
311 * If both the controller and the BIOS indicate that the controller
312 * can be switched, the process of switching the controller begins
313 * with the next step.
315 if ((PciEnableNativeModeATA
) &&
316 !(InitSafeBootMode
) &&
317 (PciIsSlotPresentInParentMethod(PdoExtension
, 'ATAN')))
319 /* The platform supports it, remember that */
320 PdoExtension
->BIOSAllowsIDESwitchToNativeMode
= TRUE
;
323 * Now switch the controller into native mode if both channels
324 * support native IDE mode. See "How Windows Switches an ATA
325 * Controller to Native Mode" in the Storage section of the
326 * Windows Driver Kit for more details.
328 PdoExtension
->SwitchedIDEToNativeMode
=
329 PciConfigureIdeController(PdoExtension
, PciData
, 1);
332 /* Is native mode enabled after all? */
333 if ((PciData
->ProgIf
& 5) != 5)
335 /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
336 PciData
->u
.type0
.InterruptPin
= 0;
340 /* Is this a PCI device with legacy VGA card decodes on the root bus? */
341 if ((PdoExtension
->HackFlags
& PCI_HACK_VIDEO_LEGACY_DECODE
) &&
342 (PCI_IS_ROOT_FDO(DeviceExtension
)) &&
343 !(DeviceExtension
->BrokenVideoHackApplied
))
345 /* Tell the arbiter to apply a hack for these older devices */
346 ario_ApplyBrokenVideoHack(DeviceExtension
);
349 /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
350 if ((PciData
->VendorID
== 0xE11) &&
351 (PciData
->DeviceID
== 0xA0F7) &&
352 (PciData
->RevisionID
== 17) &&
353 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED
)))
355 /* Turn off the decodes immediately */
356 PciData
->Command
&= ~(PCI_ENABLE_IO_SPACE
|
357 PCI_ENABLE_MEMORY_SPACE
|
358 PCI_ENABLE_BUS_MASTER
);
359 PciWriteDeviceConfig(PdoExtension
,
361 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
364 /* Do not EVER turn them on again, this will blow up the system */
365 PdoExtension
->CommandEnables
&= ~(PCI_ENABLE_IO_SPACE
|
366 PCI_ENABLE_MEMORY_SPACE
|
367 PCI_ENABLE_BUS_MASTER
);
368 PdoExtension
->HackFlags
|= PCI_HACK_PRESERVE_COMMAND
;
373 * This is called whenever resources are changed and hardware needs to be
374 * updated. It is concerned with two highly specific erratas on an IBM
375 * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
378 case PCI_HACK_FIXUP_BEFORE_UPDATE
:
380 /* There should always be a PDO extension passed in */
381 ASSERT(PdoExtension
);
383 /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
384 if ((PdoExtension
->VendorId
== 0x1014) &&
385 (PdoExtension
->DeviceId
== 0x95))
387 /* Read the current command */
388 PciReadDeviceConfig(PdoExtension
,
390 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
393 /* Turn off the decodes */
394 PciDecodeEnable(PdoExtension
, FALSE
, &Command
);
396 /* Apply the required IBM workaround */
397 PciReadDeviceConfig(PdoExtension
, &RegValue
, 0xE0, sizeof(UCHAR
));
400 PciWriteDeviceConfig(PdoExtension
, &RegValue
, 0xE0, sizeof(UCHAR
));
402 /* Restore the command to its original value */
403 PciWriteDeviceConfig(PdoExtension
,
405 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
411 * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
412 * i820, i840, i845 Chipsets) that have subtractive decode enabled,
413 * and whose hack flags do not specifiy that this support is broken.
415 if ((PdoExtension
->HeaderType
== PCI_BRIDGE_TYPE
) &&
416 (PdoExtension
->Dependent
.type1
.SubtractiveDecode
) &&
417 ((PdoExtension
->VendorId
== 0x8086) &&
418 ((PdoExtension
->DeviceId
== 0x2418) ||
419 (PdoExtension
->DeviceId
== 0x2428) ||
420 (PdoExtension
->DeviceId
== 0x244E) ||
421 (PdoExtension
->DeviceId
== 0x2448))) &&
422 !(PdoExtension
->HackFlags
& PCI_HACK_BROKEN_SUBTRACTIVE_DECODE
))
425 * The positive decode window shouldn't be used, these values are
426 * normally all read-only or initialized to 0 by the BIOS, but
427 * it appears Intel doesn't do this, so the PCI Bus Driver will
428 * do it in software instead. Note that this is used to prevent
429 * certain non-compliant PCI devices from breaking down due to the
430 * fact that these ICH bridges have a known "quirk" (which Intel
431 * documents as a known "erratum", although it's not not really
432 * an ICH bug since the PCI specification does allow for it) in
433 * that they will sometimes send non-zero addresses during special
434 * cycles (ie: non-zero data during the address phase). These
435 * broken PCI cards will mistakenly attempt to claim the special
436 * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
437 * defense, the PCI specification only requires stable data, not
438 * necessarily zero data, during the address phase.
440 PciData
->u
.type1
.MemoryBase
= 0xFFFF;
441 PciData
->u
.type1
.PrefetchBase
= 0xFFFF;
442 PciData
->u
.type1
.IOBase
= 0xFF;
443 PciData
->u
.type1
.IOLimit
= 0;
444 PciData
->u
.type1
.MemoryLimit
= 0;
445 PciData
->u
.type1
.PrefetchLimit
= 0;
446 PciData
->u
.type1
.PrefetchBaseUpper32
= 0;
447 PciData
->u
.type1
.PrefetchLimitUpper32
= 0;
448 PciData
->u
.type1
.IOBaseUpper16
= 0;
449 PciData
->u
.type1
.IOLimitUpper16
= 0;
457 /* Finally, also check if this is this a CardBUS device? */
458 if (PCI_CONFIGURATION_TYPE(PciData
) == PCI_CARDBUS_BRIDGE_TYPE
)
461 * At offset 44h the LegacyBaseAddress is stored, which is cleared by
462 * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
463 * CardBus controllers. For more information, see "Supporting CardBus
464 * Controllers under ACPI" in the "CardBus Controllers and Windows"
465 * Whitepaper on WHDC.
467 LegacyBaseAddress
= 0;
468 PciWriteDeviceConfig(PdoExtension
,
470 sizeof(PCI_COMMON_HEADER
) + sizeof(ULONG
),
477 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension
,
478 IN PPCI_COMMON_HEADER PciData
)
480 BOOLEAN IdMatch
, RevMatch
, SubsysMatch
;
481 ULONGLONG HackFlags
= DeviceExtension
->HackFlags
;
483 /* Check if the IDs match */
484 IdMatch
= (PciData
->VendorID
== DeviceExtension
->VendorId
) &&
485 (PciData
->DeviceID
== DeviceExtension
->DeviceId
);
486 if (!IdMatch
) return FALSE
;
488 /* If the device has a valid revision, check if it matches */
489 RevMatch
= (HackFlags
& PCI_HACK_NO_REVISION_AFTER_D3
) ||
490 (PciData
->RevisionID
== DeviceExtension
->RevisionId
);
491 if (!RevMatch
) return FALSE
;
493 /* For multifunction devices, this is enough to assume they're the same */
494 if (PCI_MULTIFUNCTION_DEVICE(PciData
)) return TRUE
;
496 /* For bridge devices, there's also nothing else that can be checked */
497 if (DeviceExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) return TRUE
;
499 /* Devices, on the other hand, have subsystem data that can be compared */
500 SubsysMatch
= (HackFlags
& (PCI_HACK_NO_SUBSYSTEM
|
501 PCI_HACK_NO_SUBSYSTEM_AFTER_D3
)) ||
502 ((DeviceExtension
->SubsystemVendorId
==
503 PciData
->u
.type0
.SubVendorID
) &&
504 (DeviceExtension
->SubsystemId
==
505 PciData
->u
.type0
.SubSystemID
));
511 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData
,
512 IN PCI_SLOT_NUMBER Slot
,
513 IN UCHAR OperationType
,
514 IN ULONGLONG HackFlags
)
518 /* Check if this is device enumeration */
519 if (OperationType
== PCI_SKIP_DEVICE_ENUMERATION
)
521 /* Check if there's a hackflag saying not to enumerate this device */
522 if (HackFlags
& PCI_HACK_NO_ENUM_AT_ALL
) break;
524 /* Check if this is the high end of a double decker device */
525 if ((HackFlags
& PCI_HACK_DOUBLE_DECKER
) &&
526 (Slot
.u
.bits
.DeviceNumber
>= 16))
528 /* It belongs to the same device, so skip it */
529 DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
532 Slot
.u
.bits
.DeviceNumber
,
533 Slot
.u
.bits
.FunctionNumber
);
537 else if (OperationType
== PCI_SKIP_RESOURCE_ENUMERATION
)
539 /* Resource enumeration, check for a hackflag saying not to do it */
540 if (HackFlags
& PCI_HACK_ENUM_NO_RESOURCE
) break;
544 /* Logic error in the driver */
545 ASSERTMSG(FALSE
, "PCI Skip Function - Operation type unknown.");
548 /* Check for legacy bridges during resource enumeration */
549 if ((PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
550 (PciData
->SubClass
<= PCI_SUBCLASS_BR_MCA
) &&
551 (OperationType
== PCI_SKIP_RESOURCE_ENUMERATION
))
553 /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
556 else if (PciData
->BaseClass
== PCI_CLASS_NOT_DEFINED
)
558 /* Undefined base class (usually a PCI BIOS/ROM bug) */
559 DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
564 * The Alder has an Intel Extended Express System Support Controller
565 * which presents apparently spurious BARs. When the PCI resource
566 * code tries to reassign these BARs, the second IO-APIC gets
567 * disabled (with disastrous consequences). The first BAR is the
568 * actual IO-APIC, the remaining five bars seem to be spurious
569 * resources, so ignore this device completely.
571 if ((PciData
->VendorID
== 0x8086) && (PciData
->DeviceID
== 8)) break;
574 /* Other normal PCI cards and bridges are enumerated */
575 if (PCI_CONFIGURATION_TYPE(PciData
) <= PCI_CARDBUS_BRIDGE_TYPE
) return FALSE
;
578 /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
579 DPRINT1(" Device skipped (not enumerated).\n");
585 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension
,
586 IN PPCI_COMMON_HEADER PciData
)
588 ULONG HeaderType
, CapPtr
, TargetAgpCapabilityId
;
589 DEVICE_POWER_STATE WakeLevel
;
590 PCI_CAPABILITIES_HEADER AgpCapability
;
591 PCI_PM_CAPABILITY PowerCapabilities
;
594 /* Assume no known wake level */
595 PdoExtension
->PowerState
.DeviceWakeLevel
= PowerDeviceUnspecified
;
597 /* Make sure the device has capabilities */
598 if (!(PciData
->Status
& PCI_STATUS_CAPABILITIES_LIST
))
600 /* If it doesn't, there will be no power management */
601 PdoExtension
->CapabilitiesPtr
= 0;
602 PdoExtension
->HackFlags
|= PCI_HACK_NO_PM_CAPS
;
606 /* There's capabilities, need to figure out where to get the offset */
607 HeaderType
= PCI_CONFIGURATION_TYPE(PciData
);
608 if (HeaderType
== PCI_CARDBUS_BRIDGE_TYPE
)
610 /* Use the bridge's header */
611 CapPtr
= PciData
->u
.type2
.CapabilitiesPtr
;
615 /* Use the device header */
616 ASSERT(HeaderType
<= PCI_CARDBUS_BRIDGE_TYPE
);
617 CapPtr
= PciData
->u
.type0
.CapabilitiesPtr
;
620 /* Make sure the pointer is spec-aligned and located, and save it */
621 DPRINT1("Device has capabilities at: %lx\n", CapPtr
);
622 ASSERT(((CapPtr
& 0x3) == 0) && (CapPtr
>= PCI_COMMON_HDR_LENGTH
));
623 PdoExtension
->CapabilitiesPtr
= CapPtr
;
625 /* Check for PCI-to-PCI Bridges and AGP bridges */
626 if ((PdoExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
627 ((PdoExtension
->SubClass
== PCI_SUBCLASS_BR_HOST
) ||
628 (PdoExtension
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
)))
630 /* Query either the raw AGP capabilitity, or the Target AGP one */
631 TargetAgpCapabilityId
= (PdoExtension
->SubClass
==
632 PCI_SUBCLASS_BR_PCI_TO_PCI
) ?
633 PCI_CAPABILITY_ID_AGP_TARGET
:
634 PCI_CAPABILITY_ID_AGP
;
635 if (PciReadDeviceCapability(PdoExtension
,
636 PdoExtension
->CapabilitiesPtr
,
637 TargetAgpCapabilityId
,
639 sizeof(PCI_CAPABILITIES_HEADER
)))
641 /* AGP target ID was found, store it */
642 DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId
);
643 PdoExtension
->TargetAgpCapabilityId
= TargetAgpCapabilityId
;
647 /* Check for devices that are known not to have proper power management */
648 if (!(PdoExtension
->HackFlags
& PCI_HACK_NO_PM_CAPS
))
650 /* Query if this device supports power management */
651 if (!PciReadDeviceCapability(PdoExtension
,
652 PdoExtension
->CapabilitiesPtr
,
653 PCI_CAPABILITY_ID_POWER_MANAGEMENT
,
654 &PowerCapabilities
.Header
,
655 sizeof(PCI_PM_CAPABILITY
)))
657 /* No power management, so act as if it had the hackflag set */
658 DPRINT1("No PM caps, disabling PM\n");
659 PdoExtension
->HackFlags
|= PCI_HACK_NO_PM_CAPS
;
663 /* Otherwise, pick the highest wake level that is supported */
664 WakeLevel
= PowerDeviceUnspecified
;
665 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED0
)
666 WakeLevel
= PowerDeviceD0
;
667 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED1
)
668 WakeLevel
= PowerDeviceD1
;
669 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED2
)
670 WakeLevel
= PowerDeviceD2
;
671 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED3Hot
)
672 WakeLevel
= PowerDeviceD3
;
673 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED3Cold
)
674 WakeLevel
= PowerDeviceD3
;
675 PdoExtension
->PowerState
.DeviceWakeLevel
= WakeLevel
;
677 /* Convert the PCI power state to the NT power state */
678 PdoExtension
->PowerState
.CurrentDeviceState
=
679 PowerCapabilities
.PMCSR
.ControlStatus
.PowerState
+ 1;
681 /* Save all the power capabilities */
682 PdoExtension
->PowerCapabilities
= PowerCapabilities
.PMC
.Capabilities
;
683 DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
684 WakeLevel
, PdoExtension
->PowerState
.CurrentDeviceState
);
689 /* At the very end of all this, does this device not have power management? */
690 if (PdoExtension
->HackFlags
& PCI_HACK_NO_PM_CAPS
)
692 /* Then guess the current state based on whether the decodes are on */
693 PdoExtension
->PowerState
.CurrentDeviceState
=
694 PciData
->Command
& (PCI_ENABLE_IO_SPACE
|
695 PCI_ENABLE_MEMORY_SPACE
|
696 PCI_ENABLE_BUS_MASTER
) ?
697 PowerDeviceD0
: PowerDeviceD3
;
698 DPRINT1("PM is off, so assumed device is: %d based on enables\n",
699 PdoExtension
->PowerState
.CurrentDeviceState
);
705 PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved
,
706 IN PPCI_CONFIGURATOR_CONTEXT Context
)
708 PPCI_COMMON_HEADER PciData
, Current
;
709 PPCI_PDO_EXTENSION PdoExtension
;
711 /* Grab all parameters from the context */
712 PdoExtension
= Context
->PdoExtension
;
713 Current
= Context
->Current
;
714 PciData
= Context
->PciData
;
716 /* Write the limit discovery header */
717 PciWriteDeviceConfig(PdoExtension
, PciData
, 0, PCI_COMMON_HDR_LENGTH
);
719 /* Now read what the device indicated the limits are */
720 PciReadDeviceConfig(PdoExtension
, PciData
, 0, PCI_COMMON_HDR_LENGTH
);
722 /* Then write back the original configuration header */
723 PciWriteDeviceConfig(PdoExtension
, Current
, 0, PCI_COMMON_HDR_LENGTH
);
725 /* Copy back the original command that was saved in the context */
726 Current
->Command
= Context
->Command
;
727 if (Context
->Command
)
729 /* Program it back into the device */
730 PciWriteDeviceConfig(PdoExtension
,
732 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
736 /* Copy back the original status that was saved as well */
737 Current
->Status
= Context
->Status
;
739 /* Call the configurator to restore any other data that might've changed */
740 Context
->Configurator
->RestoreCurrent(Context
);
745 PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context
)
747 PPCI_CONFIGURATOR Configurator
;
748 PPCI_COMMON_HEADER PciData
, Current
;
749 PPCI_PDO_EXTENSION PdoExtension
;
750 PCI_IPI_CONTEXT IpiContext
;
751 PIO_RESOURCE_DESCRIPTOR IoDescriptor
;
755 /* Grab all parameters from the context */
756 PdoExtension
= Context
->PdoExtension
;
757 Current
= Context
->Current
;
758 PciData
= Context
->PciData
;
760 /* Save the current PCI Command and Status word */
761 Context
->Status
= Current
->Status
;
762 Context
->Command
= Current
->Command
;
764 /* Now that they're saved, clear the status, and disable all decodes */
766 Current
->Command
&= ~(PCI_ENABLE_IO_SPACE
|
767 PCI_ENABLE_MEMORY_SPACE
|
768 PCI_ENABLE_BUS_MASTER
);
770 /* Make a copy of the current PCI configuration header (with decodes off) */
771 RtlCopyMemory(PciData
, Current
, PCI_COMMON_HDR_LENGTH
);
773 /* Locate the correct resource configurator for this type of device */
774 Configurator
= &PciConfigurators
[PdoExtension
->HeaderType
];
775 Context
->Configurator
= Configurator
;
777 /* Initialize it, which will typically setup the BARs for limit discovery */
778 Configurator
->Initialize(Context
);
780 /* Check for critical devices and PCI Debugging devices */
781 if ((PdoExtension
->HackFlags
& PCI_HACK_CRITICAL_DEVICE
) ||
782 (PdoExtension
->OnDebugPath
))
784 /* Specifically check for a PCI Debugging device */
785 if (PdoExtension
->OnDebugPath
)
787 /* Was it enabled for bus mastering? */
788 if (Context
->Command
& PCI_ENABLE_BUS_MASTER
)
790 /* This decode needs to be re-enabled so debugging can work */
791 PciData
->Command
|= PCI_ENABLE_BUS_MASTER
;
792 Current
->Command
|= PCI_ENABLE_BUS_MASTER
;
795 /* Disable the debugger while the discovery is happening */
799 /* For these devices, an IPI must be sent to force high-IRQL discovery */
800 IpiContext
.Barrier
= 1;
801 IpiContext
.RunCount
= 1;
802 IpiContext
.PdoExtension
= PdoExtension
;
803 IpiContext
.Function
= PciWriteLimitsAndRestoreCurrent
;
804 IpiContext
.Context
= Context
;
805 KeIpiGenericCall(PciExecuteCriticalSystemRoutine
, (ULONG_PTR
)&IpiContext
);
807 /* Re-enable the debugger if this was a PCI Debugging Device */
808 if (PdoExtension
->OnDebugPath
) KdEnableDebugger();
812 /* Otherwise, it's safe to do this in-line at low IRQL */
813 PciWriteLimitsAndRestoreCurrent(PdoExtension
, Context
);
817 * Check if it's valid to compare the headers to see if limit discovery mode
818 * has properly exited (the expected case is that the PCI header would now
819 * be equal to what it was before). In some cases, it is known that this will
820 * fail, because during PciApplyHacks (among other places), software hacks
821 * had to be applied to the header, which the hardware-side will not see, and
822 * thus the headers would appear "different".
824 if (!PdoExtension
->ExpectedWritebackFailure
)
826 /* Read the current PCI header now, after discovery has completed */
827 PciReadDeviceConfig(PdoExtension
, PciData
+ 1, 0, PCI_COMMON_HDR_LENGTH
);
829 /* Check if the current header at entry, is equal to the header now */
830 Offset
= RtlCompareMemory(PciData
+ 1, Current
, PCI_COMMON_HDR_LENGTH
);
831 if (Offset
!= PCI_COMMON_HDR_LENGTH
)
833 /* It's not, which means configuration somehow changed, dump this */
834 DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset
);
835 PciDebugDumpCommonConfig(PciData
+ 1);
836 DPRINT1("----------\n");
837 PciDebugDumpCommonConfig(Current
);
841 /* This PDO should not already have resources, since this is only done once */
842 ASSERT(PdoExtension
->Resources
== NULL
);
844 /* Allocate the structure that will hold the discovered resources and limits */
845 PdoExtension
->Resources
= ExAllocatePoolWithTag(NonPagedPool
,
846 sizeof(PCI_FUNCTION_RESOURCES
),
848 if (!PdoExtension
->Resources
) return STATUS_INSUFFICIENT_RESOURCES
;
850 /* Clear it out for now */
851 RtlZeroMemory(PdoExtension
->Resources
, sizeof(PCI_FUNCTION_RESOURCES
));
853 /* Now call the configurator, which will first store the limits... */
854 Configurator
->SaveLimits(Context
);
856 /* ...and then store the current resources being used */
857 Configurator
->SaveCurrentSettings(Context
);
859 /* Loop all the limit descriptors backwards */
860 IoDescriptor
= &PdoExtension
->Resources
->Limit
[PCI_TYPE0_ADDRESSES
+ 1];
863 /* Keep going until a non-null descriptor is found */
865 if (IoDescriptor
->Type
!= CmResourceTypeNull
) break;
867 /* This is a null descriptor, is it the last one? */
868 if (IoDescriptor
== &PdoExtension
->Resources
->Limit
[PCI_TYPE0_ADDRESSES
+ 1])
870 /* This means the descriptor is NULL, which means discovery failed */
871 DPRINT1("PCI Resources fail!\n");
873 /* No resources will be assigned for the device */
874 ExFreePoolWithTag(PdoExtension
->Resources
, 0);
875 PdoExtension
->Resources
= NULL
;
880 /* Return success here, even if the device has no assigned resources */
881 return STATUS_SUCCESS
;
886 PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension
,
887 IN PPCI_COMMON_HEADER Current
,
888 IN ULONGLONG HackFlags
)
891 PPCI_COMMON_HEADER PciData
;
892 PCI_CONFIGURATOR_CONTEXT Context
;
895 /* Do the hackflags indicate this device should be skipped? */
896 if (PciSkipThisFunction(Current
,
898 PCI_SKIP_RESOURCE_ENUMERATION
,
901 /* Do not process its resources */
902 return STATUS_SUCCESS
;
905 /* Allocate a buffer to hold two PCI configuration headers */
906 PciData
= ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH
, 'BicP');
907 if (!PciData
) return STATUS_INSUFFICIENT_RESOURCES
;
909 /* Set up the context for the resource enumeration, and do it */
910 Context
.Current
= Current
;
911 Context
.PciData
= PciData
;
912 Context
.PdoExtension
= PdoExtension
;
913 Status
= PcipGetFunctionLimits(&Context
);
915 /* Enumeration is completed, free the PCI headers and return the status */
916 ExFreePoolWithTag(PciData
, 0);
922 PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension
)
924 PPCI_PDO_EXTENSION PdoExtension
;
925 PDEVICE_OBJECT PhysicalDeviceObject
;
928 /* Get the PDO Extension */
929 PhysicalDeviceObject
= DeviceExtension
->PhysicalDeviceObject
;
930 PdoExtension
= (PPCI_PDO_EXTENSION
)PhysicalDeviceObject
->DeviceExtension
;
932 /* Cheeck if this is the root bus */
933 if (!PCI_IS_ROOT_FDO(DeviceExtension
))
935 /* Not really handling this year */
939 /* Check for PCI bridges with the ISA bit set, or required */
940 if ((PdoExtension
) &&
941 (PciClassifyDeviceType(PdoExtension
) == PciTypePciBridge
) &&
942 ((PdoExtension
->Dependent
.type1
.IsaBitRequired
) ||
943 (PdoExtension
->Dependent
.type1
.IsaBitSet
)))
945 /* We'll need to do some legacy support */
952 /* Scan all of the root bus' children bridges */
953 for (PdoExtension
= DeviceExtension
->ChildBridgePdoList
;
955 PdoExtension
= PdoExtension
->NextBridge
)
957 /* Find any that have the VGA decode bit on */
958 if (PdoExtension
->Dependent
.type1
.VgaBitSet
)
960 /* Again, some more legacy support we'll have to do */
967 /* Check for ACPI systems where the OS assigns bus numbers */
968 if (PciAssignBusNumbers
)
970 /* Not yet supported */
978 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension
)
980 ULONG MaxDevice
= PCI_MAX_DEVICES
;
981 BOOLEAN ProcessFlag
= FALSE
;
983 USHORT CapOffset
, TempOffset
;
985 PDEVICE_OBJECT DeviceObject
;
986 UCHAR Buffer
[PCI_COMMON_HDR_LENGTH
];
987 UCHAR BiosBuffer
[PCI_COMMON_HDR_LENGTH
];
988 PPCI_COMMON_HEADER PciData
= (PVOID
)Buffer
;
989 PPCI_COMMON_HEADER BiosData
= (PVOID
)BiosBuffer
;
990 PCI_SLOT_NUMBER PciSlot
;
993 PPCI_PDO_EXTENSION PdoExtension
, NewExtension
;
994 PPCI_PDO_EXTENSION
* BridgeExtension
;
995 PWCHAR DescriptionText
;
996 USHORT SubVendorId
, SubSystemId
;
997 PCI_CAPABILITIES_HEADER CapHeader
, PcixCapHeader
;
998 DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
999 DeviceExtension
, DeviceExtension
->BaseBus
);
1001 /* Is this the root FDO? */
1002 if (!PCI_IS_ROOT_FDO(DeviceExtension
))
1004 /* Other FDOs are not currently supported */
1009 /* Loop every device on the bus */
1010 PciSlot
.u
.bits
.Reserved
= 0;
1011 i
= DeviceExtension
->BaseBus
;
1012 for (j
= 0; j
< MaxDevice
; j
++)
1014 /* Loop every function of each device */
1015 PciSlot
.u
.bits
.DeviceNumber
= j
;
1016 for (k
= 0; k
< PCI_MAX_FUNCTION
; k
++)
1018 /* Build the final slot structure */
1019 PciSlot
.u
.bits
.FunctionNumber
= k
;
1021 /* Read the vendor for this slot */
1022 PciReadSlotConfig(DeviceExtension
,
1028 /* Skip invalid device */
1029 if (PciData
->VendorID
== PCI_INVALID_VENDORID
) continue;
1031 /* Now read the whole header */
1032 PciReadSlotConfig(DeviceExtension
,
1036 PCI_COMMON_HDR_LENGTH
- sizeof(USHORT
));
1038 /* Apply any hacks before even analyzing the configuration header */
1039 PciApplyHacks(DeviceExtension
,
1042 PCI_HACK_FIXUP_BEFORE_CONFIGURATION
,
1045 /* Dump device that was found */
1046 DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
1052 /* Dump the device's header */
1053 PciDebugDumpCommonConfig(PciData
);
1055 /* Find description for this device for the debugger's sake */
1056 DescriptionText
= PciGetDeviceDescriptionMessage(PciData
->BaseClass
,
1058 DPRINT1("Device Description \"%S\".\n",
1059 DescriptionText
? DescriptionText
: L
"(NULL)");
1060 if (DescriptionText
) ExFreePoolWithTag(DescriptionText
, 0);
1062 /* Check if there is an ACPI Watchdog Table */
1065 /* Check if this PCI device is the ACPI Watchdog Device... */
1070 /* Check for non-simple devices */
1071 if ((PCI_MULTIFUNCTION_DEVICE(PciData
)) ||
1072 (PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
))
1074 /* No subsystem data defined for these kinds of bridges */
1080 /* Read the subsystem information from the PCI header */
1081 SubVendorId
= PciData
->u
.type0
.SubVendorID
;
1082 SubSystemId
= PciData
->u
.type0
.SubSystemID
;
1085 /* Get any hack flags for this device */
1086 HackFlags
= PciGetHackFlags(PciData
->VendorID
,
1090 PciData
->RevisionID
);
1092 /* Check if this device is considered critical by the OS */
1093 if (PciIsCriticalDeviceClass(PciData
->BaseClass
, PciData
->SubClass
))
1095 /* Check if normally the decodes would be disabled */
1096 if (!(HackFlags
& PCI_HACK_DONT_DISABLE_DECODES
))
1098 /* Because this device is critical, don't disable them */
1099 DPRINT1("Not allowing PM Because device is critical\n");
1100 HackFlags
|= PCI_HACK_CRITICAL_DEVICE
;
1104 /* PCI bridges with a VGA card are also considered critical */
1105 if ((PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1106 (PciData
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
) &&
1107 (PciData
->u
.type1
.BridgeControl
& PCI_ENABLE_BRIDGE_VGA
) &&
1108 !(HackFlags
& PCI_HACK_DONT_DISABLE_DECODES
))
1110 /* Do not disable their decodes either */
1111 DPRINT1("Not allowing PM because device is VGA\n");
1112 HackFlags
|= PCI_HACK_CRITICAL_DEVICE
;
1115 /* Check if the device should be skipped for whatever reason */
1116 if (PciSkipThisFunction(PciData
,
1118 PCI_SKIP_DEVICE_ENUMERATION
,
1121 /* Skip this device */
1125 /* Check if a PDO has already been created for this device */
1126 PdoExtension
= PciFindPdoByFunction(DeviceExtension
,
1131 /* Rescan scenarios are not yet implemented */
1136 /* Bus processing will need to happen */
1139 /* Create the PDO for this device */
1140 Status
= PciPdoCreate(DeviceExtension
, PciSlot
, &DeviceObject
);
1141 ASSERT(NT_SUCCESS(Status
));
1142 NewExtension
= (PPCI_PDO_EXTENSION
)DeviceObject
->DeviceExtension
;
1144 /* Check for broken devices with wrong/no class codes */
1145 if (HackFlags
& PCI_HACK_FAKE_CLASS_CODE
)
1147 /* Setup a default one */
1148 PciData
->BaseClass
= PCI_CLASS_BASE_SYSTEM_DEV
;
1149 PciData
->SubClass
= PCI_SUBCLASS_SYS_OTHER
;
1151 /* Device will behave erratically when reading back data */
1152 NewExtension
->ExpectedWritebackFailure
= TRUE
;
1155 /* Clone all the information from the header */
1156 NewExtension
->VendorId
= PciData
->VendorID
;
1157 NewExtension
->DeviceId
= PciData
->DeviceID
;
1158 NewExtension
->RevisionId
= PciData
->RevisionID
;
1159 NewExtension
->ProgIf
= PciData
->ProgIf
;
1160 NewExtension
->SubClass
= PciData
->SubClass
;
1161 NewExtension
->BaseClass
= PciData
->BaseClass
;
1162 NewExtension
->HeaderType
= PCI_CONFIGURATION_TYPE(PciData
);
1164 /* Check for modern bridge types, which are managed by the driver */
1165 if ((NewExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1166 ((NewExtension
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
) ||
1167 (NewExtension
->SubClass
== PCI_SUBCLASS_BR_CARDBUS
)))
1169 /* Acquire this device's lock */
1170 KeEnterCriticalRegion();
1171 KeWaitForSingleObject(&DeviceExtension
->ChildListLock
,
1177 /* Scan the bridge list until the first free entry */
1178 for (BridgeExtension
= &DeviceExtension
->ChildBridgePdoList
;
1180 BridgeExtension
= &(*BridgeExtension
)->NextBridge
);
1182 /* Add this PDO as a bridge */
1183 *BridgeExtension
= NewExtension
;
1184 ASSERT(NewExtension
->NextBridge
== NULL
);
1186 /* Release this device's lock */
1187 KeSetEvent(&DeviceExtension
->ChildListLock
,
1190 KeLeaveCriticalRegion();
1193 /* Get the PCI BIOS configuration saved in the registry */
1194 Status
= PciGetBiosConfig(NewExtension
, BiosData
);
1195 if (NT_SUCCESS(Status
))
1197 /* This path has not yet been fully tested by eVb */
1198 DPRINT1("Have BIOS configuration!\n");
1201 /* Check if the PCI BIOS configuration has changed */
1202 if (!PcipIsSameDevice(NewExtension
, BiosData
))
1204 /* This is considered failure, and new data will be saved */
1205 Status
= STATUS_UNSUCCESSFUL
;
1209 /* Data is still correct, check for interrupt line change */
1210 if (BiosData
->u
.type0
.InterruptLine
!=
1211 PciData
->u
.type0
.InterruptLine
)
1213 /* Update the current BIOS with the saved interrupt line */
1214 PciWriteDeviceConfig(NewExtension
,
1215 &BiosData
->u
.type0
.InterruptLine
,
1216 FIELD_OFFSET(PCI_COMMON_HEADER
,
1217 u
.type0
.InterruptLine
),
1221 /* Save the BIOS interrupt line and the initial command */
1222 NewExtension
->RawInterruptLine
= BiosData
->u
.type0
.InterruptLine
;
1223 NewExtension
->InitialCommand
= BiosData
->Command
;
1227 /* Check if no saved data was present or if it was a mismatch */
1228 if (!NT_SUCCESS(Status
))
1230 /* Save the new data */
1231 Status
= PciSaveBiosConfig(NewExtension
, PciData
);
1232 ASSERT(NT_SUCCESS(Status
));
1234 /* Save the interrupt line and command from the device */
1235 NewExtension
->RawInterruptLine
= PciData
->u
.type0
.InterruptLine
;
1236 NewExtension
->InitialCommand
= PciData
->Command
;
1239 /* Save original command from the device and hack flags */
1240 NewExtension
->CommandEnables
= PciData
->Command
;
1241 NewExtension
->HackFlags
= HackFlags
;
1243 /* Get power, AGP, and other capability data */
1244 PciGetEnhancedCapabilities(NewExtension
, PciData
);
1246 /* Now configure the BARs */
1247 Status
= PciGetFunctionLimits(NewExtension
, PciData
, HackFlags
);
1249 /* Power up the device */
1250 PciSetPowerManagedDevicePowerState(NewExtension
, PowerDeviceD0
, FALSE
);
1252 /* Apply any device hacks required for enumeration */
1253 PciApplyHacks(DeviceExtension
,
1256 PCI_HACK_FIXUP_AFTER_CONFIGURATION
,
1259 /* Save interrupt pin */
1260 NewExtension
->InterruptPin
= PciData
->u
.type0
.InterruptPin
;
1263 * Use either this device's actual IRQ line or, if it's connected on
1264 * a master bus whose IRQ line is actually connected to the host, use
1265 * the HAL to query the bus' IRQ line and store that as the adjusted
1266 * interrupt line instead
1268 NewExtension
->AdjustedInterruptLine
= PciGetAdjustedInterruptLine(NewExtension
);
1270 /* Check if this device is used for PCI debugger cards */
1271 NewExtension
->OnDebugPath
= PciIsDeviceOnDebugPath(NewExtension
);
1273 /* Check for devices with invalid/bogus subsystem data */
1274 if (HackFlags
& PCI_HACK_NO_SUBSYSTEM
)
1276 /* Set the subsystem information to zero instead */
1277 NewExtension
->SubsystemVendorId
= 0;
1278 NewExtension
->SubsystemId
= 0;
1281 /* Scan all capabilities */
1282 CapOffset
= NewExtension
->CapabilitiesPtr
;
1285 /* Read this header */
1286 TempOffset
= PciReadDeviceCapability(NewExtension
,
1290 sizeof(PCI_CAPABILITIES_HEADER
));
1291 if (TempOffset
!= CapOffset
)
1293 /* This is a strange issue that shouldn't happen normally */
1294 DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
1296 ASSERT(TempOffset
== CapOffset
);
1299 /* Check for capabilities that this driver cares about */
1300 switch (CapHeader
.CapabilityID
)
1302 /* Power management capability is heavily used by the bus */
1303 case PCI_CAPABILITY_ID_POWER_MANAGEMENT
:
1305 /* Dump the capability */
1307 Size
= sizeof(PCI_PM_CAPABILITY
);
1310 /* AGP capability is required for AGP bus functionality */
1311 case PCI_CAPABILITY_ID_AGP
:
1313 /* Dump the capability */
1315 Size
= sizeof(PCI_AGP_CAPABILITY
);
1318 /* This driver doesn't really use anything other than that */
1321 /* Windows prints this, we could do a translation later */
1322 Name
= "UNKNOWN CAPABILITY";
1327 /* Check if this is a capability that should be dumped */
1330 /* Read the whole capability data */
1331 TempOffset
= PciReadDeviceCapability(NewExtension
,
1333 CapHeader
.CapabilityID
,
1337 if (TempOffset
!= CapOffset
)
1339 /* Again, a strange issue that shouldn't be seen */
1340 DPRINT1("- Failed to read capability data. ***\n");
1341 ASSERT(TempOffset
== CapOffset
);
1345 /* Dump this capability */
1346 DPRINT1("CAP @%02x ID %02x (%s)\n",
1347 CapOffset
, CapHeader
.CapabilityID
, Name
);
1348 for (i
= 0; i
< Size
; i
+= 2)
1349 DPRINT1(" %04x\n", *(PUSHORT
)((ULONG_PTR
)&CapHeader
+ i
));
1352 /* Check the next capability */
1353 CapOffset
= CapHeader
.Next
;
1356 /* Check for IDE controllers */
1357 if ((NewExtension
->BaseClass
== PCI_CLASS_MASS_STORAGE_CTLR
) &&
1358 (NewExtension
->SubClass
== PCI_SUBCLASS_MSC_IDE_CTLR
))
1360 /* Do not allow them to power down completely */
1361 NewExtension
->DisablePowerDown
= TRUE
;
1365 * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
1366 * bridge that is present on certain NT Alpha machines appears as
1367 * non-classified so detect it manually by scanning for its VID/PID.
1369 if (((NewExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1370 ((NewExtension
->SubClass
== PCI_SUBCLASS_BR_ISA
) ||
1371 (NewExtension
->SubClass
== PCI_SUBCLASS_BR_EISA
) ||
1372 (NewExtension
->SubClass
== PCI_SUBCLASS_BR_MCA
))) ||
1373 ((NewExtension
->VendorId
== 0x8086) &&
1374 (NewExtension
->DeviceId
== 0x482)))
1376 /* Do not allow these legacy bridges to be powered down */
1377 NewExtension
->DisablePowerDown
= TRUE
;
1380 /* Check if the BIOS did not configure a cache line size */
1381 if (!PciData
->CacheLineSize
)
1383 /* Check if the device is disabled */
1384 if (!(NewExtension
->CommandEnables
& (PCI_ENABLE_IO_SPACE
|
1385 PCI_ENABLE_MEMORY_SPACE
|
1386 PCI_ENABLE_BUS_MASTER
)))
1388 /* Check if this is a PCI-X device*/
1389 TempOffset
= PciReadDeviceCapability(NewExtension
,
1390 NewExtension
->CapabilitiesPtr
,
1391 PCI_CAPABILITY_ID_PCIX
,
1393 sizeof(PCI_CAPABILITIES_HEADER
));
1396 * A device with default cache line size and latency timer
1397 * settings is considered to be unconfigured. Note that on
1398 * PCI-X, the reset value of the latency timer field in the
1399 * header is 64, not 0, hence why the check for PCI-X caps
1400 * was required, and the value used here below.
1402 if (!(PciData
->LatencyTimer
) ||
1403 ((TempOffset
) && (PciData
->LatencyTimer
== 64)))
1405 /* Keep track of the fact that it needs configuration */
1406 DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
1408 NewExtension
->NeedsHotPlugConfiguration
= TRUE
;
1413 /* Save latency and cache size information */
1414 NewExtension
->SavedLatencyTimer
= PciData
->LatencyTimer
;
1415 NewExtension
->SavedCacheLineSize
= PciData
->CacheLineSize
;
1417 /* The PDO is now ready to go */
1418 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1422 /* Enumeration completed, do a final pass now that all devices are found */
1423 if (ProcessFlag
) PciProcessBus(DeviceExtension
);
1424 return STATUS_SUCCESS
;
1429 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension
,
1430 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
1433 PPCI_PDO_EXTENSION PdoExtension
;
1435 PDEVICE_RELATIONS DeviceRelations
, NewRelations
;
1437 PDEVICE_OBJECT DeviceObject
, *ObjectArray
;
1440 /* Make sure the FDO is started */
1441 ASSERT(DeviceExtension
->DeviceState
== PciStarted
);
1443 /* Synchronize while we enumerate the bus */
1444 Status
= PciBeginStateTransition(DeviceExtension
, PciSynchronizedOperation
);
1445 if (!NT_SUCCESS(Status
)) return Status
;
1447 /* Scan all children PDO */
1448 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
1450 PdoExtension
= PdoExtension
->Next
)
1452 /* Invalidate them */
1453 PdoExtension
->NotPresent
= TRUE
;
1456 /* Scan the PCI Bus */
1457 Status
= PciScanBus(DeviceExtension
);
1458 ASSERT(NT_SUCCESS(Status
));
1460 /* Enumerate all children PDO again */
1461 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
1463 PdoExtension
= PdoExtension
->Next
)
1465 /* Check for PDOs that are still invalidated */
1466 if (PdoExtension
->NotPresent
)
1468 /* This means this PDO existed before, but not anymore */
1469 PdoExtension
->ReportedMissing
= TRUE
;
1470 DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
1475 /* Increase count of detected PDOs */
1480 /* Read the current relations and add the newly discovered relations */
1481 DeviceRelations
= *pDeviceRelations
;
1482 Size
= FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) +
1483 PdoCount
* sizeof(PDEVICE_OBJECT
);
1484 if (DeviceRelations
) Size
+= sizeof(PDEVICE_OBJECT
) * DeviceRelations
->Count
;
1486 /* Allocate the device relations */
1487 NewRelations
= (PDEVICE_RELATIONS
)ExAllocatePoolWithTag(0, Size
, 'BicP');
1490 /* Out of space, cancel the operation */
1491 PciCancelStateTransition(DeviceExtension
, PciSynchronizedOperation
);
1492 return STATUS_INSUFFICIENT_RESOURCES
;
1495 /* Check if there were any older relations */
1496 NewRelations
->Count
= 0;
1497 if (DeviceRelations
)
1499 /* Copy the old relations into the new buffer, then free the old one */
1500 RtlCopyMemory(NewRelations
,
1502 FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) +
1503 DeviceRelations
->Count
* sizeof(PDEVICE_OBJECT
));
1504 ExFreePoolWithTag(DeviceRelations
, 0);
1507 /* Print out that we're ready to dump relations */
1508 DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
1510 DeviceExtension
->BaseBus
);
1512 /* Loop the current PDO children and the device relation object array */
1513 PdoExtension
= DeviceExtension
->ChildPdoList
;
1514 ObjectArray
= &NewRelations
->Objects
[NewRelations
->Count
];
1515 while (PdoExtension
)
1517 /* Dump this relation */
1518 DPRINT1(" QDR PDO %08x (x %08x)%s\n",
1519 PdoExtension
->PhysicalDeviceObject
,
1521 PdoExtension
->NotPresent
?
1522 "<Omitted, device flaged not present>" : "");
1524 /* Is this PDO present? */
1525 if (!PdoExtension
->NotPresent
)
1527 /* Reference it and add it to the array */
1528 DeviceObject
= PdoExtension
->PhysicalDeviceObject
;
1529 ObfReferenceObject(DeviceObject
);
1530 *ObjectArray
++ = DeviceObject
;
1533 /* Go to the next PDO */
1534 PdoExtension
= PdoExtension
->Next
;
1537 /* Terminate dumping the relations */
1538 DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
1539 NewRelations
->Count
+ PdoCount
,
1540 NewRelations
->Count
);
1542 /* Return the final count and the new buffer */
1543 NewRelations
->Count
+= PdoCount
;
1544 *pDeviceRelations
= NewRelations
;
1545 return STATUS_SUCCESS
;