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 PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension
,
55 IN PCM_RESOURCE_LIST ResourceList
)
57 PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial
, InterruptResource
;
58 PCM_PARTIAL_RESOURCE_DESCRIPTOR BaseResource
, CurrentDescriptor
;
59 PCM_PARTIAL_RESOURCE_DESCRIPTOR PreviousDescriptor
;
60 CM_PARTIAL_RESOURCE_DESCRIPTOR ResourceArray
[7];
61 PCM_FULL_RESOURCE_DESCRIPTOR FullList
;
62 BOOLEAN DrainPartial
, RangeChange
;
64 PPCI_FUNCTION_RESOURCES PciResources
;
67 /* Make sure we have either no resources, or at least one */
68 ASSERT((ResourceList
== NULL
) || (ResourceList
->Count
== 1));
70 /* Initialize no partial, interrupt descriptor, or range change */
72 InterruptResource
= NULL
;
75 /* Check if there's not actually any resources */
76 if (!(ResourceList
) || !(ResourceList
->Count
))
78 /* Then just return the hardware update state */
79 return PdoExtension
->UpdateHardware
;
82 /* Print the new specified resource list */
83 PciDebugPrintCmResList(ResourceList
);
85 /* Clear the temporary resource array */
86 for (i
= 0; i
< 7; i
++) ResourceArray
[i
].Type
= CmResourceTypeNull
;
88 /* Loop the full resource descriptor */
89 FullList
= ResourceList
->List
;
90 for (i
= 0; i
< ResourceList
->Count
; i
++)
92 /* Initialize loop variables */
96 /* Loop the partial descriptors */
97 Partial
= FullList
->PartialResourceList
.PartialDescriptors
;
98 for (j
= 0; j
< FullList
->PartialResourceList
.Count
; j
++)
100 /* Check if we were supposed to drain a partial due to device data */
103 /* Draining complete, move on to the next descriptor then */
108 /* Check what kind of descriptor this was */
109 switch (Partial
->Type
)
111 /* Base BAR resources */
112 case CmResourceTypePort
:
113 case CmResourceTypeMemory
:
115 /* Set it as the base */
116 ASSERT(BaseResource
== NULL
);
117 BaseResource
= Partial
;
120 /* Interrupt resource */
121 case CmResourceTypeInterrupt
:
123 /* Make sure it's a compatible (and the only) PCI interrupt */
124 ASSERT(InterruptResource
== NULL
);
125 ASSERT(Partial
->u
.Interrupt
.Level
== Partial
->u
.Interrupt
.Vector
);
126 InterruptResource
= Partial
;
128 /* Only 255 interrupts on x86/x64 hardware */
129 if (Partial
->u
.Interrupt
.Level
< 256)
131 /* Use the passed interrupt line */
132 PdoExtension
->AdjustedInterruptLine
= Partial
->u
.Interrupt
.Level
;
136 /* Invalid vector, so ignore it */
137 PdoExtension
->AdjustedInterruptLine
= 0;
142 /* Check for specific device data */
143 case CmResourceTypeDevicePrivate
:
145 /* Check what kind of data this was */
146 switch (Partial
->u
.DevicePrivate
.Data
[0])
148 /* Not used in the driver yet */
150 UNIMPLEMENTED_DBGBREAK();
153 /* Not used in the driver yet */
155 UNIMPLEMENTED_DBGBREAK();
158 /* A drain request */
160 /* Shouldn't be a base resource, this is a drain */
161 ASSERT(BaseResource
== NULL
);
162 DrainPartial
= Partial
->u
.DevicePrivate
.Data
[1];
163 ASSERT(DrainPartial
== TRUE
);
169 /* Move to the next descriptor */
170 Partial
= PciNextPartialDescriptor(Partial
);
173 /* We should be starting a new list now */
174 ASSERT(BaseResource
== NULL
);
175 FullList
= (PVOID
)Partial
;
178 /* Check the current assigned PCI resources */
179 PciResources
= PdoExtension
->Resources
;
180 if (!PciResources
) return FALSE
;
182 //if... // MISSING CODE
184 DPRINT1("Missing sanity checking code!\n");
186 /* Loop all the PCI function resources */
187 for (i
= 0; i
< 7; i
++)
189 /* Get the current function resource descriptor, and the new one */
190 CurrentDescriptor
= &PciResources
->Current
[i
];
191 Partial
= &ResourceArray
[i
];
193 /* Previous is current during the first loop iteration */
194 PreviousDescriptor
= &PciResources
->Current
[(i
== 0) ? (0) : (i
- 1)];
196 /* Check if this new descriptor is different than the old one */
197 if (((Partial
->Type
!= CurrentDescriptor
->Type
) ||
198 (Partial
->Type
!= CmResourceTypeNull
)) &&
199 ((Partial
->u
.Generic
.Start
.QuadPart
!=
200 CurrentDescriptor
->u
.Generic
.Start
.QuadPart
) ||
201 (Partial
->u
.Generic
.Length
!= CurrentDescriptor
->u
.Generic
.Length
)))
203 /* Record a change */
206 /* Was there a range before? */
207 if (CurrentDescriptor
->Type
!= CmResourceTypeNull
)
210 DbgPrint(" Old range-\n");
211 PciDebugPrintPartialResource(CurrentDescriptor
);
215 /* There was no range */
216 DbgPrint(" Previously unset range\n");
220 DbgPrint(" changed to\n");
221 PciDebugPrintPartialResource(Partial
);
223 /* Update to new range */
224 CurrentDescriptor
->Type
= Partial
->Type
;
225 PreviousDescriptor
->u
.Generic
.Start
= Partial
->u
.Generic
.Start
;
226 PreviousDescriptor
->u
.Generic
.Length
= Partial
->u
.Generic
.Length
;
227 CurrentDescriptor
= PreviousDescriptor
;
231 /* Either the hardware was updated, or a resource range changed */
232 return ((RangeChange
) || (PdoExtension
->UpdateHardware
));
237 PcipUpdateHardware(IN PVOID Context
,
240 PPCI_PDO_EXTENSION PdoExtension
= Context
;
241 PPCI_COMMON_HEADER PciData
= Context2
;
243 /* Check if we're allowed to disable decodes */
244 PciData
->Command
= PdoExtension
->CommandEnables
;
245 if (!(PdoExtension
->HackFlags
& PCI_HACK_PRESERVE_COMMAND
))
247 /* Disable all decodes */
248 PciData
->Command
&= ~(PCI_ENABLE_IO_SPACE
|
249 PCI_ENABLE_MEMORY_SPACE
|
250 PCI_ENABLE_BUS_MASTER
|
251 PCI_ENABLE_WRITE_AND_INVALIDATE
);
254 /* Update the device configuration */
256 PciWriteDeviceConfig(PdoExtension
, PciData
, 0, PCI_COMMON_HDR_LENGTH
);
258 /* Turn decodes back on */
259 PciDecodeEnable(PdoExtension
, TRUE
, &PdoExtension
->CommandEnables
);
264 PciUpdateHardware(IN PPCI_PDO_EXTENSION PdoExtension
,
265 IN PPCI_COMMON_HEADER PciData
)
267 PCI_IPI_CONTEXT Context
;
269 /* Check for critical devices and PCI Debugging devices */
270 if ((PdoExtension
->HackFlags
& PCI_HACK_CRITICAL_DEVICE
) ||
271 (PdoExtension
->OnDebugPath
))
273 /* Build the context and send an IPI */
274 Context
.RunCount
= 1;
276 Context
.Context
= PciData
;
277 Context
.Function
= PcipUpdateHardware
;
278 Context
.DeviceExtension
= PdoExtension
;
279 KeIpiGenericCall(PciExecuteCriticalSystemRoutine
, (ULONG_PTR
)&Context
);
283 /* Just to the update inline */
284 PcipUpdateHardware(PdoExtension
, PciData
);
288 PIO_RESOURCE_REQUIREMENTS_LIST
290 PciAllocateIoRequirementsList(IN ULONG Count
,
295 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
;
297 /* Calculate the final size of the list, including each descriptor */
298 Size
= sizeof(IO_RESOURCE_REQUIREMENTS_LIST
);
299 if (Count
> 1) Size
= sizeof(IO_RESOURCE_DESCRIPTOR
) * (Count
- 1) +
300 sizeof(IO_RESOURCE_REQUIREMENTS_LIST
);
302 /* Allocate the list */
303 RequirementsList
= ExAllocatePoolWithTag(PagedPool
, Size
, 'BicP');
304 if (!RequirementsList
) return NULL
;
307 RtlZeroMemory(RequirementsList
, Size
);
308 RequirementsList
->AlternativeLists
= 1;
309 RequirementsList
->BusNumber
= BusNumber
;
310 RequirementsList
->SlotNumber
= SlotNumber
;
311 RequirementsList
->InterfaceType
= PCIBus
;
312 RequirementsList
->ListSize
= Size
;
313 RequirementsList
->List
[0].Count
= Count
;
314 RequirementsList
->List
[0].Version
= 1;
315 RequirementsList
->List
[0].Revision
= 1;
318 return RequirementsList
;
323 PciAllocateCmResourceList(IN ULONG Count
,
327 PCM_RESOURCE_LIST ResourceList
;
329 /* Calculate the final size of the list, including each descriptor */
330 Size
= sizeof(CM_RESOURCE_LIST
);
331 if (Count
> 1) Size
= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
) * (Count
- 1) +
332 sizeof(CM_RESOURCE_LIST
);
334 /* Allocate the list */
335 ResourceList
= ExAllocatePoolWithTag(PagedPool
, Size
, 'BicP');
336 if (!ResourceList
) return NULL
;
339 RtlZeroMemory(ResourceList
, Size
);
340 ResourceList
->Count
= 1;
341 ResourceList
->List
[0].BusNumber
= BusNumber
;
342 ResourceList
->List
[0].InterfaceType
= PCIBus
;
343 ResourceList
->List
[0].PartialResourceList
.Version
= 1;
344 ResourceList
->List
[0].PartialResourceList
.Revision
= 1;
345 ResourceList
->List
[0].PartialResourceList
.Count
= Count
;
353 PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension
,
354 OUT PCM_RESOURCE_LIST
*Buffer
)
356 PPCI_FUNCTION_RESOURCES PciResources
;
357 BOOLEAN HaveVga
, HaveMemSpace
, HaveIoSpace
;
358 USHORT BridgeControl
, PciCommand
;
360 PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial
, Resource
, LastResource
;
361 PCM_RESOURCE_LIST ResourceList
;
370 /* Make sure there's some resources to query */
371 PciResources
= PdoExtension
->Resources
;
372 if (!PciResources
) return STATUS_SUCCESS
;
374 /* Read the decodes */
375 PciReadDeviceConfig(PdoExtension
,
377 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
380 /* Check which ones are turned on */
381 HaveIoSpace
= PciCommand
& PCI_ENABLE_IO_SPACE
;
382 HaveMemSpace
= PciCommand
& PCI_ENABLE_MEMORY_SPACE
;
384 /* Loop maximum possible descriptors */
385 for (i
= 0; i
< 7; i
++)
387 /* Check if the decode for this descriptor is actually turned on */
388 Partial
= &PciResources
->Current
[i
];
389 if (((HaveMemSpace
) && (Partial
->Type
== CmResourceTypeMemory
)) ||
390 ((HaveIoSpace
) && (Partial
->Type
== CmResourceTypePort
)))
392 /* One more fully active descriptor */
397 /* If there's an interrupt pin associated, check at least one decode is on */
398 if ((PdoExtension
->InterruptPin
) && ((HaveMemSpace
) || (HaveIoSpace
)))
400 /* Read the interrupt line for the pin, add a descriptor if it's valid */
401 InterruptLine
= PdoExtension
->AdjustedInterruptLine
;
402 if ((InterruptLine
) && (InterruptLine
!= -1)) Count
++;
405 /* Check for PCI bridge */
406 if (PdoExtension
->HeaderType
== PCI_BRIDGE_TYPE
)
408 /* Read bridge settings, check if VGA is present */
409 PciReadDeviceConfig(PdoExtension
,
411 FIELD_OFFSET(PCI_COMMON_HEADER
, u
.type1
.BridgeControl
),
413 if (BridgeControl
& PCI_ENABLE_BRIDGE_VGA
)
415 /* Remember for later */
418 /* One memory descriptor for 0xA0000, plus the two I/O port ranges */
419 if (HaveMemSpace
) Count
++;
420 if (HaveIoSpace
) Count
+= 2;
424 /* If there's no descriptors in use, there's no resources, so return */
425 if (!Count
) return STATUS_SUCCESS
;
427 /* Allocate a resource list to hold the resources */
428 ResourceList
= PciAllocateCmResourceList(Count
,
429 PdoExtension
->ParentFdoExtension
->BaseBus
);
430 if (!ResourceList
) return STATUS_INSUFFICIENT_RESOURCES
;
432 /* This is where the descriptors will be copied into */
433 Resource
= ResourceList
->List
[0].PartialResourceList
.PartialDescriptors
;
434 LastResource
= Resource
+ Count
+ 1;
436 /* Loop maximum possible descriptors */
437 for (i
= 0; i
< 7; i
++)
439 /* Check if the decode for this descriptor is actually turned on */
440 Partial
= &PciResources
->Current
[i
];
441 if (((HaveMemSpace
) && (Partial
->Type
== CmResourceTypeMemory
)) ||
442 ((HaveIoSpace
) && (Partial
->Type
== CmResourceTypePort
)))
444 /* Copy the descriptor into the resource list */
445 *Resource
++ = *Partial
;
449 /* Check if earlier the code detected this was a PCI bridge with VGA on it */
452 /* Are the memory decodes enabled? */
455 /* Build a memory descriptor for a 128KB framebuffer at 0xA0000 */
456 Resource
->Flags
= CM_RESOURCE_MEMORY_READ_WRITE
;
457 Resource
->u
.Generic
.Start
.HighPart
= 0;
458 Resource
->Type
= CmResourceTypeMemory
;
459 Resource
->u
.Generic
.Start
.LowPart
= 0xA0000;
460 Resource
->u
.Generic
.Length
= 0x20000;
464 /* Are the I/O decodes enabled? */
467 /* Build an I/O descriptor for the graphic ports at 0x3B0 */
468 Resource
->Type
= CmResourceTypePort
;
469 Resource
->Flags
= CM_RESOURCE_PORT_POSITIVE_DECODE
| CM_RESOURCE_PORT_10_BIT_DECODE
;
470 Resource
->u
.Port
.Start
.QuadPart
= 0x3B0u
;
471 Resource
->u
.Port
.Length
= 0xC;
474 /* Build an I/O descriptor for the graphic ports at 0x3C0 */
475 Resource
->Type
= CmResourceTypePort
;
476 Resource
->Flags
= CM_RESOURCE_PORT_POSITIVE_DECODE
| CM_RESOURCE_PORT_10_BIT_DECODE
;
477 Resource
->u
.Port
.Start
.QuadPart
= 0x3C0u
;
478 Resource
->u
.Port
.Length
= 0x20;
483 /* If there's an interrupt pin associated, check at least one decode is on */
484 if ((PdoExtension
->InterruptPin
) && ((HaveMemSpace
) || (HaveIoSpace
)))
486 /* Read the interrupt line for the pin, check if it's valid */
487 InterruptLine
= PdoExtension
->AdjustedInterruptLine
;
488 if ((InterruptLine
) && (InterruptLine
!= -1))
490 /* Make sure there's still space */
491 ASSERT(Resource
< LastResource
);
493 /* Add the interrupt descriptor */
494 Resource
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
495 Resource
->Type
= CmResourceTypeInterrupt
;
496 Resource
->ShareDisposition
= CmResourceShareShared
;
497 Resource
->u
.Interrupt
.Affinity
= -1;
498 Resource
->u
.Interrupt
.Level
= InterruptLine
;
499 Resource
->u
.Interrupt
.Vector
= InterruptLine
;
503 /* Return the resouce list */
504 *Buffer
= ResourceList
;
505 return STATUS_SUCCESS
;
510 PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension
,
511 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
513 PDEVICE_RELATIONS DeviceRelations
;
516 /* If there were existing relations, free them */
517 if (*pDeviceRelations
) ExFreePoolWithTag(*pDeviceRelations
, 0);
519 /* Allocate a new structure for the relations */
520 DeviceRelations
= ExAllocatePoolWithTag(NonPagedPool
,
521 sizeof(DEVICE_RELATIONS
),
523 if (!DeviceRelations
) return STATUS_INSUFFICIENT_RESOURCES
;
525 /* Only one relation: the PDO */
526 DeviceRelations
->Count
= 1;
527 DeviceRelations
->Objects
[0] = PdoExtension
->PhysicalDeviceObject
;
528 ObReferenceObject(DeviceRelations
->Objects
[0]);
530 /* Return the new relations */
531 *pDeviceRelations
= DeviceRelations
;
532 return STATUS_SUCCESS
;
537 PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension
,
538 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
540 UNREFERENCED_PARAMETER(PdoExtension
);
541 UNREFERENCED_PARAMETER(pDeviceRelations
);
543 /* Not yet implemented */
544 UNIMPLEMENTED_DBGBREAK();
545 return STATUS_NOT_IMPLEMENTED
;
550 PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension
,
551 IN PPCI_COMMON_HEADER PciData
,
552 OUT PIO_RESOURCE_REQUIREMENTS_LIST
* Buffer
)
554 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
;
556 UNREFERENCED_PARAMETER(PdoExtension
);
557 UNREFERENCED_PARAMETER(PciData
);
560 /* There aren't, so use the zero descriptor */
561 RequirementsList
= PciZeroIoResourceRequirements
;
563 /* Does it actually exist yet? */
564 if (!PciZeroIoResourceRequirements
)
566 /* Allocate it, and use it for future use */
567 RequirementsList
= PciAllocateIoRequirementsList(0, 0, 0);
568 PciZeroIoResourceRequirements
= RequirementsList
;
569 if (!PciZeroIoResourceRequirements
) return STATUS_INSUFFICIENT_RESOURCES
;
572 /* Return the zero requirements list to the caller */
573 *Buffer
= RequirementsList
;
574 DPRINT1("PCI - build resource reqs - early out, 0 resources\n");
575 return STATUS_SUCCESS
;
577 return STATUS_SUCCESS
;
582 PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension
,
583 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST
*RequirementsList
)
586 PCI_COMMON_HEADER PciHeader
;
589 /* Check if the PDO has any resources, or at least an interrupt pin */
590 if ((PdoExtension
->Resources
) || (PdoExtension
->InterruptPin
))
592 /* Read the current PCI header */
593 PciReadDeviceConfig(PdoExtension
, &PciHeader
, 0, PCI_COMMON_HDR_LENGTH
);
595 /* Use it to build a list of requirements */
596 Status
= PciBuildRequirementsList(PdoExtension
, &PciHeader
, RequirementsList
);
597 if (!NT_SUCCESS(Status
)) return Status
;
599 /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
600 if ((PciHeader
.VendorID
== 0xE11) &&
601 (PciHeader
.DeviceID
== 0xA0F7) &&
602 (PciHeader
.RevisionID
== 17) &&
603 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED
)))
605 /* Have not tested this on eVb's machine yet */
606 UNIMPLEMENTED_DBGBREAK();
609 /* Check if the requirements are actually the zero list */
610 if (*RequirementsList
== PciZeroIoResourceRequirements
)
612 /* A simple NULL will sufficie for the PnP Manager */
613 *RequirementsList
= NULL
;
614 DPRINT1("Returning NULL requirements list\n");
618 /* Otherwise, print out the requirements list */
619 PciDebugPrintIoResReqList(*RequirementsList
);
624 /* There aren't any resources, so simply return NULL */
625 DPRINT1("PciQueryRequirements returning NULL requirements list\n");
626 *RequirementsList
= NULL
;
629 /* This call always succeeds (but maybe with no requirements) */
630 return STATUS_SUCCESS
;
634 * 7. The IO/MEM/Busmaster decodes are disabled for the device.
635 * 8. The PCI bus driver sets the operating mode bits of the Programming
636 * Interface byte to switch the controller to native mode.
638 * Important: When the controller is set to native mode, it must quiet itself
639 * and must not decode I/O resources or generate interrupts until the operating
640 * system has enabled the ports in the PCI configuration header.
641 * The IO/MEM/BusMaster bits will be disabled before the mode change, but it
642 * is not possible to disable interrupts on the device. The device must not
643 * generate interrupts (either legacy or native mode) while the decodes are
644 * disabled in the command register.
646 * This operation is expected to be instantaneous and the operating system does
647 * not stall afterward. It is also expected that the interrupt pin register in
648 * the PCI Configuration space for this device is accurate. The operating system
649 * re-reads this data after previously ignoring it.
653 PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension
,
654 IN PPCI_COMMON_HEADER PciData
,
657 UCHAR MasterMode
, SlaveMode
, MasterFixed
, SlaveFixed
, ProgIf
, NewProgIf
;
661 /* Assume it won't work */
664 /* Get master and slave current settings, and programmability flag */
665 ProgIf
= PciData
->ProgIf
;
666 MasterMode
= (ProgIf
& 1) == 1;
667 MasterFixed
= (ProgIf
& 2) == 0;
668 SlaveMode
= (ProgIf
& 4) == 4;
669 SlaveFixed
= (ProgIf
& 8) == 0;
672 * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
673 * ATA controller from compatible mode to native mode, the following must be
676 * - The controller must indicate in its programming interface that both channels
677 * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
678 * not support switching only one IDE channel to native mode. See the PCI IDE
679 * Controller Specification Revision 1.0 for details.
681 if ((MasterMode
!= SlaveMode
) || (MasterFixed
!= SlaveFixed
))
683 /* Windows does not support this configuration, fail */
684 DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
685 PdoExtension
->VendorId
,
686 PdoExtension
->DeviceId
);
690 /* Check if the controller is already in native mode */
691 if ((MasterMode
) && (SlaveMode
))
693 /* Check if I/O decodes should be disabled */
694 if ((Initial
) || (PdoExtension
->IoSpaceUnderNativeIdeControl
))
696 /* Read the current command */
697 PciReadDeviceConfig(PdoExtension
,
699 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
702 /* Disable I/O space decode */
703 Command
&= ~PCI_ENABLE_IO_SPACE
;
705 /* Update new command in PCI IDE controller */
706 PciWriteDeviceConfig(PdoExtension
,
708 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
711 /* Save updated command value */
712 PciData
->Command
= Command
;
715 /* The controller is now in native mode */
718 else if (!(MasterFixed
) &&
720 (PdoExtension
->BIOSAllowsIDESwitchToNativeMode
) &&
721 !(PdoExtension
->HackFlags
& PCI_HACK_DISABLE_IDE_NATIVE_MODE
))
723 /* Turn off decodes */
724 PciDecodeEnable(PdoExtension
, FALSE
, NULL
);
726 /* Update the current command */
727 PciReadDeviceConfig(PdoExtension
,
729 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
732 /* Enable native mode */
733 ProgIf
= PciData
->ProgIf
| 5;
734 PciWriteDeviceConfig(PdoExtension
,
736 FIELD_OFFSET(PCI_COMMON_HEADER
, ProgIf
),
739 /* Verify the setting "stuck" */
740 PciReadDeviceConfig(PdoExtension
,
742 FIELD_OFFSET(PCI_COMMON_HEADER
, ProgIf
),
744 if (NewProgIf
== ProgIf
)
746 /* Update the header and PDO data with the new programming mode */
747 PciData
->ProgIf
= ProgIf
;
748 PdoExtension
->ProgIf
= NewProgIf
;
750 /* Clear the first four BARs to reset current BAR setttings */
751 PciData
->u
.type0
.BaseAddresses
[0] = 0;
752 PciData
->u
.type0
.BaseAddresses
[1] = 0;
753 PciData
->u
.type0
.BaseAddresses
[2] = 0;
754 PciData
->u
.type0
.BaseAddresses
[3] = 0;
755 PciWriteDeviceConfig(PdoExtension
,
756 PciData
->u
.type0
.BaseAddresses
,
757 FIELD_OFFSET(PCI_COMMON_HEADER
,
758 u
.type0
.BaseAddresses
),
761 /* Re-read the BARs to have the latest data for native mode IDE */
762 PciReadDeviceConfig(PdoExtension
,
763 PciData
->u
.type0
.BaseAddresses
,
764 FIELD_OFFSET(PCI_COMMON_HEADER
,
765 u
.type0
.BaseAddresses
),
768 /* Re-read the interrupt pin used for native mode IDE */
769 PciReadDeviceConfig(PdoExtension
,
770 &PciData
->u
.type0
.InterruptPin
,
771 FIELD_OFFSET(PCI_COMMON_HEADER
,
772 u
.type0
.InterruptPin
),
775 /* The IDE Controller is now in native mode */
780 /* Settings did not work, fail */
781 DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
787 /* Return whether or not native mode was enabled on the IDE controller */
793 PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension
,
794 IN PPCI_COMMON_HEADER PciData
,
795 IN PCI_SLOT_NUMBER SlotNumber
,
796 IN ULONG OperationType
,
797 PPCI_PDO_EXTENSION PdoExtension
)
799 ULONG LegacyBaseAddress
;
803 UNREFERENCED_PARAMETER(SlotNumber
);
805 /* Check what kind of hack operation this is */
806 switch (OperationType
)
809 * This is mostly concerned with fixing up incorrect class data that can
810 * exist on certain PCI hardware before the 2.0 spec was ratified.
812 case PCI_HACK_FIXUP_BEFORE_CONFIGURATION
:
814 /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
815 * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
816 * and appear as non-classified, so their correct class/subclass data
817 * is written here instead.
819 if ((PciData
->VendorID
== 0x8086) &&
820 ((PciData
->DeviceID
== 0x482) || (PciData
->DeviceID
== 0x484)))
822 /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
823 PciData
->SubClass
= PciData
->DeviceID
== 0x482 ?
824 PCI_SUBCLASS_BR_EISA
: PCI_SUBCLASS_BR_ISA
;
825 PciData
->BaseClass
= PCI_CLASS_BRIDGE_DEV
;
828 * Because the software is modifying the actual header data from
829 * the BIOS, this flag tells the driver to ignore failures when
830 * comparing the original BIOS data with the PCI data.
832 if (PdoExtension
) PdoExtension
->ExpectedWritebackFailure
= TRUE
;
835 /* Note that in this case, an immediate return is issued */
839 * This is concerned with setting up interrupts correctly for native IDE
840 * mode, but will also handle broken VGA decoding on older bridges as
841 * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
843 case PCI_HACK_FIXUP_AFTER_CONFIGURATION
:
845 /* There should always be a PDO extension passed in */
846 ASSERT(PdoExtension
);
849 * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
850 * and FreeBSD bug reports indicate that the system crashes when the
851 * feature is enabled (so it's disabled on that OS as well). In the
852 * NT PCI Bus Driver, it seems Microsoft too, completely disables
853 * Native IDE functionality on this controller, so it would seem OPTi
854 * simply frelled up this controller.
856 if ((PciData
->VendorID
== 0x1045) && (PciData
->DeviceID
!= 0xC621))
858 /* Disable native mode */
859 PciData
->ProgIf
&= ~5;
860 PciData
->u
.type0
.InterruptPin
= 0;
863 * Because the software is modifying the actual header data from
864 * the BIOS, this flag tells the driver to ignore failures when
865 * comparing the original BIOS data with the PCI data.
867 PdoExtension
->ExpectedWritebackFailure
= TRUE
;
869 else if ((PciData
->BaseClass
== PCI_CLASS_MASS_STORAGE_CTLR
) &&
870 (PciData
->SubClass
== PCI_SUBCLASS_MSC_IDE_CTLR
))
872 /* For other IDE controllers, start out in compatible mode */
873 PdoExtension
->BIOSAllowsIDESwitchToNativeMode
= FALSE
;
876 * Registry must have enabled native mode (typically as a result
877 * of an INF file directive part of the IDE controller's driver)
878 * and the system must not be booted in Safe Mode. If that checks
879 * out, then evaluate the ACPI NATA method to see if the platform
880 * supports this. See the section "BIOS and Platform Prerequisites
881 * for Switching a Native-Mode-Capable Controller" in the Storage
882 * section of the Windows Driver Kit for more details:
884 * 5. For each ATA controller enumerated, the PCI bus driver checks
885 * the Programming Interface register of the IDE controller to
886 * see if it supports switching both channels to native mode.
887 * 6. The PCI bus driver checks whether the BIOS/platform supports
888 * switching the controller by checking the NATA method described
889 * earlier in this article.
891 * If an ATA controller does not indicate that it is native
892 * mode-capable, or if the BIOS NATA control method is missing
893 * or does not list that device, the PCI bus driver does not
894 * switch the controller and it is assigned legacy resources.
896 * If both the controller and the BIOS indicate that the controller
897 * can be switched, the process of switching the controller begins
898 * with the next step.
900 if ((PciEnableNativeModeATA
) &&
901 !(InitSafeBootMode
) &&
902 (PciIsSlotPresentInParentMethod(PdoExtension
, 'ATAN')))
904 /* The platform supports it, remember that */
905 PdoExtension
->BIOSAllowsIDESwitchToNativeMode
= TRUE
;
908 * Now switch the controller into native mode if both channels
909 * support native IDE mode. See "How Windows Switches an ATA
910 * Controller to Native Mode" in the Storage section of the
911 * Windows Driver Kit for more details.
913 PdoExtension
->IDEInNativeMode
=
914 PciConfigureIdeController(PdoExtension
, PciData
, TRUE
);
917 /* Is native mode enabled after all? */
918 if ((PciData
->ProgIf
& 5) != 5)
920 /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
921 PciData
->u
.type0
.InterruptPin
= 0;
925 /* Is this a PCI device with legacy VGA card decodes on the root bus? */
926 if ((PdoExtension
->HackFlags
& PCI_HACK_VIDEO_LEGACY_DECODE
) &&
927 (PCI_IS_ROOT_FDO(DeviceExtension
)) &&
928 !(DeviceExtension
->BrokenVideoHackApplied
))
930 /* Tell the arbiter to apply a hack for these older devices */
931 ario_ApplyBrokenVideoHack(DeviceExtension
);
934 /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
935 if ((PciData
->VendorID
== 0xE11) &&
936 (PciData
->DeviceID
== 0xA0F7) &&
937 (PciData
->RevisionID
== 17) &&
938 (ExIsProcessorFeaturePresent(PF_PAE_ENABLED
)))
940 /* Turn off the decodes immediately */
941 PciData
->Command
&= ~(PCI_ENABLE_IO_SPACE
|
942 PCI_ENABLE_MEMORY_SPACE
|
943 PCI_ENABLE_BUS_MASTER
);
944 PciWriteDeviceConfig(PdoExtension
,
946 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
949 /* Do not EVER turn them on again, this will blow up the system */
950 PdoExtension
->CommandEnables
&= ~(PCI_ENABLE_IO_SPACE
|
951 PCI_ENABLE_MEMORY_SPACE
|
952 PCI_ENABLE_BUS_MASTER
);
953 PdoExtension
->HackFlags
|= PCI_HACK_PRESERVE_COMMAND
;
958 * This is called whenever resources are changed and hardware needs to be
959 * updated. It is concerned with two highly specific erratas on an IBM
960 * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
963 case PCI_HACK_FIXUP_BEFORE_UPDATE
:
965 /* There should always be a PDO extension passed in */
966 ASSERT(PdoExtension
);
968 /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
969 if ((PdoExtension
->VendorId
== 0x1014) &&
970 (PdoExtension
->DeviceId
== 0x95))
972 /* Read the current command */
973 PciReadDeviceConfig(PdoExtension
,
975 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
978 /* Turn off the decodes */
979 PciDecodeEnable(PdoExtension
, FALSE
, &Command
);
981 /* Apply the required IBM workaround */
982 PciReadDeviceConfig(PdoExtension
, &RegValue
, 0xE0, sizeof(UCHAR
));
985 PciWriteDeviceConfig(PdoExtension
, &RegValue
, 0xE0, sizeof(UCHAR
));
987 /* Restore the command to its original value */
988 PciWriteDeviceConfig(PdoExtension
,
990 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
996 * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
997 * i820, i840, i845 Chipsets) that have subtractive decode enabled,
998 * and whose hack flags do not specifiy that this support is broken.
1000 if ((PdoExtension
->HeaderType
== PCI_BRIDGE_TYPE
) &&
1001 (PdoExtension
->Dependent
.type1
.SubtractiveDecode
) &&
1002 ((PdoExtension
->VendorId
== 0x8086) &&
1003 ((PdoExtension
->DeviceId
== 0x2418) ||
1004 (PdoExtension
->DeviceId
== 0x2428) ||
1005 (PdoExtension
->DeviceId
== 0x244E) ||
1006 (PdoExtension
->DeviceId
== 0x2448))) &&
1007 !(PdoExtension
->HackFlags
& PCI_HACK_BROKEN_SUBTRACTIVE_DECODE
))
1010 * The positive decode window shouldn't be used, these values are
1011 * normally all read-only or initialized to 0 by the BIOS, but
1012 * it appears Intel doesn't do this, so the PCI Bus Driver will
1013 * do it in software instead. Note that this is used to prevent
1014 * certain non-compliant PCI devices from breaking down due to the
1015 * fact that these ICH bridges have a known "quirk" (which Intel
1016 * documents as a known "erratum", although it's not not really
1017 * an ICH bug since the PCI specification does allow for it) in
1018 * that they will sometimes send non-zero addresses during special
1019 * cycles (ie: non-zero data during the address phase). These
1020 * broken PCI cards will mistakenly attempt to claim the special
1021 * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
1022 * defense, the PCI specification only requires stable data, not
1023 * necessarily zero data, during the address phase.
1025 PciData
->u
.type1
.MemoryBase
= 0xFFFF;
1026 PciData
->u
.type1
.PrefetchBase
= 0xFFFF;
1027 PciData
->u
.type1
.IOBase
= 0xFF;
1028 PciData
->u
.type1
.IOLimit
= 0;
1029 PciData
->u
.type1
.MemoryLimit
= 0;
1030 PciData
->u
.type1
.PrefetchLimit
= 0;
1031 PciData
->u
.type1
.PrefetchBaseUpper32
= 0;
1032 PciData
->u
.type1
.PrefetchLimitUpper32
= 0;
1033 PciData
->u
.type1
.IOBaseUpper16
= 0;
1034 PciData
->u
.type1
.IOLimitUpper16
= 0;
1042 /* Finally, also check if this is this a CardBUS device? */
1043 if (PCI_CONFIGURATION_TYPE(PciData
) == PCI_CARDBUS_BRIDGE_TYPE
)
1046 * At offset 44h the LegacyBaseAddress is stored, which is cleared by
1047 * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
1048 * CardBus controllers. For more information, see "Supporting CardBus
1049 * Controllers under ACPI" in the "CardBus Controllers and Windows"
1050 * Whitepaper on WHDC.
1052 LegacyBaseAddress
= 0;
1053 PciWriteDeviceConfig(PdoExtension
,
1055 sizeof(PCI_COMMON_HEADER
) + sizeof(ULONG
),
1062 PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension
,
1063 IN PPCI_COMMON_HEADER PciData
)
1065 BOOLEAN IdMatch
, RevMatch
, SubsysMatch
;
1066 ULONGLONG HackFlags
= DeviceExtension
->HackFlags
;
1068 /* Check if the IDs match */
1069 IdMatch
= (PciData
->VendorID
== DeviceExtension
->VendorId
) &&
1070 (PciData
->DeviceID
== DeviceExtension
->DeviceId
);
1071 if (!IdMatch
) return FALSE
;
1073 /* If the device has a valid revision, check if it matches */
1074 RevMatch
= (HackFlags
& PCI_HACK_NO_REVISION_AFTER_D3
) ||
1075 (PciData
->RevisionID
== DeviceExtension
->RevisionId
);
1076 if (!RevMatch
) return FALSE
;
1078 /* For multifunction devices, this is enough to assume they're the same */
1079 if (PCI_MULTIFUNCTION_DEVICE(PciData
)) return TRUE
;
1081 /* For bridge devices, there's also nothing else that can be checked */
1082 if (DeviceExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) return TRUE
;
1084 /* Devices, on the other hand, have subsystem data that can be compared */
1085 SubsysMatch
= (HackFlags
& (PCI_HACK_NO_SUBSYSTEM
|
1086 PCI_HACK_NO_SUBSYSTEM_AFTER_D3
)) ||
1087 ((DeviceExtension
->SubsystemVendorId
==
1088 PciData
->u
.type0
.SubVendorID
) &&
1089 (DeviceExtension
->SubsystemId
==
1090 PciData
->u
.type0
.SubSystemID
));
1096 PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData
,
1097 IN PCI_SLOT_NUMBER Slot
,
1098 IN UCHAR OperationType
,
1099 IN ULONGLONG HackFlags
)
1103 /* Check if this is device enumeration */
1104 if (OperationType
== PCI_SKIP_DEVICE_ENUMERATION
)
1106 /* Check if there's a hackflag saying not to enumerate this device */
1107 if (HackFlags
& PCI_HACK_NO_ENUM_AT_ALL
) break;
1109 /* Check if this is the high end of a double decker device */
1110 if ((HackFlags
& PCI_HACK_DOUBLE_DECKER
) &&
1111 (Slot
.u
.bits
.DeviceNumber
>= 16))
1113 /* It belongs to the same device, so skip it */
1114 DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
1117 Slot
.u
.bits
.DeviceNumber
,
1118 Slot
.u
.bits
.FunctionNumber
);
1122 else if (OperationType
== PCI_SKIP_RESOURCE_ENUMERATION
)
1124 /* Resource enumeration, check for a hackflag saying not to do it */
1125 if (HackFlags
& PCI_HACK_ENUM_NO_RESOURCE
) break;
1129 /* Logic error in the driver */
1130 ASSERTMSG(FALSE
, "PCI Skip Function - Operation type unknown.");
1133 /* Check for legacy bridges during resource enumeration */
1134 if ((PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1135 (PciData
->SubClass
<= PCI_SUBCLASS_BR_MCA
) &&
1136 (OperationType
== PCI_SKIP_RESOURCE_ENUMERATION
))
1138 /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
1141 else if (PciData
->BaseClass
== PCI_CLASS_NOT_DEFINED
)
1143 /* Undefined base class (usually a PCI BIOS/ROM bug) */
1144 DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
1149 * The Alder has an Intel Extended Express System Support Controller
1150 * which presents apparently spurious BARs. When the PCI resource
1151 * code tries to reassign these BARs, the second IO-APIC gets
1152 * disabled (with disastrous consequences). The first BAR is the
1153 * actual IO-APIC, the remaining five bars seem to be spurious
1154 * resources, so ignore this device completely.
1156 if ((PciData
->VendorID
== 0x8086) && (PciData
->DeviceID
== 8)) break;
1159 /* Other normal PCI cards and bridges are enumerated */
1160 if (PCI_CONFIGURATION_TYPE(PciData
) <= PCI_CARDBUS_BRIDGE_TYPE
) return FALSE
;
1163 /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
1164 DPRINT1(" Device skipped (not enumerated).\n");
1170 PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension
,
1171 IN PPCI_COMMON_HEADER PciData
)
1173 ULONG HeaderType
, CapPtr
, TargetAgpCapabilityId
;
1174 DEVICE_POWER_STATE WakeLevel
;
1175 PCI_CAPABILITIES_HEADER AgpCapability
;
1176 PCI_PM_CAPABILITY PowerCapabilities
;
1179 /* Assume no known wake level */
1180 PdoExtension
->PowerState
.DeviceWakeLevel
= PowerDeviceUnspecified
;
1182 /* Make sure the device has capabilities */
1183 if (!(PciData
->Status
& PCI_STATUS_CAPABILITIES_LIST
))
1185 /* If it doesn't, there will be no power management */
1186 PdoExtension
->CapabilitiesPtr
= 0;
1187 PdoExtension
->HackFlags
|= PCI_HACK_NO_PM_CAPS
;
1191 /* There's capabilities, need to figure out where to get the offset */
1192 HeaderType
= PCI_CONFIGURATION_TYPE(PciData
);
1193 if (HeaderType
== PCI_CARDBUS_BRIDGE_TYPE
)
1195 /* Use the bridge's header */
1196 CapPtr
= PciData
->u
.type2
.CapabilitiesPtr
;
1200 /* Use the device header */
1201 ASSERT(HeaderType
<= PCI_CARDBUS_BRIDGE_TYPE
);
1202 CapPtr
= PciData
->u
.type0
.CapabilitiesPtr
;
1205 /* Skip garbage capabilities pointer */
1206 if (((CapPtr
& 0x3) != 0) || (CapPtr
< PCI_COMMON_HDR_LENGTH
))
1208 /* Report no extended capabilities */
1209 PdoExtension
->CapabilitiesPtr
= 0;
1210 PdoExtension
->HackFlags
|= PCI_HACK_NO_PM_CAPS
;
1214 DPRINT1("Device has capabilities at: %lx\n", CapPtr
);
1215 PdoExtension
->CapabilitiesPtr
= CapPtr
;
1217 /* Check for PCI-to-PCI Bridges and AGP bridges */
1218 if ((PdoExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1219 ((PdoExtension
->SubClass
== PCI_SUBCLASS_BR_HOST
) ||
1220 (PdoExtension
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
)))
1222 /* Query either the raw AGP capabilitity, or the Target AGP one */
1223 TargetAgpCapabilityId
= (PdoExtension
->SubClass
==
1224 PCI_SUBCLASS_BR_PCI_TO_PCI
) ?
1225 PCI_CAPABILITY_ID_AGP_TARGET
:
1226 PCI_CAPABILITY_ID_AGP
;
1227 if (PciReadDeviceCapability(PdoExtension
,
1228 PdoExtension
->CapabilitiesPtr
,
1229 TargetAgpCapabilityId
,
1231 sizeof(PCI_CAPABILITIES_HEADER
)))
1233 /* AGP target ID was found, store it */
1234 DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId
);
1235 PdoExtension
->TargetAgpCapabilityId
= TargetAgpCapabilityId
;
1239 /* Check for devices that are known not to have proper power management */
1240 if (!(PdoExtension
->HackFlags
& PCI_HACK_NO_PM_CAPS
))
1242 /* Query if this device supports power management */
1243 if (!PciReadDeviceCapability(PdoExtension
,
1244 PdoExtension
->CapabilitiesPtr
,
1245 PCI_CAPABILITY_ID_POWER_MANAGEMENT
,
1246 &PowerCapabilities
.Header
,
1247 sizeof(PCI_PM_CAPABILITY
)))
1249 /* No power management, so act as if it had the hackflag set */
1250 DPRINT1("No PM caps, disabling PM\n");
1251 PdoExtension
->HackFlags
|= PCI_HACK_NO_PM_CAPS
;
1255 /* Otherwise, pick the highest wake level that is supported */
1256 WakeLevel
= PowerDeviceUnspecified
;
1257 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED0
)
1258 WakeLevel
= PowerDeviceD0
;
1259 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED1
)
1260 WakeLevel
= PowerDeviceD1
;
1261 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED2
)
1262 WakeLevel
= PowerDeviceD2
;
1263 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED3Hot
)
1264 WakeLevel
= PowerDeviceD3
;
1265 if (PowerCapabilities
.PMC
.Capabilities
.Support
.PMED3Cold
)
1266 WakeLevel
= PowerDeviceD3
;
1267 PdoExtension
->PowerState
.DeviceWakeLevel
= WakeLevel
;
1269 /* Convert the PCI power state to the NT power state */
1270 PdoExtension
->PowerState
.CurrentDeviceState
=
1271 PowerCapabilities
.PMCSR
.ControlStatus
.PowerState
+ 1;
1273 /* Save all the power capabilities */
1274 PdoExtension
->PowerCapabilities
= PowerCapabilities
.PMC
.Capabilities
;
1275 DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
1276 WakeLevel
, PdoExtension
->PowerState
.CurrentDeviceState
);
1282 /* At the very end of all this, does this device not have power management? */
1283 if (PdoExtension
->HackFlags
& PCI_HACK_NO_PM_CAPS
)
1285 /* Then guess the current state based on whether the decodes are on */
1286 PdoExtension
->PowerState
.CurrentDeviceState
=
1287 PciData
->Command
& (PCI_ENABLE_IO_SPACE
|
1288 PCI_ENABLE_MEMORY_SPACE
|
1289 PCI_ENABLE_BUS_MASTER
) ?
1290 PowerDeviceD0
: PowerDeviceD3
;
1291 DPRINT1("PM is off, so assumed device is: %d based on enables\n",
1292 PdoExtension
->PowerState
.CurrentDeviceState
);
1298 PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved
,
1301 PPCI_CONFIGURATOR_CONTEXT Context
= Context2
;
1302 PPCI_COMMON_HEADER PciData
, Current
;
1303 PPCI_PDO_EXTENSION PdoExtension
;
1305 UNREFERENCED_PARAMETER(Reserved
);
1307 /* Grab all parameters from the context */
1308 PdoExtension
= Context
->PdoExtension
;
1309 Current
= Context
->Current
;
1310 PciData
= Context
->PciData
;
1312 /* Write the limit discovery header */
1313 PciWriteDeviceConfig(PdoExtension
, PciData
, 0, PCI_COMMON_HDR_LENGTH
);
1315 /* Now read what the device indicated the limits are */
1316 PciReadDeviceConfig(PdoExtension
, PciData
, 0, PCI_COMMON_HDR_LENGTH
);
1318 /* Then write back the original configuration header */
1319 PciWriteDeviceConfig(PdoExtension
, Current
, 0, PCI_COMMON_HDR_LENGTH
);
1321 /* Copy back the original command that was saved in the context */
1322 Current
->Command
= Context
->Command
;
1323 if (Context
->Command
)
1325 /* Program it back into the device */
1326 PciWriteDeviceConfig(PdoExtension
,
1328 FIELD_OFFSET(PCI_COMMON_HEADER
, Command
),
1332 /* Copy back the original status that was saved as well */
1333 Current
->Status
= Context
->Status
;
1335 /* Call the configurator to restore any other data that might've changed */
1336 Context
->Configurator
->RestoreCurrent(Context
);
1341 PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context
)
1343 PPCI_CONFIGURATOR Configurator
;
1344 PPCI_COMMON_HEADER PciData
, Current
;
1345 PPCI_PDO_EXTENSION PdoExtension
;
1346 PCI_IPI_CONTEXT IpiContext
;
1347 PIO_RESOURCE_DESCRIPTOR IoDescriptor
;
1351 /* Grab all parameters from the context */
1352 PdoExtension
= Context
->PdoExtension
;
1353 Current
= Context
->Current
;
1354 PciData
= Context
->PciData
;
1356 /* Save the current PCI Command and Status word */
1357 Context
->Status
= Current
->Status
;
1358 Context
->Command
= Current
->Command
;
1360 /* Now that they're saved, clear the status, and disable all decodes */
1361 Current
->Status
= 0;
1362 Current
->Command
&= ~(PCI_ENABLE_IO_SPACE
|
1363 PCI_ENABLE_MEMORY_SPACE
|
1364 PCI_ENABLE_BUS_MASTER
);
1366 /* Make a copy of the current PCI configuration header (with decodes off) */
1367 RtlCopyMemory(PciData
, Current
, PCI_COMMON_HDR_LENGTH
);
1369 /* Locate the correct resource configurator for this type of device */
1370 Configurator
= &PciConfigurators
[PdoExtension
->HeaderType
];
1371 Context
->Configurator
= Configurator
;
1373 /* Initialize it, which will typically setup the BARs for limit discovery */
1374 Configurator
->Initialize(Context
);
1376 /* Check for critical devices and PCI Debugging devices */
1377 if ((PdoExtension
->HackFlags
& PCI_HACK_CRITICAL_DEVICE
) ||
1378 (PdoExtension
->OnDebugPath
))
1380 /* Specifically check for a PCI Debugging device */
1381 if (PdoExtension
->OnDebugPath
)
1383 /* Was it enabled for bus mastering? */
1384 if (Context
->Command
& PCI_ENABLE_BUS_MASTER
)
1386 /* This decode needs to be re-enabled so debugging can work */
1387 PciData
->Command
|= PCI_ENABLE_BUS_MASTER
;
1388 Current
->Command
|= PCI_ENABLE_BUS_MASTER
;
1391 /* Disable the debugger while the discovery is happening */
1392 KdDisableDebugger();
1395 /* For these devices, an IPI must be sent to force high-IRQL discovery */
1396 IpiContext
.Barrier
= 1;
1397 IpiContext
.RunCount
= 1;
1398 IpiContext
.DeviceExtension
= PdoExtension
;
1399 IpiContext
.Function
= PciWriteLimitsAndRestoreCurrent
;
1400 IpiContext
.Context
= Context
;
1401 KeIpiGenericCall(PciExecuteCriticalSystemRoutine
, (ULONG_PTR
)&IpiContext
);
1403 /* Re-enable the debugger if this was a PCI Debugging Device */
1404 if (PdoExtension
->OnDebugPath
) KdEnableDebugger();
1408 /* Otherwise, it's safe to do this in-line at low IRQL */
1409 PciWriteLimitsAndRestoreCurrent(PdoExtension
, Context
);
1413 * Check if it's valid to compare the headers to see if limit discovery mode
1414 * has properly exited (the expected case is that the PCI header would now
1415 * be equal to what it was before). In some cases, it is known that this will
1416 * fail, because during PciApplyHacks (among other places), software hacks
1417 * had to be applied to the header, which the hardware-side will not see, and
1418 * thus the headers would appear "different".
1420 if (!PdoExtension
->ExpectedWritebackFailure
)
1422 /* Read the current PCI header now, after discovery has completed */
1423 PciReadDeviceConfig(PdoExtension
, PciData
+ 1, 0, PCI_COMMON_HDR_LENGTH
);
1425 /* Check if the current header at entry, is equal to the header now */
1426 Offset
= RtlCompareMemory(PciData
+ 1, Current
, PCI_COMMON_HDR_LENGTH
);
1427 if (Offset
!= PCI_COMMON_HDR_LENGTH
)
1429 /* It's not, which means configuration somehow changed, dump this */
1430 DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset
);
1431 PciDebugDumpCommonConfig(PciData
+ 1);
1432 DPRINT1("----------\n");
1433 PciDebugDumpCommonConfig(Current
);
1437 /* This PDO should not already have resources, since this is only done once */
1438 ASSERT(PdoExtension
->Resources
== NULL
);
1440 /* Allocate the structure that will hold the discovered resources and limits */
1441 PdoExtension
->Resources
= ExAllocatePoolWithTag(NonPagedPool
,
1442 sizeof(PCI_FUNCTION_RESOURCES
),
1444 if (!PdoExtension
->Resources
) return STATUS_INSUFFICIENT_RESOURCES
;
1446 /* Clear it out for now */
1447 RtlZeroMemory(PdoExtension
->Resources
, sizeof(PCI_FUNCTION_RESOURCES
));
1449 /* Now call the configurator, which will first store the limits... */
1450 Configurator
->SaveLimits(Context
);
1452 /* ...and then store the current resources being used */
1453 Configurator
->SaveCurrentSettings(Context
);
1455 /* Loop all the limit descriptors backwards */
1456 IoDescriptor
= &PdoExtension
->Resources
->Limit
[PCI_TYPE0_ADDRESSES
+ 1];
1459 /* Keep going until a non-null descriptor is found */
1461 if (IoDescriptor
->Type
!= CmResourceTypeNull
) break;
1463 /* This is a null descriptor, is it the last one? */
1464 if (IoDescriptor
== &PdoExtension
->Resources
->Limit
[PCI_TYPE0_ADDRESSES
+ 1])
1466 /* This means the descriptor is NULL, which means discovery failed */
1467 DPRINT1("PCI Resources fail!\n");
1469 /* No resources will be assigned for the device */
1470 ExFreePoolWithTag(PdoExtension
->Resources
, 0);
1471 PdoExtension
->Resources
= NULL
;
1476 /* Return success here, even if the device has no assigned resources */
1477 return STATUS_SUCCESS
;
1482 PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension
,
1483 IN PPCI_COMMON_HEADER Current
,
1484 IN ULONGLONG HackFlags
)
1487 PPCI_COMMON_HEADER PciData
;
1488 PCI_CONFIGURATOR_CONTEXT Context
;
1491 /* Do the hackflags indicate this device should be skipped? */
1492 if (PciSkipThisFunction(Current
,
1494 PCI_SKIP_RESOURCE_ENUMERATION
,
1497 /* Do not process its resources */
1498 return STATUS_SUCCESS
;
1501 /* Allocate a buffer to hold two PCI configuration headers */
1502 PciData
= ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH
, 'BicP');
1503 if (!PciData
) return STATUS_INSUFFICIENT_RESOURCES
;
1505 /* Set up the context for the resource enumeration, and do it */
1506 Context
.Current
= Current
;
1507 Context
.PciData
= PciData
;
1508 Context
.PdoExtension
= PdoExtension
;
1509 Status
= PcipGetFunctionLimits(&Context
);
1511 /* Enumeration is completed, free the PCI headers and return the status */
1512 ExFreePoolWithTag(PciData
, 0);
1518 PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension
)
1520 PPCI_PDO_EXTENSION PdoExtension
;
1521 PDEVICE_OBJECT PhysicalDeviceObject
;
1524 /* Get the PDO Extension */
1525 PhysicalDeviceObject
= DeviceExtension
->PhysicalDeviceObject
;
1526 PdoExtension
= (PPCI_PDO_EXTENSION
)PhysicalDeviceObject
->DeviceExtension
;
1528 /* Cheeck if this is the root bus */
1529 if (!PCI_IS_ROOT_FDO(DeviceExtension
))
1531 /* Not really handling this year */
1532 UNIMPLEMENTED_DBGBREAK();
1534 /* Check for PCI bridges with the ISA bit set, or required */
1535 if ((PdoExtension
) &&
1536 (PciClassifyDeviceType(PdoExtension
) == PciTypePciBridge
) &&
1537 ((PdoExtension
->Dependent
.type1
.IsaBitRequired
) ||
1538 (PdoExtension
->Dependent
.type1
.IsaBitSet
)))
1540 /* We'll need to do some legacy support */
1541 UNIMPLEMENTED_DBGBREAK();
1546 /* Scan all of the root bus' children bridges */
1547 for (PdoExtension
= DeviceExtension
->ChildBridgePdoList
;
1549 PdoExtension
= PdoExtension
->NextBridge
)
1551 /* Find any that have the VGA decode bit on */
1552 if (PdoExtension
->Dependent
.type1
.VgaBitSet
)
1554 /* Again, some more legacy support we'll have to do */
1555 UNIMPLEMENTED_DBGBREAK();
1560 /* Check for ACPI systems where the OS assigns bus numbers */
1561 if (PciAssignBusNumbers
)
1563 /* Not yet supported */
1564 UNIMPLEMENTED_DBGBREAK();
1570 PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension
)
1572 ULONG MaxDevice
= PCI_MAX_DEVICES
;
1573 BOOLEAN ProcessFlag
= FALSE
;
1574 ULONG i
, j
, k
, Size
;
1575 USHORT CapOffset
, TempOffset
;
1577 PDEVICE_OBJECT DeviceObject
;
1578 UCHAR Buffer
[PCI_COMMON_HDR_LENGTH
];
1579 UCHAR BiosBuffer
[PCI_COMMON_HDR_LENGTH
];
1580 PPCI_COMMON_HEADER PciData
= (PVOID
)Buffer
;
1581 PPCI_COMMON_HEADER BiosData
= (PVOID
)BiosBuffer
;
1582 PCI_SLOT_NUMBER PciSlot
;
1585 PPCI_PDO_EXTENSION PdoExtension
, NewExtension
;
1586 PPCI_PDO_EXTENSION
* BridgeExtension
;
1587 PWCHAR DescriptionText
;
1588 USHORT SubVendorId
, SubSystemId
;
1589 PCI_CAPABILITIES_HEADER CapHeader
, PcixCapHeader
;
1591 DPRINT1("PCI Scan Bus: FDO Extension @ 0x%p, Base Bus = 0x%x\n",
1592 DeviceExtension
, DeviceExtension
->BaseBus
);
1594 /* Is this the root FDO? */
1595 if (!PCI_IS_ROOT_FDO(DeviceExtension
))
1597 /* Get the PDO for the child bus */
1598 PdoExtension
= DeviceExtension
->PhysicalDeviceObject
->DeviceExtension
;
1599 ASSERT_PDO(PdoExtension
);
1601 /* Check for hack which only allows bus to have one child device */
1602 if (PdoExtension
->HackFlags
& PCI_HACK_ONE_CHILD
) MaxDevice
= 1;
1604 /* Check if the secondary bus number has changed */
1605 PciReadDeviceConfig(PdoExtension
,
1607 FIELD_OFFSET(PCI_COMMON_HEADER
, u
.type1
.SecondaryBus
),
1609 if (SecondaryBus
!= PdoExtension
->Dependent
.type1
.SecondaryBus
)
1611 UNIMPLEMENTED_DBGBREAK("PCI: Bus numbers have been changed! Restoring originals.\n");
1615 /* Loop every device on the bus */
1616 PciSlot
.u
.bits
.Reserved
= 0;
1617 i
= DeviceExtension
->BaseBus
;
1618 for (j
= 0; j
< MaxDevice
; j
++)
1620 /* Loop every function of each device */
1621 PciSlot
.u
.bits
.DeviceNumber
= j
;
1622 for (k
= 0; k
< PCI_MAX_FUNCTION
; k
++)
1624 /* Build the final slot structure */
1625 PciSlot
.u
.bits
.FunctionNumber
= k
;
1627 /* Read the vendor for this slot */
1628 PciReadSlotConfig(DeviceExtension
,
1634 /* Skip invalid device */
1635 if (PciData
->VendorID
== PCI_INVALID_VENDORID
) continue;
1637 /* Now read the whole header */
1638 PciReadSlotConfig(DeviceExtension
,
1642 PCI_COMMON_HDR_LENGTH
- sizeof(USHORT
));
1644 /* Apply any hacks before even analyzing the configuration header */
1645 PciApplyHacks(DeviceExtension
,
1648 PCI_HACK_FIXUP_BEFORE_CONFIGURATION
,
1651 /* Dump device that was found */
1652 DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
1658 /* Dump the device's header */
1659 PciDebugDumpCommonConfig(PciData
);
1661 /* Find description for this device for the debugger's sake */
1662 DescriptionText
= PciGetDeviceDescriptionMessage(PciData
->BaseClass
,
1664 DPRINT1("Device Description \"%S\".\n",
1665 DescriptionText
? DescriptionText
: L
"(NULL)");
1666 if (DescriptionText
) ExFreePoolWithTag(DescriptionText
, 0);
1668 /* Check if there is an ACPI Watchdog Table */
1671 /* Check if this PCI device is the ACPI Watchdog Device... */
1672 UNIMPLEMENTED_DBGBREAK();
1675 /* Check for non-simple devices */
1676 if ((PCI_MULTIFUNCTION_DEVICE(PciData
)) ||
1677 (PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
))
1679 /* No subsystem data defined for these kinds of bridges */
1685 /* Read the subsystem information from the PCI header */
1686 SubVendorId
= PciData
->u
.type0
.SubVendorID
;
1687 SubSystemId
= PciData
->u
.type0
.SubSystemID
;
1690 /* Get any hack flags for this device */
1691 HackFlags
= PciGetHackFlags(PciData
->VendorID
,
1695 PciData
->RevisionID
);
1697 /* Check if this device is considered critical by the OS */
1698 if (PciIsCriticalDeviceClass(PciData
->BaseClass
, PciData
->SubClass
))
1700 /* Check if normally the decodes would be disabled */
1701 if (!(HackFlags
& PCI_HACK_DONT_DISABLE_DECODES
))
1703 /* Because this device is critical, don't disable them */
1704 DPRINT1("Not allowing PM Because device is critical\n");
1705 HackFlags
|= PCI_HACK_CRITICAL_DEVICE
;
1709 /* PCI bridges with a VGA card are also considered critical */
1710 if ((PciData
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1711 (PciData
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
) &&
1712 (PciData
->u
.type1
.BridgeControl
& PCI_ENABLE_BRIDGE_VGA
) &&
1713 !(HackFlags
& PCI_HACK_DONT_DISABLE_DECODES
))
1715 /* Do not disable their decodes either */
1716 DPRINT1("Not allowing PM because device is VGA\n");
1717 HackFlags
|= PCI_HACK_CRITICAL_DEVICE
;
1720 /* Check if the device should be skipped for whatever reason */
1721 if (PciSkipThisFunction(PciData
,
1723 PCI_SKIP_DEVICE_ENUMERATION
,
1726 /* Skip this device */
1730 /* Check if a PDO has already been created for this device */
1731 PdoExtension
= PciFindPdoByFunction(DeviceExtension
,
1736 /* Rescan scenarios are not yet implemented */
1737 UNIMPLEMENTED_DBGBREAK();
1740 /* Bus processing will need to happen */
1743 /* Create the PDO for this device */
1744 Status
= PciPdoCreate(DeviceExtension
, PciSlot
, &DeviceObject
);
1745 ASSERT(NT_SUCCESS(Status
));
1746 NewExtension
= (PPCI_PDO_EXTENSION
)DeviceObject
->DeviceExtension
;
1748 /* Check for broken devices with wrong/no class codes */
1749 if (HackFlags
& PCI_HACK_FAKE_CLASS_CODE
)
1751 /* Setup a default one */
1752 PciData
->BaseClass
= PCI_CLASS_BASE_SYSTEM_DEV
;
1753 PciData
->SubClass
= PCI_SUBCLASS_SYS_OTHER
;
1755 /* Device will behave erratically when reading back data */
1756 NewExtension
->ExpectedWritebackFailure
= TRUE
;
1759 /* Clone all the information from the header */
1760 NewExtension
->VendorId
= PciData
->VendorID
;
1761 NewExtension
->DeviceId
= PciData
->DeviceID
;
1762 NewExtension
->RevisionId
= PciData
->RevisionID
;
1763 NewExtension
->ProgIf
= PciData
->ProgIf
;
1764 NewExtension
->SubClass
= PciData
->SubClass
;
1765 NewExtension
->BaseClass
= PciData
->BaseClass
;
1766 NewExtension
->HeaderType
= PCI_CONFIGURATION_TYPE(PciData
);
1768 /* Check for modern bridge types, which are managed by the driver */
1769 if ((NewExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1770 ((NewExtension
->SubClass
== PCI_SUBCLASS_BR_PCI_TO_PCI
) ||
1771 (NewExtension
->SubClass
== PCI_SUBCLASS_BR_CARDBUS
)))
1773 /* Acquire this device's lock */
1774 KeEnterCriticalRegion();
1775 KeWaitForSingleObject(&DeviceExtension
->ChildListLock
,
1781 /* Scan the bridge list until the first free entry */
1782 for (BridgeExtension
= &DeviceExtension
->ChildBridgePdoList
;
1784 BridgeExtension
= &(*BridgeExtension
)->NextBridge
);
1786 /* Add this PDO as a bridge */
1787 *BridgeExtension
= NewExtension
;
1788 ASSERT(NewExtension
->NextBridge
== NULL
);
1790 /* Release this device's lock */
1791 KeSetEvent(&DeviceExtension
->ChildListLock
,
1794 KeLeaveCriticalRegion();
1797 /* Get the PCI BIOS configuration saved in the registry */
1798 Status
= PciGetBiosConfig(NewExtension
, BiosData
);
1799 if (NT_SUCCESS(Status
))
1801 /* This path has not yet been fully tested by eVb */
1802 DPRINT1("Have BIOS configuration!\n");
1805 /* Check if the PCI BIOS configuration has changed */
1806 if (!PcipIsSameDevice(NewExtension
, BiosData
))
1808 /* This is considered failure, and new data will be saved */
1809 Status
= STATUS_UNSUCCESSFUL
;
1813 /* Data is still correct, check for interrupt line change */
1814 if (BiosData
->u
.type0
.InterruptLine
!=
1815 PciData
->u
.type0
.InterruptLine
)
1817 /* Update the current BIOS with the saved interrupt line */
1818 PciWriteDeviceConfig(NewExtension
,
1819 &BiosData
->u
.type0
.InterruptLine
,
1820 FIELD_OFFSET(PCI_COMMON_HEADER
,
1821 u
.type0
.InterruptLine
),
1825 /* Save the BIOS interrupt line and the initial command */
1826 NewExtension
->RawInterruptLine
= BiosData
->u
.type0
.InterruptLine
;
1827 NewExtension
->InitialCommand
= BiosData
->Command
;
1831 /* Check if no saved data was present or if it was a mismatch */
1832 if (!NT_SUCCESS(Status
))
1834 /* Save the new data */
1835 Status
= PciSaveBiosConfig(NewExtension
, PciData
);
1836 ASSERT(NT_SUCCESS(Status
));
1838 /* Save the interrupt line and command from the device */
1839 NewExtension
->RawInterruptLine
= PciData
->u
.type0
.InterruptLine
;
1840 NewExtension
->InitialCommand
= PciData
->Command
;
1843 /* Save original command from the device and hack flags */
1844 NewExtension
->CommandEnables
= PciData
->Command
;
1845 NewExtension
->HackFlags
= HackFlags
;
1847 /* Get power, AGP, and other capability data */
1848 PciGetEnhancedCapabilities(NewExtension
, PciData
);
1850 /* Now configure the BARs */
1851 Status
= PciGetFunctionLimits(NewExtension
, PciData
, HackFlags
);
1853 /* Power up the device */
1854 PciSetPowerManagedDevicePowerState(NewExtension
, PowerDeviceD0
, FALSE
);
1856 /* Apply any device hacks required for enumeration */
1857 PciApplyHacks(DeviceExtension
,
1860 PCI_HACK_FIXUP_AFTER_CONFIGURATION
,
1863 /* Save interrupt pin */
1864 NewExtension
->InterruptPin
= PciData
->u
.type0
.InterruptPin
;
1867 * Use either this device's actual IRQ line or, if it's connected on
1868 * a master bus whose IRQ line is actually connected to the host, use
1869 * the HAL to query the bus' IRQ line and store that as the adjusted
1870 * interrupt line instead
1872 NewExtension
->AdjustedInterruptLine
= PciGetAdjustedInterruptLine(NewExtension
);
1874 /* Check if this device is used for PCI debugger cards */
1875 NewExtension
->OnDebugPath
= PciIsDeviceOnDebugPath(NewExtension
);
1877 /* Check for devices with invalid/bogus subsystem data */
1878 if (HackFlags
& PCI_HACK_NO_SUBSYSTEM
)
1880 /* Set the subsystem information to zero instead */
1881 NewExtension
->SubsystemVendorId
= 0;
1882 NewExtension
->SubsystemId
= 0;
1885 /* Scan all capabilities */
1886 CapOffset
= NewExtension
->CapabilitiesPtr
;
1889 /* Read this header */
1890 TempOffset
= PciReadDeviceCapability(NewExtension
,
1894 sizeof(PCI_CAPABILITIES_HEADER
));
1895 if (TempOffset
!= CapOffset
)
1897 /* This is a strange issue that shouldn't happen normally */
1898 DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
1900 ASSERT(TempOffset
== CapOffset
);
1903 /* Check for capabilities that this driver cares about */
1904 switch (CapHeader
.CapabilityID
)
1906 /* Power management capability is heavily used by the bus */
1907 case PCI_CAPABILITY_ID_POWER_MANAGEMENT
:
1909 /* Dump the capability */
1911 Size
= sizeof(PCI_PM_CAPABILITY
);
1914 /* AGP capability is required for AGP bus functionality */
1915 case PCI_CAPABILITY_ID_AGP
:
1917 /* Dump the capability */
1919 Size
= sizeof(PCI_AGP_CAPABILITY
);
1922 /* This driver doesn't really use anything other than that */
1925 /* Windows prints this, we could do a translation later */
1926 Name
= "UNKNOWN CAPABILITY";
1931 /* Check if this is a capability that should be dumped */
1934 /* Read the whole capability data */
1935 TempOffset
= PciReadDeviceCapability(NewExtension
,
1937 CapHeader
.CapabilityID
,
1941 if (TempOffset
!= CapOffset
)
1943 /* Again, a strange issue that shouldn't be seen */
1944 DPRINT1("- Failed to read capability data. ***\n");
1945 ASSERT(TempOffset
== CapOffset
);
1949 /* Dump this capability */
1950 DPRINT1("CAP @%02x ID %02x (%s)\n",
1951 CapOffset
, CapHeader
.CapabilityID
, Name
);
1952 for (i
= 0; i
< Size
; i
+= 2)
1953 DPRINT1(" %04x\n", *(PUSHORT
)((ULONG_PTR
)&CapHeader
+ i
));
1956 /* Check the next capability */
1957 CapOffset
= CapHeader
.Next
;
1960 /* Check for IDE controllers */
1961 if ((NewExtension
->BaseClass
== PCI_CLASS_MASS_STORAGE_CTLR
) &&
1962 (NewExtension
->SubClass
== PCI_SUBCLASS_MSC_IDE_CTLR
))
1964 /* Do not allow them to power down completely */
1965 NewExtension
->DisablePowerDown
= TRUE
;
1969 * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
1970 * bridge that is present on certain NT Alpha machines appears as
1971 * non-classified so detect it manually by scanning for its VID/PID.
1973 if (((NewExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
1974 ((NewExtension
->SubClass
== PCI_SUBCLASS_BR_ISA
) ||
1975 (NewExtension
->SubClass
== PCI_SUBCLASS_BR_EISA
) ||
1976 (NewExtension
->SubClass
== PCI_SUBCLASS_BR_MCA
))) ||
1977 ((NewExtension
->VendorId
== 0x8086) &&
1978 (NewExtension
->DeviceId
== 0x482)))
1980 /* Do not allow these legacy bridges to be powered down */
1981 NewExtension
->DisablePowerDown
= TRUE
;
1984 /* Check if the BIOS did not configure a cache line size */
1985 if (!PciData
->CacheLineSize
)
1987 /* Check if the device is disabled */
1988 if (!(NewExtension
->CommandEnables
& (PCI_ENABLE_IO_SPACE
|
1989 PCI_ENABLE_MEMORY_SPACE
|
1990 PCI_ENABLE_BUS_MASTER
)))
1992 /* Check if this is a PCI-X device*/
1993 TempOffset
= PciReadDeviceCapability(NewExtension
,
1994 NewExtension
->CapabilitiesPtr
,
1995 PCI_CAPABILITY_ID_PCIX
,
1997 sizeof(PCI_CAPABILITIES_HEADER
));
2000 * A device with default cache line size and latency timer
2001 * settings is considered to be unconfigured. Note that on
2002 * PCI-X, the reset value of the latency timer field in the
2003 * header is 64, not 0, hence why the check for PCI-X caps
2004 * was required, and the value used here below.
2006 if (!(PciData
->LatencyTimer
) ||
2007 ((TempOffset
) && (PciData
->LatencyTimer
== 64)))
2009 /* Keep track of the fact that it needs configuration */
2010 DPRINT1("PCI - ScanBus, PDOx %p found unconfigured\n",
2012 NewExtension
->NeedsHotPlugConfiguration
= TRUE
;
2017 /* Save latency and cache size information */
2018 NewExtension
->SavedLatencyTimer
= PciData
->LatencyTimer
;
2019 NewExtension
->SavedCacheLineSize
= PciData
->CacheLineSize
;
2021 /* The PDO is now ready to go */
2022 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
2026 /* Enumeration completed, do a final pass now that all devices are found */
2027 if (ProcessFlag
) PciProcessBus(DeviceExtension
);
2028 return STATUS_SUCCESS
;
2033 PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension
,
2034 IN OUT PDEVICE_RELATIONS
*pDeviceRelations
)
2037 PPCI_PDO_EXTENSION PdoExtension
;
2039 PDEVICE_RELATIONS DeviceRelations
, NewRelations
;
2041 PDEVICE_OBJECT DeviceObject
, *ObjectArray
;
2044 /* Make sure the FDO is started */
2045 ASSERT(DeviceExtension
->DeviceState
== PciStarted
);
2047 /* Synchronize while we enumerate the bus */
2048 Status
= PciBeginStateTransition(DeviceExtension
, PciSynchronizedOperation
);
2049 if (!NT_SUCCESS(Status
)) return Status
;
2051 /* Scan all children PDO */
2052 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
2054 PdoExtension
= PdoExtension
->Next
)
2056 /* Invalidate them */
2057 PdoExtension
->NotPresent
= TRUE
;
2060 /* Scan the PCI Bus */
2061 Status
= PciScanBus(DeviceExtension
);
2062 ASSERT(NT_SUCCESS(Status
));
2064 /* Enumerate all children PDO again */
2065 for (PdoExtension
= DeviceExtension
->ChildPdoList
;
2067 PdoExtension
= PdoExtension
->Next
)
2069 /* Check for PDOs that are still invalidated */
2070 if (PdoExtension
->NotPresent
)
2072 /* This means this PDO existed before, but not anymore */
2073 PdoExtension
->ReportedMissing
= TRUE
;
2074 DPRINT1("PCI - Old device (pdox) %p not found on rescan.\n",
2079 /* Increase count of detected PDOs */
2084 /* Read the current relations and add the newly discovered relations */
2085 DeviceRelations
= *pDeviceRelations
;
2086 Size
= FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) +
2087 PdoCount
* sizeof(PDEVICE_OBJECT
);
2088 if (DeviceRelations
) Size
+= sizeof(PDEVICE_OBJECT
) * DeviceRelations
->Count
;
2090 /* Allocate the device relations */
2091 NewRelations
= (PDEVICE_RELATIONS
)ExAllocatePoolWithTag(0, Size
, 'BicP');
2094 /* Out of space, cancel the operation */
2095 PciCancelStateTransition(DeviceExtension
, PciSynchronizedOperation
);
2096 return STATUS_INSUFFICIENT_RESOURCES
;
2099 /* Check if there were any older relations */
2100 NewRelations
->Count
= 0;
2101 if (DeviceRelations
)
2103 /* Copy the old relations into the new buffer, then free the old one */
2104 RtlCopyMemory(NewRelations
,
2106 FIELD_OFFSET(DEVICE_RELATIONS
, Objects
) +
2107 DeviceRelations
->Count
* sizeof(PDEVICE_OBJECT
));
2108 ExFreePoolWithTag(DeviceRelations
, 0);
2111 /* Print out that we're ready to dump relations */
2112 DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %p (bus 0x%02x)\n",
2114 DeviceExtension
->BaseBus
);
2116 /* Loop the current PDO children and the device relation object array */
2117 PdoExtension
= DeviceExtension
->ChildPdoList
;
2118 ObjectArray
= &NewRelations
->Objects
[NewRelations
->Count
];
2119 while (PdoExtension
)
2121 /* Dump this relation */
2122 DPRINT1(" QDR PDO %p (x %p)%s\n",
2123 PdoExtension
->PhysicalDeviceObject
,
2125 PdoExtension
->NotPresent
?
2126 "<Omitted, device flaged not present>" : "");
2128 /* Is this PDO present? */
2129 if (!PdoExtension
->NotPresent
)
2131 /* Reference it and add it to the array */
2132 DeviceObject
= PdoExtension
->PhysicalDeviceObject
;
2133 ObReferenceObject(DeviceObject
);
2134 *ObjectArray
++ = DeviceObject
;
2137 /* Go to the next PDO */
2138 PdoExtension
= PdoExtension
->Next
;
2141 /* Terminate dumping the relations */
2142 DPRINT1(" QDR Total PDO count = %u (%u already in list)\n",
2143 NewRelations
->Count
+ PdoCount
,
2144 NewRelations
->Count
);
2146 /* Return the final count and the new buffer */
2147 NewRelations
->Count
+= PdoCount
;
2148 *pDeviceRelations
= NewRelations
;
2149 return STATUS_SUCCESS
;
2154 PciSetResources(IN PPCI_PDO_EXTENSION PdoExtension
,
2156 IN BOOLEAN SomethingSomethingDarkSide
)
2158 PPCI_FDO_EXTENSION FdoExtension
;
2159 UCHAR NewCacheLineSize
, NewLatencyTimer
;
2160 PCI_COMMON_HEADER PciData
;
2162 PPCI_CONFIGURATOR Configurator
;
2164 UNREFERENCED_PARAMETER(SomethingSomethingDarkSide
);
2166 /* Get the FDO and read the configuration data */
2167 FdoExtension
= PdoExtension
->ParentFdoExtension
;
2168 PciReadDeviceConfig(PdoExtension
, &PciData
, 0, PCI_COMMON_HDR_LENGTH
);
2170 /* Make sure this is still the same device */
2171 if (!PcipIsSameDevice(PdoExtension
, &PciData
))
2174 ASSERTMSG(FALSE
, "PCI Set resources - not same device");
2175 return STATUS_DEVICE_DOES_NOT_EXIST
;
2178 /* Nothing to set for a host bridge */
2179 if ((PdoExtension
->BaseClass
== PCI_CLASS_BRIDGE_DEV
) &&
2180 (PdoExtension
->SubClass
== PCI_SUBCLASS_BR_HOST
))
2183 return STATUS_SUCCESS
;
2186 /* Check if an IDE controller is being reset */
2188 (PdoExtension
->BaseClass
== PCI_CLASS_MASS_STORAGE_CTLR
) &&
2189 (PdoExtension
->SubClass
== PCI_SUBCLASS_MSC_IDE_CTLR
))
2191 /* Turn off native mode */
2192 Native
= PciConfigureIdeController(PdoExtension
, &PciData
, FALSE
);
2193 ASSERT(Native
== PdoExtension
->IDEInNativeMode
);
2196 /* Check for update of a hotplug device, or first configuration of one */
2197 if ((PdoExtension
->NeedsHotPlugConfiguration
) &&
2198 (FdoExtension
->HotPlugParameters
.Acquired
))
2200 /* Don't have hotplug devices to test with yet, QEMU 0.14 should */
2201 UNIMPLEMENTED_DBGBREAK();
2204 /* Locate the correct resource configurator for this type of device */
2205 Configurator
= &PciConfigurators
[PdoExtension
->HeaderType
];
2207 /* Apply the settings change */
2208 Configurator
->ChangeResourceSettings(PdoExtension
, &PciData
);
2210 /* Assume no update needed */
2211 PdoExtension
->UpdateHardware
= FALSE
;
2213 /* Check if a reset is needed */
2216 /* Reset resources */
2217 Configurator
->ResetDevice(PdoExtension
, &PciData
);
2218 PciData
.u
.type0
.InterruptLine
= PdoExtension
->RawInterruptLine
;
2221 /* Check if the latency timer changed */
2222 NewLatencyTimer
= PdoExtension
->SavedLatencyTimer
;
2223 if (PciData
.LatencyTimer
!= NewLatencyTimer
)
2225 /* Debug notification */
2226 DPRINT1("PCI (pdox %p) changing latency from %02x to %02x.\n",
2228 PciData
.LatencyTimer
,
2232 /* Check if the cache line changed */
2233 NewCacheLineSize
= PdoExtension
->SavedCacheLineSize
;
2234 if (PciData
.CacheLineSize
!= NewCacheLineSize
)
2236 /* Debug notification */
2237 DPRINT1("PCI (pdox %p) changing cache line size from %02x to %02x.\n",
2239 PciData
.CacheLineSize
,
2243 /* Inherit data from PDO extension */
2244 PciData
.LatencyTimer
= PdoExtension
->SavedLatencyTimer
;
2245 PciData
.CacheLineSize
= PdoExtension
->SavedCacheLineSize
;
2246 PciData
.u
.type0
.InterruptLine
= PdoExtension
->RawInterruptLine
;
2248 /* Apply any resource hacks required */
2249 PciApplyHacks(FdoExtension
,
2252 PCI_HACK_FIXUP_BEFORE_UPDATE
,
2255 /* Check if I/O space was disabled by administrator or driver */
2256 if (PdoExtension
->IoSpaceNotRequired
)
2258 /* Don't turn on the decode */
2259 PdoExtension
->CommandEnables
&= ~PCI_ENABLE_IO_SPACE
;
2262 /* Update the device with the new settings */
2263 PciUpdateHardware(PdoExtension
, &PciData
);
2265 /* Update complete */
2266 PdoExtension
->RawInterruptLine
= PciData
.u
.type0
.InterruptLine
;
2267 PdoExtension
->NeedsHotPlugConfiguration
= FALSE
;
2268 return STATUS_SUCCESS
;