+++ /dev/null
-/*
- * PROJECT: ReactOS PCI Bus Driver
- * LICENSE: BSD - See COPYING.ARM in the top level directory
- * FILE: drivers/bus/pci/enum.c
- * PURPOSE: PCI Bus/Device Enumeration
- * PROGRAMMERS: ReactOS Portable Systems Group
- */
-
-/* INCLUDES *******************************************************************/
-
-#include <pci.h>
-#define NDEBUG
-#include <debug.h>
-
-/* GLOBALS ********************************************************************/
-
-PIO_RESOURCE_REQUIREMENTS_LIST PciZeroIoResourceRequirements;
-
-PCI_CONFIGURATOR PciConfigurators[] =
-{
- {
- Device_MassageHeaderForLimitsDetermination,
- Device_RestoreCurrent,
- Device_SaveLimits,
- Device_SaveCurrentSettings,
- Device_ChangeResourceSettings,
- Device_GetAdditionalResourceDescriptors,
- Device_ResetDevice
- },
- {
- PPBridge_MassageHeaderForLimitsDetermination,
- PPBridge_RestoreCurrent,
- PPBridge_SaveLimits,
- PPBridge_SaveCurrentSettings,
- PPBridge_ChangeResourceSettings,
- PPBridge_GetAdditionalResourceDescriptors,
- PPBridge_ResetDevice
- },
- {
- Cardbus_MassageHeaderForLimitsDetermination,
- Cardbus_RestoreCurrent,
- Cardbus_SaveLimits,
- Cardbus_SaveCurrentSettings,
- Cardbus_ChangeResourceSettings,
- Cardbus_GetAdditionalResourceDescriptors,
- Cardbus_ResetDevice
- }
-};
-
-/* FUNCTIONS ******************************************************************/
-
-BOOLEAN
-NTAPI
-PciComputeNewCurrentSettings(IN PPCI_PDO_EXTENSION PdoExtension,
- IN PCM_RESOURCE_LIST ResourceList)
-{
- PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, InterruptResource;
- PCM_PARTIAL_RESOURCE_DESCRIPTOR BaseResource, CurrentDescriptor;
- PCM_PARTIAL_RESOURCE_DESCRIPTOR PreviousDescriptor;
- CM_PARTIAL_RESOURCE_DESCRIPTOR ResourceArray[7];
- PCM_FULL_RESOURCE_DESCRIPTOR FullList;
- BOOLEAN DrainPartial, RangeChange;
- ULONG i, j;
- PPCI_FUNCTION_RESOURCES PciResources;
- PAGED_CODE();
-
- /* Make sure we have either no resources, or at least one */
- ASSERT((ResourceList == NULL) || (ResourceList->Count == 1));
-
- /* Initialize no partial, interrupt descriptor, or range change */
- Partial = NULL;
- InterruptResource = NULL;
- RangeChange = FALSE;
-
- /* Check if there's not actually any resources */
- if (!(ResourceList) || !(ResourceList->Count))
- {
- /* Then just return the hardware update state */
- return PdoExtension->UpdateHardware;
- }
-
- /* Print the new specified resource list */
- PciDebugPrintCmResList(ResourceList);
-
- /* Clear the temporary resource array */
- for (i = 0; i < 7; i++) ResourceArray[i].Type = CmResourceTypeNull;
-
- /* Loop the full resource descriptor */
- FullList = ResourceList->List;
- for (i = 0; i < ResourceList->Count; i++)
- {
- /* Initialize loop variables */
- DrainPartial = FALSE;
- BaseResource = NULL;
-
- /* Loop the partial descriptors */
- Partial = FullList->PartialResourceList.PartialDescriptors;
- for (j = 0; j < FullList->PartialResourceList.Count; j++)
- {
- /* Check if we were supposed to drain a partial due to device data */
- if (DrainPartial)
- {
- /* Draining complete, move on to the next descriptor then */
- DrainPartial--;
- continue;
- }
-
- /* Check what kind of descriptor this was */
- switch (Partial->Type)
- {
- /* Base BAR resources */
- case CmResourceTypePort:
- case CmResourceTypeMemory:
-
- /* Set it as the base */
- ASSERT(BaseResource == NULL);
- BaseResource = Partial;
- break;
-
- /* Interrupt resource */
- case CmResourceTypeInterrupt:
-
- /* Make sure it's a compatible (and the only) PCI interrupt */
- ASSERT(InterruptResource == NULL);
- ASSERT(Partial->u.Interrupt.Level == Partial->u.Interrupt.Vector);
- InterruptResource = Partial;
-
- /* Only 255 interrupts on x86/x64 hardware */
- if (Partial->u.Interrupt.Level < 256)
- {
- /* Use the passed interrupt line */
- PdoExtension->AdjustedInterruptLine = Partial->u.Interrupt.Level;
- }
- else
- {
- /* Invalid vector, so ignore it */
- PdoExtension->AdjustedInterruptLine = 0;
- }
-
- break;
-
- /* Check for specific device data */
- case CmResourceTypeDevicePrivate:
-
- /* Check what kind of data this was */
- switch (Partial->u.DevicePrivate.Data[0])
- {
- /* Not used in the driver yet */
- case 1:
- UNIMPLEMENTED;
- while (TRUE);
- break;
-
- /* Not used in the driver yet */
- case 2:
- UNIMPLEMENTED;
- while (TRUE);
- break;
-
- /* A drain request */
- case 3:
- /* Shouldn't be a base resource, this is a drain */
- ASSERT(BaseResource == NULL);
- DrainPartial = Partial->u.DevicePrivate.Data[1];
- ASSERT(DrainPartial == TRUE);
- break;
- }
- break;
- }
-
- /* Move to the next descriptor */
- Partial = PciNextPartialDescriptor(Partial);
- }
-
- /* We should be starting a new list now */
- ASSERT(BaseResource == NULL);
- FullList = (PVOID)Partial;
- }
-
- /* Check the current assigned PCI resources */
- PciResources = PdoExtension->Resources;
- if (!PciResources) return FALSE;
-
- //if... // MISSING CODE
- UNIMPLEMENTED;
- DPRINT1("Missing sanity checking code!\n");
-
- /* Loop all the PCI function resources */
- for (i = 0; i < 7; i++)
- {
- /* Get the current function resource descriptor, and the new one */
- CurrentDescriptor = &PciResources->Current[i];
- Partial = &ResourceArray[i];
-
- /* Previous is current during the first loop iteration */
- PreviousDescriptor = &PciResources->Current[(i == 0) ? (0) : (i - 1)];
-
- /* Check if this new descriptor is different than the old one */
- if (((Partial->Type != CurrentDescriptor->Type) ||
- (Partial->Type != CmResourceTypeNull)) &&
- ((Partial->u.Generic.Start.QuadPart !=
- CurrentDescriptor->u.Generic.Start.QuadPart) ||
- (Partial->u.Generic.Length != CurrentDescriptor->u.Generic.Length)))
- {
- /* Record a change */
- RangeChange = TRUE;
-
- /* Was there a range before? */
- if (CurrentDescriptor->Type != CmResourceTypeNull)
- {
- /* Print it */
- DbgPrint(" Old range-\n");
- PciDebugPrintPartialResource(CurrentDescriptor);
- }
- else
- {
- /* There was no range */
- DbgPrint(" Previously unset range\n");
- }
-
- /* Print new one */
- DbgPrint(" changed to\n");
- PciDebugPrintPartialResource(Partial);
-
- /* Update to new range */
- CurrentDescriptor->Type = Partial->Type;
- PreviousDescriptor->u.Generic.Start = Partial->u.Generic.Start;
- PreviousDescriptor->u.Generic.Length = Partial->u.Generic.Length;
- CurrentDescriptor = PreviousDescriptor;
- }
- }
-
- /* Either the hardware was updated, or a resource range changed */
- return ((RangeChange) || (PdoExtension->UpdateHardware));
-}
-
-VOID
-NTAPI
-PcipUpdateHardware(IN PVOID Context,
- IN PVOID Context2)
-{
- PPCI_PDO_EXTENSION PdoExtension = Context;
- PPCI_COMMON_HEADER PciData = Context2;
-
- /* Check if we're allowed to disable decodes */
- PciData->Command = PdoExtension->CommandEnables;
- if (!(PdoExtension->HackFlags & PCI_HACK_PRESERVE_COMMAND))
- {
- /* Disable all decodes */
- PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
- PCI_ENABLE_MEMORY_SPACE |
- PCI_ENABLE_BUS_MASTER |
- PCI_ENABLE_WRITE_AND_INVALIDATE);
- }
-
- /* Update the device configuration */
- PciData->Status = 0;
- PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
-
- /* Turn decodes back on */
- PciDecodeEnable(PdoExtension, TRUE, &PdoExtension->CommandEnables);
-}
-
-VOID
-NTAPI
-PciUpdateHardware(IN PPCI_PDO_EXTENSION PdoExtension,
- IN PPCI_COMMON_HEADER PciData)
-{
- PCI_IPI_CONTEXT Context;
-
- /* Check for critical devices and PCI Debugging devices */
- if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
- (PdoExtension->OnDebugPath))
- {
- /* Build the context and send an IPI */
- Context.RunCount = 1;
- Context.Barrier = 1;
- Context.Context = PciData;
- Context.Function = PcipUpdateHardware;
- Context.DeviceExtension = PdoExtension;
- KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&Context);
- }
- else
- {
- /* Just to the update inline */
- PcipUpdateHardware(PdoExtension, PciData);
- }
-}
-
-PIO_RESOURCE_REQUIREMENTS_LIST
-NTAPI
-PciAllocateIoRequirementsList(IN ULONG Count,
- IN ULONG BusNumber,
- IN ULONG SlotNumber)
-{
- SIZE_T Size;
- PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
-
- /* Calculate the final size of the list, including each descriptor */
- Size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
- if (Count > 1) Size = sizeof(IO_RESOURCE_DESCRIPTOR) * (Count - 1) +
- sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
-
- /* Allocate the list */
- RequirementsList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
- if (!RequirementsList) return NULL;
-
- /* Initialize it */
- RtlZeroMemory(RequirementsList, Size);
- RequirementsList->AlternativeLists = 1;
- RequirementsList->BusNumber = BusNumber;
- RequirementsList->SlotNumber = SlotNumber;
- RequirementsList->InterfaceType = PCIBus;
- RequirementsList->ListSize = Size;
- RequirementsList->List[0].Count = Count;
- RequirementsList->List[0].Version = 1;
- RequirementsList->List[0].Revision = 1;
-
- /* Return it */
- return RequirementsList;
-}
-
-PCM_RESOURCE_LIST
-NTAPI
-PciAllocateCmResourceList(IN ULONG Count,
- IN ULONG BusNumber)
-{
- SIZE_T Size;
- PCM_RESOURCE_LIST ResourceList;
-
- /* Calculate the final size of the list, including each descriptor */
- Size = sizeof(CM_RESOURCE_LIST);
- if (Count > 1) Size = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count - 1) +
- sizeof(CM_RESOURCE_LIST);
-
- /* Allocate the list */
- ResourceList = ExAllocatePoolWithTag(PagedPool, Size, 'BicP');
- if (!ResourceList) return NULL;
-
- /* Initialize it */
- RtlZeroMemory(ResourceList, Size);
- ResourceList->Count = 1;
- ResourceList->List[0].BusNumber = BusNumber;
- ResourceList->List[0].InterfaceType = PCIBus;
- ResourceList->List[0].PartialResourceList.Version = 1;
- ResourceList->List[0].PartialResourceList.Revision = 1;
- ResourceList->List[0].PartialResourceList.Count = Count;
-
- /* Return it */
- return ResourceList;
-}
-
-NTSTATUS
-NTAPI
-PciQueryResources(IN PPCI_PDO_EXTENSION PdoExtension,
- OUT PCM_RESOURCE_LIST *Buffer)
-{
- PPCI_FUNCTION_RESOURCES PciResources;
- BOOLEAN HaveVga, HaveMemSpace, HaveIoSpace;
- USHORT BridgeControl, PciCommand;
- ULONG Count, i;
- PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial, Resource, LastResource;
- PCM_RESOURCE_LIST ResourceList;
- UCHAR InterruptLine;
- PAGED_CODE();
-
- /* Assume failure */
- Count = 0;
- HaveVga = FALSE;
- *Buffer = NULL;
-
- /* Make sure there's some resources to query */
- PciResources = PdoExtension->Resources;
- if (!PciResources) return STATUS_SUCCESS;
-
- /* Read the decodes */
- PciReadDeviceConfig(PdoExtension,
- &PciCommand,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
-
- /* Check which ones are turned on */
- HaveIoSpace = PciCommand & PCI_ENABLE_IO_SPACE;
- HaveMemSpace = PciCommand & PCI_ENABLE_MEMORY_SPACE;
-
- /* Loop maximum possible descriptors */
- for (i = 0; i < 7; i++)
- {
- /* Check if the decode for this descriptor is actually turned on */
- Partial = &PciResources->Current[i];
- if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
- ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
- {
- /* One more fully active descriptor */
- Count++;
- }
- }
-
- /* If there's an interrupt pin associated, check at least one decode is on */
- if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
- {
- /* Read the interrupt line for the pin, add a descriptor if it's valid */
- InterruptLine = PdoExtension->AdjustedInterruptLine;
- if ((InterruptLine) && (InterruptLine != -1)) Count++;
- }
-
- /* Check for PCI bridge */
- if (PdoExtension->HeaderType == PCI_BRIDGE_TYPE)
- {
- /* Read bridge settings, check if VGA is present */
- PciReadDeviceConfig(PdoExtension,
- &BridgeControl,
- FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BridgeControl),
- sizeof(USHORT));
- if (BridgeControl & PCI_ENABLE_BRIDGE_VGA)
- {
- /* Remember for later */
- HaveVga = TRUE;
-
- /* One memory descriptor for 0xA0000, plus the two I/O port ranges */
- if (HaveMemSpace) Count++;
- if (HaveIoSpace) Count += 2;
- }
- }
-
- /* If there's no descriptors in use, there's no resources, so return */
- if (!Count) return STATUS_SUCCESS;
-
- /* Allocate a resource list to hold the resources */
- ResourceList = PciAllocateCmResourceList(Count,
- PdoExtension->ParentFdoExtension->BaseBus);
- if (!ResourceList) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* This is where the descriptors will be copied into */
- Resource = ResourceList->List[0].PartialResourceList.PartialDescriptors;
- LastResource = Resource + Count + 1;
-
- /* Loop maximum possible descriptors */
- for (i = 0; i < 7; i++)
- {
- /* Check if the decode for this descriptor is actually turned on */
- Partial = &PciResources->Current[i];
- if (((HaveMemSpace) && (Partial->Type == CmResourceTypeMemory)) ||
- ((HaveIoSpace) && (Partial->Type == CmResourceTypePort)))
- {
- /* Copy the descriptor into the resource list */
- *Resource++ = *Partial;
- }
- }
-
- /* Check if earlier the code detected this was a PCI bridge with VGA on it */
- if (HaveVga)
- {
- /* Are the memory decodes enabled? */
- if (HaveMemSpace)
- {
- /* Build a memory descriptor for a 128KB framebuffer at 0xA0000 */
- Resource->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
- Resource->u.Generic.Start.HighPart = 0;
- Resource->Type = CmResourceTypeMemory;
- Resource->u.Generic.Start.LowPart = 0xA0000;
- Resource->u.Generic.Length = 0x20000;
- Resource++;
- }
-
- /* Are the I/O decodes enabled? */
- if (HaveIoSpace)
- {
- /* Build an I/O descriptor for the graphic ports at 0x3B0 */
- Resource->Type = CmResourceTypePort;
- Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
- Resource->u.Port.Start.QuadPart = 0x3B0u;
- Resource->u.Port.Length = 0xC;
- Resource++;
-
- /* Build an I/O descriptor for the graphic ports at 0x3C0 */
- Resource->Type = CmResourceTypePort;
- Resource->Flags = CM_RESOURCE_PORT_POSITIVE_DECODE | CM_RESOURCE_PORT_10_BIT_DECODE;
- Resource->u.Port.Start.QuadPart = 0x3C0u;
- Resource->u.Port.Length = 0x20;
- Resource++;
- }
- }
-
- /* If there's an interrupt pin associated, check at least one decode is on */
- if ((PdoExtension->InterruptPin) && ((HaveMemSpace) || (HaveIoSpace)))
- {
- /* Read the interrupt line for the pin, check if it's valid */
- InterruptLine = PdoExtension->AdjustedInterruptLine;
- if ((InterruptLine) && (InterruptLine != -1))
- {
- /* Make sure there's still space */
- ASSERT(Resource < LastResource);
-
- /* Add the interrupt descriptor */
- Resource->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
- Resource->Type = CmResourceTypeInterrupt;
- Resource->ShareDisposition = CmResourceShareShared;
- Resource->u.Interrupt.Affinity = -1;
- Resource->u.Interrupt.Level = InterruptLine;
- Resource->u.Interrupt.Vector = InterruptLine;
- }
- }
-
- /* Return the resouce list */
- *Buffer = ResourceList;
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-PciQueryTargetDeviceRelations(IN PPCI_PDO_EXTENSION PdoExtension,
- IN OUT PDEVICE_RELATIONS *pDeviceRelations)
-{
- PDEVICE_RELATIONS DeviceRelations;
- PAGED_CODE();
-
- /* If there were existing relations, free them */
- if (*pDeviceRelations) ExFreePoolWithTag(*pDeviceRelations, 0);
-
- /* Allocate a new structure for the relations */
- DeviceRelations = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(DEVICE_RELATIONS),
- 'BicP');
- if (!DeviceRelations) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Only one relation: the PDO */
- DeviceRelations->Count = 1;
- DeviceRelations->Objects[0] = PdoExtension->PhysicalDeviceObject;
- ObReferenceObject(DeviceRelations->Objects[0]);
-
- /* Return the new relations */
- *pDeviceRelations = DeviceRelations;
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-PciQueryEjectionRelations(IN PPCI_PDO_EXTENSION PdoExtension,
- IN OUT PDEVICE_RELATIONS *pDeviceRelations)
-{
- /* Not yet implemented */
- UNIMPLEMENTED;
- while (TRUE);
-}
-
-NTSTATUS
-NTAPI
-PciBuildRequirementsList(IN PPCI_PDO_EXTENSION PdoExtension,
- IN PPCI_COMMON_HEADER PciData,
- OUT PIO_RESOURCE_REQUIREMENTS_LIST* Buffer)
-{
- PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
- {
- /* There aren't, so use the zero descriptor */
- RequirementsList = PciZeroIoResourceRequirements;
-
- /* Does it actually exist yet? */
- if (!PciZeroIoResourceRequirements)
- {
- /* Allocate it, and use it for future use */
- RequirementsList = PciAllocateIoRequirementsList(0, 0, 0);
- PciZeroIoResourceRequirements = RequirementsList;
- if (!PciZeroIoResourceRequirements) return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- /* Return the zero requirements list to the caller */
- *Buffer = RequirementsList;
- DPRINT1("PCI - build resource reqs - early out, 0 resources\n");
- return STATUS_SUCCESS;
- }
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-PciQueryRequirements(IN PPCI_PDO_EXTENSION PdoExtension,
- IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *RequirementsList)
-{
- NTSTATUS Status;
- PCI_COMMON_HEADER PciHeader;
- PAGED_CODE();
-
- /* Check if the PDO has any resources, or at least an interrupt pin */
- if ((PdoExtension->Resources) || (PdoExtension->InterruptPin))
- {
- /* Read the current PCI header */
- PciReadDeviceConfig(PdoExtension, &PciHeader, 0, PCI_COMMON_HDR_LENGTH);
-
- /* Use it to build a list of requirements */
- Status = PciBuildRequirementsList(PdoExtension, &PciHeader, RequirementsList);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
- if ((PciHeader.VendorID == 0xE11) &&
- (PciHeader.DeviceID == 0xA0F7) &&
- (PciHeader.RevisionID == 17) &&
- (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
- {
- /* Have not tested this on eVb's machine yet */
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Check if the requirements are actually the zero list */
- if (*RequirementsList == PciZeroIoResourceRequirements)
- {
- /* A simple NULL will sufficie for the PnP Manager */
- *RequirementsList = NULL;
- DPRINT1("Returning NULL requirements list\n");
- }
- else
- {
- /* Otherwise, print out the requirements list */
- PciDebugPrintIoResReqList(*RequirementsList);
- }
- }
- else
- {
- /* There aren't any resources, so simply return NULL */
- DPRINT1("PciQueryRequirements returning NULL requirements list\n");
- *RequirementsList = NULL;
- }
-
- /* This call always succeeds (but maybe with no requirements) */
- return STATUS_SUCCESS;
-}
-
-/*
- * 7. The IO/MEM/Busmaster decodes are disabled for the device.
- * 8. The PCI bus driver sets the operating mode bits of the Programming
- * Interface byte to switch the controller to native mode.
- *
- * Important: When the controller is set to native mode, it must quiet itself
- * and must not decode I/O resources or generate interrupts until the operating
- * system has enabled the ports in the PCI configuration header.
- * The IO/MEM/BusMaster bits will be disabled before the mode change, but it
- * is not possible to disable interrupts on the device. The device must not
- * generate interrupts (either legacy or native mode) while the decodes are
- * disabled in the command register.
- *
- * This operation is expected to be instantaneous and the operating system does
- * not stall afterward. It is also expected that the interrupt pin register in
- * the PCI Configuration space for this device is accurate. The operating system
- * re-reads this data after previously ignoring it.
- */
-BOOLEAN
-NTAPI
-PciConfigureIdeController(IN PPCI_PDO_EXTENSION PdoExtension,
- IN PPCI_COMMON_HEADER PciData,
- IN BOOLEAN Initial)
-{
- UCHAR MasterMode, SlaveMode, MasterFixed, SlaveFixed, ProgIf, NewProgIf;
- BOOLEAN Switched;
- USHORT Command;
-
- /* Assume it won't work */
- Switched = FALSE;
-
- /* Get master and slave current settings, and programmability flag */
- ProgIf = PciData->ProgIf;
- MasterMode = (ProgIf & 1) == 1;
- MasterFixed = (ProgIf & 2) == 0;
- SlaveMode = (ProgIf & 4) == 4;
- SlaveFixed = (ProgIf & 8) == 0;
-
- /*
- * [..] In order for Windows XP SP1 and Windows Server 2003 to switch an ATA
- * ATA controller from compatible mode to native mode, the following must be
- * true:
- *
- * - The controller must indicate in its programming interface that both channels
- * can be switched to native mode. Windows XP SP1 and Windows Server 2003 do
- * not support switching only one IDE channel to native mode. See the PCI IDE
- * Controller Specification Revision 1.0 for details.
- */
- if ((MasterMode != SlaveMode) || (MasterFixed != SlaveFixed))
- {
- /* Windows does not support this configuration, fail */
- DPRINT1("PCI: Warning unsupported IDE controller configuration for VEN_%04x&DEV_%04x!",
- PdoExtension->VendorId,
- PdoExtension->DeviceId);
- return Switched;
- }
-
- /* Check if the controller is already in native mode */
- if ((MasterMode) && (SlaveMode))
- {
- /* Check if I/O decodes should be disabled */
- if ((Initial) || (PdoExtension->IoSpaceUnderNativeIdeControl))
- {
- /* Read the current command */
- PciReadDeviceConfig(PdoExtension,
- &Command,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
-
- /* Disable I/O space decode */
- Command &= ~PCI_ENABLE_IO_SPACE;
-
- /* Update new command in PCI IDE controller */
- PciWriteDeviceConfig(PdoExtension,
- &Command,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
-
- /* Save updated command value */
- PciData->Command = Command;
- }
-
- /* The controller is now in native mode */
- Switched = TRUE;
- }
- else if (!(MasterFixed) &&
- !(SlaveFixed) &&
- (PdoExtension->BIOSAllowsIDESwitchToNativeMode) &&
- !(PdoExtension->HackFlags & PCI_HACK_DISABLE_IDE_NATIVE_MODE))
- {
- /* Turn off decodes */
- PciDecodeEnable(PdoExtension, FALSE, NULL);
-
- /* Update the current command */
- PciReadDeviceConfig(PdoExtension,
- &PciData->Command,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
-
- /* Enable native mode */
- ProgIf = PciData->ProgIf | 5;
- PciWriteDeviceConfig(PdoExtension,
- &ProgIf,
- FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
- sizeof(UCHAR));
-
- /* Verify the setting "stuck" */
- PciReadDeviceConfig(PdoExtension,
- &NewProgIf,
- FIELD_OFFSET(PCI_COMMON_HEADER, ProgIf),
- sizeof(UCHAR));
- if (NewProgIf == ProgIf)
- {
- /* Update the header and PDO data with the new programming mode */
- PciData->ProgIf = ProgIf;
- PdoExtension->ProgIf = NewProgIf;
-
- /* Clear the first four BARs to reset current BAR setttings */
- PciData->u.type0.BaseAddresses[0] = 0;
- PciData->u.type0.BaseAddresses[1] = 0;
- PciData->u.type0.BaseAddresses[2] = 0;
- PciData->u.type0.BaseAddresses[3] = 0;
- PciWriteDeviceConfig(PdoExtension,
- PciData->u.type0.BaseAddresses,
- FIELD_OFFSET(PCI_COMMON_HEADER,
- u.type0.BaseAddresses),
- 4 * sizeof(ULONG));
-
- /* Re-read the BARs to have the latest data for native mode IDE */
- PciReadDeviceConfig(PdoExtension,
- PciData->u.type0.BaseAddresses,
- FIELD_OFFSET(PCI_COMMON_HEADER,
- u.type0.BaseAddresses),
- 4 * sizeof(ULONG));
-
- /* Re-read the interrupt pin used for native mode IDE */
- PciReadDeviceConfig(PdoExtension,
- &PciData->u.type0.InterruptPin,
- FIELD_OFFSET(PCI_COMMON_HEADER,
- u.type0.InterruptPin),
- sizeof(UCHAR));
-
- /* The IDE Controller is now in native mode */
- Switched = TRUE;
- }
- else
- {
- /* Settings did not work, fail */
- DPRINT1("PCI: Warning failed switch to native mode for IDE controller VEN_%04x&DEV_%04x!",
- PciData->VendorID,
- PciData->DeviceID);
- }
- }
-
- /* Return whether or not native mode was enabled on the IDE controller */
- return Switched;
-}
-
-VOID
-NTAPI
-PciApplyHacks(IN PPCI_FDO_EXTENSION DeviceExtension,
- IN PPCI_COMMON_HEADER PciData,
- IN PCI_SLOT_NUMBER SlotNumber,
- IN ULONG OperationType,
- PPCI_PDO_EXTENSION PdoExtension)
-{
- ULONG LegacyBaseAddress;
- USHORT Command;
- UCHAR RegValue;
-
- /* Check what kind of hack operation this is */
- switch (OperationType)
- {
- /*
- * This is mostly concerned with fixing up incorrect class data that can
- * exist on certain PCI hardware before the 2.0 spec was ratified.
- */
- case PCI_HACK_FIXUP_BEFORE_CONFIGURATION:
-
- /* Note that the i82375 PCI/EISA and the i82378 PCI/ISA bridges that
- * are present on certain DEC/NT Alpha machines are pre-PCI 2.0 devices
- * and appear as non-classified, so their correct class/subclass data
- * is written here instead.
- */
- if ((PciData->VendorID == 0x8086) &&
- ((PciData->DeviceID == 0x482) || (PciData->DeviceID == 0x484)))
- {
- /* Note that 0x482 is the i82375 (EISA), 0x484 is the i82378 (ISA) */
- PciData->SubClass = PciData->DeviceID == 0x482 ?
- PCI_SUBCLASS_BR_EISA : PCI_SUBCLASS_BR_ISA;
- PciData->BaseClass = PCI_CLASS_BRIDGE_DEV;
-
- /*
- * Because the software is modifying the actual header data from
- * the BIOS, this flag tells the driver to ignore failures when
- * comparing the original BIOS data with the PCI data.
- */
- if (PdoExtension) PdoExtension->ExpectedWritebackFailure = TRUE;
- }
-
- /* Note that in this case, an immediate return is issued */
- return;
-
- /*
- * This is concerned with setting up interrupts correctly for native IDE
- * mode, but will also handle broken VGA decoding on older bridges as
- * well as a PAE-specific hack for certain Compaq Hot-Plug Controllers.
- */
- case PCI_HACK_FIXUP_AFTER_CONFIGURATION:
-
- /* There should always be a PDO extension passed in */
- ASSERT(PdoExtension);
-
- /*
- * On the OPTi Viper-M IDE controller, Linux doesn't support IDE-DMA
- * and FreeBSD bug reports indicate that the system crashes when the
- * feature is enabled (so it's disabled on that OS as well). In the
- * NT PCI Bus Driver, it seems Microsoft too, completely disables
- * Native IDE functionality on this controller, so it would seem OPTi
- * simply frelled up this controller.
- */
- if ((PciData->VendorID == 0x1045) && (PciData->DeviceID != 0xC621))
- {
- /* Disable native mode */
- PciData->ProgIf &= ~5;
- PciData->u.type0.InterruptPin = 0;
-
- /*
- * Because the software is modifying the actual header data from
- * the BIOS, this flag tells the driver to ignore failures when
- * comparing the original BIOS data with the PCI data.
- */
- PdoExtension->ExpectedWritebackFailure = TRUE;
- }
- else if ((PciData->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
- (PciData->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
- {
- /* For other IDE controllers, start out in compatible mode */
- PdoExtension->BIOSAllowsIDESwitchToNativeMode = FALSE;
-
- /*
- * Registry must have enabled native mode (typically as a result
- * of an INF file directive part of the IDE controller's driver)
- * and the system must not be booted in Safe Mode. If that checks
- * out, then evaluate the ACPI NATA method to see if the platform
- * supports this. See the section "BIOS and Platform Prerequisites
- * for Switching a Native-Mode-Capable Controller" in the Storage
- * section of the Windows Driver Kit for more details:
- *
- * 5. For each ATA controller enumerated, the PCI bus driver checks
- * the Programming Interface register of the IDE controller to
- * see if it supports switching both channels to native mode.
- * 6. The PCI bus driver checks whether the BIOS/platform supports
- * switching the controller by checking the NATA method described
- * earlier in this article.
- *
- * If an ATA controller does not indicate that it is native
- * mode-capable, or if the BIOS NATA control method is missing
- * or does not list that device, the PCI bus driver does not
- * switch the controller and it is assigned legacy resources.
- *
- * If both the controller and the BIOS indicate that the controller
- * can be switched, the process of switching the controller begins
- * with the next step.
- */
- if ((PciEnableNativeModeATA) &&
- !(InitSafeBootMode) &&
- (PciIsSlotPresentInParentMethod(PdoExtension, 'ATAN')))
- {
- /* The platform supports it, remember that */
- PdoExtension->BIOSAllowsIDESwitchToNativeMode = TRUE;
-
- /*
- * Now switch the controller into native mode if both channels
- * support native IDE mode. See "How Windows Switches an ATA
- * Controller to Native Mode" in the Storage section of the
- * Windows Driver Kit for more details.
- */
- PdoExtension->IDEInNativeMode =
- PciConfigureIdeController(PdoExtension, PciData, TRUE);
- }
-
- /* Is native mode enabled after all? */
- if ((PciData->ProgIf & 5) != 5)
- {
- /* Compatible mode, so force ISA-style IRQ14 and IRQ 15 */
- PciData->u.type0.InterruptPin = 0;
- }
- }
-
- /* Is this a PCI device with legacy VGA card decodes on the root bus? */
- if ((PdoExtension->HackFlags & PCI_HACK_VIDEO_LEGACY_DECODE) &&
- (PCI_IS_ROOT_FDO(DeviceExtension)) &&
- !(DeviceExtension->BrokenVideoHackApplied))
- {
- /* Tell the arbiter to apply a hack for these older devices */
- ario_ApplyBrokenVideoHack(DeviceExtension);
- }
-
- /* Is this a Compaq PCI Hotplug Controller (r17) on a PAE system ? */
- if ((PciData->VendorID == 0xE11) &&
- (PciData->DeviceID == 0xA0F7) &&
- (PciData->RevisionID == 17) &&
- (ExIsProcessorFeaturePresent(PF_PAE_ENABLED)))
- {
- /* Turn off the decodes immediately */
- PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
- PCI_ENABLE_MEMORY_SPACE |
- PCI_ENABLE_BUS_MASTER);
- PciWriteDeviceConfig(PdoExtension,
- &PciData->Command,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
-
- /* Do not EVER turn them on again, this will blow up the system */
- PdoExtension->CommandEnables &= ~(PCI_ENABLE_IO_SPACE |
- PCI_ENABLE_MEMORY_SPACE |
- PCI_ENABLE_BUS_MASTER);
- PdoExtension->HackFlags |= PCI_HACK_PRESERVE_COMMAND;
- }
- break;
-
- /*
- * This is called whenever resources are changed and hardware needs to be
- * updated. It is concerned with two highly specific erratas on an IBM
- * hot-plug docking bridge used on the Thinkpad 600 Series and on Intel's
- * ICH PCI Bridges.
- */
- case PCI_HACK_FIXUP_BEFORE_UPDATE:
-
- /* There should always be a PDO extension passed in */
- ASSERT(PdoExtension);
-
- /* Is this an IBM 20H2999 PCI Docking Bridge, used on Thinkpads? */
- if ((PdoExtension->VendorId == 0x1014) &&
- (PdoExtension->DeviceId == 0x95))
- {
- /* Read the current command */
- PciReadDeviceConfig(PdoExtension,
- &Command,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
-
- /* Turn off the decodes */
- PciDecodeEnable(PdoExtension, FALSE, &Command);
-
- /* Apply the required IBM workaround */
- PciReadDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
- RegValue &= ~2;
- RegValue |= 1;
- PciWriteDeviceConfig(PdoExtension, &RegValue, 0xE0, sizeof(UCHAR));
-
- /* Restore the command to its original value */
- PciWriteDeviceConfig(PdoExtension,
- &Command,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
-
- }
-
- /*
- * Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
- * i820, i840, i845 Chipsets) that have subtractive decode enabled,
- * and whose hack flags do not specifiy that this support is broken.
- */
- if ((PdoExtension->HeaderType == PCI_BRIDGE_TYPE) &&
- (PdoExtension->Dependent.type1.SubtractiveDecode) &&
- ((PdoExtension->VendorId == 0x8086) &&
- ((PdoExtension->DeviceId == 0x2418) ||
- (PdoExtension->DeviceId == 0x2428) ||
- (PdoExtension->DeviceId == 0x244E) ||
- (PdoExtension->DeviceId == 0x2448))) &&
- !(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
- {
- /*
- * The positive decode window shouldn't be used, these values are
- * normally all read-only or initialized to 0 by the BIOS, but
- * it appears Intel doesn't do this, so the PCI Bus Driver will
- * do it in software instead. Note that this is used to prevent
- * certain non-compliant PCI devices from breaking down due to the
- * fact that these ICH bridges have a known "quirk" (which Intel
- * documents as a known "erratum", although it's not not really
- * an ICH bug since the PCI specification does allow for it) in
- * that they will sometimes send non-zero addresses during special
- * cycles (ie: non-zero data during the address phase). These
- * broken PCI cards will mistakenly attempt to claim the special
- * cycle and corrupt their I/O and RAM ranges. Again, in Intel's
- * defense, the PCI specification only requires stable data, not
- * necessarily zero data, during the address phase.
- */
- PciData->u.type1.MemoryBase = 0xFFFF;
- PciData->u.type1.PrefetchBase = 0xFFFF;
- PciData->u.type1.IOBase = 0xFF;
- PciData->u.type1.IOLimit = 0;
- PciData->u.type1.MemoryLimit = 0;
- PciData->u.type1.PrefetchLimit = 0;
- PciData->u.type1.PrefetchBaseUpper32 = 0;
- PciData->u.type1.PrefetchLimitUpper32 = 0;
- PciData->u.type1.IOBaseUpper16 = 0;
- PciData->u.type1.IOLimitUpper16 = 0;
- }
- break;
-
- default:
- return;
- }
-
- /* Finally, also check if this is this a CardBUS device? */
- if (PCI_CONFIGURATION_TYPE(PciData) == PCI_CARDBUS_BRIDGE_TYPE)
- {
- /*
- * At offset 44h the LegacyBaseAddress is stored, which is cleared by
- * ACPI-aware versions of Windows, to disable legacy-mode I/O access to
- * CardBus controllers. For more information, see "Supporting CardBus
- * Controllers under ACPI" in the "CardBus Controllers and Windows"
- * Whitepaper on WHDC.
- */
- LegacyBaseAddress = 0;
- PciWriteDeviceConfig(PdoExtension,
- &LegacyBaseAddress,
- sizeof(PCI_COMMON_HEADER) + sizeof(ULONG),
- sizeof(ULONG));
- }
-}
-
-BOOLEAN
-NTAPI
-PcipIsSameDevice(IN PPCI_PDO_EXTENSION DeviceExtension,
- IN PPCI_COMMON_HEADER PciData)
-{
- BOOLEAN IdMatch, RevMatch, SubsysMatch;
- ULONGLONG HackFlags = DeviceExtension->HackFlags;
-
- /* Check if the IDs match */
- IdMatch = (PciData->VendorID == DeviceExtension->VendorId) &&
- (PciData->DeviceID == DeviceExtension->DeviceId);
- if (!IdMatch) return FALSE;
-
- /* If the device has a valid revision, check if it matches */
- RevMatch = (HackFlags & PCI_HACK_NO_REVISION_AFTER_D3) ||
- (PciData->RevisionID == DeviceExtension->RevisionId);
- if (!RevMatch) return FALSE;
-
- /* For multifunction devices, this is enough to assume they're the same */
- if (PCI_MULTIFUNCTION_DEVICE(PciData)) return TRUE;
-
- /* For bridge devices, there's also nothing else that can be checked */
- if (DeviceExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) return TRUE;
-
- /* Devices, on the other hand, have subsystem data that can be compared */
- SubsysMatch = (HackFlags & (PCI_HACK_NO_SUBSYSTEM |
- PCI_HACK_NO_SUBSYSTEM_AFTER_D3)) ||
- ((DeviceExtension->SubsystemVendorId ==
- PciData->u.type0.SubVendorID) &&
- (DeviceExtension->SubsystemId ==
- PciData->u.type0.SubSystemID));
- return SubsysMatch;
-}
-
-BOOLEAN
-NTAPI
-PciSkipThisFunction(IN PPCI_COMMON_HEADER PciData,
- IN PCI_SLOT_NUMBER Slot,
- IN UCHAR OperationType,
- IN ULONGLONG HackFlags)
-{
- do
- {
- /* Check if this is device enumeration */
- if (OperationType == PCI_SKIP_DEVICE_ENUMERATION)
- {
- /* Check if there's a hackflag saying not to enumerate this device */
- if (HackFlags & PCI_HACK_NO_ENUM_AT_ALL) break;
-
- /* Check if this is the high end of a double decker device */
- if ((HackFlags & PCI_HACK_DOUBLE_DECKER) &&
- (Slot.u.bits.DeviceNumber >= 16))
- {
- /* It belongs to the same device, so skip it */
- DPRINT1(" Device (Ven %04x Dev %04x (d=0x%x, f=0x%x)) is a ghost.\n",
- PciData->VendorID,
- PciData->DeviceID,
- Slot.u.bits.DeviceNumber,
- Slot.u.bits.FunctionNumber);
- break;
- }
- }
- else if (OperationType == PCI_SKIP_RESOURCE_ENUMERATION)
- {
- /* Resource enumeration, check for a hackflag saying not to do it */
- if (HackFlags & PCI_HACK_ENUM_NO_RESOURCE) break;
- }
- else
- {
- /* Logic error in the driver */
- ASSERTMSG(FALSE, "PCI Skip Function - Operation type unknown.");
- }
-
- /* Check for legacy bridges during resource enumeration */
- if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
- (PciData->SubClass <= PCI_SUBCLASS_BR_MCA) &&
- (OperationType == PCI_SKIP_RESOURCE_ENUMERATION))
- {
- /* Their resources are not enumerated, only PCI and Cardbus/PCMCIA */
- break;
- }
- else if (PciData->BaseClass == PCI_CLASS_NOT_DEFINED)
- {
- /* Undefined base class (usually a PCI BIOS/ROM bug) */
- DPRINT1(" Vendor %04x, Device %04x has class code of PCI_CLASS_NOT_DEFINED\n",
- PciData->VendorID,
- PciData->DeviceID);
-
- /*
- * The Alder has an Intel Extended Express System Support Controller
- * which presents apparently spurious BARs. When the PCI resource
- * code tries to reassign these BARs, the second IO-APIC gets
- * disabled (with disastrous consequences). The first BAR is the
- * actual IO-APIC, the remaining five bars seem to be spurious
- * resources, so ignore this device completely.
- */
- if ((PciData->VendorID == 0x8086) && (PciData->DeviceID == 8)) break;
- }
-
- /* Other normal PCI cards and bridges are enumerated */
- if (PCI_CONFIGURATION_TYPE(PciData) <= PCI_CARDBUS_BRIDGE_TYPE) return FALSE;
- } while (FALSE);
-
- /* Hit one of the known bugs/hackflags, or this is a new kind of PCI unit */
- DPRINT1(" Device skipped (not enumerated).\n");
- return TRUE;
-}
-
-VOID
-NTAPI
-PciGetEnhancedCapabilities(IN PPCI_PDO_EXTENSION PdoExtension,
- IN PPCI_COMMON_HEADER PciData)
-{
- ULONG HeaderType, CapPtr, TargetAgpCapabilityId;
- DEVICE_POWER_STATE WakeLevel;
- PCI_CAPABILITIES_HEADER AgpCapability;
- PCI_PM_CAPABILITY PowerCapabilities;
- PAGED_CODE();
-
- /* Assume no known wake level */
- PdoExtension->PowerState.DeviceWakeLevel = PowerDeviceUnspecified;
-
- /* Make sure the device has capabilities */
- if (!(PciData->Status & PCI_STATUS_CAPABILITIES_LIST))
- {
- /* If it doesn't, there will be no power management */
- PdoExtension->CapabilitiesPtr = 0;
- PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
- }
- else
- {
- /* There's capabilities, need to figure out where to get the offset */
- HeaderType = PCI_CONFIGURATION_TYPE(PciData);
- if (HeaderType == PCI_CARDBUS_BRIDGE_TYPE)
- {
- /* Use the bridge's header */
- CapPtr = PciData->u.type2.CapabilitiesPtr;
- }
- else
- {
- /* Use the device header */
- ASSERT(HeaderType <= PCI_CARDBUS_BRIDGE_TYPE);
- CapPtr = PciData->u.type0.CapabilitiesPtr;
- }
-
- /* Make sure the pointer is spec-aligned and located, and save it */
- DPRINT1("Device has capabilities at: %lx\n", CapPtr);
- ASSERT(((CapPtr & 0x3) == 0) && (CapPtr >= PCI_COMMON_HDR_LENGTH));
- PdoExtension->CapabilitiesPtr = CapPtr;
-
- /* Check for PCI-to-PCI Bridges and AGP bridges */
- if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
- ((PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST) ||
- (PdoExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI)))
- {
- /* Query either the raw AGP capabilitity, or the Target AGP one */
- TargetAgpCapabilityId = (PdoExtension->SubClass ==
- PCI_SUBCLASS_BR_PCI_TO_PCI) ?
- PCI_CAPABILITY_ID_AGP_TARGET :
- PCI_CAPABILITY_ID_AGP;
- if (PciReadDeviceCapability(PdoExtension,
- PdoExtension->CapabilitiesPtr,
- TargetAgpCapabilityId,
- &AgpCapability,
- sizeof(PCI_CAPABILITIES_HEADER)))
- {
- /* AGP target ID was found, store it */
- DPRINT1("AGP ID: %lx\n", TargetAgpCapabilityId);
- PdoExtension->TargetAgpCapabilityId = TargetAgpCapabilityId;
- }
- }
-
- /* Check for devices that are known not to have proper power management */
- if (!(PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS))
- {
- /* Query if this device supports power management */
- if (!PciReadDeviceCapability(PdoExtension,
- PdoExtension->CapabilitiesPtr,
- PCI_CAPABILITY_ID_POWER_MANAGEMENT,
- &PowerCapabilities.Header,
- sizeof(PCI_PM_CAPABILITY)))
- {
- /* No power management, so act as if it had the hackflag set */
- DPRINT1("No PM caps, disabling PM\n");
- PdoExtension->HackFlags |= PCI_HACK_NO_PM_CAPS;
- }
- else
- {
- /* Otherwise, pick the highest wake level that is supported */
- WakeLevel = PowerDeviceUnspecified;
- if (PowerCapabilities.PMC.Capabilities.Support.PMED0)
- WakeLevel = PowerDeviceD0;
- if (PowerCapabilities.PMC.Capabilities.Support.PMED1)
- WakeLevel = PowerDeviceD1;
- if (PowerCapabilities.PMC.Capabilities.Support.PMED2)
- WakeLevel = PowerDeviceD2;
- if (PowerCapabilities.PMC.Capabilities.Support.PMED3Hot)
- WakeLevel = PowerDeviceD3;
- if (PowerCapabilities.PMC.Capabilities.Support.PMED3Cold)
- WakeLevel = PowerDeviceD3;
- PdoExtension->PowerState.DeviceWakeLevel = WakeLevel;
-
- /* Convert the PCI power state to the NT power state */
- PdoExtension->PowerState.CurrentDeviceState =
- PowerCapabilities.PMCSR.ControlStatus.PowerState + 1;
-
- /* Save all the power capabilities */
- PdoExtension->PowerCapabilities = PowerCapabilities.PMC.Capabilities;
- DPRINT1("PM Caps Found! Wake Level: %d Power State: %d\n",
- WakeLevel, PdoExtension->PowerState.CurrentDeviceState);
- }
- }
- }
-
- /* At the very end of all this, does this device not have power management? */
- if (PdoExtension->HackFlags & PCI_HACK_NO_PM_CAPS)
- {
- /* Then guess the current state based on whether the decodes are on */
- PdoExtension->PowerState.CurrentDeviceState =
- PciData->Command & (PCI_ENABLE_IO_SPACE |
- PCI_ENABLE_MEMORY_SPACE |
- PCI_ENABLE_BUS_MASTER) ?
- PowerDeviceD0: PowerDeviceD3;
- DPRINT1("PM is off, so assumed device is: %d based on enables\n",
- PdoExtension->PowerState.CurrentDeviceState);
- }
-}
-
-VOID
-NTAPI
-PciWriteLimitsAndRestoreCurrent(IN PVOID Reserved,
- IN PVOID Context2)
-{
- PPCI_CONFIGURATOR_CONTEXT Context = Context2;
- PPCI_COMMON_HEADER PciData, Current;
- PPCI_PDO_EXTENSION PdoExtension;
-
- /* Grab all parameters from the context */
- PdoExtension = Context->PdoExtension;
- Current = Context->Current;
- PciData = Context->PciData;
-
- /* Write the limit discovery header */
- PciWriteDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
-
- /* Now read what the device indicated the limits are */
- PciReadDeviceConfig(PdoExtension, PciData, 0, PCI_COMMON_HDR_LENGTH);
-
- /* Then write back the original configuration header */
- PciWriteDeviceConfig(PdoExtension, Current, 0, PCI_COMMON_HDR_LENGTH);
-
- /* Copy back the original command that was saved in the context */
- Current->Command = Context->Command;
- if (Context->Command)
- {
- /* Program it back into the device */
- PciWriteDeviceConfig(PdoExtension,
- &Context->Command,
- FIELD_OFFSET(PCI_COMMON_HEADER, Command),
- sizeof(USHORT));
- }
-
- /* Copy back the original status that was saved as well */
- Current->Status = Context->Status;
-
- /* Call the configurator to restore any other data that might've changed */
- Context->Configurator->RestoreCurrent(Context);
-}
-
-NTSTATUS
-NTAPI
-PcipGetFunctionLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
-{
- PPCI_CONFIGURATOR Configurator;
- PPCI_COMMON_HEADER PciData, Current;
- PPCI_PDO_EXTENSION PdoExtension;
- PCI_IPI_CONTEXT IpiContext;
- PIO_RESOURCE_DESCRIPTOR IoDescriptor;
- ULONG Offset;
- PAGED_CODE();
-
- /* Grab all parameters from the context */
- PdoExtension = Context->PdoExtension;
- Current = Context->Current;
- PciData = Context->PciData;
-
- /* Save the current PCI Command and Status word */
- Context->Status = Current->Status;
- Context->Command = Current->Command;
-
- /* Now that they're saved, clear the status, and disable all decodes */
- Current->Status = 0;
- Current->Command &= ~(PCI_ENABLE_IO_SPACE |
- PCI_ENABLE_MEMORY_SPACE |
- PCI_ENABLE_BUS_MASTER);
-
- /* Make a copy of the current PCI configuration header (with decodes off) */
- RtlCopyMemory(PciData, Current, PCI_COMMON_HDR_LENGTH);
-
- /* Locate the correct resource configurator for this type of device */
- Configurator = &PciConfigurators[PdoExtension->HeaderType];
- Context->Configurator = Configurator;
-
- /* Initialize it, which will typically setup the BARs for limit discovery */
- Configurator->Initialize(Context);
-
- /* Check for critical devices and PCI Debugging devices */
- if ((PdoExtension->HackFlags & PCI_HACK_CRITICAL_DEVICE) ||
- (PdoExtension->OnDebugPath))
- {
- /* Specifically check for a PCI Debugging device */
- if (PdoExtension->OnDebugPath)
- {
- /* Was it enabled for bus mastering? */
- if (Context->Command & PCI_ENABLE_BUS_MASTER)
- {
- /* This decode needs to be re-enabled so debugging can work */
- PciData->Command |= PCI_ENABLE_BUS_MASTER;
- Current->Command |= PCI_ENABLE_BUS_MASTER;
- }
-
- /* Disable the debugger while the discovery is happening */
- KdDisableDebugger();
- }
-
- /* For these devices, an IPI must be sent to force high-IRQL discovery */
- IpiContext.Barrier = 1;
- IpiContext.RunCount = 1;
- IpiContext.DeviceExtension = PdoExtension;
- IpiContext.Function = PciWriteLimitsAndRestoreCurrent;
- IpiContext.Context = Context;
- KeIpiGenericCall(PciExecuteCriticalSystemRoutine, (ULONG_PTR)&IpiContext);
-
- /* Re-enable the debugger if this was a PCI Debugging Device */
- if (PdoExtension->OnDebugPath) KdEnableDebugger();
- }
- else
- {
- /* Otherwise, it's safe to do this in-line at low IRQL */
- PciWriteLimitsAndRestoreCurrent(PdoExtension, Context);
- }
-
- /*
- * Check if it's valid to compare the headers to see if limit discovery mode
- * has properly exited (the expected case is that the PCI header would now
- * be equal to what it was before). In some cases, it is known that this will
- * fail, because during PciApplyHacks (among other places), software hacks
- * had to be applied to the header, which the hardware-side will not see, and
- * thus the headers would appear "different".
- */
- if (!PdoExtension->ExpectedWritebackFailure)
- {
- /* Read the current PCI header now, after discovery has completed */
- PciReadDeviceConfig(PdoExtension, PciData + 1, 0, PCI_COMMON_HDR_LENGTH);
-
- /* Check if the current header at entry, is equal to the header now */
- Offset = RtlCompareMemory(PciData + 1, Current, PCI_COMMON_HDR_LENGTH);
- if (Offset != PCI_COMMON_HDR_LENGTH)
- {
- /* It's not, which means configuration somehow changed, dump this */
- DPRINT1("PCI - CFG space write verify failed at offset 0x%x\n", Offset);
- PciDebugDumpCommonConfig(PciData + 1);
- DPRINT1("----------\n");
- PciDebugDumpCommonConfig(Current);
- }
- }
-
- /* This PDO should not already have resources, since this is only done once */
- ASSERT(PdoExtension->Resources == NULL);
-
- /* Allocate the structure that will hold the discovered resources and limits */
- PdoExtension->Resources = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(PCI_FUNCTION_RESOURCES),
- 'BicP');
- if (!PdoExtension->Resources) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Clear it out for now */
- RtlZeroMemory(PdoExtension->Resources, sizeof(PCI_FUNCTION_RESOURCES));
-
- /* Now call the configurator, which will first store the limits... */
- Configurator->SaveLimits(Context);
-
- /* ...and then store the current resources being used */
- Configurator->SaveCurrentSettings(Context);
-
- /* Loop all the limit descriptors backwards */
- IoDescriptor = &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1];
- while (TRUE)
- {
- /* Keep going until a non-null descriptor is found */
- IoDescriptor--;
- if (IoDescriptor->Type != CmResourceTypeNull) break;
-
- /* This is a null descriptor, is it the last one? */
- if (IoDescriptor == &PdoExtension->Resources->Limit[PCI_TYPE0_ADDRESSES + 1])
- {
- /* This means the descriptor is NULL, which means discovery failed */
- DPRINT1("PCI Resources fail!\n");
-
- /* No resources will be assigned for the device */
- ExFreePoolWithTag(PdoExtension->Resources, 0);
- PdoExtension->Resources = NULL;
- break;
- }
- }
-
- /* Return success here, even if the device has no assigned resources */
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-PciGetFunctionLimits(IN PPCI_PDO_EXTENSION PdoExtension,
- IN PPCI_COMMON_HEADER Current,
- IN ULONGLONG HackFlags)
-{
- NTSTATUS Status;
- PPCI_COMMON_HEADER PciData;
- PCI_CONFIGURATOR_CONTEXT Context;
- PAGED_CODE();
-
- /* Do the hackflags indicate this device should be skipped? */
- if (PciSkipThisFunction(Current,
- PdoExtension->Slot,
- PCI_SKIP_RESOURCE_ENUMERATION,
- HackFlags))
- {
- /* Do not process its resources */
- return STATUS_SUCCESS;
- }
-
- /* Allocate a buffer to hold two PCI configuration headers */
- PciData = ExAllocatePoolWithTag(0, 2 * PCI_COMMON_HDR_LENGTH, 'BicP');
- if (!PciData) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Set up the context for the resource enumeration, and do it */
- Context.Current = Current;
- Context.PciData = PciData;
- Context.PdoExtension = PdoExtension;
- Status = PcipGetFunctionLimits(&Context);
-
- /* Enumeration is completed, free the PCI headers and return the status */
- ExFreePoolWithTag(PciData, 0);
- return Status;
-}
-
-VOID
-NTAPI
-PciProcessBus(IN PPCI_FDO_EXTENSION DeviceExtension)
-{
- PPCI_PDO_EXTENSION PdoExtension;
- PDEVICE_OBJECT PhysicalDeviceObject;
- PAGED_CODE();
-
- /* Get the PDO Extension */
- PhysicalDeviceObject = DeviceExtension->PhysicalDeviceObject;
- PdoExtension = (PPCI_PDO_EXTENSION)PhysicalDeviceObject->DeviceExtension;
-
- /* Cheeck if this is the root bus */
- if (!PCI_IS_ROOT_FDO(DeviceExtension))
- {
- /* Not really handling this year */
- UNIMPLEMENTED;
- while (TRUE);
-
- /* Check for PCI bridges with the ISA bit set, or required */
- if ((PdoExtension) &&
- (PciClassifyDeviceType(PdoExtension) == PciTypePciBridge) &&
- ((PdoExtension->Dependent.type1.IsaBitRequired) ||
- (PdoExtension->Dependent.type1.IsaBitSet)))
- {
- /* We'll need to do some legacy support */
- UNIMPLEMENTED;
- while (TRUE);
- }
- }
- else
- {
- /* Scan all of the root bus' children bridges */
- for (PdoExtension = DeviceExtension->ChildBridgePdoList;
- PdoExtension;
- PdoExtension = PdoExtension->NextBridge)
- {
- /* Find any that have the VGA decode bit on */
- if (PdoExtension->Dependent.type1.VgaBitSet)
- {
- /* Again, some more legacy support we'll have to do */
- UNIMPLEMENTED;
- while (TRUE);
- }
- }
- }
-
- /* Check for ACPI systems where the OS assigns bus numbers */
- if (PciAssignBusNumbers)
- {
- /* Not yet supported */
- UNIMPLEMENTED;
- while (TRUE);
- }
-}
-
-NTSTATUS
-NTAPI
-PciScanBus(IN PPCI_FDO_EXTENSION DeviceExtension)
-{
- ULONG MaxDevice = PCI_MAX_DEVICES;
- BOOLEAN ProcessFlag = FALSE;
- ULONG i, j, k, Size;
- USHORT CapOffset, TempOffset;
- LONGLONG HackFlags;
- PDEVICE_OBJECT DeviceObject;
- UCHAR Buffer[PCI_COMMON_HDR_LENGTH];
- UCHAR BiosBuffer[PCI_COMMON_HDR_LENGTH];
- PPCI_COMMON_HEADER PciData = (PVOID)Buffer;
- PPCI_COMMON_HEADER BiosData = (PVOID)BiosBuffer;
- PCI_SLOT_NUMBER PciSlot;
- PCHAR Name;
- NTSTATUS Status;
- PPCI_PDO_EXTENSION PdoExtension, NewExtension;
- PPCI_PDO_EXTENSION* BridgeExtension;
- PWCHAR DescriptionText;
- USHORT SubVendorId, SubSystemId;
- PCI_CAPABILITIES_HEADER CapHeader, PcixCapHeader;
- UCHAR SecondaryBus;
- DPRINT1("PCI Scan Bus: FDO Extension @ 0x%x, Base Bus = 0x%x\n",
- DeviceExtension, DeviceExtension->BaseBus);
-
- /* Is this the root FDO? */
- if (!PCI_IS_ROOT_FDO(DeviceExtension))
- {
- /* Get the PDO for the child bus */
- PdoExtension = DeviceExtension->PhysicalDeviceObject->DeviceExtension;
- ASSERT_PDO(PdoExtension);
-
- /* Check for hack which only allows bus to have one child device */
- if (PdoExtension->HackFlags & PCI_HACK_ONE_CHILD) MaxDevice = 1;
-
- /* Check if the secondary bus number has changed */
- PciReadDeviceConfig(PdoExtension,
- &SecondaryBus,
- FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.SecondaryBus),
- sizeof(UCHAR));
- if (SecondaryBus != PdoExtension->Dependent.type1.SecondaryBus)
- {
- DPRINT1("PCI: Bus numbers have been changed! Restoring originals.\n");
- UNIMPLEMENTED;
- while (TRUE);
- }
- }
-
- /* Loop every device on the bus */
- PciSlot.u.bits.Reserved = 0;
- i = DeviceExtension->BaseBus;
- for (j = 0; j < MaxDevice; j++)
- {
- /* Loop every function of each device */
- PciSlot.u.bits.DeviceNumber = j;
- for (k = 0; k < PCI_MAX_FUNCTION; k++)
- {
- /* Build the final slot structure */
- PciSlot.u.bits.FunctionNumber = k;
-
- /* Read the vendor for this slot */
- PciReadSlotConfig(DeviceExtension,
- PciSlot,
- PciData,
- 0,
- sizeof(USHORT));
-
- /* Skip invalid device */
- if (PciData->VendorID == PCI_INVALID_VENDORID) continue;
-
- /* Now read the whole header */
- PciReadSlotConfig(DeviceExtension,
- PciSlot,
- &PciData->DeviceID,
- sizeof(USHORT),
- PCI_COMMON_HDR_LENGTH - sizeof(USHORT));
-
- /* Apply any hacks before even analyzing the configuration header */
- PciApplyHacks(DeviceExtension,
- PciData,
- PciSlot,
- PCI_HACK_FIXUP_BEFORE_CONFIGURATION,
- NULL);
-
- /* Dump device that was found */
- DPRINT1("Scan Found Device 0x%x (b=0x%x, d=0x%x, f=0x%x)\n",
- PciSlot.u.AsULONG,
- i,
- j,
- k);
-
- /* Dump the device's header */
- PciDebugDumpCommonConfig(PciData);
-
- /* Find description for this device for the debugger's sake */
- DescriptionText = PciGetDeviceDescriptionMessage(PciData->BaseClass,
- PciData->SubClass);
- DPRINT1("Device Description \"%S\".\n",
- DescriptionText ? DescriptionText : L"(NULL)");
- if (DescriptionText) ExFreePoolWithTag(DescriptionText, 0);
-
- /* Check if there is an ACPI Watchdog Table */
- if (WdTable)
- {
- /* Check if this PCI device is the ACPI Watchdog Device... */
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Check for non-simple devices */
- if ((PCI_MULTIFUNCTION_DEVICE(PciData)) ||
- (PciData->BaseClass == PCI_CLASS_BRIDGE_DEV))
- {
- /* No subsystem data defined for these kinds of bridges */
- SubVendorId = 0;
- SubSystemId = 0;
- }
- else
- {
- /* Read the subsystem information from the PCI header */
- SubVendorId = PciData->u.type0.SubVendorID;
- SubSystemId = PciData->u.type0.SubSystemID;
- }
-
- /* Get any hack flags for this device */
- HackFlags = PciGetHackFlags(PciData->VendorID,
- PciData->DeviceID,
- SubVendorId,
- SubSystemId,
- PciData->RevisionID);
-
- /* Check if this device is considered critical by the OS */
- if (PciIsCriticalDeviceClass(PciData->BaseClass, PciData->SubClass))
- {
- /* Check if normally the decodes would be disabled */
- if (!(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
- {
- /* Because this device is critical, don't disable them */
- DPRINT1("Not allowing PM Because device is critical\n");
- HackFlags |= PCI_HACK_CRITICAL_DEVICE;
- }
- }
-
- /* PCI bridges with a VGA card are also considered critical */
- if ((PciData->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
- (PciData->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) &&
- (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA) &&
- !(HackFlags & PCI_HACK_DONT_DISABLE_DECODES))
- {
- /* Do not disable their decodes either */
- DPRINT1("Not allowing PM because device is VGA\n");
- HackFlags |= PCI_HACK_CRITICAL_DEVICE;
- }
-
- /* Check if the device should be skipped for whatever reason */
- if (PciSkipThisFunction(PciData,
- PciSlot,
- PCI_SKIP_DEVICE_ENUMERATION,
- HackFlags))
- {
- /* Skip this device */
- continue;
- }
-
- /* Check if a PDO has already been created for this device */
- PdoExtension = PciFindPdoByFunction(DeviceExtension,
- PciSlot.u.AsULONG,
- PciData);
- if (PdoExtension)
- {
- /* Rescan scenarios are not yet implemented */
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Bus processing will need to happen */
- ProcessFlag = TRUE;
-
- /* Create the PDO for this device */
- Status = PciPdoCreate(DeviceExtension, PciSlot, &DeviceObject);
- ASSERT(NT_SUCCESS(Status));
- NewExtension = (PPCI_PDO_EXTENSION)DeviceObject->DeviceExtension;
-
- /* Check for broken devices with wrong/no class codes */
- if (HackFlags & PCI_HACK_FAKE_CLASS_CODE)
- {
- /* Setup a default one */
- PciData->BaseClass = PCI_CLASS_BASE_SYSTEM_DEV;
- PciData->SubClass = PCI_SUBCLASS_SYS_OTHER;
-
- /* Device will behave erratically when reading back data */
- NewExtension->ExpectedWritebackFailure = TRUE;
- }
-
- /* Clone all the information from the header */
- NewExtension->VendorId = PciData->VendorID;
- NewExtension->DeviceId = PciData->DeviceID;
- NewExtension->RevisionId = PciData->RevisionID;
- NewExtension->ProgIf = PciData->ProgIf;
- NewExtension->SubClass = PciData->SubClass;
- NewExtension->BaseClass = PciData->BaseClass;
- NewExtension->HeaderType = PCI_CONFIGURATION_TYPE(PciData);
-
- /* Check for modern bridge types, which are managed by the driver */
- if ((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
- ((NewExtension->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI) ||
- (NewExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS)))
- {
- /* Acquire this device's lock */
- KeEnterCriticalRegion();
- KeWaitForSingleObject(&DeviceExtension->ChildListLock,
- Executive,
- KernelMode,
- FALSE,
- NULL);
-
- /* Scan the bridge list until the first free entry */
- for (BridgeExtension = &DeviceExtension->ChildBridgePdoList;
- *BridgeExtension;
- BridgeExtension = &(*BridgeExtension)->NextBridge);
-
- /* Add this PDO as a bridge */
- *BridgeExtension = NewExtension;
- ASSERT(NewExtension->NextBridge == NULL);
-
- /* Release this device's lock */
- KeSetEvent(&DeviceExtension->ChildListLock,
- IO_NO_INCREMENT,
- FALSE);
- KeLeaveCriticalRegion();
- }
-
- /* Get the PCI BIOS configuration saved in the registry */
- Status = PciGetBiosConfig(NewExtension, BiosData);
- if (NT_SUCCESS(Status))
- {
- /* This path has not yet been fully tested by eVb */
- DPRINT1("Have BIOS configuration!\n");
- UNIMPLEMENTED;
-
- /* Check if the PCI BIOS configuration has changed */
- if (!PcipIsSameDevice(NewExtension, BiosData))
- {
- /* This is considered failure, and new data will be saved */
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
- /* Data is still correct, check for interrupt line change */
- if (BiosData->u.type0.InterruptLine !=
- PciData->u.type0.InterruptLine)
- {
- /* Update the current BIOS with the saved interrupt line */
- PciWriteDeviceConfig(NewExtension,
- &BiosData->u.type0.InterruptLine,
- FIELD_OFFSET(PCI_COMMON_HEADER,
- u.type0.InterruptLine),
- sizeof(UCHAR));
- }
-
- /* Save the BIOS interrupt line and the initial command */
- NewExtension->RawInterruptLine = BiosData->u.type0.InterruptLine;
- NewExtension->InitialCommand = BiosData->Command;
- }
- }
-
- /* Check if no saved data was present or if it was a mismatch */
- if (!NT_SUCCESS(Status))
- {
- /* Save the new data */
- Status = PciSaveBiosConfig(NewExtension, PciData);
- ASSERT(NT_SUCCESS(Status));
-
- /* Save the interrupt line and command from the device */
- NewExtension->RawInterruptLine = PciData->u.type0.InterruptLine;
- NewExtension->InitialCommand = PciData->Command;
- }
-
- /* Save original command from the device and hack flags */
- NewExtension->CommandEnables = PciData->Command;
- NewExtension->HackFlags = HackFlags;
-
- /* Get power, AGP, and other capability data */
- PciGetEnhancedCapabilities(NewExtension, PciData);
-
- /* Now configure the BARs */
- Status = PciGetFunctionLimits(NewExtension, PciData, HackFlags);
-
- /* Power up the device */
- PciSetPowerManagedDevicePowerState(NewExtension, PowerDeviceD0, FALSE);
-
- /* Apply any device hacks required for enumeration */
- PciApplyHacks(DeviceExtension,
- PciData,
- PciSlot,
- PCI_HACK_FIXUP_AFTER_CONFIGURATION,
- NewExtension);
-
- /* Save interrupt pin */
- NewExtension->InterruptPin = PciData->u.type0.InterruptPin;
-
- /*
- * Use either this device's actual IRQ line or, if it's connected on
- * a master bus whose IRQ line is actually connected to the host, use
- * the HAL to query the bus' IRQ line and store that as the adjusted
- * interrupt line instead
- */
- NewExtension->AdjustedInterruptLine = PciGetAdjustedInterruptLine(NewExtension);
-
- /* Check if this device is used for PCI debugger cards */
- NewExtension->OnDebugPath = PciIsDeviceOnDebugPath(NewExtension);
-
- /* Check for devices with invalid/bogus subsystem data */
- if (HackFlags & PCI_HACK_NO_SUBSYSTEM)
- {
- /* Set the subsystem information to zero instead */
- NewExtension->SubsystemVendorId = 0;
- NewExtension->SubsystemId = 0;
- }
-
- /* Scan all capabilities */
- CapOffset = NewExtension->CapabilitiesPtr;
- while (CapOffset)
- {
- /* Read this header */
- TempOffset = PciReadDeviceCapability(NewExtension,
- CapOffset,
- 0,
- &CapHeader,
- sizeof(PCI_CAPABILITIES_HEADER));
- if (TempOffset != CapOffset)
- {
- /* This is a strange issue that shouldn't happen normally */
- DPRINT1("PCI - Failed to read PCI capability at offset 0x%02x\n",
- CapOffset);
- ASSERT(TempOffset == CapOffset);
- }
-
- /* Check for capabilities that this driver cares about */
- switch (CapHeader.CapabilityID)
- {
- /* Power management capability is heavily used by the bus */
- case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
-
- /* Dump the capability */
- Name = "POWER";
- Size = sizeof(PCI_PM_CAPABILITY);
- break;
-
- /* AGP capability is required for AGP bus functionality */
- case PCI_CAPABILITY_ID_AGP:
-
- /* Dump the capability */
- Name = "AGP";
- Size = sizeof(PCI_AGP_CAPABILITY);
- break;
-
- /* This driver doesn't really use anything other than that */
- default:
-
- /* Windows prints this, we could do a translation later */
- Name = "UNKNOWN CAPABILITY";
- Size = 0;
- break;
- }
-
- /* Check if this is a capability that should be dumped */
- if (Size)
- {
- /* Read the whole capability data */
- TempOffset = PciReadDeviceCapability(NewExtension,
- CapOffset,
- CapHeader.CapabilityID,
- &CapHeader,
- Size);
-
- if (TempOffset != CapOffset)
- {
- /* Again, a strange issue that shouldn't be seen */
- DPRINT1("- Failed to read capability data. ***\n");
- ASSERT(TempOffset == CapOffset);
- }
- }
-
- /* Dump this capability */
- DPRINT1("CAP @%02x ID %02x (%s)\n",
- CapOffset, CapHeader.CapabilityID, Name);
- for (i = 0; i < Size; i += 2)
- DPRINT1(" %04x\n", *(PUSHORT)((ULONG_PTR)&CapHeader + i));
- DPRINT1("\n");
-
- /* Check the next capability */
- CapOffset = CapHeader.Next;
- }
-
- /* Check for IDE controllers */
- if ((NewExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
- (NewExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
- {
- /* Do not allow them to power down completely */
- NewExtension->DisablePowerDown = TRUE;
- }
-
- /*
- * Check if this is a legacy bridge. Note that the i82375 PCI/EISA
- * bridge that is present on certain NT Alpha machines appears as
- * non-classified so detect it manually by scanning for its VID/PID.
- */
- if (((NewExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
- ((NewExtension->SubClass == PCI_SUBCLASS_BR_ISA) ||
- (NewExtension->SubClass == PCI_SUBCLASS_BR_EISA) ||
- (NewExtension->SubClass == PCI_SUBCLASS_BR_MCA))) ||
- ((NewExtension->VendorId == 0x8086) &&
- (NewExtension->DeviceId == 0x482)))
- {
- /* Do not allow these legacy bridges to be powered down */
- NewExtension->DisablePowerDown = TRUE;
- }
-
- /* Check if the BIOS did not configure a cache line size */
- if (!PciData->CacheLineSize)
- {
- /* Check if the device is disabled */
- if (!(NewExtension->CommandEnables & (PCI_ENABLE_IO_SPACE |
- PCI_ENABLE_MEMORY_SPACE |
- PCI_ENABLE_BUS_MASTER)))
- {
- /* Check if this is a PCI-X device*/
- TempOffset = PciReadDeviceCapability(NewExtension,
- NewExtension->CapabilitiesPtr,
- PCI_CAPABILITY_ID_PCIX,
- &PcixCapHeader,
- sizeof(PCI_CAPABILITIES_HEADER));
-
- /*
- * A device with default cache line size and latency timer
- * settings is considered to be unconfigured. Note that on
- * PCI-X, the reset value of the latency timer field in the
- * header is 64, not 0, hence why the check for PCI-X caps
- * was required, and the value used here below.
- */
- if (!(PciData->LatencyTimer) ||
- ((TempOffset) && (PciData->LatencyTimer == 64)))
- {
- /* Keep track of the fact that it needs configuration */
- DPRINT1("PCI - ScanBus, PDOx %x found unconfigured\n",
- NewExtension);
- NewExtension->NeedsHotPlugConfiguration = TRUE;
- }
- }
- }
-
- /* Save latency and cache size information */
- NewExtension->SavedLatencyTimer = PciData->LatencyTimer;
- NewExtension->SavedCacheLineSize = PciData->CacheLineSize;
-
- /* The PDO is now ready to go */
- DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
- }
- }
-
- /* Enumeration completed, do a final pass now that all devices are found */
- if (ProcessFlag) PciProcessBus(DeviceExtension);
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-PciQueryDeviceRelations(IN PPCI_FDO_EXTENSION DeviceExtension,
- IN OUT PDEVICE_RELATIONS *pDeviceRelations)
-{
- NTSTATUS Status;
- PPCI_PDO_EXTENSION PdoExtension;
- ULONG PdoCount = 0;
- PDEVICE_RELATIONS DeviceRelations, NewRelations;
- SIZE_T Size;
- PDEVICE_OBJECT DeviceObject, *ObjectArray;
- PAGED_CODE();
-
- /* Make sure the FDO is started */
- ASSERT(DeviceExtension->DeviceState == PciStarted);
-
- /* Synchronize while we enumerate the bus */
- Status = PciBeginStateTransition(DeviceExtension, PciSynchronizedOperation);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Scan all children PDO */
- for (PdoExtension = DeviceExtension->ChildPdoList;
- PdoExtension;
- PdoExtension = PdoExtension->Next)
- {
- /* Invalidate them */
- PdoExtension->NotPresent = TRUE;
- }
-
- /* Scan the PCI Bus */
- Status = PciScanBus(DeviceExtension);
- ASSERT(NT_SUCCESS(Status));
-
- /* Enumerate all children PDO again */
- for (PdoExtension = DeviceExtension->ChildPdoList;
- PdoExtension;
- PdoExtension = PdoExtension->Next)
- {
- /* Check for PDOs that are still invalidated */
- if (PdoExtension->NotPresent)
- {
- /* This means this PDO existed before, but not anymore */
- PdoExtension->ReportedMissing = TRUE;
- DPRINT1("PCI - Old device (pdox) %08x not found on rescan.\n",
- PdoExtension);
- }
- else
- {
- /* Increase count of detected PDOs */
- PdoCount++;
- }
- }
-
- /* Read the current relations and add the newly discovered relations */
- DeviceRelations = *pDeviceRelations;
- Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
- PdoCount * sizeof(PDEVICE_OBJECT);
- if (DeviceRelations) Size += sizeof(PDEVICE_OBJECT) * DeviceRelations->Count;
-
- /* Allocate the device relations */
- NewRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(0, Size, 'BicP');
- if (!NewRelations)
- {
- /* Out of space, cancel the operation */
- PciCancelStateTransition(DeviceExtension, PciSynchronizedOperation);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- /* Check if there were any older relations */
- NewRelations->Count = 0;
- if (DeviceRelations)
- {
- /* Copy the old relations into the new buffer, then free the old one */
- RtlCopyMemory(NewRelations,
- DeviceRelations,
- FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
- DeviceRelations->Count * sizeof(PDEVICE_OBJECT));
- ExFreePoolWithTag(DeviceRelations, 0);
- }
-
- /* Print out that we're ready to dump relations */
- DPRINT1("PCI QueryDeviceRelations/BusRelations FDOx %08x (bus 0x%02x)\n",
- DeviceExtension,
- DeviceExtension->BaseBus);
-
- /* Loop the current PDO children and the device relation object array */
- PdoExtension = DeviceExtension->ChildPdoList;
- ObjectArray = &NewRelations->Objects[NewRelations->Count];
- while (PdoExtension)
- {
- /* Dump this relation */
- DPRINT1(" QDR PDO %08x (x %08x)%s\n",
- PdoExtension->PhysicalDeviceObject,
- PdoExtension,
- PdoExtension->NotPresent ?
- "<Omitted, device flaged not present>" : "");
-
- /* Is this PDO present? */
- if (!PdoExtension->NotPresent)
- {
- /* Reference it and add it to the array */
- DeviceObject = PdoExtension->PhysicalDeviceObject;
- ObfReferenceObject(DeviceObject);
- *ObjectArray++ = DeviceObject;
- }
-
- /* Go to the next PDO */
- PdoExtension = PdoExtension->Next;
- }
-
- /* Terminate dumping the relations */
- DPRINT1(" QDR Total PDO count = %d (%d already in list)\n",
- NewRelations->Count + PdoCount,
- NewRelations->Count);
-
- /* Return the final count and the new buffer */
- NewRelations->Count += PdoCount;
- *pDeviceRelations = NewRelations;
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-PciSetResources(IN PPCI_PDO_EXTENSION PdoExtension,
- IN BOOLEAN DoReset,
- IN BOOLEAN SomethingSomethingDarkSide)
-{
- PPCI_FDO_EXTENSION FdoExtension;
- UCHAR NewCacheLineSize, NewLatencyTimer;
- PCI_COMMON_HEADER PciData;
- BOOLEAN Native;
- PPCI_CONFIGURATOR Configurator;
-
- /* Get the FDO and read the configuration data */
- FdoExtension = PdoExtension->ParentFdoExtension;
- PciReadDeviceConfig(PdoExtension, &PciData, 0, PCI_COMMON_HDR_LENGTH);
-
- /* Make sure this is still the same device */
- if (!PcipIsSameDevice(PdoExtension, &PciData))
- {
- /* Fail */
- ASSERTMSG(FALSE, "PCI Set resources - not same device");
- return STATUS_DEVICE_DOES_NOT_EXIST;
- }
-
- /* Nothing to set for a host bridge */
- if ((PdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
- (PdoExtension->SubClass == PCI_SUBCLASS_BR_HOST))
- {
- /* Fake success */
- return STATUS_SUCCESS;
- }
-
- /* Check if an IDE controller is being reset */
- if ((DoReset) &&
- (PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
- (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR))
- {
- /* Turn off native mode */
- Native = PciConfigureIdeController(PdoExtension, &PciData, FALSE);
- ASSERT(Native == PdoExtension->IDEInNativeMode);
- }
-
- /* Check for update of a hotplug device, or first configuration of one */
- if ((PdoExtension->NeedsHotPlugConfiguration) &&
- (FdoExtension->HotPlugParameters.Acquired))
- {
- /* Don't have hotplug devices to test with yet, QEMU 0.14 should */
- UNIMPLEMENTED;
- while (TRUE);
- }
-
- /* Locate the correct resource configurator for this type of device */
- Configurator = &PciConfigurators[PdoExtension->HeaderType];
-
- /* Apply the settings change */
- Configurator->ChangeResourceSettings(PdoExtension, &PciData);
-
- /* Assume no update needed */
- PdoExtension->UpdateHardware = FALSE;
-
- /* Check if a reset is needed */
- if (DoReset)
- {
- /* Reset resources */
- Configurator->ResetDevice(PdoExtension, &PciData);
- PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine;
- }
-
- /* Check if the latency timer changed */
- NewLatencyTimer = PdoExtension->SavedLatencyTimer;
- if (PciData.LatencyTimer != NewLatencyTimer)
- {
- /* Debug notification */
- DPRINT1("PCI (pdox %08x) changing latency from %02x to %02x.\n",
- PdoExtension,
- PciData.LatencyTimer,
- NewLatencyTimer);
- }
-
- /* Check if the cache line changed */
- NewCacheLineSize = PdoExtension->SavedCacheLineSize;
- if (PciData.CacheLineSize != NewCacheLineSize)
- {
- /* Debug notification */
- DPRINT1("PCI (pdox %08x) changing cache line size from %02x to %02x.\n",
- PdoExtension,
- PciData.CacheLineSize,
- NewCacheLineSize);
- }
-
- /* Inherit data from PDO extension */
- PciData.LatencyTimer = PdoExtension->SavedLatencyTimer;
- PciData.CacheLineSize = PdoExtension->SavedCacheLineSize;
- PciData.u.type0.InterruptLine = PdoExtension->RawInterruptLine;
-
- /* Apply any resource hacks required */
- PciApplyHacks(FdoExtension,
- &PciData,
- PdoExtension->Slot,
- PCI_HACK_FIXUP_BEFORE_UPDATE,
- PdoExtension);
-
- /* Check if I/O space was disabled by administrator or driver */
- if (PdoExtension->IoSpaceNotRequired)
- {
- /* Don't turn on the decode */
- PdoExtension->CommandEnables &= ~PCI_ENABLE_IO_SPACE;
- }
-
- /* Update the device with the new settings */
- PciUpdateHardware(PdoExtension, &PciData);
-
- /* Update complete */
- PdoExtension->RawInterruptLine = PciData.u.type0.InterruptLine;
- PdoExtension->NeedsHotPlugConfiguration = FALSE;
- return STATUS_SUCCESS;
-}
-
-/* EOF */