37bf55bcb7cf83839ee3232c552aeae263513d25
[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 PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
18
19 PCI_CONFIGURATOR PciConfigurators[] =
20 {
21 {
22 Device_MassageHeaderForLimitsDetermination,
23 Device_RestoreCurrent,
24 Device_SaveLimits,
25 Device_SaveCurrentSettings,
26 Device_ChangeResourceSettings,
27 Device_GetAdditionalResourceDescriptors,
28 Device_ResetDevice
29 },
30 {
31 PPBridge_MassageHeaderForLimitsDetermination,
32 PPBridge_RestoreCurrent,
33 PPBridge_SaveLimits,
34 PPBridge_SaveCurrentSettings,
35 PPBridge_ChangeResourceSettings,
36 PPBridge_GetAdditionalResourceDescriptors,
37 PPBridge_ResetDevice
38 },
39 {
40 Cardbus_MassageHeaderForLimitsDetermination,
41 Cardbus_RestoreCurrent,
42 Cardbus_SaveLimits,
43 Cardbus_SaveCurrentSettings,
44 Cardbus_ChangeResourceSettings,
45 Cardbus_GetAdditionalResourceDescriptors,
46 Cardbus_ResetDevice
47 }
48 };
49
50 /* FUNCTIONS ******************************************************************/
51
52 PCM_RESOURCE_LIST
53 NTAPI
54 PciAllocateCmResourceList(IN ULONG Count,
55 IN ULONG BusNumber)
56 {
57 SIZE_T Size;
58 PCM_RESOURCE_LIST ResourceList;
59
60 /* Calculate the final size of the list, including each descriptor */
61 Size = sizeof(CM_RESOURCE_LIST);
62 if (Count > 1) Size = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count - 1) +
63 sizeof(CM_RESOURCE_LIST);
64
65 /* Allocate the list */
66 ResourceList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
67 if (!ResourceList) return NULL;
68
69 /* Initialize it */
70 RtlZeroMemory(ResourceList, Size);
71 ResourceList->Count = 1;
72 ResourceList->List[0].BusNumber = BusNumber;
73 ResourceList->List[0].InterfaceType = PCIBus;
74 ResourceList->List[0].PartialResourceList.Version = 1;
75 ResourceList->List[0].PartialResourceList.Revision = 1;
76 ResourceList->List[0].PartialResourceList.Count = Count;
77
78 /* Return it */
79 return ResourceList;
80 }
81
82 NTSTATUS
83 NTAPI
84 PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,
85 OUT PCM_RESOURCE_LIST *Buffer)
86 {
87 PPCI_FUNCTION_RESOURCES PciResources;
88 BOOLEAN HaveVga, HaveMemSpace, HaveIoSpace;
89 USHORT BridgeControl, PciCommand;
90 ULONG Count, i;
91 PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, Resource, LastResource;
92 PCM_RESOURCE_LIST ResourceList;
93 UCHAR InterruptLine;
94 PAGED_CODE();
95
96 /* Assume failure */
97 Count = 0;
98 HaveVga = FALSE;
99 *Buffer = NULL;
100
101 /* Make sure there's some resources to query */
102 PciResources = PdoExtension->Resources;
103 if (!PciResources) return STATUS_SUCCESS;
104
105 /* Read the decodes */
106 PciReadDeviceConfig(PdoExtension,
107 &PciCommand,
108 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
109 sizeof(USHORT));
110
111 /* Check which ones are turned on */
112 HaveIoSpace = PciCommand & PCI_ENABLE_IO_SPACE;
113 HaveMemSpace = PciCommand & PCI_ENABLE_MEMORY_SPACE;
114
115 /* Loop maximum possible descriptors */
116 for (i = 0; i < 7; i++)
117 {
118 /* Check if the decode for this descriptor is actually turned on */
119 Partial = &PciResources->Current[i];
120 if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
121 ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
122 {
123 /* One more fully active descriptor */
124 Count++;
125 }
126 }
127
128 /* If there's an interrupt pin associated, check at least one decode is on */
129 if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
130 {
131 /* Read the interrupt line for the pin, add a descriptor if it's valid */
132 InterruptLine = PdoExtension->AdjustedInterruptLine;
133 if ((InterruptLine) && (InterruptLine != -1)) Count++;
134 }
135
136 /* Check for PCI bridge */
137 if (PdoExtension->HeaderType == PCI_BRIDGE_TYPE)
138 {
139 /* Read bridge settings, check if VGA is present */
140 PciReadDeviceConfig(PdoExtension,
141 &BridgeControl,
142 FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BridgeControl),
143 sizeof(USHORT));
144 if (BridgeControl & PCI_ENABLE_BRIDGE_VGA)
145 {
146 /* Remember for later */
147 HaveVga = TRUE;
148
149 /* One memory descriptor for 0xA0000, plus the two I/O port ranges */
150 if (HaveMemSpace) Count++;
151 if (HaveIoSpace) Count += 2;
152 }
153 }
154
155 /* If there's no descriptors in use, there's no resources, so return */
156 if (!Count) return STATUS_SUCCESS;
157
158 /* Allocate a resource list to hold the resources */
159 ResourceList = PciAllocateCmResourceList(Count,
160 PdoExtension->ParentFdoExtension->BaseBus);
161 if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES;
162
163 /* This is where the descriptors will be copied into */
164 Resource = ResourceList->List[0].PartialResourceList.PartialDescriptors;
165 LastResource = Resource + Count + 1;
166
167 /* Loop maximum possible descriptors */
168 for (i = 0; i < 7; i++)
169 {
170 /* Check if the decode for this descriptor is actually turned on */
171 Partial = &PciResources->Current[i];
172 if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
173 ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
174 {
175 /* Copy the descriptor into the resource list */
176 *Resource++ = *Partial;
177 }
178 }
179
180 /* Check if earlier the code detected this was a PCI bridge with VGA on it */
181 if (HaveVga)
182 {
183 /* Are the memory decodes enabled? */
184 if (HaveMemSpace)
185 {
186 /* Build a memory descriptor for a 128KB framebuffer at 0xA0000 */
187 Resource->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
188 Resource->u.Generic.Start.HighPart = 0;
189 Resource->Type = CmResourceTypeMemory;
190 Resource->u.Generic.Start.LowPart = 0xA0000;
191 Resource->u.Generic.Length = 0x20000;
192 Resource++;
193 }
194
195 /* Are the I/O decodes enabled? */
196 if (HaveIoSpace)
197 {
198 /* Build an I/O descriptor for the graphic ports at 0x3B0 */
199 Resource->Type = CmResourceTypePort;
200 Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
201 Resource->u.Port.Start.QuadPart = 0x3B0u;
202 Resource->u.Port.Length = 0xC;
203 Resource++;
204
205 /* Build an I/O descriptor for the graphic ports at 0x3C0 */
206 Resource->Type = CmResourceTypePort;
207 Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
208 Resource->u.Port.Start.QuadPart = 0x3C0u;
209 Resource->u.Port.Length = 0x20;
210 Resource++;
211 }
212 }
213
214 /* If there's an interrupt pin associated, check at least one decode is on */
215 if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
216 {
217 /* Read the interrupt line for the pin, check if it's valid */
218 InterruptLine = PdoExtension->AdjustedInterruptLine;
219 if ((InterruptLine) && (InterruptLine != -1))
220 {
221 /* Make sure there's still space */
222 ASSERT(Resource < LastResource);
223
224 /* Add the interrupt descriptor */
225 Resource->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
226 Resource->Type = CmResourceTypeInterrupt;
227 Resource->ShareDisposition = CmResourceShareShared;
228 Resource->u.Interrupt.Affinity = -1;
229 Resource->u.Interrupt.Level = InterruptLine;
230 Resource->u.Interrupt.Vector = InterruptLine;
231 }
232 }
233
234 /* Return the resouce list */
235 *Buffer = ResourceList;
236 return STATUS_SUCCESS;
237 }
238
239 NTSTATUS
240 NTAPI
241 PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,
242 IN OUT PDEVICE_RELATIONS *pDeviceRelations)
243 {
244 PDEVICE_RELATIONS DeviceRelations;
245 PAGED_CODE();
246
247 /* If there were existing relations, free them */
248 if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
249
250 /* Allocate a new structure for the relations */
251 DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
252 sizeof(DEVICE_RELATIONS),
253 'BicP');
254 if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
255
256 /* Only one relation: the PDO */
257 DeviceRelations->Count = 1;
258 DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject;
259 ObReferenceObject(DeviceRelations->Objects[0]);
260
261 /* Return the new relations */
262 *pDeviceRelations = DeviceRelations;
263 return STATUS_SUCCESS;
264 }
265
266 NTSTATUS
267 NTAPI
268 PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,
269 IN OUT PDEVICE_RELATIONS *pDeviceRelations)
270 {
271 /* Not yet implemented */
272 UNIMPLEMENTED;
273 while (TRUE);
274 }
275
276 NTSTATUS
277 NTAPI
278 PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,
279 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList)
280 {
281 /* Not yet implemented */
282 UNIMPLEMENTED;
283 while (TRUE);
284 return STATUS_SUCCESS;
285 }
286
287 /*
288 * 7. The IO/MEM/Busmaster decodes are disabled for the device.
289 * 8. The PCI bus driver sets the operating mode bits of the Programming
290 * Interface byte to switch the controller to native mode.
291 *
292 * Important: When the controller is set to native mode, it must quiet itself
293 * and must not decode I/O resources or generate interrupts until the operating
294 * system has enabled the ports in the PCI configuration header.
295 * The IO/MEM/BusMaster bits will be disabled before the mode change, but it
296 * is not possible to disable interrupts on the device. The device must not
297 * generate interrupts (either legacy or native mode) while the decodes are
298 * disabled in the command register.
299 *
300 * This operation is expected to be instantaneous and the operating system does
301 * not stall afterward. It is also expected that the interrupt pin register in
302 * the PCI Configuration space for this device is accurate. The operating system
303 * re-reads this data after previously ignoring it.
304 */
305 BOOLEAN
306 NTAPI
307 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
308 IN PPCI_COMMON_HEADER PciData,
309 IN BOOLEAN Initial)
310 {
311 UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
312 BOOLEAN Switched;
313 USHORT Command;
314
315 /* Assume it won't work */
316 Switched = FALSE;
317
318 /* Get master and slave current settings, and programmability flag */
319 ProgIf = PciData->ProgIf;
320 MasterMode = (ProgIf & 1) == 1;
321 MasterFixed = (ProgIf & 2) == 0;
322 SlaveMode = (ProgIf & 4) == 4;
323 SlaveFixed = (ProgIf & 8) == 0;
324
325 /*
326 * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
327 * ATA controller from compatible mode to native mode, the following must be
328 * true:
329 *
330 * - The controller must indicate in its programming interface that both channels
331 * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
332 * not support switching only one IDE channel to native mode. See the PCI IDE
333 * Controller Specification Revision 1.0 for details.
334 */
335 if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
336 {
337 /* Windows does not support this configuration, fail */
338 DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
339 PdoExtension->VendorId,
340 PdoExtension->DeviceId);
341 return Switched;
342 }
343
344 /* Check if the controller is already in native mode */
345 if ((MasterMode) && (SlaveMode))
346 {
347 /* Check if I/O decodes should be disabled */
348 if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
349 {
350 /* Read the current command */
351 PciReadDeviceConfig(PdoExtension,
352 &Command,
353 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
354 sizeof(USHORT));
355
356 /* Disable I/O space decode */
357 Command &= ~PCI_ENABLE_IO_SPACE;
358
359 /* Update new command in PCI IDE controller */
360 PciWriteDeviceConfig(PdoExtension,
361 &Command,
362 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
363 sizeof(USHORT));
364
365 /* Save updated command value */
366 PciData->Command = Command;
367 }
368
369 /* The controller is now in native mode */
370 Switched = TRUE;
371 }
372 else if (!(MasterFixed) &&
373 !(SlaveFixed) &&
374 (PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
375 !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
376 {
377 /* Turn off decodes */
378 PciDecodeEnable(PdoExtension, FALSE, NULL);
379
380 /* Update the current command */
381 PciReadDeviceConfig(PdoExtension,
382 &PciData->Command,
383 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
384 sizeof(USHORT));
385
386 /* Enable native mode */
387 ProgIf = PciData->ProgIf | 5;
388 PciWriteDeviceConfig(PdoExtension,
389 &ProgIf,
390 FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
391 sizeof(UCHAR));
392
393 /* Verify the setting "stuck" */
394 PciReadDeviceConfig(PdoExtension,
395 &NewProgIf,
396 FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
397 sizeof(UCHAR));
398 if (NewProgIf == ProgIf)
399 {
400 /* Update the header and PDO data with the new programming mode */
401 PciData->ProgIf = ProgIf;
402 PdoExtension->ProgIf = NewProgIf;
403
404 /* Clear the first four BARs to reset current BAR setttings */
405 PciData->u.type0.BaseAddresses[0] = 0;
406 PciData->u.type0.BaseAddresses[1] = 0;
407 PciData->u.type0.BaseAddresses[2] = 0;
408 PciData->u.type0.BaseAddresses[3] = 0;
409 PciWriteDeviceConfig(PdoExtension,
410 PciData->u.type0.BaseAddresses,
411 FIELD_OFFSET(PCI_COMMON_HEADER,
412 u.type0.BaseAddresses),
413 4 * sizeof(ULONG));
414
415 /* Re-read the BARs to have the latest data for native mode IDE */
416 PciReadDeviceConfig(PdoExtension,
417 PciData->u.type0.BaseAddresses,
418 FIELD_OFFSET(PCI_COMMON_HEADER,
419 u.type0.BaseAddresses),
420 4 * sizeof(ULONG));
421
422 /* Re-read the interrupt pin used for native mode IDE */
423 PciReadDeviceConfig(PdoExtension,
424 &PciData->u.type0.InterruptPin,
425 FIELD_OFFSET(PCI_COMMON_HEADER,
426 u.type0.InterruptPin),
427 sizeof(UCHAR));
428
429 /* The IDE Controller is now in native mode */
430 Switched = TRUE;
431 }
432 else
433 {
434 /* Settings did not work, fail */
435 DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
436 PciData->VendorID,
437 PciData->DeviceID);
438 }
439 }
440
441 /* Return whether or not native mode was enabled on the IDE controller */
442 return Switched;
443 }
444
445 VOID
446 NTAPI
447 PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
448 IN PPCI_COMMON_HEADER PciData,
449 IN PCI_SLOT_NUMBER SlotNumber,
450 IN ULONG OperationType,
451 PPCI_PDO_EXTENSION PdoExtension)
452 {
453 ULONG LegacyBaseAddress;
454 USHORT Command;
455 UCHAR RegValue;
456
457 /* Check what kind of hack operation this is */
458 switch (OperationType)
459 {
460 /*
461 * This is mostly concerned with fixing up incorrect class data that can
462 * exist on certain PCI hardware before the 2.0 spec was ratified.
463 */
464 case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
465
466 /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
467 * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
468 * and appear as non-classified, so their correct class/subclass data
469 * is written here instead.
470 */
471 if ((PciData->VendorID == 0x8086) &&
472 ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
473 {
474 /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
475 PciData->SubClass = PciData->DeviceID == 0x482 ?
476 PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
477 PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
478
479 /*
480 * Because the software is modifying the actual header data from
481 * the BIOS, this flag tells the driver to ignore failures when
482 * comparing the original BIOS data with the PCI data.
483 */
484 if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
485 }
486
487 /* Note that in this case, an immediate return is issued */
488 return;
489
490 /*
491 * This is concerned with setting up interrupts correctly for native IDE
492 * mode, but will also handle broken VGA decoding on older bridges as
493 * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
494 */
495 case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
496
497 /* There should always be a PDO extension passed in */
498 ASSERT(PdoExtension);
499
500 /*
501 * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
502 * and FreeBSD bug reports indicate that the system crashes when the
503 * feature is enabled (so it's disabled on that OS as well). In the
504 * NT PCI Bus Driver, it seems Microsoft too, completely disables
505 * Native IDE functionality on this controller, so it would seem OPTi
506 * simply frelled up this controller.
507 */
508 if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
509 {
510 /* Disable native mode */
511 PciData->ProgIf &= ~5;
512 PciData->u.type0.InterruptPin = 0;
513
514 /*
515 * Because the software is modifying the actual header data from
516 * the BIOS, this flag tells the driver to ignore failures when
517 * comparing the original BIOS data with the PCI data.
518 */
519 PdoExtension->ExpectedWritebackFailure = TRUE;
520 }
521 else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
522 (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
523 {
524 /* For other IDE controllers, start out in compatible mode */
525 PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
526
527 /*
528 * Registry must have enabled native mode (typically as a result
529 * of an INF file directive part of the IDE controller's driver)
530 * and the system must not be booted in Safe Mode. If that checks
531 * out, then evaluate the ACPI NATA method to see if the platform
532 * supports this. See the section "BIOS and Platform Prerequisites
533 * for Switching a Native-Mode-Capable Controller" in the Storage
534 * section of the Windows Driver Kit for more details:
535 *
536 * 5. For each ATA controller enumerated, the PCI bus driver checks
537 * the Programming Interface register of the IDE controller to
538 * see if it supports switching both channels to native mode.
539 * 6. The PCI bus driver checks whether the BIOS/platform supports
540 * switching the controller by checking the NATA method described
541 * earlier in this article.
542 *
543 * If an ATA controller does not indicate that it is native
544 * mode-capable, or if the BIOS NATA control method is missing
545 * or does not list that device, the PCI bus driver does not
546 * switch the controller and it is assigned legacy resources.
547 *
548 * If both the controller and the BIOS indicate that the controller
549 * can be switched, the process of switching the controller begins
550 * with the next step.
551 */
552 if ((PciEnableNativeModeATA) &&
553 !(InitSafeBootMode) &&
554 (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
555 {
556 /* The platform supports it, remember that */
557 PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
558
559 /*
560 * Now switch the controller into native mode if both channels
561 * support native IDE mode. See "How Windows Switches an ATA
562 * Controller to Native Mode" in the Storage section of the
563 * Windows Driver Kit for more details.
564 */
565 PdoExtension->SwitchedIDEToNativeMode =
566 PciConfigureIdeController(PdoExtension, PciData, 1);
567 }
568
569 /* Is native mode enabled after all? */
570 if ((PciData->ProgIf & 5) != 5)
571 {
572 /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
573 PciData->u.type0.InterruptPin = 0;
574 }
575 }
576
577 /* Is this a PCI device with legacy VGA card decodes on the root bus? */
578 if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
579 (PCI_IS_ROOT_FDO(DeviceExtension)) &&
580 !(DeviceExtension->BrokenVideoHackApplied))
581 {
582 /* Tell the arbiter to apply a hack for these older devices */
583 ario_ApplyBrokenVideoHack(DeviceExtension);
584 }
585
586 /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
587 if ((PciData->VendorID == 0xE11) &&
588 (PciData->DeviceID == 0xA0F7) &&
589 (PciData->RevisionID == 17) &&
590 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
591 {
592 /* Turn off the decodes immediately */
593 PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
594 PCI_ENABLE_MEMORY_SPACE |
595 PCI_ENABLE_BUS_MASTER);
596 PciWriteDeviceConfig(PdoExtension,
597 &PciData->Command,
598 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
599 sizeof(USHORT));
600
601 /* Do not EVER turn them on again, this will blow up the system */
602 PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
603 PCI_ENABLE_MEMORY_SPACE |
604 PCI_ENABLE_BUS_MASTER);
605 PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
606 }
607 break;
608
609 /*
610 * This is called whenever resources are changed and hardware needs to be
611 * updated. It is concerned with two highly specific erratas on an IBM
612 * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
613 * ICH PCI Bridges.
614 */
615 case PCI_HACK_FIXUP_BEFORE_UPDATE:
616
617 /* There should always be a PDO extension passed in */
618 ASSERT(PdoExtension);
619
620 /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
621 if ((PdoExtension->VendorId == 0x1014) &&
622 (PdoExtension->DeviceId == 0x95))
623 {
624 /* Read the current command */
625 PciReadDeviceConfig(PdoExtension,
626 &Command,
627 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
628 sizeof(USHORT));
629
630 /* Turn off the decodes */
631 PciDecodeEnable(PdoExtension, FALSE, &Command);
632
633 /* Apply the required IBM workaround */
634 PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
635 RegValue &= ~2;
636 RegValue |= 1;
637 PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
638
639 /* Restore the command to its original value */
640 PciWriteDeviceConfig(PdoExtension,
641 &Command,
642 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
643 sizeof(USHORT));
644
645 }
646
647 /*
648 * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
649 * i820, i840, i845 Chipsets) that have subtractive decode enabled,
650 * and whose hack flags do not specifiy that this support is broken.
651 */
652 if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
653 (PdoExtension->Dependent.type1.SubtractiveDecode) &&
654 ((PdoExtension->VendorId == 0x8086) &&
655 ((PdoExtension->DeviceId == 0x2418) ||
656 (PdoExtension->DeviceId == 0x2428) ||
657 (PdoExtension->DeviceId == 0x244E) ||
658 (PdoExtension->DeviceId == 0x2448))) &&
659 !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
660 {
661 /*
662 * The positive decode window shouldn't be used, these values are
663 * normally all read-only or initialized to 0 by the BIOS, but
664 * it appears Intel doesn't do this, so the PCI Bus Driver will
665 * do it in software instead. Note that this is used to prevent
666 * certain non-compliant PCI devices from breaking down due to the
667 * fact that these ICH bridges have a known "quirk" (which Intel
668 * documents as a known "erratum", although it's not not really
669 * an ICH bug since the PCI specification does allow for it) in
670 * that they will sometimes send non-zero addresses during special
671 * cycles (ie: non-zero data during the address phase). These
672 * broken PCI cards will mistakenly attempt to claim the special
673 * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
674 * defense, the PCI specification only requires stable data, not
675 * necessarily zero data, during the address phase.
676 */
677 PciData->u.type1.MemoryBase = 0xFFFF;
678 PciData->u.type1.PrefetchBase = 0xFFFF;
679 PciData->u.type1.IOBase = 0xFF;
680 PciData->u.type1.IOLimit = 0;
681 PciData->u.type1.MemoryLimit = 0;
682 PciData->u.type1.PrefetchLimit = 0;
683 PciData->u.type1.PrefetchBaseUpper32 = 0;
684 PciData->u.type1.PrefetchLimitUpper32 = 0;
685 PciData->u.type1.IOBaseUpper16 = 0;
686 PciData->u.type1.IOLimitUpper16 = 0;
687 }
688 break;
689
690 default:
691 return;
692 }
693
694 /* Finally, also check if this is this a CardBUS device? */
695 if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
696 {
697 /*
698 * At offset 44h the LegacyBaseAddress is stored, which is cleared by
699 * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
700 * CardBus controllers. For more information, see "Supporting CardBus
701 * Controllers under ACPI" in the "CardBus Controllers and Windows"
702 * Whitepaper on WHDC.
703 */
704 LegacyBaseAddress = 0;
705 PciWriteDeviceConfig(PdoExtension,
706 &LegacyBaseAddress,
707 sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
708 sizeof(ULONG));
709 }
710 }
711
712 BOOLEAN
713 NTAPI
714 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
715 IN PPCI_COMMON_HEADER PciData)
716 {
717 BOOLEAN IdMatch, RevMatch, SubsysMatch;
718 ULONGLONG HackFlags = DeviceExtension->HackFlags;
719
720 /* Check if the IDs match */
721 IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
722 (PciData->DeviceID == DeviceExtension->DeviceId);
723 if (!IdMatch) return FALSE;
724
725 /* If the device has a valid revision, check if it matches */
726 RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
727 (PciData->RevisionID == DeviceExtension->RevisionId);
728 if (!RevMatch) return FALSE;
729
730 /* For multifunction devices, this is enough to assume they're the same */
731 if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
732
733 /* For bridge devices, there's also nothing else that can be checked */
734 if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
735
736 /* Devices, on the other hand, have subsystem data that can be compared */
737 SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
738 PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
739 ((DeviceExtension->SubsystemVendorId ==
740 PciData->u.type0.SubVendorID) &&
741 (DeviceExtension->SubsystemId ==
742 PciData->u.type0.SubSystemID));
743 return SubsysMatch;
744 }
745
746 BOOLEAN
747 NTAPI
748 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
749 IN PCI_SLOT_NUMBER Slot,
750 IN UCHAR OperationType,
751 IN ULONGLONG HackFlags)
752 {
753 do
754 {
755 /* Check if this is device enumeration */
756 if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
757 {
758 /* Check if there's a hackflag saying not to enumerate this device */
759 if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
760
761 /* Check if this is the high end of a double decker device */
762 if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
763 (Slot.u.bits.DeviceNumber >= 16))
764 {
765 /* It belongs to the same device, so skip it */
766 DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
767 PciData->VendorID,
768 PciData->DeviceID,
769 Slot.u.bits.DeviceNumber,
770 Slot.u.bits.FunctionNumber);
771 break;
772 }
773 }
774 else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
775 {
776 /* Resource enumeration, check for a hackflag saying not to do it */
777 if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
778 }
779 else
780 {
781 /* Logic error in the driver */
782 ASSERTMSG(FALSE, "PCI Skip Function - Operation type unknown.");
783 }
784
785 /* Check for legacy bridges during resource enumeration */
786 if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
787 (PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
788 (OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
789 {
790 /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
791 break;
792 }
793 else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
794 {
795 /* Undefined base class (usually a PCI BIOS/ROM bug) */
796 DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
797 PciData->VendorID,
798 PciData->DeviceID);
799
800 /*
801 * The Alder has an Intel Extended Express System Support Controller
802 * which presents apparently spurious BARs. When the PCI resource
803 * code tries to reassign these BARs, the second IO-APIC gets
804 * disabled (with disastrous consequences). The first BAR is the
805 * actual IO-APIC, the remaining five bars seem to be spurious
806 * resources, so ignore this device completely.
807 */
808 if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
809 }
810
811 /* Other normal PCI cards and bridges are enumerated */
812 if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
813 } while (FALSE);
814
815 /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
816 DPRINT1(" Device skipped (not enumerated).\n");
817 return TRUE;
818 }
819
820 VOID
821 NTAPI
822 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
823 IN PPCI_COMMON_HEADER PciData)
824 {
825 ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
826 DEVICE_POWER_STATE WakeLevel;
827 PCI_CAPABILITIES_HEADER AgpCapability;
828 PCI_PM_CAPABILITY PowerCapabilities;
829 PAGED_CODE();
830
831 /* Assume no known wake level */
832 PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
833
834 /* Make sure the device has capabilities */
835 if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
836 {
837 /* If it doesn't, there will be no power management */
838 PdoExtension->CapabilitiesPtr = 0;
839 PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
840 }
841 else
842 {
843 /* There's capabilities, need to figure out where to get the offset */
844 HeaderType = PCI_CONFIGURATION_TYPE(PciData);
845 if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
846 {
847 /* Use the bridge's header */
848 CapPtr = PciData->u.type2.CapabilitiesPtr;
849 }
850 else
851 {
852 /* Use the device header */
853 ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
854 CapPtr = PciData->u.type0.CapabilitiesPtr;
855 }
856
857 /* Make sure the pointer is spec-aligned and located, and save it */
858 DPRINT1("Device has capabilities at: %lx\n", CapPtr);
859 ASSERT(((CapPtr & 0x3) == 0) && (CapPtr >= PCI_COMMON_HDR_LENGTH));
860 PdoExtension->CapabilitiesPtr = CapPtr;
861
862 /* Check for PCI-to-PCI Bridges and AGP bridges */
863 if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
864 ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
865 (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
866 {
867 /* Query either the raw AGP capabilitity, or the Target AGP one */
868 TargetAgpCapabilityId = (PdoExtension->SubClass ==
869 PCI_SUBCLASS_BR_PCI_TO_PCI) ?
870 PCI_CAPABILITY_ID_AGP_TARGET :
871 PCI_CAPABILITY_ID_AGP;
872 if (PciReadDeviceCapability(PdoExtension,
873 PdoExtension->CapabilitiesPtr,
874 TargetAgpCapabilityId,
875 &AgpCapability,
876 sizeof(PCI_CAPABILITIES_HEADER)))
877 {
878 /* AGP target ID was found, store it */
879 DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
880 PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
881 }
882 }
883
884 /* Check for devices that are known not to have proper power management */
885 if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
886 {
887 /* Query if this device supports power management */
888 if (!PciReadDeviceCapability(PdoExtension,
889 PdoExtension->CapabilitiesPtr,
890 PCI_CAPABILITY_ID_POWER_MANAGEMENT,
891 &PowerCapabilities.Header,
892 sizeof(PCI_PM_CAPABILITY)))
893 {
894 /* No power management, so act as if it had the hackflag set */
895 DPRINT1("No PM caps, disabling PM\n");
896 PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
897 }
898 else
899 {
900 /* Otherwise, pick the highest wake level that is supported */
901 WakeLevel = PowerDeviceUnspecified;
902 if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
903 WakeLevel = PowerDeviceD0;
904 if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
905 WakeLevel = PowerDeviceD1;
906 if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
907 WakeLevel = PowerDeviceD2;
908 if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
909 WakeLevel = PowerDeviceD3;
910 if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
911 WakeLevel = PowerDeviceD3;
912 PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
913
914 /* Convert the PCI power state to the NT power state */
915 PdoExtension->PowerState.CurrentDeviceState =
916 PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
917
918 /* Save all the power capabilities */
919 PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
920 DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
921 WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
922 }
923 }
924 }
925
926 /* At the very end of all this, does this device not have power management? */
927 if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
928 {
929 /* Then guess the current state based on whether the decodes are on */
930 PdoExtension->PowerState.CurrentDeviceState =
931 PciData->Command & (PCI_ENABLE_IO_SPACE |
932 PCI_ENABLE_MEMORY_SPACE |
933 PCI_ENABLE_BUS_MASTER) ?
934 PowerDeviceD0: PowerDeviceD3;
935 DPRINT1("PM is off, so assumed device is: %d based on enables\n",
936 PdoExtension->PowerState.CurrentDeviceState);
937 }
938 }
939
940 VOID
941 NTAPI
942 PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved,
943 IN PPCI_CONFIGURATOR_CONTEXT Context)
944 {
945 PPCI_COMMON_HEADER PciData, Current;
946 PPCI_PDO_EXTENSION PdoExtension;
947
948 /* Grab all parameters from the context */
949 PdoExtension = Context->PdoExtension;
950 Current = Context->Current;
951 PciData = Context->PciData;
952
953 /* Write the limit discovery header */
954 PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
955
956 /* Now read what the device indicated the limits are */
957 PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
958
959 /* Then write back the original configuration header */
960 PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH);
961
962 /* Copy back the original command that was saved in the context */
963 Current->Command = Context->Command;
964 if (Context->Command)
965 {
966 /* Program it back into the device */
967 PciWriteDeviceConfig(PdoExtension,
968 &Context->Command,
969 FIELD_OFFSET(PCI_COMMON_HEADER, Command),
970 sizeof(USHORT));
971 }
972
973 /* Copy back the original status that was saved as well */
974 Current->Status = Context->Status;
975
976 /* Call the configurator to restore any other data that might've changed */
977 Context->Configurator->RestoreCurrent(Context);
978 }
979
980 NTSTATUS
981 NTAPI
982 PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
983 {
984 PPCI_CONFIGURATOR Configurator;
985 PPCI_COMMON_HEADER PciData, Current;
986 PPCI_PDO_EXTENSION PdoExtension;
987 PCI_IPI_CONTEXT IpiContext;
988 PIO_RESOURCE_DESCRIPTOR IoDescriptor;
989 ULONG Offset;
990 PAGED_CODE();
991
992 /* Grab all parameters from the context */
993 PdoExtension = Context->PdoExtension;
994 Current = Context->Current;
995 PciData = Context->PciData;
996
997 /* Save the current PCI Command and Status word */
998 Context->Status = Current->Status;
999 Context->Command = Current->Command;
1000
1001 /* Now that they're saved, clear the status, and disable all decodes */
1002 Current->Status = 0;
1003 Current->Command &= ~(PCI_ENABLE_IO_SPACE |
1004 PCI_ENABLE_MEMORY_SPACE |
1005 PCI_ENABLE_BUS_MASTER);
1006
1007 /* Make a copy of the current PCI configuration header (with decodes off) */
1008 RtlCopyMemory(PciData, Current, PCI_COMMON_HDR_LENGTH);
1009
1010 /* Locate the correct resource configurator for this type of device */
1011 Configurator = &PciConfigurators[PdoExtension->HeaderType];
1012 Context->Configurator = Configurator;
1013
1014 /* Initialize it, which will typically setup the BARs for limit discovery */
1015 Configurator->Initialize(Context);
1016
1017 /* Check for critical devices and PCI Debugging devices */
1018 if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
1019 (PdoExtension->OnDebugPath))
1020 {
1021 /* Specifically check for a PCI Debugging device */
1022 if (PdoExtension->OnDebugPath)
1023 {
1024 /* Was it enabled for bus mastering? */
1025 if (Context->Command & PCI_ENABLE_BUS_MASTER)
1026 {
1027 /* This decode needs to be re-enabled so debugging can work */
1028 PciData->Command |= PCI_ENABLE_BUS_MASTER;
1029 Current->Command |= PCI_ENABLE_BUS_MASTER;
1030 }
1031
1032 /* Disable the debugger while the discovery is happening */
1033 KdDisableDebugger();
1034 }
1035
1036 /* For these devices, an IPI must be sent to force high-IRQL discovery */
1037 IpiContext.Barrier = 1;
1038 IpiContext.RunCount = 1;
1039 IpiContext.PdoExtension = PdoExtension;
1040 IpiContext.Function = PciWriteLimitsAndRestoreCurrent;
1041 IpiContext.Context = Context;
1042 KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&IpiContext);
1043
1044 /* Re-enable the debugger if this was a PCI Debugging Device */
1045 if (PdoExtension->OnDebugPath) KdEnableDebugger();
1046 }
1047 else
1048 {
1049 /* Otherwise, it's safe to do this in-line at low IRQL */
1050 PciWriteLimitsAndRestoreCurrent(PdoExtension, Context);
1051 }
1052
1053 /*
1054 * Check if it's valid to compare the headers to see if limit discovery mode
1055 * has properly exited (the expected case is that the PCI header would now
1056 * be equal to what it was before). In some cases, it is known that this will
1057 * fail, because during PciApplyHacks (among other places), software hacks
1058 * had to be applied to the header, which the hardware-side will not see, and
1059 * thus the headers would appear "different".
1060 */
1061 if (!PdoExtension->ExpectedWritebackFailure)
1062 {
1063 /* Read the current PCI header now, after discovery has completed */
1064 PciReadDeviceConfig(PdoExtension, PciData + 1, 0, PCI_COMMON_HDR_LENGTH);
1065
1066 /* Check if the current header at entry, is equal to the header now */
1067 Offset = RtlCompareMemory(PciData + 1, Current, PCI_COMMON_HDR_LENGTH);
1068 if (Offset != PCI_COMMON_HDR_LENGTH)
1069 {
1070 /* It's not, which means configuration somehow changed, dump this */
1071 DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset);
1072 PciDebugDumpCommonConfig(PciData + 1);
1073 DPRINT1("----------\n");
1074 PciDebugDumpCommonConfig(Current);
1075 }
1076 }
1077
1078 /* This PDO should not already have resources, since this is only done once */
1079 ASSERT(PdoExtension->Resources == NULL);
1080
1081 /* Allocate the structure that will hold the discovered resources and limits */
1082 PdoExtension->Resources = ExAllocatePoolWithTag(NonPagedPool,
1083 sizeof(PCI_FUNCTION_RESOURCES),
1084 'BicP');
1085 if (!PdoExtension->Resources) return STATUS_INSUFFICIENT_RESOURCES;
1086
1087 /* Clear it out for now */
1088 RtlZeroMemory(PdoExtension->Resources, sizeof(PCI_FUNCTION_RESOURCES));
1089
1090 /* Now call the configurator, which will first store the limits... */
1091 Configurator->SaveLimits(Context);
1092
1093 /* ...and then store the current resources being used */
1094 Configurator->SaveCurrentSettings(Context);
1095
1096 /* Loop all the limit descriptors backwards */
1097 IoDescriptor = &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1];
1098 while (TRUE)
1099 {
1100 /* Keep going until a non-null descriptor is found */
1101 IoDescriptor--;
1102 if (IoDescriptor->Type != CmResourceTypeNull) break;
1103
1104 /* This is a null descriptor, is it the last one? */
1105 if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1])
1106 {
1107 /* This means the descriptor is NULL, which means discovery failed */
1108 DPRINT1("PCI Resources fail!\n");
1109
1110 /* No resources will be assigned for the device */
1111 ExFreePoolWithTag(PdoExtension->Resources, 0);
1112 PdoExtension->Resources = NULL;
1113 break;
1114 }
1115 }
1116
1117 /* Return success here, even if the device has no assigned resources */
1118 return STATUS_SUCCESS;
1119 }
1120
1121 NTSTATUS
1122 NTAPI
1123 PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension,
1124 IN PPCI_COMMON_HEADER Current,
1125 IN ULONGLONG HackFlags)
1126 {
1127 NTSTATUS Status;
1128 PPCI_COMMON_HEADER PciData;
1129 PCI_CONFIGURATOR_CONTEXT Context;
1130 PAGED_CODE();
1131
1132 /* Do the hackflags indicate this device should be skipped? */
1133 if (PciSkipThisFunction(Current,
1134 PdoExtension->Slot,
1135 PCI_SKIP_RESOURCE_ENUMERATION,
1136 HackFlags))
1137 {
1138 /* Do not process its resources */
1139 return STATUS_SUCCESS;
1140 }
1141
1142 /* Allocate a buffer to hold two PCI configuration headers */
1143 PciData = ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH, 'BicP');
1144 if (!PciData) return STATUS_INSUFFICIENT_RESOURCES;
1145
1146 /* Set up the context for the resource enumeration, and do it */
1147 Context.Current = Current;
1148 Context.PciData = PciData;
1149 Context.PdoExtension = PdoExtension;
1150 Status = PcipGetFunctionLimits(&Context);
1151
1152 /* Enumeration is completed, free the PCI headers and return the status */
1153 ExFreePoolWithTag(PciData, 0);
1154 return Status;
1155 }
1156
1157 VOID
1158 NTAPI
1159 PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension)
1160 {
1161 PPCI_PDO_EXTENSION PdoExtension;
1162 PDEVICE_OBJECT PhysicalDeviceObject;
1163 PAGED_CODE();
1164
1165 /* Get the PDO Extension */
1166 PhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject;
1167 PdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
1168
1169 /* Cheeck if this is the root bus */
1170 if (!PCI_IS_ROOT_FDO(DeviceExtension))
1171 {
1172 /* Not really handling this year */
1173 UNIMPLEMENTED;
1174 while (TRUE);
1175
1176 /* Check for PCI bridges with the ISA bit set, or required */
1177 if ((PdoExtension) &&
1178 (PciClassifyDeviceType(PdoExtension) == PciTypePciBridge) &&
1179 ((PdoExtension->Dependent.type1.IsaBitRequired) ||
1180 (PdoExtension->Dependent.type1.IsaBitSet)))
1181 {
1182 /* We'll need to do some legacy support */
1183 UNIMPLEMENTED;
1184 while (TRUE);
1185 }
1186 }
1187 else
1188 {
1189 /* Scan all of the root bus' children bridges */
1190 for (PdoExtension = DeviceExtension->ChildBridgePdoList;
1191 PdoExtension;
1192 PdoExtension = PdoExtension->NextBridge)
1193 {
1194 /* Find any that have the VGA decode bit on */
1195 if (PdoExtension->Dependent.type1.VgaBitSet)
1196 {
1197 /* Again, some more legacy support we'll have to do */
1198 UNIMPLEMENTED;
1199 while (TRUE);
1200 }
1201 }
1202 }
1203
1204 /* Check for ACPI systems where the OS assigns bus numbers */
1205 if (PciAssignBusNumbers)
1206 {
1207 /* Not yet supported */
1208 UNIMPLEMENTED;
1209 while (TRUE);
1210 }
1211 }
1212
1213 NTSTATUS
1214 NTAPI
1215 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
1216 {
1217 ULONG MaxDevice = PCI_MAX_DEVICES;
1218 BOOLEAN ProcessFlag = FALSE;
1219 ULONG i, j, k, Size;
1220 USHORT CapOffset, TempOffset;
1221 LONGLONG HackFlags;
1222 PDEVICE_OBJECT DeviceObject;
1223 UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
1224 UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
1225 PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
1226 PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
1227 PCI_SLOT_NUMBER PciSlot;
1228 PCHAR Name;
1229 NTSTATUS Status;
1230 PPCI_PDO_EXTENSION PdoExtension, NewExtension;
1231 PPCI_PDO_EXTENSION* BridgeExtension;
1232 PWCHAR DescriptionText;
1233 USHORT SubVendorId, SubSystemId;
1234 PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
1235 DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
1236 DeviceExtension, DeviceExtension->BaseBus);
1237
1238 /* Is this the root FDO? */
1239 if (!PCI_IS_ROOT_FDO(DeviceExtension))
1240 {
1241 /* Other FDOs are not currently supported */
1242 UNIMPLEMENTED;
1243 while (TRUE);
1244 }
1245
1246 /* Loop every device on the bus */
1247 PciSlot.u.bits.Reserved = 0;
1248 i = DeviceExtension->BaseBus;
1249 for (j = 0; j < MaxDevice; j++)
1250 {
1251 /* Loop every function of each device */
1252 PciSlot.u.bits.DeviceNumber = j;
1253 for (k = 0; k < PCI_MAX_FUNCTION; k++)
1254 {
1255 /* Build the final slot structure */
1256 PciSlot.u.bits.FunctionNumber = k;
1257
1258 /* Read the vendor for this slot */
1259 PciReadSlotConfig(DeviceExtension,
1260 PciSlot,
1261 PciData,
1262 0,
1263 sizeof(USHORT));
1264
1265 /* Skip invalid device */
1266 if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
1267
1268 /* Now read the whole header */
1269 PciReadSlotConfig(DeviceExtension,
1270 PciSlot,
1271 &PciData->DeviceID,
1272 sizeof(USHORT),
1273 PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
1274
1275 /* Apply any hacks before even analyzing the configuration header */
1276 PciApplyHacks(DeviceExtension,
1277 PciData,
1278 PciSlot,
1279 PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
1280 NULL);
1281
1282 /* Dump device that was found */
1283 DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
1284 PciSlot.u.AsULONG,
1285 i,
1286 j,
1287 k);
1288
1289 /* Dump the device's header */
1290 PciDebugDumpCommonConfig(PciData);
1291
1292 /* Find description for this device for the debugger's sake */
1293 DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
1294 PciData->SubClass);
1295 DPRINT1("Device Description \"%S\".\n",
1296 DescriptionText ? DescriptionText : L"(NULL)");
1297 if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
1298
1299 /* Check if there is an ACPI Watchdog Table */
1300 if (WdTable)
1301 {
1302 /* Check if this PCI device is the ACPI Watchdog Device... */
1303 UNIMPLEMENTED;
1304 while (TRUE);
1305 }
1306
1307 /* Check for non-simple devices */
1308 if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
1309 (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
1310 {
1311 /* No subsystem data defined for these kinds of bridges */
1312 SubVendorId = 0;
1313 SubSystemId = 0;
1314 }
1315 else
1316 {
1317 /* Read the subsystem information from the PCI header */
1318 SubVendorId = PciData->u.type0.SubVendorID;
1319 SubSystemId = PciData->u.type0.SubSystemID;
1320 }
1321
1322 /* Get any hack flags for this device */
1323 HackFlags = PciGetHackFlags(PciData->VendorID,
1324 PciData->DeviceID,
1325 SubVendorId,
1326 SubSystemId,
1327 PciData->RevisionID);
1328
1329 /* Check if this device is considered critical by the OS */
1330 if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
1331 {
1332 /* Check if normally the decodes would be disabled */
1333 if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
1334 {
1335 /* Because this device is critical, don't disable them */
1336 DPRINT1("Not allowing PM Because device is critical\n");
1337 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
1338 }
1339 }
1340
1341 /* PCI bridges with a VGA card are also considered critical */
1342 if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1343 (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
1344 (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
1345 !(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
1346 {
1347 /* Do not disable their decodes either */
1348 DPRINT1("Not allowing PM because device is VGA\n");
1349 HackFlags |= PCI_HACK_CRITICAL_DEVICE;
1350 }
1351
1352 /* Check if the device should be skipped for whatever reason */
1353 if (PciSkipThisFunction(PciData,
1354 PciSlot,
1355 PCI_SKIP_DEVICE_ENUMERATION,
1356 HackFlags))
1357 {
1358 /* Skip this device */
1359 continue;
1360 }
1361
1362 /* Check if a PDO has already been created for this device */
1363 PdoExtension = PciFindPdoByFunction(DeviceExtension,
1364 PciSlot.u.AsULONG,
1365 PciData);
1366 if (PdoExtension)
1367 {
1368 /* Rescan scenarios are not yet implemented */
1369 UNIMPLEMENTED;
1370 while (TRUE);
1371 }
1372
1373 /* Bus processing will need to happen */
1374 ProcessFlag = TRUE;
1375
1376 /* Create the PDO for this device */
1377 Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject);
1378 ASSERT(NT_SUCCESS(Status));
1379 NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
1380
1381 /* Check for broken devices with wrong/no class codes */
1382 if (HackFlags & PCI_HACK_FAKE_CLASS_CODE)
1383 {
1384 /* Setup a default one */
1385 PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV;
1386 PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
1387
1388 /* Device will behave erratically when reading back data */
1389 NewExtension->ExpectedWritebackFailure = TRUE;
1390 }
1391
1392 /* Clone all the information from the header */
1393 NewExtension->VendorId = PciData->VendorID;
1394 NewExtension->DeviceId = PciData->DeviceID;
1395 NewExtension->RevisionId = PciData->RevisionID;
1396 NewExtension->ProgIf = PciData->ProgIf;
1397 NewExtension->SubClass = PciData->SubClass;
1398 NewExtension->BaseClass = PciData->BaseClass;
1399 NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
1400
1401 /* Check for modern bridge types, which are managed by the driver */
1402 if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1403 ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
1404 (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
1405 {
1406 /* Acquire this device's lock */
1407 KeEnterCriticalRegion();
1408 KeWaitForSingleObject(&DeviceExtension->ChildListLock,
1409 Executive,
1410 KernelMode,
1411 FALSE,
1412 NULL);
1413
1414 /* Scan the bridge list until the first free entry */
1415 for (BridgeExtension = &DeviceExtension->ChildBridgePdoList;
1416 *BridgeExtension;
1417 BridgeExtension = &(*BridgeExtension)->NextBridge);
1418
1419 /* Add this PDO as a bridge */
1420 *BridgeExtension = NewExtension;
1421 ASSERT(NewExtension->NextBridge == NULL);
1422
1423 /* Release this device's lock */
1424 KeSetEvent(&DeviceExtension->ChildListLock,
1425 IO_NO_INCREMENT,
1426 FALSE);
1427 KeLeaveCriticalRegion();
1428 }
1429
1430 /* Get the PCI BIOS configuration saved in the registry */
1431 Status = PciGetBiosConfig(NewExtension, BiosData);
1432 if (NT_SUCCESS(Status))
1433 {
1434 /* This path has not yet been fully tested by eVb */
1435 DPRINT1("Have BIOS configuration!\n");
1436 UNIMPLEMENTED;
1437
1438 /* Check if the PCI BIOS configuration has changed */
1439 if (!PcipIsSameDevice(NewExtension, BiosData))
1440 {
1441 /* This is considered failure, and new data will be saved */
1442 Status = STATUS_UNSUCCESSFUL;
1443 }
1444 else
1445 {
1446 /* Data is still correct, check for interrupt line change */
1447 if (BiosData->u.type0.InterruptLine !=
1448 PciData->u.type0.InterruptLine)
1449 {
1450 /* Update the current BIOS with the saved interrupt line */
1451 PciWriteDeviceConfig(NewExtension,
1452 &BiosData->u.type0.InterruptLine,
1453 FIELD_OFFSET(PCI_COMMON_HEADER,
1454 u.type0.InterruptLine),
1455 sizeof(UCHAR));
1456 }
1457
1458 /* Save the BIOS interrupt line and the initial command */
1459 NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
1460 NewExtension->InitialCommand = BiosData->Command;
1461 }
1462 }
1463
1464 /* Check if no saved data was present or if it was a mismatch */
1465 if (!NT_SUCCESS(Status))
1466 {
1467 /* Save the new data */
1468 Status = PciSaveBiosConfig(NewExtension, PciData);
1469 ASSERT(NT_SUCCESS(Status));
1470
1471 /* Save the interrupt line and command from the device */
1472 NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
1473 NewExtension->InitialCommand = PciData->Command;
1474 }
1475
1476 /* Save original command from the device and hack flags */
1477 NewExtension->CommandEnables = PciData->Command;
1478 NewExtension->HackFlags = HackFlags;
1479
1480 /* Get power, AGP, and other capability data */
1481 PciGetEnhancedCapabilities(NewExtension, PciData);
1482
1483 /* Now configure the BARs */
1484 Status = PciGetFunctionLimits(NewExtension, PciData, HackFlags);
1485
1486 /* Power up the device */
1487 PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
1488
1489 /* Apply any device hacks required for enumeration */
1490 PciApplyHacks(DeviceExtension,
1491 PciData,
1492 PciSlot,
1493 PCI_HACK_FIXUP_AFTER_CONFIGURATION,
1494 NewExtension);
1495
1496 /* Save interrupt pin */
1497 NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
1498
1499 /*
1500 * Use either this device's actual IRQ line or, if it's connected on
1501 * a master bus whose IRQ line is actually connected to the host, use
1502 * the HAL to query the bus' IRQ line and store that as the adjusted
1503 * interrupt line instead
1504 */
1505 NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
1506
1507 /* Check if this device is used for PCI debugger cards */
1508 NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
1509
1510 /* Check for devices with invalid/bogus subsystem data */
1511 if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
1512 {
1513 /* Set the subsystem information to zero instead */
1514 NewExtension->SubsystemVendorId = 0;
1515 NewExtension->SubsystemId = 0;
1516 }
1517
1518 /* Scan all capabilities */
1519 CapOffset = NewExtension->CapabilitiesPtr;
1520 while (CapOffset)
1521 {
1522 /* Read this header */
1523 TempOffset = PciReadDeviceCapability(NewExtension,
1524 CapOffset,
1525 0,
1526 &CapHeader,
1527 sizeof(PCI_CAPABILITIES_HEADER));
1528 if (TempOffset != CapOffset)
1529 {
1530 /* This is a strange issue that shouldn't happen normally */
1531 DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
1532 CapOffset);
1533 ASSERT(TempOffset == CapOffset);
1534 }
1535
1536 /* Check for capabilities that this driver cares about */
1537 switch (CapHeader.CapabilityID)
1538 {
1539 /* Power management capability is heavily used by the bus */
1540 case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
1541
1542 /* Dump the capability */
1543 Name = "POWER";
1544 Size = sizeof(PCI_PM_CAPABILITY);
1545 break;
1546
1547 /* AGP capability is required for AGP bus functionality */
1548 case PCI_CAPABILITY_ID_AGP:
1549
1550 /* Dump the capability */
1551 Name = "AGP";
1552 Size = sizeof(PCI_AGP_CAPABILITY);
1553 break;
1554
1555 /* This driver doesn't really use anything other than that */
1556 default:
1557
1558 /* Windows prints this, we could do a translation later */
1559 Name = "UNKNOWN CAPABILITY";
1560 Size = 0;
1561 break;
1562 }
1563
1564 /* Check if this is a capability that should be dumped */
1565 if (Size)
1566 {
1567 /* Read the whole capability data */
1568 TempOffset = PciReadDeviceCapability(NewExtension,
1569 CapOffset,
1570 CapHeader.CapabilityID,
1571 &CapHeader,
1572 Size);
1573
1574 if (TempOffset != CapOffset)
1575 {
1576 /* Again, a strange issue that shouldn't be seen */
1577 DPRINT1("- Failed to read capability data. ***\n");
1578 ASSERT(TempOffset == CapOffset);
1579 }
1580 }
1581
1582 /* Dump this capability */
1583 DPRINT1("CAP @%02x ID %02x (%s)\n",
1584 CapOffset, CapHeader.CapabilityID, Name);
1585 for (i = 0; i < Size; i += 2)
1586 DPRINT1(" %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
1587 DPRINT1("\n");
1588
1589 /* Check the next capability */
1590 CapOffset = CapHeader.Next;
1591 }
1592
1593 /* Check for IDE controllers */
1594 if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
1595 (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
1596 {
1597 /* Do not allow them to power down completely */
1598 NewExtension->DisablePowerDown = TRUE;
1599 }
1600
1601 /*
1602 * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
1603 * bridge that is present on certain NT Alpha machines appears as
1604 * non-classified so detect it manually by scanning for its VID/PID.
1605 */
1606 if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
1607 ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
1608 (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
1609 (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
1610 ((NewExtension->VendorId == 0x8086) &&
1611 (NewExtension->DeviceId == 0x482)))
1612 {
1613 /* Do not allow these legacy bridges to be powered down */
1614 NewExtension->DisablePowerDown = TRUE;
1615 }
1616
1617 /* Check if the BIOS did not configure a cache line size */
1618 if (!PciData->CacheLineSize)
1619 {
1620 /* Check if the device is disabled */
1621 if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
1622 PCI_ENABLE_MEMORY_SPACE |
1623 PCI_ENABLE_BUS_MASTER)))
1624 {
1625 /* Check if this is a PCI-X device*/
1626 TempOffset = PciReadDeviceCapability(NewExtension,
1627 NewExtension->CapabilitiesPtr,
1628 PCI_CAPABILITY_ID_PCIX,
1629 &PcixCapHeader,
1630 sizeof(PCI_CAPABILITIES_HEADER));
1631
1632 /*
1633 * A device with default cache line size and latency timer
1634 * settings is considered to be unconfigured. Note that on
1635 * PCI-X, the reset value of the latency timer field in the
1636 * header is 64, not 0, hence why the check for PCI-X caps
1637 * was required, and the value used here below.
1638 */
1639 if (!(PciData->LatencyTimer) ||
1640 ((TempOffset) && (PciData->LatencyTimer == 64)))
1641 {
1642 /* Keep track of the fact that it needs configuration */
1643 DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
1644 NewExtension);
1645 NewExtension->NeedsHotPlugConfiguration = TRUE;
1646 }
1647 }
1648 }
1649
1650 /* Save latency and cache size information */
1651 NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
1652 NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
1653
1654 /* The PDO is now ready to go */
1655 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1656 }
1657 }
1658
1659 /* Enumeration completed, do a final pass now that all devices are found */
1660 if (ProcessFlag) PciProcessBus(DeviceExtension);
1661 return STATUS_SUCCESS;
1662 }
1663
1664 NTSTATUS
1665 NTAPI
1666 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
1667 IN OUT PDEVICE_RELATIONS *pDeviceRelations)
1668 {
1669 NTSTATUS Status;
1670 PPCI_PDO_EXTENSION PdoExtension;
1671 ULONG PdoCount = 0;
1672 PDEVICE_RELATIONS DeviceRelations, NewRelations;
1673 SIZE_T Size;
1674 PDEVICE_OBJECT DeviceObject, *ObjectArray;
1675 PAGED_CODE();
1676
1677 /* Make sure the FDO is started */
1678 ASSERT(DeviceExtension->DeviceState == PciStarted);
1679
1680 /* Synchronize while we enumerate the bus */
1681 Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
1682 if (!NT_SUCCESS(Status)) return Status;
1683
1684 /* Scan all children PDO */
1685 for (PdoExtension = DeviceExtension->ChildPdoList;
1686 PdoExtension;
1687 PdoExtension = PdoExtension->Next)
1688 {
1689 /* Invalidate them */
1690 PdoExtension->NotPresent = TRUE;
1691 }
1692
1693 /* Scan the PCI Bus */
1694 Status = PciScanBus(DeviceExtension);
1695 ASSERT(NT_SUCCESS(Status));
1696
1697 /* Enumerate all children PDO again */
1698 for (PdoExtension = DeviceExtension->ChildPdoList;
1699 PdoExtension;
1700 PdoExtension = PdoExtension->Next)
1701 {
1702 /* Check for PDOs that are still invalidated */
1703 if (PdoExtension->NotPresent)
1704 {
1705 /* This means this PDO existed before, but not anymore */
1706 PdoExtension->ReportedMissing = TRUE;
1707 DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
1708 PdoExtension);
1709 }
1710 else
1711 {
1712 /* Increase count of detected PDOs */
1713 PdoCount++;
1714 }
1715 }
1716
1717 /* Read the current relations and add the newly discovered relations */
1718 DeviceRelations = *pDeviceRelations;
1719 Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
1720 PdoCount * sizeof(PDEVICE_OBJECT);
1721 if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
1722
1723 /* Allocate the device relations */
1724 NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
1725 if (!NewRelations)
1726 {
1727 /* Out of space, cancel the operation */
1728 PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
1729 return STATUS_INSUFFICIENT_RESOURCES;
1730 }
1731
1732 /* Check if there were any older relations */
1733 NewRelations->Count = 0;
1734 if (DeviceRelations)
1735 {
1736 /* Copy the old relations into the new buffer, then free the old one */
1737 RtlCopyMemory(NewRelations,
1738 DeviceRelations,
1739 FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
1740 DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
1741 ExFreePoolWithTag(DeviceRelations, 0);
1742 }
1743
1744 /* Print out that we're ready to dump relations */
1745 DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
1746 DeviceExtension,
1747 DeviceExtension->BaseBus);
1748
1749 /* Loop the current PDO children and the device relation object array */
1750 PdoExtension = DeviceExtension->ChildPdoList;
1751 ObjectArray = &NewRelations->Objects[NewRelations->Count];
1752 while (PdoExtension)
1753 {
1754 /* Dump this relation */
1755 DPRINT1(" QDR PDO %08x (x %08x)%s\n",
1756 PdoExtension->PhysicalDeviceObject,
1757 PdoExtension,
1758 PdoExtension->NotPresent ?
1759 "<Omitted, device flaged not present>" : "");
1760
1761 /* Is this PDO present? */
1762 if (!PdoExtension->NotPresent)
1763 {
1764 /* Reference it and add it to the array */
1765 DeviceObject = PdoExtension->PhysicalDeviceObject;
1766 ObfReferenceObject(DeviceObject);
1767 *ObjectArray++ = DeviceObject;
1768 }
1769
1770 /* Go to the next PDO */
1771 PdoExtension = PdoExtension->Next;
1772 }
1773
1774 /* Terminate dumping the relations */
1775 DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
1776 NewRelations->Count + PdoCount,
1777 NewRelations->Count);
1778
1779 /* Return the final count and the new buffer */
1780 NewRelations->Count += PdoCount;
1781 *pDeviceRelations = NewRelations;
1782 return STATUS_SUCCESS;
1783 }
1784
1785 /* EOF */