windows-nt/Source/XPSP1/NT/base/busdrv/pci/cardbus.c
2020-09-26 16:20:57 +08:00

1174 lines
29 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
cardbus.c
Abstract:
This module contains functions associated with enumerating
PCI to Cardbus bridges (PCI Header Type 2).
This module also contain Cardbus/Pci Private interface functions.
Author:
Peter Johnston (peterj) 09-Mar-1997
Revision History:
--*/
#include "pcip.h"
//
// Prototypes for routines exposed only thru the "interface"
// mechanism.
//
NTSTATUS
pcicbintrf_AddCardBus(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PVOID * DeviceContext
);
NTSTATUS
pcicbintrf_DeleteCardBus(
IN PVOID DeviceContext
);
NTSTATUS
pcicbintrf_DispatchPnp(
IN PVOID DeviceContext,
IN PIRP Irp
);
NTSTATUS
pcicbintrf_GetLocation(
IN PDEVICE_OBJECT Pdo,
OUT UCHAR *Bus,
OUT UCHAR *DeviceNumber,
OUT UCHAR *FunctionNumber,
OUT BOOLEAN *OnDebugPath
);
NTSTATUS
pcicbintrf_Constructor(
PVOID DeviceExtension,
PVOID PciInterface,
PVOID InterfaceSpecificData,
USHORT Version,
USHORT Size,
PINTERFACE InterfaceReturn
);
VOID
pcicbintrf_Reference(
IN PVOID Context
);
VOID
pcicbintrf_Dereference(
IN PVOID Context
);
NTSTATUS
pcicbintrf_Initializer(
IN PPCI_ARBITER_INSTANCE Instance
);
//
// Define the PCI-Cardbus private interface.
//
PCI_INTERFACE PciCardbusPrivateInterface = {
&GUID_PCI_CARDBUS_INTERFACE_PRIVATE, // InterfaceType
sizeof(PCI_CARDBUS_INTERFACE_PRIVATE), // MinSize
PCI_CB_INTRF_VERSION, // MinVersion
PCI_CB_INTRF_VERSION, // MaxVersion
PCIIF_PDO, // Flags
0, // ReferenceCount
PciInterface_PciCb, // Signature
pcicbintrf_Constructor, // Constructor
pcicbintrf_Initializer // Instance Initializer
};
#ifdef ALLOC_PRAGMA
//
// Query Interface routines
//
#pragma alloc_text(PAGE, pcicbintrf_AddCardBus)
#pragma alloc_text(PAGE, pcicbintrf_DeleteCardBus)
#pragma alloc_text(PAGE, pcicbintrf_DispatchPnp)
#pragma alloc_text(PAGE, pcicbintrf_Constructor)
#pragma alloc_text(PAGE, pcicbintrf_Dereference)
#pragma alloc_text(PAGE, pcicbintrf_Initializer)
#pragma alloc_text(PAGE, pcicbintrf_Reference)
//
// Standard PCI enumeration routines
//
#pragma alloc_text(PAGE, Cardbus_MassageHeaderForLimitsDetermination)
#pragma alloc_text(PAGE, Cardbus_RestoreCurrent)
#pragma alloc_text(PAGE, Cardbus_SaveLimits)
#pragma alloc_text(PAGE, Cardbus_SaveCurrentSettings)
#pragma alloc_text(PAGE, Cardbus_GetAdditionalResourceDescriptors)
#endif
NTSTATUS
pcicbintrf_AddCardBus(
IN PDEVICE_OBJECT ControllerPdo,
IN OUT PVOID *DeviceContext
)
{
PPCI_PDO_EXTENSION controllerPdoExtension;
PPCI_FDO_EXTENSION fdoExtension = NULL;
PPCI_FDO_EXTENSION parent;
NTSTATUS status;
PciDebugPrint(
PciDbgCardBus,
"PCI - AddCardBus FDO for PDO %08x\n",
ControllerPdo
);
//
// DeviceObject is the PDO for this CardBus controller. Ensure
// the PCI driver created it and knows what it is.
//
controllerPdoExtension = (PPCI_PDO_EXTENSION)ControllerPdo->DeviceExtension;
ASSERT_PCI_PDO_EXTENSION(controllerPdoExtension);
if ((controllerPdoExtension->BaseClass != PCI_CLASS_BRIDGE_DEV) ||
(controllerPdoExtension->SubClass != PCI_SUBCLASS_BR_CARDBUS)) {
ASSERT(controllerPdoExtension->BaseClass == PCI_CLASS_BRIDGE_DEV);
ASSERT(controllerPdoExtension->SubClass == PCI_SUBCLASS_BR_CARDBUS);
status = STATUS_INVALID_DEVICE_REQUEST;
goto cleanup;
}
//
// Sanity check.
//
parent = PCI_PARENT_FDOX(controllerPdoExtension);
if ( (controllerPdoExtension->Dependent.type2.PrimaryBus !=
parent->BaseBus)
|| (controllerPdoExtension->Dependent.type2.SecondaryBus <=
parent->BaseBus)
|| (controllerPdoExtension->Dependent.type2.SubordinateBus <
controllerPdoExtension->Dependent.type2.SecondaryBus)
) {
PciDebugPrint(
PciDbgAlways,
"PCI Cardbus Bus Number configuration error (%02x>=%02x>%02x=%02x)\n",
controllerPdoExtension->Dependent.type2.SubordinateBus,
controllerPdoExtension->Dependent.type2.SecondaryBus,
controllerPdoExtension->Dependent.type2.PrimaryBus,
parent->BaseBus
);
ASSERT(controllerPdoExtension->Dependent.type2.PrimaryBus == parent->BaseBus);
ASSERT(controllerPdoExtension->Dependent.type2.SecondaryBus > parent->BaseBus);
ASSERT(controllerPdoExtension->Dependent.type2.SubordinateBus >=
controllerPdoExtension->Dependent.type2.SecondaryBus);
status = STATUS_INVALID_DEVICE_REQUEST;
goto cleanup;
}
fdoExtension = ExAllocatePool(NonPagedPool, sizeof(PCI_FDO_EXTENSION));
if (fdoExtension == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
PciInitializeFdoExtensionCommonFields(
fdoExtension,
parent->FunctionalDeviceObject, // borrow parent's fdo
ControllerPdo
);
//
// We are probably only going to see QUERY_DEVICE_RELATIONS
// Irps so initialize the FDO extension to a working state.
//
fdoExtension->PowerState.CurrentSystemState = PowerSystemWorking;
fdoExtension->PowerState.CurrentDeviceState = PowerDeviceD0;
fdoExtension->DeviceState = PciStarted;
fdoExtension->TentativeNextState = PciStarted;
fdoExtension->BaseBus = controllerPdoExtension->Dependent.type2.SecondaryBus;
//
// Copy the access methods from the root fdo and set
// the root fdo back pointer.
//
fdoExtension->BusRootFdoExtension = parent->BusRootFdoExtension;
//
// Initialize arbiters for this FDO.
//
status = PciInitializeArbiters(fdoExtension);
if (!NT_SUCCESS(status)) {
goto cleanup;
}
//
// Point the PDOextension to the new FDOextension (also indicates
// the object is a bridge) and vice versa.
//
controllerPdoExtension->BridgeFdoExtension = fdoExtension;
fdoExtension->ParentFdoExtension = parent;
//
// Flag that this FDO extension doesn't have a REAL FDO
// associated with it.
//
fdoExtension->Fake = TRUE;
//
// Normaly we set the arbiter's ranges on a START_DEVICE IRP
// but this has happened long before we get here so we must
// regenerate the resource list.
//
{
PCM_RESOURCE_LIST allocatedResources;
status = PciQueryResources(
controllerPdoExtension,
&allocatedResources
);
if (NT_SUCCESS(status)) {
//
// Note: there's really not much that can be done if
// the above failed,...
//
// Note: Find the first memory range, it should be length
// 0x1000, we really don't want the arbiter using this so
// nullify it.
//
PCM_FULL_RESOURCE_DESCRIPTOR full;
PCM_PARTIAL_RESOURCE_LIST partial;
PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
ULONG count;
ASSERT(allocatedResources != NULL);
ASSERT(allocatedResources->Count == 1);
full = allocatedResources->List; ASSERT(full);
partial = &full->PartialResourceList; ASSERT(partial);
descriptor = partial->PartialDescriptors; ASSERT(descriptor);
count = partial->Count; ASSERT(count);
while (count--) {
if (descriptor->Type == CmResourceTypeMemory) {
ASSERT(descriptor->u.Generic.Length == 4096);
descriptor->Type = CmResourceTypeNull;
break;
}
}
status = PciInitializeArbiterRanges(fdoExtension, allocatedResources);
ASSERT(NT_SUCCESS(status));
ExFreePool(allocatedResources);
}
}
//
// If the PDO has resource requirements squirreled away somewhere,
// cause them to be reevaluated.
//
PciInvalidateResourceInfoCache(controllerPdoExtension);
//
// Insert this Fdo in the list of PCI parent Fdos.
//
PciInsertEntryAtTail(&PciFdoExtensionListHead,
&fdoExtension->List,
&PciGlobalLock);
//
// Return the device context (really a pointer to our fake
// FDO extension) that will be used on all subsequent calls
// for this device.
//
*DeviceContext = fdoExtension;
return STATUS_SUCCESS;
cleanup:
if (fdoExtension) {
ExFreePool(fdoExtension);
}
return status;
}
NTSTATUS
pcicbintrf_DeleteCardBus(
IN PVOID DeviceContext
)
{
PPCI_FDO_EXTENSION fdoExtension;
PPCI_PDO_EXTENSION pdoExtension;
fdoExtension = (PPCI_FDO_EXTENSION)DeviceContext;
ASSERT_PCI_FDO_EXTENSION(fdoExtension);
pdoExtension = fdoExtension->PhysicalDeviceObject->DeviceExtension;
ASSERT_PCI_PDO_EXTENSION(pdoExtension);
ASSERT(pdoExtension->BridgeFdoExtension == fdoExtension);
pdoExtension->BridgeFdoExtension = NULL;
PciDebugPrint(
PciDbgCardBus,
"PCI - DeleteCardBus (fake) FDO %08x for PDO %08x\n",
fdoExtension,
pdoExtension
);
//
// Free the (fake) FDO extension we created to run this
// bus with.
//
ASSERT(fdoExtension->ChildPdoList == NULL);
PciRemoveEntryFromList(&PciFdoExtensionListHead,
&fdoExtension->List,
&PciGlobalLock);
ExFreePool(fdoExtension);
return STATUS_SUCCESS;
}
NTSTATUS
pcicbintrf_DispatchPnp(
IN PVOID DeviceContext,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpSp;
NTSTATUS status;
PPCI_FDO_EXTENSION fdoExtension;
PVOID irpReturnVal;
PAGED_CODE();
fdoExtension = (PPCI_FDO_EXTENSION)DeviceContext;
ASSERT_PCI_FDO_EXTENSION(fdoExtension);
ASSERT(fdoExtension->Fake == TRUE);
//
// Get the stack location and take appropriate action based
// on the minor function.
//
irpSp = IoGetCurrentIrpStackLocation(Irp);
ASSERT(irpSp->MajorFunction == IRP_MJ_PNP);
#if DBG
PciDebugPrint(
PciDbgCardBus,
"PCI CardBus Dispatch PNP: FDO(%x, bus 0x%02x)<-%s\n",
fdoExtension,
fdoExtension->BaseBus,
PciDebugPnpIrpTypeToText(irpSp->MinorFunction)
);
#endif
return PciFdoIrpQueryDeviceRelations(
Irp,
irpSp,
(PPCI_COMMON_EXTENSION) fdoExtension
);
}
NTSTATUS
pcicbintrf_GetLocation(
IN PDEVICE_OBJECT Pdo,
OUT UCHAR *Bus,
OUT UCHAR *DeviceNumber,
OUT UCHAR *FunctionNumber,
OUT BOOLEAN *OnDebugPath
)
{
PPCI_PDO_EXTENSION PdoExt = (PPCI_PDO_EXTENSION)Pdo->DeviceExtension;
ASSERT(Bus);
ASSERT(DeviceNumber);
ASSERT(FunctionNumber);
//
// Verify that this PDO actually belongs to us.
//
if (!PdoExt) {
return STATUS_NOT_FOUND;
}
//
// Verify that it is actually a PDO.
//
if (PdoExt->ExtensionType != PciPdoExtensionType) {
return STATUS_NOT_FOUND;
}
*Bus = (UCHAR) PCI_PARENT_FDOX(PdoExt)->BaseBus;
*DeviceNumber = (UCHAR) PdoExt->Slot.u.bits.DeviceNumber;
*FunctionNumber = (UCHAR) PdoExt->Slot.u.bits.FunctionNumber;
*OnDebugPath = PdoExt->OnDebugPath;
return STATUS_SUCCESS;
}
VOID
pcicbintrf_Reference(
IN PVOID Context
)
{
}
VOID
pcicbintrf_Dereference(
IN PVOID Context
)
{
}
NTSTATUS
pcicbintrf_Constructor(
PVOID DeviceExtension,
PVOID PciInterface,
PVOID InterfaceSpecificData,
USHORT Version,
USHORT Size,
PINTERFACE InterfaceReturn
)
/*++
Routine Description:
Initialize the PCI_CARDBUS_INTERFACE_PRIVATE fields.
Arguments:
PciInterface Pointer to the PciInterface record for this
interface type.
InterfaceSpecificData
A ULONG containing the resource type for which
arbitration is required.
InterfaceReturn
Return Value:
Status of this operation.
--*/
{
PPCI_CARDBUS_INTERFACE_PRIVATE interface;
interface = (PPCI_CARDBUS_INTERFACE_PRIVATE)InterfaceReturn;
//
// Standard interface stuff
//
interface->Size = sizeof(PCI_CARDBUS_INTERFACE_PRIVATE);
interface->Version = PCI_CB_INTRF_VERSION;
interface->Context = DeviceExtension;
interface->InterfaceReference = pcicbintrf_Reference;
interface->InterfaceDereference = pcicbintrf_Dereference;
//
// PCI-CardBus private
//
interface->DriverObject = PciDriverObject;
interface->AddCardBus = pcicbintrf_AddCardBus;
interface->DeleteCardBus = pcicbintrf_DeleteCardBus;
interface->DispatchPnp = pcicbintrf_DispatchPnp;
interface->GetLocation = pcicbintrf_GetLocation;
return STATUS_SUCCESS;
}
NTSTATUS
pcicbintrf_Initializer(
IN PPCI_ARBITER_INSTANCE Instance
)
/*++
Routine Description:
For pci-cardbus interface, does nothing, shouldn't actually be called.
Arguments:
Instance Pointer to the PDO extension.
Return Value:
Returns the status of this operation.
--*/
{
ASSERTMSG("PCI pcicbintrf_Initializer, unexpected call.", 0);
return STATUS_UNSUCCESSFUL;
}
VOID
Cardbus_MassageHeaderForLimitsDetermination(
IN PPCI_CONFIGURABLE_OBJECT This
)
/*++
Description:
The configuration header for a cardbus bridge has one BAR, the
SocketRegistersBaseAddress (which is handled in the same way as
a normal device BAR (see device.c)) and four range descriptions,
two for I/O and two for memory. Either or both of the memory
ranges can be prefetchable.
Arguments:
This - Pointer to a PCI driver "configurable" object. This
object contains configuration data for the function
currently being configured.
Return Value:
The Working configuration has been modified so that all range
fields have been set to their maximum possible values.
The Current configuration has been modified such that writing it
to the hardware will restore the hardware to it's current (disabled)
state.
--*/
{
PPCI_COMMON_CONFIG working = This->Working;
PPCI_COMMON_CONFIG current = This->Current;
ULONG index;
ULONG mask;
working->u.type2.SocketRegistersBaseAddress = 0xffffffff;
for (index = 0; index < (PCI_TYPE2_ADDRESSES-1); index++) {
working->u.type2.Range[index].Base = 0xffffffff;
working->u.type2.Range[index].Limit = 0xffffffff;
}
This->PrivateData = This->Current->u.type2.SecondaryStatus;
This->Current->u.type2.SecondaryStatus = 0;
This->Working->u.type2.SecondaryStatus = 0;
//
// For cardbus, disregard whatever the BIOS set as resource
// windows, PnP will assign new windows as appropriate.
//
if (!This->PdoExtension->OnDebugPath) {
mask = 0xfffff000;
for (index = 0; index < (PCI_TYPE2_ADDRESSES-1); index++) {
current->u.type2.Range[index].Base = mask;
current->u.type2.Range[index].Limit = 0;
if (index == 2) {
//
// Switch to IO (first two are memory).
//
mask = 0xfffffffc;
}
}
}
}
VOID
Cardbus_RestoreCurrent(
IN PPCI_CONFIGURABLE_OBJECT This
)
/*++
Description:
Restore any type specific fields in the original copy of config
space. In the case of Cardbus bridges, the secondary status field.
Arguments:
This - Pointer to a PCI driver "configurable" object. This
object contains configuration data for the function
currently being configured.
Return Value:
None.
--*/
{
This->Current->u.type2.SecondaryStatus = (USHORT)(This->PrivateData);
}
VOID
Cardbus_SaveLimits(
IN PPCI_CONFIGURABLE_OBJECT This
)
/*++
Description:
Fill in the Limit structure with a IO_RESOURCE_REQUIREMENT
for each implemented BAR.
Arguments:
This - Pointer to a PCI driver "configurable" object. This
object contains configuration data for the function
currently being configured.
Return Value:
None.
--*/
{
BOOLEAN DbgChk64Bit;
ULONG index;
PIO_RESOURCE_DESCRIPTOR descriptor;
PPCI_COMMON_CONFIG working = This->Working;
ULONG endOffset;
ULONG base;
ULONG limit;
TYPE2EXTRAS type2extras;
ULONG tempLegacyModeBaseAddress;
NTSTATUS status;
descriptor = This->PdoExtension->Resources->Limit;
DbgChk64Bit = PciCreateIoDescriptorFromBarLimit(
descriptor,
&working->u.type2.SocketRegistersBaseAddress,
FALSE);
ASSERT(!DbgChk64Bit);
descriptor++;
for (index = 0;
index < (PCI_TYPE2_ADDRESSES-1);
index++, descriptor++) {
if (index < 2) {
//
// First two are Memory
//
endOffset = 0xfff;
descriptor->Type = CmResourceTypeMemory;
descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
} else {
//
// Next two are IO
//
if ((working->u.type2.Range[index].Base & 0x3) == 0x0) {
//
// Only the lower 16 bits are implemented.
//
ASSERT((working->u.type2.Range[index].Limit & 0x3) == 0x0);
working->u.type2.Range[index].Base &= 0xffff;
working->u.type2.Range[index].Limit &= 0xffff;
}
endOffset = 0x3;
descriptor->Type = CmResourceTypePort;
descriptor->Flags = CM_RESOURCE_PORT_IO
| CM_RESOURCE_PORT_POSITIVE_DECODE
| CM_RESOURCE_PORT_WINDOW_DECODE;
}
base = working->u.type2.Range[index].Base & ~endOffset;
limit = working->u.type2.Range[index].Limit | endOffset;
//
// Is this range in use?
//
if ((base != 0) && (base < limit)) {
//
// Yep.
//
descriptor->u.Generic.MinimumAddress.QuadPart = 0;
descriptor->u.Generic.MaximumAddress.QuadPart = limit;
descriptor->u.Generic.Alignment = endOffset + 1;
//
// Length is meaningless here, report zero.
//
descriptor->u.Generic.Length = 0;
} else {
//
// Not in use, don't report it.
//
descriptor->Type = CmResourceTypeNull;
}
}
//
// Cardbus has an additional base address register in config
// space beyond the common header. Also there are the subsystem
// ID and subsystem vendor ID so get those while we're there.
//
PciReadDeviceConfig(This->PdoExtension,
&type2extras,
FIELD_OFFSET(PCI_COMMON_CONFIG,
DeviceSpecific),
sizeof(type2extras));
This->PdoExtension->SubsystemVendorId = type2extras.SubVendorID;
This->PdoExtension->SubsystemId = type2extras.SubSystemID;
//
// CardBus always wants a 4K apperture in the first memory BAR.
// Note that when saving the original settings we discarded
// whatever was there already.
//
ASSERT(This->PdoExtension->Resources->Limit[1].u.Generic.Length == 0);
This->PdoExtension->Resources->Limit[1].u.Generic.Length = 4096;
}
VOID
Cardbus_SaveCurrentSettings(
IN PPCI_CONFIGURABLE_OBJECT This
)
/*++
Description:
Fill in the Current array in the PDO extension with the current
settings for each implemented BAR.
Also, fill in the PDO Extension's Dependent structure.
Arguments:
This - Pointer to a PCI driver "configurable" object. This
object contains configuration data for the function
currently being configured.
Return Value:
None.
--*/
{
ULONG index;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor;
PPCI_COMMON_CONFIG current = This->Current;
ULONG endOffset;
ULONG base;
ULONG limit;
partial = This->PdoExtension->Resources->Current;
ioResourceDescriptor = This->PdoExtension->Resources->Limit;
for (index = 0;
index < PCI_TYPE2_RANGE_COUNT;
index++, partial++, ioResourceDescriptor++) {
partial->Type = ioResourceDescriptor->Type;
if (partial->Type == CmResourceTypeNull) {
//
// This entry is not implemented (or permanently disabled)
// no further processing required.
//
continue;
}
partial->Flags = ioResourceDescriptor->Flags;
partial->ShareDisposition = ioResourceDescriptor->ShareDisposition;
//
// The first and last entries are in PCI Base Address Register
// form.
//
if (index == 0) {
partial->u.Generic.Length = ioResourceDescriptor->u.Generic.Length;
base = current->u.type2.SocketRegistersBaseAddress;
base &= ~(partial->u.Generic.Length - 1);
partial->u.Generic.Start.QuadPart = base;
continue;
} else if (index == (PCI_TYPE2_RANGE_COUNT - 1)) {
//
// We don't use LegacyModeBaseAddress any more its always set to 0
//
continue;
}
//
// Following entries are in the form of ranges.
//
base = current->u.type2.Range[index-1].Base;
limit = current->u.type2.Range[index-1].Limit;
if (index < 3) {
//
// after the BAR come two memory ranges.
//
endOffset = 0xfff;
} else {
//
// Next two are IO
//
if ((current->u.type2.Range[index].Base & 0x3) == 0x0) {
//
// Only the lower 16 bits are implemented.
//
base &= 0xffff;
limit &= 0xffff;
}
endOffset = 0x3;
}
base &= ~endOffset;
limit |= endOffset;
//
// Is this range in use?
//
if (base && (base < limit)) {
//
// Yep.
//
partial->u.Generic.Start.QuadPart = base;
partial->u.Generic.Length = limit - base + 1;
} else {
//
// Not in use, don't report it.
//
partial->Type = CmResourceTypeNull;
}
}
//
// Always clear the ISA bit on a cardbus bridge
//
This->PdoExtension->Dependent.type2.IsaBitSet = FALSE;
//
// If any of the MEM0_PREFETCH, MEM1_PREFETCH or ISA bits are set in brigde
// control register force us to update the hardware so we will clear them
// in ChangeResourceSettings
//
if (current->u.type2.BridgeControl & (PCI_ENABLE_CARDBUS_MEM0_PREFETCH
| PCI_ENABLE_CARDBUS_MEM1_PREFETCH
| PCI_ENABLE_BRIDGE_ISA)) {
This->PdoExtension->UpdateHardware = TRUE;
}
//
// Save the bridge's PCI bus #'s
//
This->PdoExtension->Dependent.type2.PrimaryBus =
current->u.type2.PrimaryBus;
This->PdoExtension->Dependent.type2.SecondaryBus =
current->u.type2.SecondaryBus;
This->PdoExtension->Dependent.type2.SubordinateBus =
current->u.type2.SubordinateBus;
}
VOID
Cardbus_ChangeResourceSettings(
IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_CONFIG CommonConfig
)
{
ULONG index;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor;
ULONG lowPart;
ULONG length;
struct _type2_range {
ULONG Base;
ULONG Limit;
} *range;
#if DBG
PHYSICAL_ADDRESS upperBound;
ULONG align;
#endif
//
// Close the bridge windows and only open them is appropriate resources
// have been assigned
//
for (index = 0; index < PCI_TYPE2_ADDRESSES-1; index++) {
CommonConfig->u.type2.Range[index].Base = 0xffffffff;
CommonConfig->u.type2.Range[index].Limit = 0x0;
}
if (PdoExtension->Resources) {
partial = PdoExtension->Resources->Current;
ioResourceDescriptor = PdoExtension->Resources->Limit;
for (index = 0;
index < PCI_TYPE2_RANGE_COUNT;
index++, partial++, ioResourceDescriptor++) {
//
// If this entry is not implemented, skip.
//
if (partial->Type == CmResourceTypeNull) {
continue;
}
ASSERT(partial->Type == ioResourceDescriptor->Type);
//
// Cardbus supports 32 (or 16) bit addresses only.
//
lowPart = partial->u.Generic.Start.LowPart;
ASSERT(partial->u.Generic.Start.HighPart == 0);
//
// Type 2 headers
//
// entry cfg offset size what
//
// 0 10 4 CB Socket reg/EXCA BAR
// 1 1c 8 Mem base/limit (32 bits each)
// 2 24 8 "" "" 2nd aperture
// 3 2c 8(*) IO base/limit
// 4 34 8(*) "" "" 2nd aperture
// 5 40 4(**) 16 bit PC card legacy mode BAR
//
// * Optionally 16 or 32 bits.
// ** Optional. Not supported at present (Memphis says they don't
// support it at all). Peterj 11/5/97.
//
if (index == 0) {
ASSERT(partial->Type == CmResourceTypeMemory);
CommonConfig->u.type2.SocketRegistersBaseAddress = lowPart;
} else if (index == (PCI_TYPE2_RANGE_COUNT-1)) {
//
// We don't use LegacyModeBaseAddress any more its always set to 0
//
ASSERT(partial->Type = CmResourceTypeNull);
continue;
} else {
//
// It's one of the range/limit pairs.
//
range =
(struct _type2_range *)&CommonConfig->u.type2.Range[index-1];
length = partial->u.Generic.Length;
#if DBG
//
// Verify type and upper bound.
//
upperBound.QuadPart = lowPart + (partial->u.Generic.Length - 1);
ASSERT(upperBound.HighPart == 0);
if (index < 3) {
//
// Memory ranges, 4KB alignment.
//
align = 0xfff;
} else {
//
// IO ranges, verify type, 4 Byte alignment and
// upperbound if 16 bit only.
//
align = 0x3;
if ((range->Base & 0x3) == 0) {
//
// 16 bit
//
ASSERT((upperBound.LowPart & 0xffff0000) == 0);
}
}
ASSERT((lowPart & align) == 0);
ASSERT(((length & align) == 0) && (length > align));
#endif
range->Base = lowPart;
range->Limit = lowPart + (length - 1);
continue;
}
}
}
//
// Restore the bridge's PCI bus #'s
//
CommonConfig->u.type2.PrimaryBus = PdoExtension->Dependent.type2.PrimaryBus;
CommonConfig->u.type2.SecondaryBus = PdoExtension->Dependent.type2.SecondaryBus;
CommonConfig->u.type2.SubordinateBus = PdoExtension->Dependent.type2.SubordinateBus;
//
// Always clear the MEM0_PREFETCH, MEM1_PREFETCH and ISA enables
// for a cardbus contoller as we don't support these.
//
ASSERT(!PdoExtension->Dependent.type2.IsaBitSet);
CommonConfig->u.type2.BridgeControl &= ~(PCI_ENABLE_CARDBUS_MEM0_PREFETCH
| PCI_ENABLE_CARDBUS_MEM1_PREFETCH
| PCI_ENABLE_BRIDGE_ISA);
//
// Set the bridge control register bits we might have changes
//
if (PdoExtension->Dependent.type2.VgaBitSet) {
CommonConfig->u.type2.BridgeControl |= PCI_ENABLE_BRIDGE_VGA;
}
}
VOID
Cardbus_GetAdditionalResourceDescriptors(
IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_CONFIG CommonConfig,
IN PIO_RESOURCE_DESCRIPTOR Resource
)
{
//
// For the moment, do nothing, need to add the same sort of
// support as is in pci-pci bridges.
//
return;
}
NTSTATUS
Cardbus_ResetDevice(
IN PPCI_PDO_EXTENSION PdoExtension,
IN PPCI_COMMON_CONFIG CommonConfig
)
{
//
// While you might logically expect to find code in this
// function, RavisP assures me that the cardbus driver
// handles resets correctly and the PCI driver doesn't
// need to touch it.
//
return STATUS_SUCCESS;
}