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 /* FUNCTIONS ******************************************************************/
21 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData
,
22 IN PCI_SLOT_NUMBER Slot
,
23 IN UCHAR OperationType
,
24 IN ULONGLONG HackFlags
)
28 /* Check if this is device enumeration */
29 if (OperationType
== PCI_SKIP_DEVICE_ENUMERATION
)
31 /* Check if there's a hackflag saying not to enumerate this device */
32 if (HackFlags
& PCI_HACK_NO_ENUM_AT_ALL
) break;
34 /* Check if this is the high end of a double decker device */
35 if ((HackFlags
& PCI_HACK_DOUBLE_DECKER
) &&
36 (Slot
.u
.bits
.DeviceNumber
>= 16))
38 /* It belongs to the same device, so skip it */
39 DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
42 Slot
.u
.bits
.DeviceNumber
,
43 Slot
.u
.bits
.FunctionNumber
);
47 else if (OperationType
== PCI_SKIP_RESOURCE_ENUMERATION
)
49 /* Resource enumeration, check for a hackflag saying not to do it */
50 if (HackFlags
& PCI_HACK_ENUM_NO_RESOURCE
) break;
54 /* Logic error in the driver */
55 ASSERTMSG(FALSE
, "PCI Skip Function - Operation type unknown.");
58 /* Check for legacy bridges during resource enumeration */
59 if ((PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
60 (PciData
->SubClass
<= PCI_SUBCLASS_BR_MCA
) &&
61 (OperationType
== PCI_SKIP_RESOURCE_ENUMERATION
))
63 /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
66 else if (PciData
->BaseClass
== PCI_CLASS_NOT_DEFINED
)
68 /* Undefined base class (usually a PCI BIOS/ROM bug) */
69 DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
74 * The Alder has an Intel Extended Express System Support Controller
75 * which presents apparently spurious BARs. When the PCI resource
76 * code tries to reassign these BARs, the second IO-APIC gets
77 * disabled (with disastrous consequences). The first BAR is the
78 * actual IO-APIC, the remaining five bars seem to be spurious
79 * resources, so ignore this device completely.
81 if ((PciData
->VendorID
== 0x8086) && (PciData
->DeviceID
== 8)) break;
84 /* Other normal PCI cards and bridges are enumerated */
85 if (PCI_CONFIGURATION_TYPE(PciData
) <= PCI_CARDBUS_BRIDGE_TYPE
) return FALSE
;
88 /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
89 DPRINT1(" Device skipped (not enumerated).\n");
95 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension
)
97 ULONG MaxDevice
= PCI_MAX_DEVICES
;
100 UCHAR Buffer
[PCI_COMMON_HDR_LENGTH
];
101 PPCI_COMMON_HEADER PciData
= (PVOID
)Buffer
;
102 PCI_SLOT_NUMBER PciSlot
;
103 PWCHAR DescriptionText
;
104 USHORT SubVendorId
, SubSystemId
;
105 PPCI_PDO_EXTENSION PdoExtension
;
106 DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
107 DeviceExtension
, DeviceExtension
->BaseBus
);
109 /* Is this the root FDO? */
110 if (!PCI_IS_ROOT_FDO(DeviceExtension
))
112 /* Other FDOs are not currently supported */
117 /* Loop every device on the bus */
118 PciSlot
.u
.bits
.Reserved
= 0;
119 i
= DeviceExtension
->BaseBus
;
120 for (j
= 0; j
< MaxDevice
; j
++)
122 /* Loop every function of each device */
123 PciSlot
.u
.bits
.DeviceNumber
= j
;
124 for (k
= 0; k
< PCI_MAX_FUNCTION
; k
++)
126 /* Build the final slot structure */
127 PciSlot
.u
.bits
.FunctionNumber
= k
;
129 /* Read the vendor for this slot */
130 PciReadSlotConfig(DeviceExtension
,
136 /* Skip invalid device */
137 if (PciData
->VendorID
== PCI_INVALID_VENDORID
) continue;
139 /* Now read the whole header */
140 PciReadSlotConfig(DeviceExtension
,
144 PCI_COMMON_HDR_LENGTH
- sizeof(USHORT
));
146 /* Dump device that was found */
147 DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
153 /* Dump the device's header */
154 PciDebugDumpCommonConfig(PciData
);
156 /* Find description for this device for the debugger's sake */
157 DescriptionText
= PciGetDeviceDescriptionMessage(PciData
->BaseClass
,
159 DPRINT1("Device Description \"%S\".\n", DescriptionText
? DescriptionText
: L
"(NULL)");
160 if (DescriptionText
) ExFreePoolWithTag(DescriptionText
, 0);
162 /* Check if there is an ACPI Watchdog Table */
165 /* Check if this PCI device is the ACPI Watchdog Device... */
170 /* Check for non-simple devices */
171 if ((PCI_MULTIFUNCTION_DEVICE(PciData
)) ||
172 (PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
))
174 /* No subsystem data defined for these kinds of bridges */
180 /* Read the subsystem information from the PCI header */
181 SubVendorId
= PciData
->u
.type0
.SubVendorID
;
182 SubSystemId
= PciData
->u
.type0
.SubSystemID
;
185 /* Get any hack flags for this device */
186 HackFlags
= PciGetHackFlags(PciData
->VendorID
,
190 PciData
->RevisionID
);
192 /* Check if this device is considered critical by the OS */
193 if (PciIsCriticalDeviceClass(PciData
->BaseClass
, PciData
->SubClass
))
195 /* Check if normally the decodes would be disabled */
196 if (!(HackFlags
& PCI_HACK_DONT_DISABLE_DECODES
))
198 /* Because this device is critical, don't disable them */
199 DPRINT1("Not allowing PM Because device is critical\n");
200 HackFlags
|= PCI_HACK_CRITICAL_DEVICE
;
204 /* PCI bridges with a VGA card are also considered critical */
205 if ((PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
206 (PciData
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
) &&
207 (PciData
->u
.type1
.BridgeControl
& PCI_ENABLE_BRIDGE_VGA
) &&
208 !(HackFlags
& PCI_HACK_DONT_DISABLE_DECODES
))
210 /* Do not disable their decodes either */
211 DPRINT1("Not allowing PM because device is VGA\n");
212 HackFlags
|= PCI_HACK_CRITICAL_DEVICE
;
215 /* Also skip devices that should not be enumerated */
216 if (PciSkipThisFunction(PciData
, PciSlot
, 1, HackFlags
)) continue;
218 /* Check if a PDO has already been created for this device */
219 PdoExtension
= PciFindPdoByFunction(DeviceExtension
,
220 PciSlot
.u
.bits
.FunctionNumber
,
224 /* Rescan scenarios are not yet implemented */
231 /* Enumeration is completed */
232 return STATUS_SUCCESS
;
237 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension
,
238 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
241 PPCI_PDO_EXTENSION PdoExtension
;
243 PDEVICE_RELATIONS DeviceRelations
, NewRelations
;
245 PDEVICE_OBJECT DeviceObject
, *ObjectArray
;
248 /* Make sure the FDO is started */
249 ASSERT(DeviceExtension
->DeviceState
== PciStarted
);
251 /* Synchronize while we enumerate the bus */
252 Status
= PciBeginStateTransition(DeviceExtension
, PciSynchronizedOperation
);
253 if (!NT_SUCCESS(Status
)) return Status
;
255 /* Scan all children PDO */
256 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
258 PdoExtension
= PdoExtension
->Next
)
260 /* Invalidate them */
261 PdoExtension
->NotPresent
= TRUE
;
264 /* Scan the PCI Bus */
265 Status
= PciScanBus(DeviceExtension
);
266 ASSERT(NT_SUCCESS(Status
));
268 /* Enumerate all children PDO again */
269 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
271 PdoExtension
= PdoExtension
->Next
)
273 /* Check for PDOs that are still invalidated */
274 if (PdoExtension
->NotPresent
)
276 /* This means this PDO existed before, but not anymore */
277 PdoExtension
->ReportedMissing
= TRUE
;
278 DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
283 /* Increase count of detected PDOs */
288 /* Read the current relations and add the newly discovered relations */
289 DeviceRelations
= *pDeviceRelations
;
290 Size
= FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) +
291 PdoCount
* sizeof(PDEVICE_OBJECT
);
292 if (DeviceRelations
) Size
+= sizeof(PDEVICE_OBJECT
) * DeviceRelations
->Count
;
294 /* Allocate the device relations */
295 NewRelations
= (PDEVICE_RELATIONS
)ExAllocatePoolWithTag(0, Size
, 'BicP');
298 /* Out of space, cancel the operation */
299 PciCancelStateTransition(DeviceExtension
, PciSynchronizedOperation
);
300 return STATUS_INSUFFICIENT_RESOURCES
;
303 /* Check if there were any older relations */
304 NewRelations
->Count
= 0;
307 /* Copy the old relations into the new buffer, then free the old one */
308 RtlCopyMemory(NewRelations
,
310 FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) +
311 DeviceRelations
->Count
* sizeof(PDEVICE_OBJECT
));
312 ExFreePoolWithTag(DeviceRelations
, 0);
315 /* Print out that we're ready to dump relations */
316 DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
318 DeviceExtension
->BaseBus
);
320 /* Loop the current PDO children and the device relation object array */
321 PdoExtension
= DeviceExtension
->ChildPdoList
;
322 ObjectArray
= &NewRelations
->Objects
[NewRelations
->Count
];
325 /* Dump this relation */
326 DPRINT1(" QDR PDO %08x (x %08x)%s\n",
327 PdoExtension
->PhysicalDeviceObject
,
329 PdoExtension
->NotPresent
?
330 "<Omitted, device flaged not present>" : "");
332 /* Is this PDO present? */
333 if (!PdoExtension
->NotPresent
)
335 /* Reference it and add it to the array */
336 DeviceObject
= PdoExtension
->PhysicalDeviceObject
;
337 ObfReferenceObject(DeviceObject
);
338 *ObjectArray
++ = DeviceObject
;
341 /* Go to the next PDO */
342 PdoExtension
= PdoExtension
->Next
;
345 /* Terminate dumping the relations */
346 DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
347 NewRelations
->Count
+ PdoCount
,
348 NewRelations
->Count
);
350 /* Return the final count and the new buffer */
351 NewRelations
->Count
+= PdoCount
;
352 *pDeviceRelations
= NewRelations
;
353 return STATUS_SUCCESS
;