2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/enum.c
5 * PURPOSE: PCI Bus/Device Enumeration
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements
;
19 PCI_CONFIGURATOR PciConfigurators
[] =
22 Device_MassageHeaderForLimitsDetermination
,
23 Device_RestoreCurrent
,
25 Device_SaveCurrentSettings
,
26 Device_ChangeResourceSettings
,
27 Device_GetAdditionalResourceDescriptors
,
31 PPBridge_MassageHeaderForLimitsDetermination
,
32 PPBridge_RestoreCurrent
,
34 PPBridge_SaveCurrentSettings
,
35 PPBridge_ChangeResourceSettings
,
36 PPBridge_GetAdditionalResourceDescriptors
,
40 Cardbus_MassageHeaderForLimitsDetermination
,
41 Cardbus_RestoreCurrent
,
43 Cardbus_SaveCurrentSettings
,
44 Cardbus_ChangeResourceSettings
,
45 Cardbus_GetAdditionalResourceDescriptors
,
50 /* FUNCTIONS ******************************************************************/
54 PciAllocateCmResourceList(IN ULONG Count
,
58 PCM_RESOURCE_LIST ResourceList
;
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
);
65 /* Allocate the list */
66 ResourceList
= ExAllocatePoolWithTag(PagedPool
, Size
, 'BicP');
67 if (!ResourceList
) return NULL
;
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
;
84 PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension
,
85 OUT PCM_RESOURCE_LIST
*Buffer
)
87 PPCI_FUNCTION_RESOURCES PciResources
;
88 BOOLEAN HaveVga
, HaveMemSpace
, HaveIoSpace
;
89 USHORT BridgeControl
, PciCommand
;
91 PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial
, Resource
, LastResource
;
92 PCM_RESOURCE_LIST ResourceList
;
101 /* Make sure there's some resources to query */
102 PciResources
= PdoExtension
->Resources
;
103 if (!PciResources
) return STATUS_SUCCESS
;
105 /* Read the decodes */
106 PciReadDeviceConfig(PdoExtension
,
108 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
111 /* Check which ones are turned on */
112 HaveIoSpace
= PciCommand
& PCI_ENABLE_IO_SPACE
;
113 HaveMemSpace
= PciCommand
& PCI_ENABLE_MEMORY_SPACE
;
115 /* Loop maximum possible descriptors */
116 for (i
= 0; i
< 7; i
++)
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
)))
123 /* One more fully active descriptor */
128 /* If there's an interrupt pin associated, check at least one decode is on */
129 if ((PdoExtension
->InterruptPin
) && ((HaveMemSpace
) || (HaveIoSpace
)))
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
++;
136 /* Check for PCI bridge */
137 if (PdoExtension
->HeaderType
== PCI_BRIDGE_TYPE
)
139 /* Read bridge settings, check if VGA is present */
140 PciReadDeviceConfig(PdoExtension
,
142 FIELD_OFFSET(PCI_COMMON_HEADER
, u
.type1
.BridgeControl
),
144 if (BridgeControl
& PCI_ENABLE_BRIDGE_VGA
)
146 /* Remember for later */
149 /* One memory descriptor for 0xA0000, plus the two I/O port ranges */
150 if (HaveMemSpace
) Count
++;
151 if (HaveIoSpace
) Count
+= 2;
155 /* If there's no descriptors in use, there's no resources, so return */
156 if (!Count
) return STATUS_SUCCESS
;
158 /* Allocate a resource list to hold the resources */
159 ResourceList
= PciAllocateCmResourceList(Count
,
160 PdoExtension
->ParentFdoExtension
->BaseBus
);
161 if (!ResourceList
) return STATUS_INSUFFICIENT_RESOURCES
;
163 /* This is where the descriptors will be copied into */
164 Resource
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
165 LastResource
= Resource
+ Count
+ 1;
167 /* Loop maximum possible descriptors */
168 for (i
= 0; i
< 7; i
++)
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
)))
175 /* Copy the descriptor into the resource list */
176 *Resource
++ = *Partial
;
180 /* Check if earlier the code detected this was a PCI bridge with VGA on it */
183 /* Are the memory decodes enabled? */
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;
195 /* Are the I/O decodes enabled? */
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;
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;
214 /* If there's an interrupt pin associated, check at least one decode is on */
215 if ((PdoExtension
->InterruptPin
) && ((HaveMemSpace
) || (HaveIoSpace
)))
217 /* Read the interrupt line for the pin, check if it's valid */
218 InterruptLine
= PdoExtension
->AdjustedInterruptLine
;
219 if ((InterruptLine
) && (InterruptLine
!= -1))
221 /* Make sure there's still space */
222 ASSERT(Resource
< LastResource
);
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
;
234 /* Return the resouce list */
235 *Buffer
= ResourceList
;
236 return STATUS_SUCCESS
;
241 PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension
,
242 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
244 PDEVICE_RELATIONS DeviceRelations
;
247 /* If there were existing relations, free them */
248 if (*pDeviceRelations
) ExFreePoolWithTag(*pDeviceRelations
, 0);
250 /* Allocate a new structure for the relations */
251 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
,
252 sizeof(DEVICE_RELATIONS
),
254 if (!DeviceRelations
) return STATUS_INSUFFICIENT_RESOURCES
;
256 /* Only one relation: the PDO */
257 DeviceRelations
->Count
= 1;
258 DeviceRelations
->Objects
[0] = PdoExtension
->PhysicalDeviceObject
;
259 ObReferenceObject(DeviceRelations
->Objects
[0]);
261 /* Return the new relations */
262 *pDeviceRelations
= DeviceRelations
;
263 return STATUS_SUCCESS
;
268 PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension
,
269 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
271 /* Not yet implemented */
278 PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension
,
279 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST
*RequirementsList
)
281 /* Not yet implemented */
284 return STATUS_SUCCESS
;
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.
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.
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.
307 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension
,
308 IN PPCI_COMMON_HEADER PciData
,
311 UCHAR MasterMode
, SlaveMode
, MasterFixed
, SlaveFixed
, ProgIf
, NewProgIf
;
315 /* Assume it won't work */
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;
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
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.
335 if ((MasterMode
!= SlaveMode
) || (MasterFixed
!= SlaveFixed
))
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
);
344 /* Check if the controller is already in native mode */
345 if ((MasterMode
) && (SlaveMode
))
347 /* Check if I/O decodes should be disabled */
348 if ((Initial
) || (PdoExtension
->IoSpaceUnderNativeIdeControl
))
350 /* Read the current command */
351 PciReadDeviceConfig(PdoExtension
,
353 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
356 /* Disable I/O space decode */
357 Command
&= ~PCI_ENABLE_IO_SPACE
;
359 /* Update new command in PCI IDE controller */
360 PciWriteDeviceConfig(PdoExtension
,
362 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
365 /* Save updated command value */
366 PciData
->Command
= Command
;
369 /* The controller is now in native mode */
372 else if (!(MasterFixed
) &&
374 (PdoExtension
->BIOSAllowsIDESwitchToNativeMode
) &&
375 !(PdoExtension
->HackFlags
& PCI_HACK_DISABLE_IDE_NATIVE_MODE
))
377 /* Turn off decodes */
378 PciDecodeEnable(PdoExtension
, FALSE
, NULL
);
380 /* Update the current command */
381 PciReadDeviceConfig(PdoExtension
,
383 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
386 /* Enable native mode */
387 ProgIf
= PciData
->ProgIf
| 5;
388 PciWriteDeviceConfig(PdoExtension
,
390 FIELD_OFFSET(PCI_COMMON_HEADER
, ProgIf
),
393 /* Verify the setting "stuck" */
394 PciReadDeviceConfig(PdoExtension
,
396 FIELD_OFFSET(PCI_COMMON_HEADER
, ProgIf
),
398 if (NewProgIf
== ProgIf
)
400 /* Update the header and PDO data with the new programming mode */
401 PciData
->ProgIf
= ProgIf
;
402 PdoExtension
->ProgIf
= NewProgIf
;
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
),
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
),
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
),
429 /* The IDE Controller is now in native mode */
434 /* Settings did not work, fail */
435 DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
441 /* Return whether or not native mode was enabled on the IDE controller */
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
)
453 ULONG LegacyBaseAddress
;
457 /* Check what kind of hack operation this is */
458 switch (OperationType
)
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.
464 case PCI_HACK_FIXUP_BEFORE_CONFIGURATION
:
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.
471 if ((PciData
->VendorID
== 0x8086) &&
472 ((PciData
->DeviceID
== 0x482) || (PciData
->DeviceID
== 0x484)))
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
;
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.
484 if (PdoExtension
) PdoExtension
->ExpectedWritebackFailure
= TRUE
;
487 /* Note that in this case, an immediate return is issued */
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.
495 case PCI_HACK_FIXUP_AFTER_CONFIGURATION
:
497 /* There should always be a PDO extension passed in */
498 ASSERT(PdoExtension
);
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.
508 if ((PciData
->VendorID
== 0x1045) && (PciData
->DeviceID
!= 0xC621))
510 /* Disable native mode */
511 PciData
->ProgIf
&= ~5;
512 PciData
->u
.type0
.InterruptPin
= 0;
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.
519 PdoExtension
->ExpectedWritebackFailure
= TRUE
;
521 else if ((PciData
->BaseClass
== PCI_CLASS_MASS_STORAGE_CTLR
) &&
522 (PciData
->SubClass
== PCI_SUBCLASS_MSC_IDE_CTLR
))
524 /* For other IDE controllers, start out in compatible mode */
525 PdoExtension
->BIOSAllowsIDESwitchToNativeMode
= FALSE
;
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:
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.
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.
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.
552 if ((PciEnableNativeModeATA
) &&
553 !(InitSafeBootMode
) &&
554 (PciIsSlotPresentInParentMethod(PdoExtension
, 'ATAN')))
556 /* The platform supports it, remember that */
557 PdoExtension
->BIOSAllowsIDESwitchToNativeMode
= TRUE
;
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.
565 PdoExtension
->SwitchedIDEToNativeMode
=
566 PciConfigureIdeController(PdoExtension
, PciData
, 1);
569 /* Is native mode enabled after all? */
570 if ((PciData
->ProgIf
& 5) != 5)
572 /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
573 PciData
->u
.type0
.InterruptPin
= 0;
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
))
582 /* Tell the arbiter to apply a hack for these older devices */
583 ario_ApplyBrokenVideoHack(DeviceExtension
);
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
)))
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
,
598 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
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
;
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
615 case PCI_HACK_FIXUP_BEFORE_UPDATE
:
617 /* There should always be a PDO extension passed in */
618 ASSERT(PdoExtension
);
620 /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
621 if ((PdoExtension
->VendorId
== 0x1014) &&
622 (PdoExtension
->DeviceId
== 0x95))
624 /* Read the current command */
625 PciReadDeviceConfig(PdoExtension
,
627 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
630 /* Turn off the decodes */
631 PciDecodeEnable(PdoExtension
, FALSE
, &Command
);
633 /* Apply the required IBM workaround */
634 PciReadDeviceConfig(PdoExtension
, &RegValue
, 0xE0, sizeof(UCHAR
));
637 PciWriteDeviceConfig(PdoExtension
, &RegValue
, 0xE0, sizeof(UCHAR
));
639 /* Restore the command to its original value */
640 PciWriteDeviceConfig(PdoExtension
,
642 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
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.
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
))
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.
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;
694 /* Finally, also check if this is this a CardBUS device? */
695 if (PCI_CONFIGURATION_TYPE(PciData
) == PCI_CARDBUS_BRIDGE_TYPE
)
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.
704 LegacyBaseAddress
= 0;
705 PciWriteDeviceConfig(PdoExtension
,
707 sizeof(PCI_COMMON_HEADER
) + sizeof(ULONG
),
714 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension
,
715 IN PPCI_COMMON_HEADER PciData
)
717 BOOLEAN IdMatch
, RevMatch
, SubsysMatch
;
718 ULONGLONG HackFlags
= DeviceExtension
->HackFlags
;
720 /* Check if the IDs match */
721 IdMatch
= (PciData
->VendorID
== DeviceExtension
->VendorId
) &&
722 (PciData
->DeviceID
== DeviceExtension
->DeviceId
);
723 if (!IdMatch
) return FALSE
;
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
;
730 /* For multifunction devices, this is enough to assume they're the same */
731 if (PCI_MULTIFUNCTION_DEVICE(PciData
)) return TRUE
;
733 /* For bridge devices, there's also nothing else that can be checked */
734 if (DeviceExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) return TRUE
;
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
));
748 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData
,
749 IN PCI_SLOT_NUMBER Slot
,
750 IN UCHAR OperationType
,
751 IN ULONGLONG HackFlags
)
755 /* Check if this is device enumeration */
756 if (OperationType
== PCI_SKIP_DEVICE_ENUMERATION
)
758 /* Check if there's a hackflag saying not to enumerate this device */
759 if (HackFlags
& PCI_HACK_NO_ENUM_AT_ALL
) break;
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))
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",
769 Slot
.u
.bits
.DeviceNumber
,
770 Slot
.u
.bits
.FunctionNumber
);
774 else if (OperationType
== PCI_SKIP_RESOURCE_ENUMERATION
)
776 /* Resource enumeration, check for a hackflag saying not to do it */
777 if (HackFlags
& PCI_HACK_ENUM_NO_RESOURCE
) break;
781 /* Logic error in the driver */
782 ASSERTMSG(FALSE
, "PCI Skip Function - Operation type unknown.");
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
))
790 /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
793 else if (PciData
->BaseClass
== PCI_CLASS_NOT_DEFINED
)
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",
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.
808 if ((PciData
->VendorID
== 0x8086) && (PciData
->DeviceID
== 8)) break;
811 /* Other normal PCI cards and bridges are enumerated */
812 if (PCI_CONFIGURATION_TYPE(PciData
) <= PCI_CARDBUS_BRIDGE_TYPE
) return FALSE
;
815 /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
816 DPRINT1(" Device skipped (not enumerated).\n");
822 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension
,
823 IN PPCI_COMMON_HEADER PciData
)
825 ULONG HeaderType
, CapPtr
, TargetAgpCapabilityId
;
826 DEVICE_POWER_STATE WakeLevel
;
827 PCI_CAPABILITIES_HEADER AgpCapability
;
828 PCI_PM_CAPABILITY PowerCapabilities
;
831 /* Assume no known wake level */
832 PdoExtension
->PowerState
.DeviceWakeLevel
= PowerDeviceUnspecified
;
834 /* Make sure the device has capabilities */
835 if (!(PciData
->Status
& PCI_STATUS_CAPABILITIES_LIST
))
837 /* If it doesn't, there will be no power management */
838 PdoExtension
->CapabilitiesPtr
= 0;
839 PdoExtension
->HackFlags
|= PCI_HACK_NO_PM_CAPS
;
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
)
847 /* Use the bridge's header */
848 CapPtr
= PciData
->u
.type2
.CapabilitiesPtr
;
852 /* Use the device header */
853 ASSERT(HeaderType
<= PCI_CARDBUS_BRIDGE_TYPE
);
854 CapPtr
= PciData
->u
.type0
.CapabilitiesPtr
;
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
;
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
)))
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
,
876 sizeof(PCI_CAPABILITIES_HEADER
)))
878 /* AGP target ID was found, store it */
879 DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId
);
880 PdoExtension
->TargetAgpCapabilityId
= TargetAgpCapabilityId
;
884 /* Check for devices that are known not to have proper power management */
885 if (!(PdoExtension
->HackFlags
& PCI_HACK_NO_PM_CAPS
))
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
)))
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
;
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
;
914 /* Convert the PCI power state to the NT power state */
915 PdoExtension
->PowerState
.CurrentDeviceState
=
916 PowerCapabilities
.PMCSR
.ControlStatus
.PowerState
+ 1;
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
);
926 /* At the very end of all this, does this device not have power management? */
927 if (PdoExtension
->HackFlags
& PCI_HACK_NO_PM_CAPS
)
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
);
942 PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved
,
943 IN PPCI_CONFIGURATOR_CONTEXT Context
)
945 PPCI_COMMON_HEADER PciData
, Current
;
946 PPCI_PDO_EXTENSION PdoExtension
;
948 /* Grab all parameters from the context */
949 PdoExtension
= Context
->PdoExtension
;
950 Current
= Context
->Current
;
951 PciData
= Context
->PciData
;
953 /* Write the limit discovery header */
954 PciWriteDeviceConfig(PdoExtension
, PciData
, 0, PCI_COMMON_HDR_LENGTH
);
956 /* Now read what the device indicated the limits are */
957 PciReadDeviceConfig(PdoExtension
, PciData
, 0, PCI_COMMON_HDR_LENGTH
);
959 /* Then write back the original configuration header */
960 PciWriteDeviceConfig(PdoExtension
, Current
, 0, PCI_COMMON_HDR_LENGTH
);
962 /* Copy back the original command that was saved in the context */
963 Current
->Command
= Context
->Command
;
964 if (Context
->Command
)
966 /* Program it back into the device */
967 PciWriteDeviceConfig(PdoExtension
,
969 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
973 /* Copy back the original status that was saved as well */
974 Current
->Status
= Context
->Status
;
976 /* Call the configurator to restore any other data that might've changed */
977 Context
->Configurator
->RestoreCurrent(Context
);
982 PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context
)
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
;
992 /* Grab all parameters from the context */
993 PdoExtension
= Context
->PdoExtension
;
994 Current
= Context
->Current
;
995 PciData
= Context
->PciData
;
997 /* Save the current PCI Command and Status word */
998 Context
->Status
= Current
->Status
;
999 Context
->Command
= Current
->Command
;
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
);
1007 /* Make a copy of the current PCI configuration header (with decodes off) */
1008 RtlCopyMemory(PciData
, Current
, PCI_COMMON_HDR_LENGTH
);
1010 /* Locate the correct resource configurator for this type of device */
1011 Configurator
= &PciConfigurators
[PdoExtension
->HeaderType
];
1012 Context
->Configurator
= Configurator
;
1014 /* Initialize it, which will typically setup the BARs for limit discovery */
1015 Configurator
->Initialize(Context
);
1017 /* Check for critical devices and PCI Debugging devices */
1018 if ((PdoExtension
->HackFlags
& PCI_HACK_CRITICAL_DEVICE
) ||
1019 (PdoExtension
->OnDebugPath
))
1021 /* Specifically check for a PCI Debugging device */
1022 if (PdoExtension
->OnDebugPath
)
1024 /* Was it enabled for bus mastering? */
1025 if (Context
->Command
& PCI_ENABLE_BUS_MASTER
)
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
;
1032 /* Disable the debugger while the discovery is happening */
1033 KdDisableDebugger();
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
);
1044 /* Re-enable the debugger if this was a PCI Debugging Device */
1045 if (PdoExtension
->OnDebugPath
) KdEnableDebugger();
1049 /* Otherwise, it's safe to do this in-line at low IRQL */
1050 PciWriteLimitsAndRestoreCurrent(PdoExtension
, Context
);
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".
1061 if (!PdoExtension
->ExpectedWritebackFailure
)
1063 /* Read the current PCI header now, after discovery has completed */
1064 PciReadDeviceConfig(PdoExtension
, PciData
+ 1, 0, PCI_COMMON_HDR_LENGTH
);
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
)
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
);
1078 /* This PDO should not already have resources, since this is only done once */
1079 ASSERT(PdoExtension
->Resources
== NULL
);
1081 /* Allocate the structure that will hold the discovered resources and limits */
1082 PdoExtension
->Resources
= ExAllocatePoolWithTag(NonPagedPool
,
1083 sizeof(PCI_FUNCTION_RESOURCES
),
1085 if (!PdoExtension
->Resources
) return STATUS_INSUFFICIENT_RESOURCES
;
1087 /* Clear it out for now */
1088 RtlZeroMemory(PdoExtension
->Resources
, sizeof(PCI_FUNCTION_RESOURCES
));
1090 /* Now call the configurator, which will first store the limits... */
1091 Configurator
->SaveLimits(Context
);
1093 /* ...and then store the current resources being used */
1094 Configurator
->SaveCurrentSettings(Context
);
1096 /* Loop all the limit descriptors backwards */
1097 IoDescriptor
= &PdoExtension
->Resources
->Limit
[PCI_TYPE0_ADDRESSES
+ 1];
1100 /* Keep going until a non-null descriptor is found */
1102 if (IoDescriptor
->Type
!= CmResourceTypeNull
) break;
1104 /* This is a null descriptor, is it the last one? */
1105 if (IoDescriptor
== &PdoExtension
->Resources
->Limit
[PCI_TYPE0_ADDRESSES
+ 1])
1107 /* This means the descriptor is NULL, which means discovery failed */
1108 DPRINT1("PCI Resources fail!\n");
1110 /* No resources will be assigned for the device */
1111 ExFreePoolWithTag(PdoExtension
->Resources
, 0);
1112 PdoExtension
->Resources
= NULL
;
1117 /* Return success here, even if the device has no assigned resources */
1118 return STATUS_SUCCESS
;
1123 PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension
,
1124 IN PPCI_COMMON_HEADER Current
,
1125 IN ULONGLONG HackFlags
)
1128 PPCI_COMMON_HEADER PciData
;
1129 PCI_CONFIGURATOR_CONTEXT Context
;
1132 /* Do the hackflags indicate this device should be skipped? */
1133 if (PciSkipThisFunction(Current
,
1135 PCI_SKIP_RESOURCE_ENUMERATION
,
1138 /* Do not process its resources */
1139 return STATUS_SUCCESS
;
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
;
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
);
1152 /* Enumeration is completed, free the PCI headers and return the status */
1153 ExFreePoolWithTag(PciData
, 0);
1159 PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension
)
1161 PPCI_PDO_EXTENSION PdoExtension
;
1162 PDEVICE_OBJECT PhysicalDeviceObject
;
1165 /* Get the PDO Extension */
1166 PhysicalDeviceObject
= DeviceExtension
->PhysicalDeviceObject
;
1167 PdoExtension
= (PPCI_PDO_EXTENSION
)PhysicalDeviceObject
->DeviceExtension
;
1169 /* Cheeck if this is the root bus */
1170 if (!PCI_IS_ROOT_FDO(DeviceExtension
))
1172 /* Not really handling this year */
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
)))
1182 /* We'll need to do some legacy support */
1189 /* Scan all of the root bus' children bridges */
1190 for (PdoExtension
= DeviceExtension
->ChildBridgePdoList
;
1192 PdoExtension
= PdoExtension
->NextBridge
)
1194 /* Find any that have the VGA decode bit on */
1195 if (PdoExtension
->Dependent
.type1
.VgaBitSet
)
1197 /* Again, some more legacy support we'll have to do */
1204 /* Check for ACPI systems where the OS assigns bus numbers */
1205 if (PciAssignBusNumbers
)
1207 /* Not yet supported */
1215 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension
)
1217 ULONG MaxDevice
= PCI_MAX_DEVICES
;
1218 BOOLEAN ProcessFlag
= FALSE
;
1219 ULONG i
, j
, k
, Size
;
1220 USHORT CapOffset
, TempOffset
;
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
;
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
);
1238 /* Is this the root FDO? */
1239 if (!PCI_IS_ROOT_FDO(DeviceExtension
))
1241 /* Other FDOs are not currently supported */
1246 /* Loop every device on the bus */
1247 PciSlot
.u
.bits
.Reserved
= 0;
1248 i
= DeviceExtension
->BaseBus
;
1249 for (j
= 0; j
< MaxDevice
; j
++)
1251 /* Loop every function of each device */
1252 PciSlot
.u
.bits
.DeviceNumber
= j
;
1253 for (k
= 0; k
< PCI_MAX_FUNCTION
; k
++)
1255 /* Build the final slot structure */
1256 PciSlot
.u
.bits
.FunctionNumber
= k
;
1258 /* Read the vendor for this slot */
1259 PciReadSlotConfig(DeviceExtension
,
1265 /* Skip invalid device */
1266 if (PciData
->VendorID
== PCI_INVALID_VENDORID
) continue;
1268 /* Now read the whole header */
1269 PciReadSlotConfig(DeviceExtension
,
1273 PCI_COMMON_HDR_LENGTH
- sizeof(USHORT
));
1275 /* Apply any hacks before even analyzing the configuration header */
1276 PciApplyHacks(DeviceExtension
,
1279 PCI_HACK_FIXUP_BEFORE_CONFIGURATION
,
1282 /* Dump device that was found */
1283 DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
1289 /* Dump the device's header */
1290 PciDebugDumpCommonConfig(PciData
);
1292 /* Find description for this device for the debugger's sake */
1293 DescriptionText
= PciGetDeviceDescriptionMessage(PciData
->BaseClass
,
1295 DPRINT1("Device Description \"%S\".\n",
1296 DescriptionText
? DescriptionText
: L
"(NULL)");
1297 if (DescriptionText
) ExFreePoolWithTag(DescriptionText
, 0);
1299 /* Check if there is an ACPI Watchdog Table */
1302 /* Check if this PCI device is the ACPI Watchdog Device... */
1307 /* Check for non-simple devices */
1308 if ((PCI_MULTIFUNCTION_DEVICE(PciData
)) ||
1309 (PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
))
1311 /* No subsystem data defined for these kinds of bridges */
1317 /* Read the subsystem information from the PCI header */
1318 SubVendorId
= PciData
->u
.type0
.SubVendorID
;
1319 SubSystemId
= PciData
->u
.type0
.SubSystemID
;
1322 /* Get any hack flags for this device */
1323 HackFlags
= PciGetHackFlags(PciData
->VendorID
,
1327 PciData
->RevisionID
);
1329 /* Check if this device is considered critical by the OS */
1330 if (PciIsCriticalDeviceClass(PciData
->BaseClass
, PciData
->SubClass
))
1332 /* Check if normally the decodes would be disabled */
1333 if (!(HackFlags
& PCI_HACK_DONT_DISABLE_DECODES
))
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
;
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
))
1347 /* Do not disable their decodes either */
1348 DPRINT1("Not allowing PM because device is VGA\n");
1349 HackFlags
|= PCI_HACK_CRITICAL_DEVICE
;
1352 /* Check if the device should be skipped for whatever reason */
1353 if (PciSkipThisFunction(PciData
,
1355 PCI_SKIP_DEVICE_ENUMERATION
,
1358 /* Skip this device */
1362 /* Check if a PDO has already been created for this device */
1363 PdoExtension
= PciFindPdoByFunction(DeviceExtension
,
1368 /* Rescan scenarios are not yet implemented */
1373 /* Bus processing will need to happen */
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
;
1381 /* Check for broken devices with wrong/no class codes */
1382 if (HackFlags
& PCI_HACK_FAKE_CLASS_CODE
)
1384 /* Setup a default one */
1385 PciData
->BaseClass
= PCI_CLASS_BASE_SYSTEM_DEV
;
1386 PciData
->SubClass
= PCI_SUBCLASS_SYS_OTHER
;
1388 /* Device will behave erratically when reading back data */
1389 NewExtension
->ExpectedWritebackFailure
= TRUE
;
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
);
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
)))
1406 /* Acquire this device's lock */
1407 KeEnterCriticalRegion();
1408 KeWaitForSingleObject(&DeviceExtension
->ChildListLock
,
1414 /* Scan the bridge list until the first free entry */
1415 for (BridgeExtension
= &DeviceExtension
->ChildBridgePdoList
;
1417 BridgeExtension
= &(*BridgeExtension
)->NextBridge
);
1419 /* Add this PDO as a bridge */
1420 *BridgeExtension
= NewExtension
;
1421 ASSERT(NewExtension
->NextBridge
== NULL
);
1423 /* Release this device's lock */
1424 KeSetEvent(&DeviceExtension
->ChildListLock
,
1427 KeLeaveCriticalRegion();
1430 /* Get the PCI BIOS configuration saved in the registry */
1431 Status
= PciGetBiosConfig(NewExtension
, BiosData
);
1432 if (NT_SUCCESS(Status
))
1434 /* This path has not yet been fully tested by eVb */
1435 DPRINT1("Have BIOS configuration!\n");
1438 /* Check if the PCI BIOS configuration has changed */
1439 if (!PcipIsSameDevice(NewExtension
, BiosData
))
1441 /* This is considered failure, and new data will be saved */
1442 Status
= STATUS_UNSUCCESSFUL
;
1446 /* Data is still correct, check for interrupt line change */
1447 if (BiosData
->u
.type0
.InterruptLine
!=
1448 PciData
->u
.type0
.InterruptLine
)
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
),
1458 /* Save the BIOS interrupt line and the initial command */
1459 NewExtension
->RawInterruptLine
= BiosData
->u
.type0
.InterruptLine
;
1460 NewExtension
->InitialCommand
= BiosData
->Command
;
1464 /* Check if no saved data was present or if it was a mismatch */
1465 if (!NT_SUCCESS(Status
))
1467 /* Save the new data */
1468 Status
= PciSaveBiosConfig(NewExtension
, PciData
);
1469 ASSERT(NT_SUCCESS(Status
));
1471 /* Save the interrupt line and command from the device */
1472 NewExtension
->RawInterruptLine
= PciData
->u
.type0
.InterruptLine
;
1473 NewExtension
->InitialCommand
= PciData
->Command
;
1476 /* Save original command from the device and hack flags */
1477 NewExtension
->CommandEnables
= PciData
->Command
;
1478 NewExtension
->HackFlags
= HackFlags
;
1480 /* Get power, AGP, and other capability data */
1481 PciGetEnhancedCapabilities(NewExtension
, PciData
);
1483 /* Now configure the BARs */
1484 Status
= PciGetFunctionLimits(NewExtension
, PciData
, HackFlags
);
1486 /* Power up the device */
1487 PciSetPowerManagedDevicePowerState(NewExtension
, PowerDeviceD0
, FALSE
);
1489 /* Apply any device hacks required for enumeration */
1490 PciApplyHacks(DeviceExtension
,
1493 PCI_HACK_FIXUP_AFTER_CONFIGURATION
,
1496 /* Save interrupt pin */
1497 NewExtension
->InterruptPin
= PciData
->u
.type0
.InterruptPin
;
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
1505 NewExtension
->AdjustedInterruptLine
= PciGetAdjustedInterruptLine(NewExtension
);
1507 /* Check if this device is used for PCI debugger cards */
1508 NewExtension
->OnDebugPath
= PciIsDeviceOnDebugPath(NewExtension
);
1510 /* Check for devices with invalid/bogus subsystem data */
1511 if (HackFlags
& PCI_HACK_NO_SUBSYSTEM
)
1513 /* Set the subsystem information to zero instead */
1514 NewExtension
->SubsystemVendorId
= 0;
1515 NewExtension
->SubsystemId
= 0;
1518 /* Scan all capabilities */
1519 CapOffset
= NewExtension
->CapabilitiesPtr
;
1522 /* Read this header */
1523 TempOffset
= PciReadDeviceCapability(NewExtension
,
1527 sizeof(PCI_CAPABILITIES_HEADER
));
1528 if (TempOffset
!= CapOffset
)
1530 /* This is a strange issue that shouldn't happen normally */
1531 DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
1533 ASSERT(TempOffset
== CapOffset
);
1536 /* Check for capabilities that this driver cares about */
1537 switch (CapHeader
.CapabilityID
)
1539 /* Power management capability is heavily used by the bus */
1540 case PCI_CAPABILITY_ID_POWER_MANAGEMENT
:
1542 /* Dump the capability */
1544 Size
= sizeof(PCI_PM_CAPABILITY
);
1547 /* AGP capability is required for AGP bus functionality */
1548 case PCI_CAPABILITY_ID_AGP
:
1550 /* Dump the capability */
1552 Size
= sizeof(PCI_AGP_CAPABILITY
);
1555 /* This driver doesn't really use anything other than that */
1558 /* Windows prints this, we could do a translation later */
1559 Name
= "UNKNOWN CAPABILITY";
1564 /* Check if this is a capability that should be dumped */
1567 /* Read the whole capability data */
1568 TempOffset
= PciReadDeviceCapability(NewExtension
,
1570 CapHeader
.CapabilityID
,
1574 if (TempOffset
!= CapOffset
)
1576 /* Again, a strange issue that shouldn't be seen */
1577 DPRINT1("- Failed to read capability data. ***\n");
1578 ASSERT(TempOffset
== CapOffset
);
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
));
1589 /* Check the next capability */
1590 CapOffset
= CapHeader
.Next
;
1593 /* Check for IDE controllers */
1594 if ((NewExtension
->BaseClass
== PCI_CLASS_MASS_STORAGE_CTLR
) &&
1595 (NewExtension
->SubClass
== PCI_SUBCLASS_MSC_IDE_CTLR
))
1597 /* Do not allow them to power down completely */
1598 NewExtension
->DisablePowerDown
= TRUE
;
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.
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)))
1613 /* Do not allow these legacy bridges to be powered down */
1614 NewExtension
->DisablePowerDown
= TRUE
;
1617 /* Check if the BIOS did not configure a cache line size */
1618 if (!PciData
->CacheLineSize
)
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
)))
1625 /* Check if this is a PCI-X device*/
1626 TempOffset
= PciReadDeviceCapability(NewExtension
,
1627 NewExtension
->CapabilitiesPtr
,
1628 PCI_CAPABILITY_ID_PCIX
,
1630 sizeof(PCI_CAPABILITIES_HEADER
));
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.
1639 if (!(PciData
->LatencyTimer
) ||
1640 ((TempOffset
) && (PciData
->LatencyTimer
== 64)))
1642 /* Keep track of the fact that it needs configuration */
1643 DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
1645 NewExtension
->NeedsHotPlugConfiguration
= TRUE
;
1650 /* Save latency and cache size information */
1651 NewExtension
->SavedLatencyTimer
= PciData
->LatencyTimer
;
1652 NewExtension
->SavedCacheLineSize
= PciData
->CacheLineSize
;
1654 /* The PDO is now ready to go */
1655 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1659 /* Enumeration completed, do a final pass now that all devices are found */
1660 if (ProcessFlag
) PciProcessBus(DeviceExtension
);
1661 return STATUS_SUCCESS
;
1666 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension
,
1667 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
1670 PPCI_PDO_EXTENSION PdoExtension
;
1672 PDEVICE_RELATIONS DeviceRelations
, NewRelations
;
1674 PDEVICE_OBJECT DeviceObject
, *ObjectArray
;
1677 /* Make sure the FDO is started */
1678 ASSERT(DeviceExtension
->DeviceState
== PciStarted
);
1680 /* Synchronize while we enumerate the bus */
1681 Status
= PciBeginStateTransition(DeviceExtension
, PciSynchronizedOperation
);
1682 if (!NT_SUCCESS(Status
)) return Status
;
1684 /* Scan all children PDO */
1685 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
1687 PdoExtension
= PdoExtension
->Next
)
1689 /* Invalidate them */
1690 PdoExtension
->NotPresent
= TRUE
;
1693 /* Scan the PCI Bus */
1694 Status
= PciScanBus(DeviceExtension
);
1695 ASSERT(NT_SUCCESS(Status
));
1697 /* Enumerate all children PDO again */
1698 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
1700 PdoExtension
= PdoExtension
->Next
)
1702 /* Check for PDOs that are still invalidated */
1703 if (PdoExtension
->NotPresent
)
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",
1712 /* Increase count of detected PDOs */
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
;
1723 /* Allocate the device relations */
1724 NewRelations
= (PDEVICE_RELATIONS
)ExAllocatePoolWithTag(0, Size
, 'BicP');
1727 /* Out of space, cancel the operation */
1728 PciCancelStateTransition(DeviceExtension
, PciSynchronizedOperation
);
1729 return STATUS_INSUFFICIENT_RESOURCES
;
1732 /* Check if there were any older relations */
1733 NewRelations
->Count
= 0;
1734 if (DeviceRelations
)
1736 /* Copy the old relations into the new buffer, then free the old one */
1737 RtlCopyMemory(NewRelations
,
1739 FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) +
1740 DeviceRelations
->Count
* sizeof(PDEVICE_OBJECT
));
1741 ExFreePoolWithTag(DeviceRelations
, 0);
1744 /* Print out that we're ready to dump relations */
1745 DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
1747 DeviceExtension
->BaseBus
);
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
)
1754 /* Dump this relation */
1755 DPRINT1(" QDR PDO %08x (x %08x)%s\n",
1756 PdoExtension
->PhysicalDeviceObject
,
1758 PdoExtension
->NotPresent
?
1759 "<Omitted, device flaged not present>" : "");
1761 /* Is this PDO present? */
1762 if (!PdoExtension
->NotPresent
)
1764 /* Reference it and add it to the array */
1765 DeviceObject
= PdoExtension
->PhysicalDeviceObject
;
1766 ObfReferenceObject(DeviceObject
);
1767 *ObjectArray
++ = DeviceObject
;
1770 /* Go to the next PDO */
1771 PdoExtension
= PdoExtension
->Next
;
1774 /* Terminate dumping the relations */
1775 DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
1776 NewRelations
->Count
+ PdoCount
,
1777 NewRelations
->Count
);
1779 /* Return the final count and the new buffer */
1780 NewRelations
->Count
+= PdoCount
;
1781 *pDeviceRelations
= NewRelations
;
1782 return STATUS_SUCCESS
;