700f942d7213357b968ae95f62fa6baa2378721f
[reactos.git] / reactos / drivers / bus / pcix / enum.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 /* FUNCTIONS ******************************************************************/
18
19 /*
20 * 7. The IO/MEM/Busmaster decodes are disabled for the device.
21 * 8. The PCI bus driver sets the operating mode bits of the Programming
22 * Interface byte to switch the controller to native mode.
23 *
24 * Important: When the controller is set to native mode, it must quiet itself
25 * and must not decode I/O resources or generate interrupts until the operating
26 * system has enabled the ports in the PCI configuration header.
27 * The IO/MEM/BusMaster bits will be disabled before the mode change, but it
28 * is not possible to disable interrupts on the device. The device must not
29 * generate interrupts (either legacy or native mode) while the decodes are
30 * disabled in the command register.
31 *
32 * This operation is expected to be instantaneous and the operating system does
33 * not stall afterward. It is also expected that the interrupt pin register in
34 * the PCI Configuration space for this device is accurate. The operating system
35 * re-reads this data after previously ignoring it.
36 */
37 BOOLEAN
38 NTAPI
39 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
40 IN PPCI_COMMON_HEADER PciData,
41 IN BOOLEAN Initial)
42 {
43 UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
44 BOOLEAN Switched;
45 USHORT Command;
46
47 /* Assume it won't work */
48 Switched = FALSE;
49
50 /* Get master and slave current settings, and programmability flag */
51 ProgIf = PciData->ProgIf;
52 MasterMode = (ProgIf & 1) == 1;
53 MasterFixed = (ProgIf & 2) == 0;
54 SlaveMode = (ProgIf & 4) == 4;
55 SlaveFixed = (ProgIf & 8) == 0;
56
57 /*
58 * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
59 * ATA controller from compatible mode to native mode, the following must be
60 * true:
61 *
62 * - The controller must indicate in its programming interface that both channels
63 * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
64 * not support switching only one IDE channel to native mode. See the PCI IDE
65 * Controller Specification Revision 1.0 for details.
66 */
67 if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
68 {
69 /* Windows does not support this configuration, fail */
70 DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
71 PdoExtension->VendorId,
72 PdoExtension->DeviceId);
73 return Switched;
74 }
75
76 /* Check if the controller is already in native mode */
77 if ((MasterMode) && (SlaveMode))
78 {
79 /* Check if I/O decodes should be disabled */
80 if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
81 {
82 /* Read the current command */
83 PciReadDeviceConfig(PdoExtension,
84 &Command,
85 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
86 sizeof(USHORT));
87
88 /* Disable I/O space decode */
89 Command &= ~PCI_ENABLE_IO_SPACE;
90
91 /* Update new command in PCI IDE controller */
92 PciWriteDeviceConfig(PdoExtension,
93 &Command,
94 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
95 sizeof(USHORT));
96
97 /* Save updated command value */
98 PciData->Command = Command;
99 }
100
101 /* The controller is now in native mode */
102 Switched = TRUE;
103 }
104 else if (!(MasterFixed) &&
105 !(SlaveFixed) &&
106 (PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
107 !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
108 {
109 /* Turn off decodes */
110 PciDecodeEnable(PdoExtension, FALSE, NULL);
111
112 /* Update the current command */
113 PciReadDeviceConfig(PdoExtension,
114 &PciData->Command,
115 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
116 sizeof(USHORT));
117
118 /* Enable native mode */
119 ProgIf = PciData->ProgIf | 5;
120 PciWriteDeviceConfig(PdoExtension,
121 &ProgIf,
122 FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
123 sizeof(UCHAR));
124
125 /* Verify the setting "stuck" */
126 PciReadDeviceConfig(PdoExtension,
127 &NewProgIf,
128 FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
129 sizeof(UCHAR));
130 if (NewProgIf == ProgIf)
131 {
132 /* Update the header and PDO data with the new programming mode */
133 PciData->ProgIf = ProgIf;
134 PdoExtension->ProgIf = NewProgIf;
135
136 /* Clear the first four BARs to reset current BAR setttings */
137 PciData->u.type0.BaseAddresses[0] = 0;
138 PciData->u.type0.BaseAddresses[1] = 0;
139 PciData->u.type0.BaseAddresses[2] = 0;
140 PciData->u.type0.BaseAddresses[3] = 0;
141 PciWriteDeviceConfig(PdoExtension,
142 PciData->u.type0.BaseAddresses,
143 FIELD_OFFSET(PCI_COMMON_HEADER,
144 u.type0.BaseAddresses),
145 4 * sizeof(ULONG));
146
147 /* Re-read the BARs to have the latest data for native mode IDE */
148 PciReadDeviceConfig(PdoExtension,
149 PciData->u.type0.BaseAddresses,
150 FIELD_OFFSET(PCI_COMMON_HEADER,
151 u.type0.BaseAddresses),
152 4 * sizeof(ULONG));
153
154 /* Re-read the interrupt pin used for native mode IDE */
155 PciReadDeviceConfig(PdoExtension,
156 &PciData->u.type0.InterruptPin,
157 FIELD_OFFSET(PCI_COMMON_HEADER,
158 u.type0.InterruptPin),
159 sizeof(UCHAR));
160
161 /* The IDE Controller is now in native mode */
162 Switched = TRUE;
163 }
164 else
165 {
166 /* Settings did not work, fail */
167 DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
168 PciData->VendorID,
169 PciData->DeviceID);
170 }
171 }
172
173 /* Return whether or not native mode was enabled on the IDE controller */
174 return Switched;
175 }
176
177 VOID
178 NTAPI
179 PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
180 IN PPCI_COMMON_HEADER PciData,
181 IN PCI_SLOT_NUMBER SlotNumber,
182 IN ULONG OperationType,
183 PPCI_PDO_EXTENSION PdoExtension)
184 {
185 ULONG LegacyBaseAddress;
186 USHORT Command;
187 UCHAR RegValue;
188
189 /* There should always be a PDO extension passed in */
190 ASSERT(PdoExtension);
191
192 /* Check what kind of hack operation this is */
193 switch (OperationType)
194 {
195 /*
196 * This is mostly concerned with fixing up incorrect class data that can
197 * exist on certain PCI hardware before the 2.0 spec was ratified.
198 */
199 case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
200
201 /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
202 * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
203 * and appear as non-classified, so their correct class/subclass data
204 * is written here instead.
205 */
206 if ((PciData->VendorID == 0x8086) &&
207 ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
208 {
209 /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
210 PciData->SubClass = PciData->DeviceID == 0x482 ?
211 PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
212 PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
213
214 /*
215 * Because the software is modifying the actual header data from
216 * the BIOS, this flag tells the driver to ignore failures when
217 * comparing the original BIOS data with the PCI data.
218 */
219 if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
220 }
221
222 /* Note that in this case, an immediate return is issued */
223 return;
224
225 /*
226 * This is concerned with setting up interrupts correctly for native IDE
227 * mode, but will also handle broken VGA decoding on older bridges as
228 * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
229 */
230 case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
231
232 /*
233 * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
234 * and FreeBSD bug reports indicate that the system crashes when the
235 * feature is enabled (so it's disabled on that OS as well). In the
236 * NT PCI Bus Driver, it seems Microsoft too, completely disables
237 * Native IDE functionality on this controller, so it would seem OPTi
238 * simply frelled up this controller.
239 */
240 if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
241 {
242 /* Disable native mode */
243 PciData->ProgIf &= ~5;
244 PciData->u.type0.InterruptPin = 0;
245
246 /*
247 * Because the software is modifying the actual header data from
248 * the BIOS, this flag tells the driver to ignore failures when
249 * comparing the original BIOS data with the PCI data.
250 */
251 PdoExtension->ExpectedWritebackFailure = TRUE;
252 }
253 else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
254 (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
255 {
256 /* For other IDE controllers, start out in compatible mode */
257 PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
258
259 /*
260 * Registry must have enabled native mode (typically as a result
261 * of an INF file directive part of the IDE controller's driver)
262 * and the system must not be booted in Safe Mode. If that checks
263 * out, then evaluate the ACPI NATA method to see if the platform
264 * supports this. See the section "BIOS and Platform Prerequisites
265 * for Switching a Native-Mode-Capable Controller" in the Storage
266 * section of the Windows Driver Kit for more details:
267 *
268 * 5. For each ATA controller enumerated, the PCI bus driver checks
269 * the Programming Interface register of the IDE controller to
270 * see if it supports switching both channels to native mode.
271 * 6. The PCI bus driver checks whether the BIOS/platform supports
272 * switching the controller by checking the NATA method described
273 * earlier in this article.
274 *
275 * If an ATA controller does not indicate that it is native
276 * mode-capable, or if the BIOS NATA control method is missing
277 * or does not list that device, the PCI bus driver does not
278 * switch the controller and it is assigned legacy resources.
279 *
280 * If both the controller and the BIOS indicate that the controller
281 * can be switched, the process of switching the controller begins
282 * with the next step.
283 */
284 if ((PciEnableNativeModeATA) &&
285 !(InitSafeBootMode) &&
286 (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
287 {
288 /* The platform supports it, remember that */
289 PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
290
291 /*
292 * Now switch the controller into native mode if both channels
293 * support native IDE mode. See "How Windows Switches an ATA
294 * Controller to Native Mode" in the Storage section of the
295 * Windows Driver Kit for more details.
296 */
297 PdoExtension->SwitchedIDEToNativeMode =
298 PciConfigureIdeController(PdoExtension, PciData, 1);
299 }
300
301 /* Is native mode enabled after all? */
302 if ((PciData->ProgIf & 5) != 5)
303 {
304 /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
305 PciData->u.type0.InterruptPin = 0;
306 }
307 }
308
309 /* Is this a PCI device with legacy VGA card decodes on the root bus? */
310 if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
311 (PCI_IS_ROOT_FDO(DeviceExtension)) &&
312 !(DeviceExtension->BrokenVideoHackApplied))
313 {
314 /* Tell the arbiter to apply a hack for these older devices */
315 ario_ApplyBrokenVideoHack(DeviceExtension);
316 }
317
318 /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
319 if ((PciData->VendorID == 0xE11) &&
320 (PciData->DeviceID == 0xA0F7) &&
321 (PciData->RevisionID == 17) &&
322 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
323 {
324 /* Turn off the decodes immediately */
325 PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
326 PCI_ENABLE_MEMORY_SPACE |
327 PCI_ENABLE_BUS_MASTER);
328 PciWriteDeviceConfig(PdoExtension,
329 &PciData->Command,
330 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
331 sizeof(USHORT));
332
333 /* Do not EVER turn them on again, this will blow up the system */
334 PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
335 PCI_ENABLE_MEMORY_SPACE |
336 PCI_ENABLE_BUS_MASTER);
337 PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
338 }
339 break;
340
341 /*
342 * This is called whenever resources are changed and hardware needs to be
343 * updated. It is concerned with two highly specific erratas on an IBM
344 * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
345 * ICH PCI Bridges.
346 */
347 case PCI_HACK_FIXUP_BEFORE_UPDATE:
348
349 /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
350 if ((PdoExtension->VendorId == 0x1014) &&
351 (PdoExtension->DeviceId == 0x95))
352 {
353 /* Read the current command */
354 PciReadDeviceConfig(PdoExtension,
355 &Command,
356 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
357 sizeof(USHORT));
358
359 /* Turn off the decodes */
360 PciDecodeEnable(PdoExtension, FALSE, &Command);
361
362 /* Apply the required IBM workaround */
363 PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
364 RegValue &= ~2;
365 RegValue |= 1;
366 PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
367
368 /* Restore the command to its original value */
369 PciWriteDeviceConfig(PdoExtension,
370 &Command,
371 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
372 sizeof(USHORT));
373
374 }
375
376 /*
377 * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
378 * i820, i840, i845 Chipsets) that have subtractive decode enabled,
379 * and whose hack flags do not specifiy that this support is broken.
380 */
381 if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
382 (PdoExtension->Dependent.type1.SubtractiveDecode) &&
383 ((PdoExtension->VendorId == 0x8086) &&
384 ((PdoExtension->DeviceId == 0x2418) ||
385 (PdoExtension->DeviceId == 0x2428) ||
386 (PdoExtension->DeviceId == 0x244E) ||
387 (PdoExtension->DeviceId == 0x2448))) &&
388 !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
389 {
390 /*
391 * The positive decode window shouldn't be used, these values are
392 * normally all read-only or initialized to 0 by the BIOS, but
393 * it appears Intel doesn't do this, so the PCI Bus Driver will
394 * do it in software instead. Note that this is used to prevent
395 * certain non-compliant PCI devices from breaking down due to the
396 * fact that these ICH bridges have a known "quirk" (which Intel
397 * documents as a known "erratum", although it's not not really
398 * an ICH bug since the PCI specification does allow for it) in
399 * that they will sometimes send non-zero addresses during special
400 * cycles (ie: non-zero data during the address phase). These
401 * broken PCI cards will mistakenly attempt to claim the special
402 * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
403 * defense, the PCI specification only requires stable data, not
404 * necessarily zero data, during the address phase.
405 */
406 PciData->u.type1.MemoryBase = 0xFFFF;
407 PciData->u.type1.PrefetchBase = 0xFFFF;
408 PciData->u.type1.IOBase = 0xFF;
409 PciData->u.type1.IOLimit = 0;
410 PciData->u.type1.MemoryLimit = 0;
411 PciData->u.type1.PrefetchLimit = 0;
412 PciData->u.type1.PrefetchBaseUpper32 = 0;
413 PciData->u.type1.PrefetchLimitUpper32 = 0;
414 PciData->u.type1.IOBaseUpper16 = 0;
415 PciData->u.type1.IOLimitUpper16 = 0;
416 }
417 break;
418
419 default:
420 return;
421 }
422
423 /* Finally, also check if this is this a CardBUS device? */
424 if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
425 {
426 /*
427 * At offset 44h the LegacyBaseAddress is stored, which is cleared by
428 * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
429 * CardBus controllers. For more information, see "Supporting CardBus
430 * Controllers under ACPI" in the "CardBus Controllers and Windows"
431 * Whitepaper on WHDC.
432 */
433 LegacyBaseAddress = 0;
434 PciWriteDeviceConfig(PdoExtension,
435 &LegacyBaseAddress,
436 sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
437 sizeof(ULONG));
438 }
439 }
440
441
442 BOOLEAN
443 NTAPI
444 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
445 IN PPCI_COMMON_HEADER PciData)
446 {
447 BOOLEAN IdMatch, RevMatch, SubsysMatch;
448 ULONGLONG HackFlags = DeviceExtension->HackFlags;
449
450 /* Check if the IDs match */
451 IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
452 (PciData->DeviceID == DeviceExtension->DeviceId);
453 if (!IdMatch) return FALSE;
454
455 /* If the device has a valid revision, check if it matches */
456 RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
457 (PciData->RevisionID == DeviceExtension->RevisionId);
458 if (!RevMatch) return FALSE;
459
460 /* For multifunction devices, this is enough to assume they're the same */
461 if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
462
463 /* For bridge devices, there's also nothing else that can be checked */
464 if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
465
466 /* Devices, on the other hand, have subsystem data that can be compared */
467 SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
468 PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
469 ((DeviceExtension->SubsystemVendorId ==
470 PciData->u.type0.SubVendorID) &&
471 (DeviceExtension->SubsystemId ==
472 PciData->u.type0.SubSystemID));
473 return SubsysMatch;
474 }
475
476 BOOLEAN
477 NTAPI
478 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
479 IN PCI_SLOT_NUMBER Slot,
480 IN UCHAR OperationType,
481 IN ULONGLONG HackFlags)
482 {
483 do
484 {
485 /* Check if this is device enumeration */
486 if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
487 {
488 /* Check if there's a hackflag saying not to enumerate this device */
489 if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
490
491 /* Check if this is the high end of a double decker device */
492 if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
493 (Slot.u.bits.DeviceNumber >= 16))
494 {
495 /* It belongs to the same device, so skip it */
496 DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
497 PciData->VendorID,
498 PciData->DeviceID,
499 Slot.u.bits.DeviceNumber,
500 Slot.u.bits.FunctionNumber);
501 break;
502 }
503 }
504 else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
505 {
506 /* Resource enumeration, check for a hackflag saying not to do it */
507 if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
508 }
509 else
510 {
511 /* Logic error in the driver */
512 ASSERTMSG(FALSE, "PCI Skip Function - Operation type unknown.");
513 }
514
515 /* Check for legacy bridges during resource enumeration */
516 if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
517 (PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
518 (OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
519 {
520 /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
521 break;
522 }
523 else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
524 {
525 /* Undefined base class (usually a PCI BIOS/ROM bug) */
526 DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
527 PciData->VendorID,
528 PciData->DeviceID);
529
530 /*
531 * The Alder has an Intel Extended Express System Support Controller
532 * which presents apparently spurious BARs. When the PCI resource
533 * code tries to reassign these BARs, the second IO-APIC gets
534 * disabled (with disastrous consequences). The first BAR is the
535 * actual IO-APIC, the remaining five bars seem to be spurious
536 * resources, so ignore this device completely.
537 */
538 if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
539 }
540
541 /* Other normal PCI cards and bridges are enumerated */
542 if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
543 } while (FALSE);
544
545 /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
546 DPRINT1(" Device skipped (not enumerated).\n");
547 return TRUE;
548 }
549
550 VOID
551 NTAPI
552 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
553 IN PPCI_COMMON_HEADER PciData)
554 {
555 ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
556 DEVICE_POWER_STATE WakeLevel;
557 PCI_CAPABILITIES_HEADER AgpCapability;
558 PCI_PM_CAPABILITY PowerCapabilities;
559 PAGED_CODE();
560
561 /* Assume no known wake level */
562 PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
563
564 /* Make sure the device has capabilities */
565 if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
566 {
567 /* If it doesn't, there will be no power management */
568 PdoExtension->CapabilitiesPtr = 0;
569 PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
570 }
571 else
572 {
573 /* There's capabilities, need to figure out where to get the offset */
574 HeaderType = PCI_CONFIGURATION_TYPE(PciData);
575 if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
576 {
577 /* Use the bridge's header */
578 CapPtr = PciData->u.type2.CapabilitiesPtr;
579 }
580 else
581 {
582 /* Use the device header */
583 ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
584 CapPtr = PciData->u.type0.CapabilitiesPtr;
585 }
586
587 /* Make sure the pointer is spec-aligned and located, and save it */
588 DPRINT1("Device has capabilities at: %lx\n", CapPtr);
589 ASSERT(((CapPtr & 0x3) == 0) && (CapPtr >= PCI_COMMON_HDR_LENGTH));
590 PdoExtension->CapabilitiesPtr = CapPtr;
591
592 /* Check for PCI-to-PCI Bridges and AGP bridges */
593 if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
594 ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
595 (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
596 {
597 /* Query either the raw AGP capabilitity, or the Target AGP one */
598 TargetAgpCapabilityId = (PdoExtension->SubClass ==
599 PCI_SUBCLASS_BR_PCI_TO_PCI) ?
600 PCI_CAPABILITY_ID_AGP_TARGET :
601 PCI_CAPABILITY_ID_AGP;
602 if (PciReadDeviceCapability(PdoExtension,
603 PdoExtension->CapabilitiesPtr,
604 TargetAgpCapabilityId,
605 &AgpCapability,
606 sizeof(PCI_CAPABILITIES_HEADER)))
607 {
608 /* AGP target ID was found, store it */
609 DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
610 PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
611 }
612 }
613
614 /* Check for devices that are known not to have proper power management */
615 if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
616 {
617 /* Query if this device supports power management */
618 if (!PciReadDeviceCapability(PdoExtension,
619 PdoExtension->CapabilitiesPtr,
620 PCI_CAPABILITY_ID_POWER_MANAGEMENT,
621 &PowerCapabilities.Header,
622 sizeof(PCI_PM_CAPABILITY)))
623 {
624 /* No power management, so act as if it had the hackflag set */
625 DPRINT1("No PM caps, disabling PM\n");
626 PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
627 }
628 else
629 {
630 /* Otherwise, pick the highest wake level that is supported */
631 WakeLevel = PowerDeviceUnspecified;
632 if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
633 WakeLevel = PowerDeviceD0;
634 if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
635 WakeLevel = PowerDeviceD1;
636 if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
637 WakeLevel = PowerDeviceD2;
638 if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
639 WakeLevel = PowerDeviceD3;
640 if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
641 WakeLevel = PowerDeviceD3;
642 PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
643
644 /* Convert the PCI power state to the NT power state */
645 PdoExtension->PowerState.CurrentDeviceState =
646 PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
647
648 /* Save all the power capabilities */
649 PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
650 DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
651 WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
652 }
653 }
654 }
655
656 /* At the very end of all this, does this device not have power management? */
657 if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
658 {
659 /* Then guess the current state based on whether the decodes are on */
660 PdoExtension->PowerState.CurrentDeviceState =
661 PciData->Command & (PCI_ENABLE_IO_SPACE |
662 PCI_ENABLE_MEMORY_SPACE |
663 PCI_ENABLE_BUS_MASTER) ?
664 PowerDeviceD0: PowerDeviceD3;
665 DPRINT1("PM is off, so assumed device is: %d based on enables\n",
666 PdoExtension->PowerState.CurrentDeviceState);
667 }
668 }
669
670 NTSTATUS
671 NTAPI
672 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
673 {
674 ULONG MaxDevice = PCI_MAX_DEVICES;
675 BOOLEAN ProcessFlag = FALSE;
676 ULONG i, j, k, Size;
677 USHORT CapOffset, TempOffset;
678 LONGLONG HackFlags;
679 PDEVICE_OBJECT DeviceObject;
680 UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
681 UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
682 PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
683 PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
684 PCI_SLOT_NUMBER PciSlot;
685 PCHAR Name;
686 NTSTATUS Status;
687 PPCI_PDO_EXTENSION PdoExtension, NewExtension;
688 PPCI_PDO_EXTENSION* BridgeExtension;
689 PWCHAR DescriptionText;
690 USHORT SubVendorId, SubSystemId;
691 PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
692 DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
693 DeviceExtension, DeviceExtension->BaseBus);
694
695 /* Is this the root FDO? */
696 if (!PCI_IS_ROOT_FDO(DeviceExtension))
697 {
698 /* Other FDOs are not currently supported */
699 UNIMPLEMENTED;
700 while (TRUE);
701 }
702
703 /* Loop every device on the bus */
704 PciSlot.u.bits.Reserved = 0;
705 i = DeviceExtension->BaseBus;
706 for (j = 0; j < MaxDevice; j++)
707 {
708 /* Loop every function of each device */
709 PciSlot.u.bits.DeviceNumber = j;
710 for (k = 0; k < PCI_MAX_FUNCTION; k++)
711 {
712 /* Build the final slot structure */
713 PciSlot.u.bits.FunctionNumber = k;
714
715 /* Read the vendor for this slot */
716 PciReadSlotConfig(DeviceExtension,
717 PciSlot,
718 PciData,
719 0,
720 sizeof(USHORT));
721
722 /* Skip invalid device */
723 if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
724
725 /* Now read the whole header */
726 PciReadSlotConfig(DeviceExtension,
727 PciSlot,
728 &PciData->DeviceID,
729 sizeof(USHORT),
730 PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
731
732 /* Apply any hacks before even analyzing the configuration header */
733 PciApplyHacks(DeviceExtension,
734 PciData,
735 PciSlot,
736 PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
737 NULL);
738
739 /* Dump device that was found */
740 DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
741 PciSlot.u.AsULONG,
742 i,
743 j,
744 k);
745
746 /* Dump the device's header */
747 PciDebugDumpCommonConfig(PciData);
748
749 /* Find description for this device for the debugger's sake */
750 DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
751 PciData->SubClass);
752 DPRINT1("Device Description \"%S\".\n",
753 DescriptionText ? DescriptionText : L"(NULL)");
754 if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
755
756 /* Check if there is an ACPI Watchdog Table */
757 if (WdTable)
758 {
759 /* Check if this PCI device is the ACPI Watchdog Device... */
760 UNIMPLEMENTED;
761 while (TRUE);
762 }
763
764 /* Check for non-simple devices */
765 if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
766 (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
767 {
768 /* No subsystem data defined for these kinds of bridges */
769 SubVendorId = 0;
770 SubSystemId = 0;
771 }
772 else
773 {
774 /* Read the subsystem information from the PCI header */
775 SubVendorId = PciData->u.type0.SubVendorID;
776 SubSystemId = PciData->u.type0.SubSystemID;
777 }
778
779 /* Get any hack flags for this device */
780 HackFlags = PciGetHackFlags(PciData->VendorID,
781 PciData->DeviceID,
782 SubVendorId,
783 SubSystemId,
784 PciData->RevisionID);
785
786 /* Check if this device is considered critical by the OS */
787 if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
788 {
789 /* Check if normally the decodes would be disabled */
790 if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
791 {
792 /* Because this device is critical, don't disable them */
793 DPRINT1("Not allowing PM Because device is critical\n");
794 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
795 }
796 }
797
798 /* PCI bridges with a VGA card are also considered critical */
799 if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
800 (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
801 (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
802 !(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
803 {
804 /* Do not disable their decodes either */
805 DPRINT1("Not allowing PM because device is VGA\n");
806 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
807 }
808
809 /* Check if the device should be skipped for whatever reason */
810 if (PciSkipThisFunction(PciData,
811 PciSlot,
812 PCI_SKIP_DEVICE_ENUMERATION,
813 HackFlags))
814 {
815 /* Skip this device */
816 continue;
817 }
818
819 /* Check if a PDO has already been created for this device */
820 PdoExtension = PciFindPdoByFunction(DeviceExtension,
821 PciSlot.u.AsULONG,
822 PciData);
823 if (PdoExtension)
824 {
825 /* Rescan scenarios are not yet implemented */
826 UNIMPLEMENTED;
827 while (TRUE);
828 }
829
830 /* Bus processing will need to happen */
831 ProcessFlag = TRUE;
832
833 /* Create the PDO for this device */
834 Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject);
835 ASSERT(NT_SUCCESS(Status));
836 NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
837
838 /* Check for broken devices with wrong/no class codes */
839 if (HackFlags & PCI_HACK_FAKE_CLASS_CODE)
840 {
841 /* Setup a default one */
842 PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV;
843 PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
844
845 /* Device will behave erratically when reading back data */
846 NewExtension->ExpectedWritebackFailure = TRUE;
847 }
848
849 /* Clone all the information from the header */
850 NewExtension->VendorId = PciData->VendorID;
851 NewExtension->DeviceId = PciData->DeviceID;
852 NewExtension->RevisionId = PciData->RevisionID;
853 NewExtension->ProgIf = PciData->ProgIf;
854 NewExtension->SubClass = PciData->SubClass;
855 NewExtension->BaseClass = PciData->BaseClass;
856 NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
857
858 /* Check for modern bridge types, which are managed by the driver */
859 if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
860 ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
861 (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
862 {
863 /* Acquire this device's lock */
864 KeEnterCriticalRegion();
865 KeWaitForSingleObject(&DeviceExtension->ChildListLock,
866 Executive,
867 KernelMode,
868 FALSE,
869 NULL);
870
871 /* Scan the bridge list until the first free entry */
872 for (BridgeExtension = &DeviceExtension->ChildBridgePdoList;
873 *BridgeExtension;
874 BridgeExtension = &(*BridgeExtension)->NextBridge);
875
876 /* Add this PDO as a bridge */
877 *BridgeExtension = NewExtension;
878 ASSERT(NewExtension->NextBridge == NULL);
879
880 /* Release this device's lock */
881 KeSetEvent(&DeviceExtension->ChildListLock,
882 IO_NO_INCREMENT,
883 FALSE);
884 KeLeaveCriticalRegion();
885 }
886
887 /* Get the PCI BIOS configuration saved in the registry */
888 Status = PciGetBiosConfig(NewExtension, BiosData);
889 if (NT_SUCCESS(Status))
890 {
891 /* This path has not yet been fully tested by eVb */
892 DPRINT1("Have BIOS configuration!\n");
893 UNIMPLEMENTED;
894
895 /* Check if the PCI BIOS configuration has changed */
896 if (!PcipIsSameDevice(NewExtension, BiosData))
897 {
898 /* This is considered failure, and new data will be saved */
899 Status = STATUS_UNSUCCESSFUL;
900 }
901 else
902 {
903 /* Data is still correct, check for interrupt line change */
904 if (BiosData->u.type0.InterruptLine !=
905 PciData->u.type0.InterruptLine)
906 {
907 /* Update the current BIOS with the saved interrupt line */
908 PciWriteDeviceConfig(NewExtension,
909 &BiosData->u.type0.InterruptLine,
910 FIELD_OFFSET(PCI_COMMON_HEADER,
911 u.type0.InterruptLine),
912 sizeof(UCHAR));
913 }
914
915 /* Save the BIOS interrupt line and the initial command */
916 NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
917 NewExtension->InitialCommand = BiosData->Command;
918 }
919 }
920
921 /* Check if no saved data was present or if it was a mismatch */
922 if (!NT_SUCCESS(Status))
923 {
924 /* Save the new data */
925 Status = PciSaveBiosConfig(NewExtension, PciData);
926 ASSERT(NT_SUCCESS(Status));
927
928 /* Save the interrupt line and command from the device */
929 NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
930 NewExtension->InitialCommand = PciData->Command;
931 }
932
933 /* Save original command from the device and hack flags */
934 NewExtension->CommandEnables = PciData->Command;
935 NewExtension->HackFlags = HackFlags;
936
937 /* Get power, AGP, and other capability data */
938 PciGetEnhancedCapabilities(NewExtension, PciData);
939
940 /* Power up the device */
941 PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
942
943 /* Apply any device hacks required for enumeration */
944 PciApplyHacks(DeviceExtension,
945 PciData,
946 PciSlot,
947 PCI_HACK_FIXUP_AFTER_CONFIGURATION,
948 NewExtension);
949
950 /* Save interrupt pin */
951 NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
952
953 /*
954 * Use either this device's actual IRQ line or, if it's connected on
955 * a master bus whose IRQ line is actually connected to the host, use
956 * the HAL to query the bus' IRQ line and store that as the adjusted
957 * interrupt line instead
958 */
959 NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
960
961 /* Check if this device is used for PCI debugger cards */
962 NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
963
964 /* Check for devices with invalid/bogus subsystem data */
965 if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
966 {
967 /* Set the subsystem information to zero instead */
968 NewExtension->SubsystemVendorId = 0;
969 NewExtension->SubsystemId = 0;
970 }
971
972 /* Scan all capabilities */
973 CapOffset = NewExtension->CapabilitiesPtr;
974 while (CapOffset)
975 {
976 /* Read this header */
977 TempOffset = PciReadDeviceCapability(NewExtension,
978 CapOffset,
979 0,
980 &CapHeader,
981 sizeof(PCI_CAPABILITIES_HEADER));
982 if (TempOffset != CapOffset)
983 {
984 /* This is a strange issue that shouldn't happen normally */
985 DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
986 CapOffset);
987 ASSERT(TempOffset == CapOffset);
988 }
989
990 /* Check for capabilities that this driver cares about */
991 switch (CapHeader.CapabilityID)
992 {
993 /* Power management capability is heavily used by the bus */
994 case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
995
996 /* Dump the capability */
997 Name = "POWER";
998 Size = sizeof(PCI_PM_CAPABILITY);
999 break;
1000
1001 /* AGP capability is required for AGP bus functionality */
1002 case PCI_CAPABILITY_ID_AGP:
1003
1004 /* Dump the capability */
1005 Name = "AGP";
1006 Size = sizeof(PCI_AGP_CAPABILITY);
1007 break;
1008
1009 /* This driver doesn't really use anything other than that */
1010 default:
1011
1012 /* Windows prints this, we could do a translation later */
1013 Name = "UNKNOWN CAPABILITY";
1014 Size = 0;
1015 break;
1016 }
1017
1018 /* Check if this is a capability that should be dumped */
1019 if (Size)
1020 {
1021 /* Read the whole capability data */
1022 TempOffset = PciReadDeviceCapability(NewExtension,
1023 CapOffset,
1024 CapHeader.CapabilityID,
1025 &CapHeader,
1026 Size);
1027
1028 if (TempOffset != CapOffset)
1029 {
1030 /* Again, a strange issue that shouldn't be seen */
1031 DPRINT1("- Failed to read capability data. ***\n");
1032 ASSERT(TempOffset == CapOffset);
1033 }
1034 }
1035
1036 /* Dump this capability */
1037 DPRINT1("CAP @%02x ID %02x (%s)\n",
1038 CapOffset, CapHeader.CapabilityID, Name);
1039 for (i = 0; i < Size; i += 2)
1040 DPRINT1(" %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
1041 DPRINT1("\n");
1042
1043 /* Check the next capability */
1044 CapOffset = CapHeader.Next;
1045 }
1046
1047 /* Check for IDE controllers */
1048 if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
1049 (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
1050 {
1051 /* Do not allow them to power down completely */
1052 NewExtension->DisablePowerDown = TRUE;
1053 }
1054
1055 /*
1056 * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
1057 * bridge that is present on certain NT Alpha machines appears as
1058 * non-classified so detect it manually by scanning for its VID/PID.
1059 */
1060 if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1061 ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
1062 (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
1063 (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
1064 ((NewExtension->VendorId == 0x8086) &&
1065 (NewExtension->DeviceId == 0x482)))
1066 {
1067 /* Do not allow these legacy bridges to be powered down */
1068 NewExtension->DisablePowerDown = TRUE;
1069 }
1070
1071 /* Check if the BIOS did not configure a cache line size */
1072 if (!PciData->CacheLineSize)
1073 {
1074 /* Check if the device is disabled */
1075 if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
1076 PCI_ENABLE_MEMORY_SPACE |
1077 PCI_ENABLE_BUS_MASTER)))
1078 {
1079 /* Check if this is a PCI-X device*/
1080 TempOffset = PciReadDeviceCapability(NewExtension,
1081 NewExtension->CapabilitiesPtr,
1082 PCI_CAPABILITY_ID_PCIX,
1083 &PcixCapHeader,
1084 sizeof(PCI_CAPABILITIES_HEADER));
1085
1086 /*
1087 * A device with default cache line size and latency timer
1088 * settings is considered to be unconfigured. Note that on
1089 * PCI-X, the reset value of the latency timer field in the
1090 * header is 64, not 0, hence why the check for PCI-X caps
1091 * was required, and the value used here below.
1092 */
1093 if (!(PciData->LatencyTimer) ||
1094 ((TempOffset) && (PciData->LatencyTimer == 64)))
1095 {
1096 /* Keep track of the fact that it needs configuration */
1097 DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
1098 NewExtension);
1099 NewExtension->NeedsHotPlugConfiguration = TRUE;
1100 }
1101 }
1102 }
1103
1104 /* Save latency and cache size information */
1105 NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
1106 NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
1107
1108 /* The PDO is now ready to go */
1109 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1110 }
1111 }
1112
1113 /* Enumeration is completed */
1114 return STATUS_SUCCESS;
1115 }
1116
1117 NTSTATUS
1118 NTAPI
1119 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
1120 IN OUT PDEVICE_RELATIONS *pDeviceRelations)
1121 {
1122 NTSTATUS Status;
1123 PPCI_PDO_EXTENSION PdoExtension;
1124 ULONG PdoCount = 0;
1125 PDEVICE_RELATIONS DeviceRelations, NewRelations;
1126 SIZE_T Size;
1127 PDEVICE_OBJECT DeviceObject, *ObjectArray;
1128 PAGED_CODE();
1129
1130 /* Make sure the FDO is started */
1131 ASSERT(DeviceExtension->DeviceState == PciStarted);
1132
1133 /* Synchronize while we enumerate the bus */
1134 Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
1135 if (!NT_SUCCESS(Status)) return Status;
1136
1137 /* Scan all children PDO */
1138 for (PdoExtension = DeviceExtension->ChildPdoList;
1139 PdoExtension;
1140 PdoExtension = PdoExtension->Next)
1141 {
1142 /* Invalidate them */
1143 PdoExtension->NotPresent = TRUE;
1144 }
1145
1146 /* Scan the PCI Bus */
1147 Status = PciScanBus(DeviceExtension);
1148 ASSERT(NT_SUCCESS(Status));
1149
1150 /* Enumerate all children PDO again */
1151 for (PdoExtension = DeviceExtension->ChildPdoList;
1152 PdoExtension;
1153 PdoExtension = PdoExtension->Next)
1154 {
1155 /* Check for PDOs that are still invalidated */
1156 if (PdoExtension->NotPresent)
1157 {
1158 /* This means this PDO existed before, but not anymore */
1159 PdoExtension->ReportedMissing = TRUE;
1160 DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
1161 PdoExtension);
1162 }
1163 else
1164 {
1165 /* Increase count of detected PDOs */
1166 PdoCount++;
1167 }
1168 }
1169
1170 /* Read the current relations and add the newly discovered relations */
1171 DeviceRelations = *pDeviceRelations;
1172 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
1173 PdoCount * sizeof(PDEVICE_OBJECT);
1174 if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
1175
1176 /* Allocate the device relations */
1177 NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
1178 if (!NewRelations)
1179 {
1180 /* Out of space, cancel the operation */
1181 PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
1182 return STATUS_INSUFFICIENT_RESOURCES;
1183 }
1184
1185 /* Check if there were any older relations */
1186 NewRelations->Count = 0;
1187 if (DeviceRelations)
1188 {
1189 /* Copy the old relations into the new buffer, then free the old one */
1190 RtlCopyMemory(NewRelations,
1191 DeviceRelations,
1192 FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
1193 DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
1194 ExFreePoolWithTag(DeviceRelations, 0);
1195 }
1196
1197 /* Print out that we're ready to dump relations */
1198 DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
1199 DeviceExtension,
1200 DeviceExtension->BaseBus);
1201
1202 /* Loop the current PDO children and the device relation object array */
1203 PdoExtension = DeviceExtension->ChildPdoList;
1204 ObjectArray = &NewRelations->Objects[NewRelations->Count];
1205 while (PdoExtension)
1206 {
1207 /* Dump this relation */
1208 DPRINT1(" QDR PDO %08x (x %08x)%s\n",
1209 PdoExtension->PhysicalDeviceObject,
1210 PdoExtension,
1211 PdoExtension->NotPresent ?
1212 "<Omitted, device flaged not present>" : "");
1213
1214 /* Is this PDO present? */
1215 if (!PdoExtension->NotPresent)
1216 {
1217 /* Reference it and add it to the array */
1218 DeviceObject = PdoExtension->PhysicalDeviceObject;
1219 ObfReferenceObject(DeviceObject);
1220 *ObjectArray++ = DeviceObject;
1221 }
1222
1223 /* Go to the next PDO */
1224 PdoExtension = PdoExtension->Next;
1225 }
1226
1227 /* Terminate dumping the relations */
1228 DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
1229 NewRelations->Count + PdoCount,
1230 NewRelations->Count);
1231
1232 /* Return the final count and the new buffer */
1233 NewRelations->Count += PdoCount;
1234 *pDeviceRelations = NewRelations;
1235 return STATUS_SUCCESS;
1236 }
1237
1238 /* EOF */