2965 lines
94 KiB
C
2965 lines
94 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pdopnp.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code to handle
|
||
the IRP_MJ_PNP dispatches for the PDOs
|
||
enumerated by the PCMCIA bus driver
|
||
|
||
|
||
Authors:
|
||
|
||
Ravisankar Pudipeddi (ravisp)
|
||
Neil Sandlin (neilsa) 1-Jun-1999
|
||
|
||
Environment:
|
||
|
||
Kernel mode only
|
||
|
||
Notes:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
//
|
||
// Internal References
|
||
//
|
||
|
||
NTSTATUS
|
||
PcmciaFilterPcCardResourceRequirements(
|
||
IN PPDO_EXTENSION DeviceExtension,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaFilterPcCardInterrupts(
|
||
IN PIO_RESOURCE_REQUIREMENTS_LIST oldReqList,
|
||
IN ULONG IrqCount,
|
||
IN ULONG IrqMask,
|
||
OUT PIO_RESOURCE_REQUIREMENTS_LIST * FilteredReqList,
|
||
BOOLEAN RouteIsaToPci
|
||
);
|
||
|
||
VOID
|
||
PcmciaCleanupSocketData(
|
||
IN PSOCKET_DATA SocketData
|
||
);
|
||
|
||
VOID
|
||
PcmciaCleanupSocketConfiguration(
|
||
PPDO_EXTENSION pdoExtension
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaPdoDeviceCapabilities(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaGetPcCardResourceRequirements(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
PULONG_PTR Information
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaConfigEntriesToResourceListChain(
|
||
PPDO_EXTENSION pdoExtension,
|
||
PCONFIG_LIST ConfigList,
|
||
ULONG configCount,
|
||
PPCMCIA_RESOURCE_CHAIN *ResListChainHead
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaMergeResourceChainToList(
|
||
PPCMCIA_RESOURCE_CHAIN ResListChain,
|
||
PIO_RESOURCE_REQUIREMENTS_LIST *GeneratedResourceRequirementsList
|
||
);
|
||
|
||
VOID
|
||
PcmciaFreeResourceChain(
|
||
PPCMCIA_RESOURCE_CHAIN ResListChain
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaStartPcCard(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PCM_RESOURCE_LIST AllocatedResources,
|
||
IN OUT PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaStopPcCard(
|
||
IN PDEVICE_OBJECT Pdo
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaRemovePcCard(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaMfEnumerateConfigurations(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
IN PSOCKET_DATA socketData,
|
||
PCONFIG_LIST ConfigList,
|
||
IN ULONG Depth,
|
||
PPCMCIA_RESOURCE_CHAIN *MfResListChain
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaMfGetResourceRequirements(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
PULONG_PTR Information
|
||
);
|
||
|
||
VOID
|
||
PcmciaMfBuildResourceMapInfo(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
PCONFIG_LIST ConfigList,
|
||
ULONG ConfigCount
|
||
);
|
||
|
||
BOOLEAN
|
||
PcmciaMfCheckForOverlappingRanges(
|
||
PCONFIG_LIST ConfigList,
|
||
LONG ConfigCount
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaPdoGetBusInformation(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
OUT PPNP_BUS_INFORMATION * BusInformation
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaQueryDeviceText(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN OUT PIRP Irp
|
||
);
|
||
|
||
VOID
|
||
PcmciaPdoGetDeviceInfSettings(
|
||
IN PPDO_EXTENSION PdoExtension
|
||
);
|
||
|
||
VOID
|
||
PcmciaPdoSetDeviceIrqRouting(
|
||
IN PPDO_EXTENSION PdoExtension
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, PcmciaPdoPnpDispatch)
|
||
#pragma alloc_text(PAGE, PcmciaPdoGetDeviceInfSettings)
|
||
#pragma alloc_text(PAGE, PcmciaPdoSetDeviceIrqRouting)
|
||
#pragma alloc_text(PAGE, PcmciaFilterPcCardInterrupts)
|
||
#pragma alloc_text(PAGE, PcmciaFilterPcCardResourceRequirements)
|
||
#pragma alloc_text(PAGE, PcmciaQueryDeviceText)
|
||
#pragma alloc_text(PAGE, PcmciaGetPcCardResourceRequirements)
|
||
#pragma alloc_text(PAGE, PcmciaConfigEntriesToResourceListChain)
|
||
#pragma alloc_text(PAGE, PcmciaMergeResourceChainToList)
|
||
#pragma alloc_text(PAGE, PcmciaFreeResourceChain)
|
||
#pragma alloc_text(PAGE, PcmciaPdoGetBusInformation)
|
||
#pragma alloc_text(PAGE, PcmciaStartPcCard)
|
||
#pragma alloc_text(PAGE, PcmciaStopPcCard)
|
||
#pragma alloc_text(PAGE, PcmciaRemovePcCard)
|
||
#pragma alloc_text(PAGE, PcmciaPdoDeviceCapabilities)
|
||
#pragma alloc_text(PAGE, PcmciaPdoDeviceControl)
|
||
#pragma alloc_text(PAGE, PcmciaPdoGetDeviceInfSettings)
|
||
#pragma alloc_text(PAGE, PcmciaMfGetResourceRequirements)
|
||
#pragma alloc_text(PAGE, PcmciaMfEnumerateConfigurations)
|
||
#pragma alloc_text(PAGE, PcmciaMfBuildResourceMapInfo)
|
||
#pragma alloc_text(PAGE, PcmciaMfCheckForOverlappingRanges)
|
||
#endif
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaPdoPnpDispatch(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles pnp requests
|
||
for the PDOs.
|
||
|
||
Arguments:
|
||
|
||
Pdo - pointer to the physical device object
|
||
Irp - pointer to the io request packet
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
|
||
{
|
||
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// CardBus PnP Dispatch
|
||
//
|
||
|
||
if (IsCardBusCard(pdoExtension)) { //
|
||
return PcmciaPdoCardBusPnPDispatch(Pdo, Irp);
|
||
}
|
||
|
||
#if DBG
|
||
if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
|
||
DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x Unknown minor function %x\n",
|
||
Pdo, Irp, irpStack->MinorFunction));
|
||
} else {
|
||
DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x --> %s\n",
|
||
Pdo, Irp, PNP_IRP_STRING(irpStack->MinorFunction)));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// 16-bit (R2) PcCard PnP Dispatch
|
||
//
|
||
switch (irpStack->MinorFunction) {
|
||
|
||
case IRP_MN_START_DEVICE: {
|
||
status = PcmciaStartPcCard(Pdo, irpStack->Parameters.StartDevice.AllocatedResources, Irp);
|
||
PcmciaDoStartSound(pdoExtension->Socket, status);
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_STOP_DEVICE:{
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_CANCEL_STOP_DEVICE:{
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_STOP_DEVICE: {
|
||
status = PcmciaStopPcCard(Pdo);
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_REMOVE_DEVICE:{
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_CANCEL_REMOVE_DEVICE:{
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_REMOVE_DEVICE: {
|
||
status = PcmciaRemovePcCard(Pdo, Irp);
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_SURPRISE_REMOVAL: {
|
||
|
||
PcmciaReleaseSocketPower(pdoExtension, NULL);
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_ID: {
|
||
|
||
UNICODE_STRING unicodeId;
|
||
|
||
status = Irp->IoStatus.Status;
|
||
RtlInitUnicodeString(&unicodeId, NULL);
|
||
|
||
switch (irpStack->Parameters.QueryId.IdType) {
|
||
|
||
case BusQueryDeviceID: {
|
||
DebugPrint((PCMCIA_DEBUG_INFO, " Device Id for pdo %x\n", Pdo));
|
||
status = PcmciaGetDeviceId(Pdo, PCMCIA_MULTIFUNCTION_PARENT, &unicodeId);
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case BusQueryInstanceID: {
|
||
DebugPrint((PCMCIA_DEBUG_INFO, " Instance Id for pdo %x\n", Pdo));
|
||
status = PcmciaGetInstanceId(Pdo, &unicodeId);
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case BusQueryHardwareIDs: {
|
||
DebugPrint((PCMCIA_DEBUG_INFO, " Hardware Ids for pdo %x\n", Pdo));
|
||
status = PcmciaGetHardwareIds(Pdo, PCMCIA_MULTIFUNCTION_PARENT, &unicodeId);
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case BusQueryCompatibleIDs: {
|
||
DebugPrint((PCMCIA_DEBUG_INFO, " Compatible Ids for pdo %x\n", Pdo));
|
||
status = PcmciaGetCompatibleIds( Pdo, PCMCIA_MULTIFUNCTION_PARENT, &unicodeId);
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
|
||
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: {
|
||
//
|
||
// PcmciaGetPcCardResourceRequirements will
|
||
// allocate storage for the resource requirements which will be released
|
||
// by the OS.
|
||
//
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
PcmciaPdoGetDeviceInfSettings(pdoExtension);
|
||
PcmciaPdoSetDeviceIrqRouting(pdoExtension);
|
||
|
||
if (IsDeviceMultifunction(pdoExtension)) {
|
||
status = PcmciaMfGetResourceRequirements(pdoExtension,
|
||
&Irp->IoStatus.Information);
|
||
} else {
|
||
status = PcmciaGetPcCardResourceRequirements(pdoExtension,
|
||
&Irp->IoStatus.Information);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_WRITE_CONFIG:
|
||
case IRP_MN_READ_CONFIG: {
|
||
PFDO_EXTENSION fdoExtension= pdoExtension->Socket->DeviceExtension;
|
||
ULONG whichSpace;
|
||
PVOID buffer;
|
||
ULONG offset;
|
||
ULONG length;
|
||
|
||
whichSpace = irpStack->Parameters.ReadWriteConfig.WhichSpace;
|
||
buffer = irpStack->Parameters.ReadWriteConfig.Buffer;
|
||
offset = irpStack->Parameters.ReadWriteConfig.Offset;
|
||
length = irpStack->Parameters.ReadWriteConfig.Length;
|
||
|
||
if (irpStack->MinorFunction == IRP_MN_READ_CONFIG) {
|
||
status = PcmciaReadWriteCardMemory(Pdo,
|
||
whichSpace,
|
||
buffer,
|
||
offset,
|
||
length,
|
||
TRUE);
|
||
} else {
|
||
status = PcmciaReadWriteCardMemory(Pdo,
|
||
whichSpace,
|
||
buffer,
|
||
offset,
|
||
length,
|
||
FALSE);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_DEVICE_RELATIONS: {
|
||
|
||
PDEVICE_RELATIONS deviceRelations;
|
||
|
||
if (irpStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) {
|
||
status = Irp->IoStatus.Status;
|
||
break;
|
||
}
|
||
|
||
deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
||
if (deviceRelations == NULL) {
|
||
|
||
DebugPrint((PCMCIA_DEBUG_FAIL,
|
||
"PcmciaPdoPnpDispatch:unable to allocate memory for device relations\n"));
|
||
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
status = ObReferenceObjectByPointer(Pdo,
|
||
0,
|
||
NULL,
|
||
KernelMode);
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(deviceRelations);
|
||
break;
|
||
}
|
||
|
||
deviceRelations->Count = 1;
|
||
deviceRelations->Objects[0] = Pdo;
|
||
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_CAPABILITIES: {
|
||
status = PcmciaPdoDeviceCapabilities(Pdo, Irp);
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_INTERFACE: {
|
||
status = PcmciaPdoQueryInterface(Pdo, Irp);
|
||
//
|
||
// QueryInterface completes the passed in Irp.
|
||
// So just return immediately.
|
||
//
|
||
return status;
|
||
}
|
||
|
||
case IRP_MN_QUERY_DEVICE_TEXT: {
|
||
|
||
status = PcmciaQueryDeviceText(Pdo, Irp);
|
||
|
||
if (status == STATUS_NOT_SUPPORTED ) {
|
||
//
|
||
// Do not change IRP status if this IRP is
|
||
// not handled
|
||
//
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: {
|
||
status = PcmciaFilterPcCardResourceRequirements(pdoExtension, Irp);
|
||
break;
|
||
}
|
||
|
||
case IRP_MN_QUERY_BUS_INFORMATION: {
|
||
status = PcmciaPdoGetBusInformation(pdoExtension,
|
||
(PPNP_BUS_INFORMATION *) &Irp->IoStatus.Information);
|
||
break;
|
||
}
|
||
|
||
default: {
|
||
//
|
||
// Retain the status
|
||
//
|
||
DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x Skipping unsupported irp\n", Pdo, Irp));
|
||
status = Irp->IoStatus.Status;
|
||
break;
|
||
}
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
DebugPrint((PCMCIA_DEBUG_PNP, "pdo %08x irp %08x comp %s %08x\n", Pdo, Irp,
|
||
STATUS_STRING(status), status));
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaPdoGetBusInformation(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
OUT PPNP_BUS_INFORMATION * BusInformation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the bus type information for the pc-card.
|
||
Bus type is GUID_BUS_TYPE_PCMCIA(legacy type is PcmciaBus) for R2 cards
|
||
Bus numbers are not implemented for PCMCIA, so it's always 0
|
||
|
||
Arguments:
|
||
|
||
PdoExtension - pointer to device extension for the pc-card
|
||
|
||
BusInformation - pointer to the bus information structure that
|
||
needs to be filled in
|
||
|
||
Return value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PAGED_CODE();
|
||
|
||
*BusInformation = ExAllocatePool(PagedPool, sizeof (PNP_BUS_INFORMATION));
|
||
if (!*BusInformation) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlCopyMemory(&((*BusInformation)->BusTypeGuid),
|
||
&GUID_BUS_TYPE_PCMCIA,
|
||
sizeof(GUID));
|
||
(*BusInformation)->LegacyBusType = PCMCIABus;
|
||
(*BusInformation)->BusNumber = 0;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
PcmciaPdoGetDeviceInfSettings(
|
||
IN PPDO_EXTENSION PdoExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves settings from the INF for this device.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension - Device extension of the Pc-Card
|
||
|
||
Return value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PSOCKET socket = PdoExtension->Socket;
|
||
UNICODE_STRING KeyName;
|
||
HANDLE instanceHandle;
|
||
UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
|
||
PKEY_VALUE_PARTIAL_INFORMATION value = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
|
||
ULONG length;
|
||
|
||
PAGED_CODE();
|
||
|
||
status = IoOpenDeviceRegistryKey(PdoExtension->DeviceObject,
|
||
PLUGPLAY_REGKEY_DRIVER,
|
||
KEY_READ,
|
||
&instanceHandle
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Look to see if PcmciaExclusiveIrq is specified
|
||
//
|
||
RtlInitUnicodeString(&KeyName, L"PcmciaExclusiveIrq");
|
||
|
||
status = ZwQueryValueKey(instanceHandle,
|
||
&KeyName,
|
||
KeyValuePartialInformation,
|
||
value,
|
||
sizeof(buffer),
|
||
&length);
|
||
|
||
|
||
//
|
||
// If the key doesn't exist, or zero was specified, it means that
|
||
// routing is ok
|
||
//
|
||
if (NT_SUCCESS(status) && (*(PULONG)(value->Data) != 0)) {
|
||
SetDeviceFlag(PdoExtension, PCMCIA_PDO_EXCLUSIVE_IRQ);
|
||
}
|
||
|
||
//
|
||
// Look to see if PcmciaAutoPowerOff is specified
|
||
//
|
||
RtlInitUnicodeString(&KeyName, L"PcmciaAutoPowerOff");
|
||
|
||
status = ZwQueryValueKey(instanceHandle,
|
||
&KeyName,
|
||
KeyValuePartialInformation,
|
||
value,
|
||
sizeof(buffer),
|
||
&length);
|
||
|
||
|
||
//
|
||
// If zero was specified, then don't automatically cut power on shutdown
|
||
//
|
||
if (NT_SUCCESS(status) && (*(PULONG)(value->Data) == 0)) {
|
||
SetDeviceFlag(socket->DeviceExtension, PCMCIA_FDO_DISABLE_AUTO_POWEROFF);
|
||
}
|
||
|
||
//
|
||
// Look to see if PcmciaEnableAudio is specified
|
||
//
|
||
RtlInitUnicodeString(&KeyName, L"PcmciaEnableAudio");
|
||
|
||
status = ZwQueryValueKey(instanceHandle,
|
||
&KeyName,
|
||
KeyValuePartialInformation,
|
||
value,
|
||
sizeof(buffer),
|
||
&length);
|
||
|
||
|
||
//
|
||
// If zero was specified, then don't automatically cut power on shutdown
|
||
//
|
||
if (NT_SUCCESS(status) && (*(PULONG)(value->Data) != 0)) {
|
||
SetDeviceFlag(PdoExtension, PCMCIA_PDO_ENABLE_AUDIO);
|
||
}
|
||
|
||
ZwClose(instanceHandle);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
PcmciaPdoSetDeviceIrqRouting(
|
||
IN PPDO_EXTENSION PdoExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine retrieves settings from the INF for this device.
|
||
|
||
Notes:
|
||
|
||
PcmciaExclusiveIrq in the INF determines how the IRQ for the R2 card will be routed.
|
||
Currently, the following logic is used:
|
||
|
||
if (routing disabled)
|
||
choose either detected or legacy
|
||
else
|
||
if !detected, use FdoIrq
|
||
|
||
So, if routing to PCI at all, then only the PCI IRQ will show up in the IoResList.
|
||
BUT: Another approach would be to use the following logic:
|
||
|
||
if (routing disabled)
|
||
choose either detected or legacy
|
||
else
|
||
*merge detected with FdoIrq*
|
||
|
||
This way we may end up using an exclusive IRQ or routing to PCI, depending on what
|
||
the arbiter has decided. That is the reason why I kept both Detected and Legacy around
|
||
in the FdoExtension, because otherwise it would have made more sense just to choose
|
||
and merge them back when they were generated.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension - Device extension of the Pc-Card
|
||
|
||
Return value:
|
||
|
||
None (SOCKET structure is updated)
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PSOCKET socket = PdoExtension->Socket;
|
||
PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
ResetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
|
||
//
|
||
// First check the conditions that specify we definitely don't want to route to PCI
|
||
//
|
||
|
||
if (!pcmciaDisableIsaPciRouting &&
|
||
CardBusExtension(fdoExtension) &&
|
||
!IsDeviceFlagSet(PdoExtension, PCMCIA_PDO_EXCLUSIVE_IRQ)) {
|
||
|
||
//
|
||
// Here we know we *could* route to PCI, now determine if we *should*. This takes
|
||
// into account several registry settings, as well as the result from the NtDetect
|
||
// IRQ detection algorithm.
|
||
//
|
||
|
||
|
||
//
|
||
// First check to see if there was an override with specifically targeted this
|
||
// controller. This will take precedence.
|
||
//
|
||
if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_FORCE_PCI_ROUTING)) {
|
||
SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
}
|
||
else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_FORCE_ISA_ROUTING)) {
|
||
ResetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
}
|
||
|
||
//
|
||
// Now check to see if the detection algorithm succeeded. We should honor this result,
|
||
// particularly if the map was zero, which tells us there are no ISA IRQs attached.
|
||
//
|
||
else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_IRQ_DETECT_COMPLETED)) {
|
||
if (fdoExtension->DetectedIrqMask == 0) {
|
||
SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Now see if there was a general override based on this controller type. This has
|
||
// less precedence than the detection algorithm.
|
||
//
|
||
else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_PREFER_PCI_ROUTING)) {
|
||
SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
}
|
||
else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_PREFER_ISA_ROUTING)) {
|
||
ResetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
}
|
||
|
||
|
||
//
|
||
// Here look to see if the device was found, but the irq detection failed for some
|
||
// reason. With no special registry overrides, we fall back on the global default.
|
||
//
|
||
else if (IsFdoFlagSet(fdoExtension, PCMCIA_FDO_IRQ_DETECT_DEVICE_FOUND)) {
|
||
if (!(PcmciaGlobalFlags & PCMCIA_DEFAULT_ROUTE_R2_TO_ISA)) {
|
||
SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Here ntdetect never saw the device. Maybe we just hot-docked.
|
||
// We will base our decision on if it was in ACPI namespace or not. If it
|
||
// isn't in ACPI namespace, then it probably is not connected to ISA
|
||
//
|
||
else {
|
||
if (!IsFdoFlagSet(fdoExtension, PCMCIA_FDO_IN_ACPI_NAMESPACE)) {
|
||
SetSocketFlag(socket, SOCKET_CB_ROUTE_R2_TO_PCI);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
socket->IrqMask = fdoExtension->DetectedIrqMask ? fdoExtension->DetectedIrqMask : fdoExtension->LegacyIrqMask;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x IRQ routing=%s, IRQMask=%08x\n", PdoExtension->DeviceObject,
|
||
IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI) ? "PCI" : "ISA",
|
||
socket->IrqMask));
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaFilterPcCardInterrupts(
|
||
IN PIO_RESOURCE_REQUIREMENTS_LIST oldReqList,
|
||
IN ULONG IrqCount,
|
||
IN ULONG IrqMask,
|
||
OUT PIO_RESOURCE_REQUIREMENTS_LIST * FilteredReqList,
|
||
BOOLEAN RouteIsaToPci
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Filters the interrupt resource requirements for R2 Pc-Cards
|
||
|
||
Arguments:
|
||
|
||
oldReqList - Original, 'raw' resource requirements list
|
||
IrqCount - # of irq's that will be deleted (already computed by caller)
|
||
IrqMask - bit mask which indicates which interrupts are valid
|
||
FilteredReqList - pointer to the filtered requirements list which
|
||
will be filled in by this routine
|
||
|
||
Return value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
|
||
PIO_RESOURCE_LIST oldList, newList;
|
||
ULONG newReqSize;
|
||
ULONG oldlistSize, newlistSize;
|
||
ULONG index, oldIndex, newIndex;
|
||
BOOLEAN irqAlternative;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// Compute the size of the structure with the offending IRQs removed.
|
||
//
|
||
newReqSize = oldReqList->ListSize - IrqCount*sizeof(IO_RESOURCE_DESCRIPTOR);
|
||
|
||
newReqList = ExAllocatePool(PagedPool, newReqSize);
|
||
|
||
if (newReqList == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlCopyMemory(newReqList, oldReqList, FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List));
|
||
newReqList->ListSize = newReqSize;
|
||
|
||
newList = newReqList->List;
|
||
oldList = oldReqList->List;
|
||
|
||
//
|
||
// Loop through each alternative list
|
||
//
|
||
for (index = 0; index < oldReqList->AlternativeLists; index++) {
|
||
newList->Version = oldList->Version;
|
||
newList->Revision = oldList->Revision;
|
||
|
||
irqAlternative = FALSE;
|
||
//
|
||
// Loop through each descriptor in the old list
|
||
//
|
||
for (oldIndex = 0, newIndex = 0; oldIndex < oldList->Count; oldIndex++) {
|
||
|
||
if (oldList->Descriptors[oldIndex].Type == CmResourceTypeInterrupt) {
|
||
|
||
if (RouteIsaToPci) {
|
||
|
||
if (!irqAlternative) {
|
||
//
|
||
// First interrupt found, this will be the one we use to route
|
||
//
|
||
newList->Descriptors[newIndex++] = oldList->Descriptors[oldIndex];
|
||
irqAlternative = TRUE;
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// Normal case (not routed). Filter out irqs that aren't in our mask
|
||
//
|
||
if ((IrqMask & (1<<oldList->Descriptors[oldIndex].u.Interrupt.MinimumVector)) != 0) {
|
||
//
|
||
// Not a bad interrupt descriptor. Copy the old to the new
|
||
//
|
||
newList->Descriptors[newIndex] = oldList->Descriptors[oldIndex];
|
||
|
||
if (newList->Descriptors[newIndex].Type == CmResourceTypeInterrupt) {
|
||
if (irqAlternative) {
|
||
newList->Descriptors[newIndex].Option = IO_RESOURCE_ALTERNATIVE;
|
||
} else {
|
||
irqAlternative = TRUE;
|
||
newList->Descriptors[newIndex].Option = 0;
|
||
}
|
||
}
|
||
newIndex++;
|
||
}
|
||
}
|
||
} else {
|
||
//
|
||
// Not an interrupt descriptor. Copy the old to the new
|
||
//
|
||
newList->Descriptors[newIndex++] = oldList->Descriptors[oldIndex];
|
||
}
|
||
}
|
||
newList->Count = newIndex;
|
||
oldlistSize = sizeof(IO_RESOURCE_LIST) + (oldList->Count-1) * sizeof(IO_RESOURCE_DESCRIPTOR);
|
||
newlistSize = sizeof(IO_RESOURCE_LIST) + (newList->Count-1) * sizeof(IO_RESOURCE_DESCRIPTOR);
|
||
oldList = (PIO_RESOURCE_LIST) (((PUCHAR) oldList) + oldlistSize);
|
||
newList = (PIO_RESOURCE_LIST) (((PUCHAR) newList) + newlistSize);
|
||
}
|
||
|
||
*FilteredReqList = newReqList;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaFilterPcCardResourceRequirements(
|
||
IN PPDO_EXTENSION DeviceExtension,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Filters the resource requirements for R2 Pc-Cards
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension - Device extension of the Pc-Card
|
||
|
||
Return value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
PIO_RESOURCE_REQUIREMENTS_LIST IoReqList;
|
||
PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
|
||
PIO_RESOURCE_LIST ioResourceList;
|
||
PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
|
||
PSOCKET socket;
|
||
PFDO_EXTENSION fdoExtension;
|
||
ULONG index1, index2, len;
|
||
ULONGLONG low, high;
|
||
ULONG IrqsToDeleteCount = 0;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
BOOLEAN RouteIrqFound;
|
||
|
||
PAGED_CODE();
|
||
|
||
IoReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information;
|
||
|
||
if (IoReqList == NULL) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
socket = DeviceExtension->Socket;
|
||
fdoExtension = socket->DeviceExtension;
|
||
|
||
for (index1 = 0, ioResourceList = IoReqList->List;
|
||
index1 < IoReqList->AlternativeLists; index1++) {
|
||
ioResourceDesc = ioResourceList->Descriptors;
|
||
|
||
RouteIrqFound = FALSE;
|
||
|
||
for (index2 = 0 ; index2 < ioResourceList->Count; index2++, ioResourceDesc++) {
|
||
if (ioResourceDesc->Type == CmResourceTypeInterrupt) {
|
||
|
||
if (IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)) {
|
||
|
||
//
|
||
// make sure there is space for just 1 level interrupt requirement
|
||
//
|
||
if (!RouteIrqFound) {
|
||
RouteIrqFound = TRUE;
|
||
ioResourceDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
ioResourceDesc->Option = 0;
|
||
ioResourceDesc->ShareDisposition = CmResourceShareShared;
|
||
ioResourceDesc->u.Interrupt.MinimumVector = socket->FdoIrq;
|
||
ioResourceDesc->u.Interrupt.MaximumVector = socket->FdoIrq;
|
||
|
||
} else {
|
||
//
|
||
// Don't need any other IRQs in this list
|
||
//
|
||
IrqsToDeleteCount++;
|
||
}
|
||
|
||
} else {
|
||
ASSERT (ioResourceDesc->u.Interrupt.MinimumVector == ioResourceDesc->u.Interrupt.MaximumVector);
|
||
//
|
||
// Look to see if there are IRQ's specified in this IoResList which are
|
||
// not in our mask. If so, we are going to have to create a new IoResList.
|
||
// Keep track of how many
|
||
|
||
if (!(socket->IrqMask & (1<<ioResourceDesc->u.Interrupt.MinimumVector))) {
|
||
IrqsToDeleteCount++;
|
||
}
|
||
}
|
||
|
||
} else if (ioResourceDesc->Type == CmResourceTypePort) {
|
||
//
|
||
// We might want to filter this..
|
||
//
|
||
low = ioResourceDesc->u.Port.MinimumAddress.QuadPart;
|
||
high = ioResourceDesc->u.Port.MaximumAddress.QuadPart;
|
||
len = ioResourceDesc->u.Port.Length;
|
||
|
||
//
|
||
// A set of messy rules to see if we should filter the requirements.
|
||
//
|
||
// We don't filter if:
|
||
// 1. User requested number of ports which are more than
|
||
// we can legally ask with our filtered high & low caps on the
|
||
// requirements.
|
||
// 2. User requested a 'fixed' resource requirement, i.e. a specific
|
||
// set of ports of a specified length.
|
||
// 3. User specified resource requirements range is smaller
|
||
// than the range we would obtain if we filter it. We don't filter
|
||
// in this case because the filtering is supposed to restrict the range
|
||
// not expand it. If user thinks he can restrict better than us,
|
||
// honor it .
|
||
//
|
||
//
|
||
if (len > (fdoExtension->IoHigh - fdoExtension->IoLow + 1)) {
|
||
//
|
||
// Case 1. above.
|
||
// Don't filter this.
|
||
//
|
||
continue;
|
||
}
|
||
|
||
if ((low + len -1) >= high) {
|
||
//
|
||
// Case 2.
|
||
// This is a fixed requirement. Don't filter it
|
||
//
|
||
continue;
|
||
}
|
||
|
||
|
||
if (((ULONG)(high - low)) <= (fdoExtension->IoHigh - fdoExtension->IoLow)) {
|
||
//
|
||
// Case 3.
|
||
// Don't filter this
|
||
//
|
||
continue;
|
||
}
|
||
|
||
if ((ULONG) low < fdoExtension->IoLow) {
|
||
low = (ULONGLONG) fdoExtension->IoLow;
|
||
}
|
||
|
||
if ((ULONG) high > fdoExtension->IoHigh) {
|
||
high = (ULONGLONG) fdoExtension->IoHigh;
|
||
}
|
||
|
||
ioResourceDesc->u.Port.MinimumAddress.QuadPart = low;
|
||
ioResourceDesc->u.Port.MaximumAddress.QuadPart = high;
|
||
|
||
} else if (ioResourceDesc->Type == CmResourceTypeMemory) {
|
||
|
||
//
|
||
// pccard hardware can't handle > 32bit addressing
|
||
//
|
||
ASSERT(ioResourceDesc->u.Memory.MinimumAddress.HighPart == 0);
|
||
ioResourceDesc->u.Memory.MaximumAddress.HighPart = 0;
|
||
|
||
if (fdoExtension->Flags & PCMCIA_MEMORY_24BIT) {
|
||
|
||
ASSERT((ioResourceDesc->u.Memory.MinimumAddress.LowPart & 0xFF000000) == 0);
|
||
ioResourceDesc->u.Memory.MaximumAddress.LowPart &= 0xFFFFFF;
|
||
|
||
}
|
||
|
||
//
|
||
// win2k had a bug where o2micro controllers were marked as 24bit. When
|
||
// that was fixed, an o2micro smart card device with an INF bug suddenly
|
||
// stopped working (because the first bug masked the second). This code
|
||
// fixes their INF.
|
||
//
|
||
if ((ioResourceDesc->Flags & CM_RESOURCE_MEMORY_24) &&
|
||
(ioResourceDesc->u.Memory.MinimumAddress.LowPart > 0xFFFFFF) &&
|
||
(PcmciaClassFromControllerType(fdoExtension->ControllerType) == PcmciaO2Micro)) {
|
||
|
||
ioResourceDesc->u.Memory.MinimumAddress.LowPart &= 0xFFFFFF;
|
||
}
|
||
}
|
||
}
|
||
|
||
ioResourceList = (PIO_RESOURCE_LIST) (((PUCHAR) ioResourceList) +
|
||
sizeof(IO_RESOURCE_LIST) +
|
||
(ioResourceList->Count - 1)* sizeof(IO_RESOURCE_DESCRIPTOR));
|
||
} // outer for loop
|
||
|
||
if (IrqsToDeleteCount) {
|
||
|
||
status = PcmciaFilterPcCardInterrupts(IoReqList,
|
||
IrqsToDeleteCount,
|
||
socket->IrqMask,
|
||
&newReqList,
|
||
IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)
|
||
);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
Irp->IoStatus.Information = (ULONG_PTR) newReqList;
|
||
ExFreePool(IoReqList);
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaQueryDeviceText(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN OUT PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns descriptive text information about the
|
||
PDO (location and device desc.)
|
||
|
||
Arguments:
|
||
|
||
Pdo - Pointer to the PC-Card's device object
|
||
Irp - IRP_MN_QUERY_DEVICE_TEXT Irp
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_NOT_SUPPORTED - if not supported
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
||
UNICODE_STRING unicodeString;
|
||
ANSI_STRING ansiString;
|
||
UCHAR deviceText[128];
|
||
NTSTATUS status;
|
||
USHORT deviceTextLength;
|
||
PSOCKET_DATA socketData = pdoExtension->SocketData;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (irpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) {
|
||
|
||
if (*(socketData->Mfg) == '\0' ) {
|
||
if (socketData->Flags & SDF_JEDEC_ID) {
|
||
sprintf(deviceText, "%s %s-%04x", PCMCIA_ID_STRING, PCMCIA_MEMORY_ID_STRING, socketData->JedecId);
|
||
|
||
} else {
|
||
sprintf(deviceText, "%s %s", PCMCIA_ID_STRING, PCMCIA_UNKNOWN_MANUFACTURER_STRING);
|
||
}
|
||
} else {
|
||
sprintf(deviceText, "%s %s", socketData->Mfg, socketData->Ident);
|
||
}
|
||
RtlInitAnsiString(&ansiString, deviceText);
|
||
|
||
deviceTextLength = (strlen(deviceText) + 1)*sizeof(WCHAR);
|
||
unicodeString.Buffer = ExAllocatePool(PagedPool, deviceTextLength);
|
||
if (unicodeString.Buffer == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
unicodeString.MaximumLength = deviceTextLength;
|
||
unicodeString.Length = 0;
|
||
|
||
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
|
||
if (!NT_SUCCESS(status)) {
|
||
ExFreePool(unicodeString.Buffer);
|
||
return status;
|
||
}
|
||
|
||
unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR)] = L'\0';
|
||
Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer;
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
status = STATUS_NOT_SUPPORTED ;
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaGetPcCardResourceRequirements(
|
||
PPDO_EXTENSION pdoExtension,
|
||
PULONG_PTR Information
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
Fills in the resource requirements for the PC-Card obtained from the tuple information
|
||
|
||
Arguments:
|
||
|
||
PdoExtension - Pointer to the device extension for the PDO of the pc-card
|
||
Information - Pointer to an allocated resource requirements list is stored in this
|
||
argument. Caller's responsibility to free the list
|
||
|
||
Return value:
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES Could not allocate the list
|
||
STATUS_SUCCES Obtained resource requirements, Information contains the pointer
|
||
to the IO_RESOURCE_REQUIREMENTS list
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PPCMCIA_RESOURCE_CHAIN resListChain = NULL;
|
||
PIO_RESOURCE_REQUIREMENTS_LIST ioResourceRequirementsList;
|
||
PSOCKET socket = pdoExtension->Socket;
|
||
PSOCKET_DATA socketData = pdoExtension->SocketData;
|
||
PCONFIG_ENTRY currentConfigEntry;
|
||
PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
|
||
CONFIG_LIST configList;
|
||
|
||
PAGED_CODE();
|
||
ASSERT (!IsDeviceMultifunction(pdoExtension));
|
||
|
||
//
|
||
// Run through the config entry chains for IO space & Mem space requirements
|
||
//
|
||
configList.SocketData = socketData;
|
||
|
||
for (currentConfigEntry=socketData->ConfigEntryChain; currentConfigEntry != NULL; currentConfigEntry=currentConfigEntry->NextEntry) {
|
||
|
||
if (currentConfigEntry->Flags & PCMCIA_INVALID_CONFIGURATION) {
|
||
continue;
|
||
}
|
||
|
||
configList.ConfigEntry = currentConfigEntry;
|
||
|
||
status = PcmciaConfigEntriesToResourceListChain(pdoExtension,
|
||
&configList,
|
||
(ULONG)1,
|
||
&resListChain
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
}
|
||
|
||
status = PcmciaMergeResourceChainToList(resListChain, &ioResourceRequirementsList);
|
||
|
||
if (NT_SUCCESS(status) && (ioResourceRequirementsList != NULL)) {
|
||
ioResourceRequirementsList->InterfaceType = Isa;
|
||
ioResourceRequirementsList->BusNumber = fdoExtension->Configuration.BusNumber;
|
||
ioResourceRequirementsList->SlotNumber = 0; // Need to revisit this..
|
||
*Information = (ULONG_PTR) ioResourceRequirementsList;
|
||
}
|
||
|
||
PcmciaFreeResourceChain(resListChain);
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaConfigEntriesToResourceListChain(
|
||
PPDO_EXTENSION pdoExtension,
|
||
PCONFIG_LIST ConfigList,
|
||
ULONG configCount,
|
||
PPCMCIA_RESOURCE_CHAIN *ResListChainHead
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Fills in the resource requirements for the PC-Card obtained from the tuple information
|
||
|
||
Arguments:
|
||
|
||
PdoExtension - Pointer to the device extension for the PDO of the pc-card
|
||
|
||
Return value:
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES Could not allocate the list
|
||
STATUS_SUCCES Obtained resource requirements, Information contains the pointer
|
||
to the IO_RESOURCE_REQUIREMENTS list
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
PSOCKET socket = pdoExtension->Socket;
|
||
PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
|
||
PCONFIG_ENTRY currentConfigEntry;
|
||
PPCMCIA_RESOURCE_CHAIN resListChain;
|
||
PIO_RESOURCE_LIST ioResourceList;
|
||
PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
|
||
ULONG irqMask = 0, i, iConfig;
|
||
ULONG totalDescriptorCount = 0;
|
||
ULONG TotalIoRanges = 0;
|
||
ULONG listSize;
|
||
BOOLEAN IoRangeIs16Bit[MAX_NUMBER_OF_IO_RANGES] = {0};
|
||
BOOLEAN irqAlternative;
|
||
|
||
PAGED_CODE();
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x build ioreslist from configlist %08x, config count=%d\n",
|
||
pdoExtension->DeviceObject, ConfigList, configCount));
|
||
|
||
//
|
||
// Calculate how many descriptors we need. This involves also generating
|
||
// the irqmask with the intersection of the irqmasks of the config entries
|
||
// in the array.
|
||
//
|
||
|
||
for (iConfig = 0; iConfig < configCount; iConfig++) {
|
||
currentConfigEntry = ConfigList[iConfig].ConfigEntry;
|
||
|
||
irqMask |= currentConfigEntry->IrqMask;
|
||
|
||
totalDescriptorCount += currentConfigEntry->NumberOfIoPortRanges;
|
||
totalDescriptorCount += currentConfigEntry->NumberOfMemoryRanges;
|
||
}
|
||
|
||
if (irqMask) {
|
||
if (IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)) {
|
||
totalDescriptorCount++;
|
||
} else {
|
||
totalDescriptorCount += PcmciaCountOnes(socket->IrqMask);
|
||
}
|
||
}
|
||
|
||
if (!totalDescriptorCount) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Add one more for our private DPTYPE_PCMCIA_CONFIGURATION
|
||
//
|
||
totalDescriptorCount++;
|
||
|
||
if (configCount > 1) {
|
||
//
|
||
// Add more for our private DPTYPE_PCMCIA_MF_CONFIGURATION
|
||
//
|
||
totalDescriptorCount+=configCount;
|
||
}
|
||
|
||
//
|
||
// Calculate the size of IO_RESOURCE_LIST, allocate and clear it
|
||
//
|
||
|
||
listSize = (totalDescriptorCount - 1) * sizeof(IO_RESOURCE_DESCRIPTOR)
|
||
+ sizeof(IO_RESOURCE_LIST);
|
||
|
||
ioResourceList = ExAllocatePool(PagedPool, listSize);
|
||
if (ioResourceList == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(ioResourceList, listSize);
|
||
|
||
//
|
||
// Now that we have the resource list allocated, fill it in
|
||
//
|
||
|
||
ioResourceList->Version = IO_RESOURCE_LIST_VERSION;
|
||
ioResourceList->Revision = IO_RESOURCE_LIST_REVISION;
|
||
ioResourceList->Count = totalDescriptorCount;
|
||
ioResourceDesc = &ioResourceList->Descriptors[0];
|
||
|
||
//
|
||
// Fill in the IRQ info.
|
||
//
|
||
if (irqMask) {
|
||
if (IsSocketFlagSet(socket, SOCKET_CB_ROUTE_R2_TO_PCI)) {
|
||
|
||
ioResourceDesc->Type = CmResourceTypeInterrupt;
|
||
ioResourceDesc->Option = 0;
|
||
|
||
ioResourceDesc->Flags = (USHORT)CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
ioResourceDesc->ShareDisposition = CmResourceShareShared;
|
||
ioResourceDesc->u.Interrupt.MinimumVector = socket->FdoIrq;
|
||
ioResourceDesc->u.Interrupt.MaximumVector = socket->FdoIrq;
|
||
ioResourceDesc++;
|
||
|
||
} else {
|
||
ULONG irqn;
|
||
|
||
irqMask = socket->IrqMask;
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "irq mask %04x\n", irqMask));
|
||
|
||
//
|
||
// For each IRQ supported, fill in a separate IO descriptor
|
||
//
|
||
irqAlternative = FALSE;
|
||
for (irqn = 0 ;irqMask; irqMask = (irqMask >> 1), irqn++) {
|
||
if (irqMask & 0x1) {
|
||
if (irqAlternative) {
|
||
ioResourceDesc->Option = IO_RESOURCE_ALTERNATIVE;
|
||
} else {
|
||
irqAlternative = TRUE;
|
||
ioResourceDesc->Option = 0;
|
||
}
|
||
ioResourceDesc->Type = CmResourceTypeInterrupt;
|
||
//
|
||
// This is for 16-bit pc-cards.. so request an edge-triggered
|
||
// exclusive interrupt
|
||
//
|
||
ioResourceDesc->Flags = (USHORT)CM_RESOURCE_INTERRUPT_LATCHED;
|
||
ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
ioResourceDesc->u.Interrupt.MinimumVector =
|
||
ioResourceDesc->u.Interrupt.MaximumVector = irqn;
|
||
ioResourceDesc++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
for (iConfig = 0; iConfig < configCount; iConfig++) {
|
||
currentConfigEntry = ConfigList[iConfig].ConfigEntry;
|
||
|
||
//
|
||
// for each I/O range, fill in an IoResourceDescriptor
|
||
//
|
||
for (i = 0; i < currentConfigEntry->NumberOfIoPortRanges; i++) {
|
||
PHYSICAL_ADDRESS port;
|
||
|
||
ioResourceDesc->Option = 0;
|
||
ioResourceDesc->Type = CmResourceTypePort;
|
||
ioResourceDesc->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_16_BIT_DECODE;
|
||
ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
|
||
if (currentConfigEntry->IoPortBase[i] == 0) {
|
||
//
|
||
// This is a flexible requirement. Basically means we need
|
||
// any system address range of specified length & alignment
|
||
//
|
||
port=RtlConvertUlongToLargeInteger(fdoExtension->IoLow);
|
||
ioResourceDesc->u.Port.MinimumAddress = port;
|
||
port=RtlConvertUlongToLargeInteger(fdoExtension->IoHigh);
|
||
ioResourceDesc->u.Port.MaximumAddress = port;
|
||
} else {
|
||
|
||
port = RtlConvertUlongToLargeInteger((ULONG) currentConfigEntry->IoPortBase[i]);
|
||
ioResourceDesc->u.Port.MinimumAddress = port;
|
||
port = RtlConvertUlongToLargeInteger((ULONG) (currentConfigEntry->IoPortBase[i]+
|
||
currentConfigEntry->IoPortLength[i]));
|
||
ioResourceDesc->u.Port.MaximumAddress = port;
|
||
}
|
||
ioResourceDesc->u.Port.Length = (ULONG) currentConfigEntry->IoPortLength[i]+1;
|
||
ioResourceDesc->u.Port.Alignment = currentConfigEntry->IoPortAlignment[i];
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Port range: %08x-%08x, Length %04x\n",
|
||
ioResourceDesc->u.Port.MinimumAddress.LowPart,
|
||
ioResourceDesc->u.Port.MaximumAddress.LowPart,
|
||
ioResourceDesc->u.Port.Length
|
||
));
|
||
|
||
if ((TotalIoRanges < MAX_NUMBER_OF_IO_RANGES) &&
|
||
(currentConfigEntry->Io16BitAccess)) {
|
||
IoRangeIs16Bit[TotalIoRanges] = TRUE;
|
||
}
|
||
TotalIoRanges++;
|
||
|
||
ioResourceDesc++;
|
||
}
|
||
}
|
||
|
||
for (iConfig = 0; iConfig < configCount; iConfig++) {
|
||
currentConfigEntry = ConfigList[iConfig].ConfigEntry;
|
||
|
||
//
|
||
// for each memory range, fill in an IoResourceDescriptor
|
||
//
|
||
for (i = 0; i < currentConfigEntry->NumberOfMemoryRanges; i++) {
|
||
PHYSICAL_ADDRESS mem;
|
||
|
||
ioResourceDesc->Option = 0;
|
||
ioResourceDesc->Type = CmResourceTypeMemory;
|
||
ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
||
ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
if (currentConfigEntry->MemoryHostBase[i]) {
|
||
mem = RtlConvertUlongToLargeInteger((ULONG) currentConfigEntry->MemoryHostBase[i]);
|
||
ioResourceDesc->u.Memory.MinimumAddress = mem;
|
||
mem = RtlConvertUlongToLargeInteger((ULONG) currentConfigEntry->MemoryHostBase[i]+
|
||
(ULONG) currentConfigEntry->MemoryLength[i]-1);
|
||
ioResourceDesc->u.Memory.MaximumAddress = mem;
|
||
} else {
|
||
//
|
||
// Any physical address is ok
|
||
//
|
||
mem = RtlConvertUlongToLargeInteger(0);
|
||
ioResourceDesc->u.Memory.MinimumAddress = mem;
|
||
//
|
||
// Only decode 24 bit memory addresses if there is no page register
|
||
//
|
||
if ((fdoExtension->Flags & PCMCIA_MEMORY_24BIT) == 0) {
|
||
mem = RtlConvertUlongToLargeInteger(0xFFFFFFFF);
|
||
} else {
|
||
mem = RtlConvertUlongToLargeInteger(0xFFFFFF);
|
||
}
|
||
ioResourceDesc->u.Memory.MaximumAddress = mem;
|
||
}
|
||
|
||
ioResourceDesc->u.Memory.Length = currentConfigEntry->MemoryLength[i];
|
||
//
|
||
// Alignment has to be 12 bits
|
||
//
|
||
ioResourceDesc->u.Memory.Alignment = 0x1000;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Mem range: %08x-%08x, Length %08x\n",
|
||
ioResourceDesc->u.Memory.MinimumAddress.LowPart,
|
||
ioResourceDesc->u.Memory.MaximumAddress.LowPart,
|
||
ioResourceDesc->u.Memory.Length
|
||
));
|
||
|
||
ioResourceDesc++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Fill in device private containing our config index
|
||
//
|
||
ioResourceDesc->Option = 0;
|
||
ioResourceDesc->Type = CmResourceTypeDevicePrivate;
|
||
PCMRES_SET_DESCRIPTOR_TYPE(ioResourceDesc, DPTYPE_PCMCIA_CONFIGURATION);
|
||
|
||
currentConfigEntry = ConfigList[0].ConfigEntry;
|
||
PCMRES_SET_CONFIG_INDEX(ioResourceDesc, currentConfigEntry->IndexForThisConfiguration);
|
||
|
||
for (i = 0; i < MAX_NUMBER_OF_IO_RANGES; i++) {
|
||
if (IoRangeIs16Bit[i]) {
|
||
PCMRES_SET_IO_FLAG(ioResourceDesc, i, PCMRESF_IO_16BIT_ACCESS);
|
||
PCMRES_SET_IO_FLAG(ioResourceDesc, i, PCMRESF_IO_SOURCE_16);
|
||
PCMRES_SET_IO_FLAG(ioResourceDesc, i, PCMRESF_IO_WAIT_16);
|
||
}
|
||
}
|
||
|
||
PCMRES_SET_MEMORY_CARDBASE(ioResourceDesc, 0, currentConfigEntry->MemoryCardBase[0]);
|
||
PCMRES_SET_MEMORY_CARDBASE(ioResourceDesc, 1, currentConfigEntry->MemoryCardBase[1]);
|
||
|
||
//
|
||
// Set defaults
|
||
//
|
||
PCMRES_SET_MEMORY_WAITSTATES(ioResourceDesc, 0, PCMRESF_MEM_WAIT_3);
|
||
PCMRES_SET_MEMORY_WAITSTATES(ioResourceDesc, 1, PCMRESF_MEM_WAIT_3);
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "device private %08x %08x %08x\n",
|
||
ioResourceDesc->u.DevicePrivate.Data[0],
|
||
ioResourceDesc->u.DevicePrivate.Data[1],
|
||
ioResourceDesc->u.DevicePrivate.Data[2]
|
||
));
|
||
|
||
ioResourceDesc++;
|
||
|
||
//
|
||
// Fill in device private for MF configurations
|
||
//
|
||
|
||
if (configCount > 1) {
|
||
|
||
for (iConfig = 0; iConfig < configCount; iConfig++) {
|
||
PSOCKET_DATA socketData;
|
||
|
||
currentConfigEntry = ConfigList[iConfig].ConfigEntry;
|
||
socketData = ConfigList[iConfig].SocketData;
|
||
|
||
ioResourceDesc->Option = 0;
|
||
ioResourceDesc->Type = CmResourceTypeDevicePrivate;
|
||
PCMRES_SET_DESCRIPTOR_TYPE(ioResourceDesc, DPTYPE_PCMCIA_MF_CONFIGURATION);
|
||
|
||
PCMRES_SET_CONFIG_OPTIONS(ioResourceDesc, currentConfigEntry->IndexForThisConfiguration);
|
||
PCMRES_SET_PORT_RESOURCE_INDEX(ioResourceDesc, socketData->MfIoPortResourceMapIndex);
|
||
if (socketData->DeviceType == PCCARD_TYPE_MODEM) {
|
||
PCMRES_SET_AUDIO_ENABLE(ioResourceDesc);
|
||
}
|
||
PCMRES_SET_CONFIG_REGISTER_BASE(ioResourceDesc, socketData->ConfigRegisterBase);
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "device private MF %08x %08x %08x\n",
|
||
ioResourceDesc->u.DevicePrivate.Data[0],
|
||
ioResourceDesc->u.DevicePrivate.Data[1],
|
||
ioResourceDesc->u.DevicePrivate.Data[2]
|
||
));
|
||
ioResourceDesc++;
|
||
}
|
||
}
|
||
|
||
ASSERT(ioResourceDesc == &ioResourceList->Descriptors[ioResourceList->Count]);
|
||
|
||
//
|
||
// Allocate an PCMCIA_RESOURCE_CHAIN structure to track the IO_RESOURCE_LIST.
|
||
//
|
||
resListChain = ExAllocatePool(PagedPool, sizeof(PCMCIA_RESOURCE_CHAIN));
|
||
if (resListChain == NULL) {
|
||
ExFreePool(ioResourceList);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
resListChain->IoResList = ioResourceList;
|
||
|
||
//
|
||
// Link this new node onto the passed in chain
|
||
//
|
||
resListChain->NextList = *ResListChainHead;
|
||
*ResListChainHead = resListChain;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Added resource chain node %08x, ioreslist %08x\n",
|
||
resListChain, ioResourceList));
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaMergeResourceChainToList(
|
||
PPCMCIA_RESOURCE_CHAIN ResListChainHead,
|
||
PIO_RESOURCE_REQUIREMENTS_LIST *GeneratedResourceRequirementsList
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PPCMCIA_RESOURCE_CHAIN resListChain;
|
||
PIO_RESOURCE_REQUIREMENTS_LIST ioResourceRequirementsList;
|
||
PIO_RESOURCE_LIST newIoResList, oldIoResList;
|
||
ULONG listSize, listCount, totalDescriptorCount;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// Now merge the newly created IO_RESOURCE_LISTs into one big
|
||
// IO_RESOURCE_REQUIREMENTS list.
|
||
//
|
||
|
||
listCount = 0;
|
||
totalDescriptorCount = 0;
|
||
|
||
for (resListChain = ResListChainHead; resListChain != NULL; resListChain = resListChain->NextList) {
|
||
listCount++;
|
||
totalDescriptorCount += resListChain->IoResList->Count;
|
||
}
|
||
|
||
if (totalDescriptorCount > 0) {
|
||
|
||
listSize = (totalDescriptorCount - listCount) * sizeof(IO_RESOURCE_DESCRIPTOR)
|
||
+ (listCount-1) * sizeof(IO_RESOURCE_LIST)
|
||
+ sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
|
||
|
||
//
|
||
// Allocate space for the res. req. list here
|
||
//
|
||
ioResourceRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, listSize);
|
||
|
||
if (ioResourceRequirementsList == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Init the list
|
||
//
|
||
|
||
RtlZeroMemory(ioResourceRequirementsList, listSize);
|
||
ioResourceRequirementsList->ListSize = listSize;
|
||
ioResourceRequirementsList->AlternativeLists = listCount;
|
||
|
||
//
|
||
// Copy in all the other lists. Point the target pointer (newIoResList)
|
||
// at the end of the list, and lay each new list preceding the old
|
||
// one. This is done because the list is LIFO.
|
||
//
|
||
|
||
newIoResList = (PIO_RESOURCE_LIST) (((PUCHAR) ioResourceRequirementsList) + listSize);
|
||
|
||
for (resListChain = ResListChainHead; resListChain != NULL; resListChain = resListChain->NextList) {
|
||
|
||
oldIoResList = resListChain->IoResList;
|
||
listSize = sizeof(IO_RESOURCE_LIST) + (oldIoResList->Count-1)*sizeof(IO_RESOURCE_DESCRIPTOR);
|
||
newIoResList = (PIO_RESOURCE_LIST) (((PUCHAR) newIoResList) - listSize);
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Merge resource chain node %08x, ioreslist %08x\n",
|
||
resListChain, oldIoResList));
|
||
|
||
RtlCopyMemory(newIoResList, oldIoResList, listSize);
|
||
}
|
||
|
||
ASSERT(newIoResList == &ioResourceRequirementsList->List[0]);
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Resource chain merged to ioResourceRequirementsList %08x\n",
|
||
ioResourceRequirementsList));
|
||
|
||
} else {
|
||
ioResourceRequirementsList = NULL;
|
||
}
|
||
|
||
*GeneratedResourceRequirementsList = ioResourceRequirementsList;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
PcmciaFreeResourceChain(
|
||
PPCMCIA_RESOURCE_CHAIN ResListChain
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PPCMCIA_RESOURCE_CHAIN prevResListChain;
|
||
|
||
PAGED_CODE();
|
||
//
|
||
// free the temporary structures
|
||
//
|
||
while (ResListChain != NULL) {
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Delete resource chain node %08x, ioreslist %08x\n",
|
||
ResListChain, ResListChain->IoResList));
|
||
if (ResListChain->IoResList) {
|
||
ExFreePool(ResListChain->IoResList);
|
||
}
|
||
prevResListChain = ResListChain;
|
||
ResListChain = ResListChain->NextList;
|
||
ExFreePool(prevResListChain);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaMfEnumerateConfigurations(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
IN PSOCKET_DATA socketData,
|
||
PCONFIG_LIST ConfigList,
|
||
IN ULONG Depth,
|
||
PPCMCIA_RESOURCE_CHAIN *MfResListChain
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is responsible for enumerating combinations of resource
|
||
requirements for the functions in a true R2 MF card. It is called
|
||
recursively to perform this function.
|
||
|
||
See the description of PcmciaMfGetResourceRequirements() to see the
|
||
initial state. This routine runs down the linked list of SocketData
|
||
structures, and each corresponding linked list of ConfigData structures.
|
||
|
||
When it finds itself at the end of the SocketData list, it is ready
|
||
to build an IoResList for a single permutation. It calls
|
||
PcmciaConfigEntriesToResourceList() to build a single IoResList.
|
||
|
||
In the example MF card with two functions, and 2 and 3 resource
|
||
alternatives respectively, this routine will build a list that looks
|
||
something like this:
|
||
|
||
+--------------+
|
||
|MfResListChain|
|
||
+--------------+
|
||
| +-----------------------+ +----------------+
|
||
+--------|MF_RESOURCE_LIST(A1+B1)|-----|IoResList(A1+B1)|
|
||
+-----------------------+ +----------------+
|
||
|
|
||
+-----------------------+ +----------------+
|
||
|MF_RESOURCE_LIST(A1+B2)|-----|IoResList(A1+B2)|
|
||
+-----------------------+ +----------------+
|
||
|
|
||
+-----------------------+ +----------------+
|
||
|MF_RESOURCE_LIST(A1+B3)|-----|IoResList(A1+B3)|
|
||
+-----------------------+ +----------------+
|
||
|
|
||
+-----------------------+ +----------------+
|
||
|MF_RESOURCE_LIST(A2+B1)|-----|IoResList(A2+B1)|
|
||
+-----------------------+ +----------------+
|
||
|
|
||
+-----------------------+ +----------------+
|
||
|MF_RESOURCE_LIST(A2+B2)|-----|IoResList(A2+B2)|
|
||
+-----------------------+ +----------------+
|
||
|
|
||
+-----------------------+ +----------------+
|
||
|MF_RESOURCE_LIST(A2+B3)|-----|IoResList(A2+B3)|
|
||
+-----------------------+ +----------------+
|
||
|
||
It returns to PcmciaMfGetResourceRequirements() when the list is complete.
|
||
|
||
|
||
Arguments:
|
||
|
||
PdoExtension - Pointer to the device extension for the PDO of the pc-card
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PFDO_EXTENSION fdoExtension = PdoExtension->Socket->DeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!socketData) {
|
||
//
|
||
// End of SocketData chain, now ready to generate IoResList for this
|
||
//
|
||
|
||
if (PcmciaMfCheckForOverlappingRanges(ConfigList, (LONG)Depth)) {
|
||
//
|
||
// This combination would have generated a bad IoResList
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Build an io resource list from the current config list
|
||
//
|
||
|
||
status = PcmciaConfigEntriesToResourceListChain(PdoExtension,
|
||
ConfigList,
|
||
Depth,
|
||
MfResListChain
|
||
);
|
||
|
||
} else {
|
||
PCONFIG_ENTRY configEntry;
|
||
//
|
||
// Not at the bottom of the tree. Recurse through each config entry
|
||
// in this socket data.
|
||
//
|
||
|
||
ConfigList[Depth].SocketData = socketData;
|
||
|
||
for (configEntry = socketData->ConfigEntryChain;
|
||
configEntry != NULL; configEntry = configEntry->NextEntry) {
|
||
|
||
if (configEntry->Flags & PCMCIA_INVALID_CONFIGURATION) {
|
||
continue;
|
||
}
|
||
|
||
ConfigList[Depth].ConfigEntry = configEntry;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x mf enum %d sktdata %08x configEntry %08x\n",
|
||
PdoExtension->DeviceObject, Depth, socketData, configEntry));
|
||
|
||
status = PcmciaMfEnumerateConfigurations(PdoExtension,
|
||
socketData->Next,
|
||
ConfigList,
|
||
Depth+1,
|
||
MfResListChain);
|
||
}
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaMfGetResourceRequirements(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
PULONG_PTR Information
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
For true Multifunction R2 cards, this routine generates a conglomerate
|
||
IoResourceList based on the permutations of configurations of the
|
||
functions.
|
||
|
||
Initially the tuple parsing code builds an internal representation of
|
||
the configuration requirements of the cards with SocketData and
|
||
ConfigData structures. Each SocketData structure represents an
|
||
individual function, and each ConfigData represents an alternative
|
||
resource requirement list for that function.
|
||
|
||
So for example, an MF card that has two functions may have an internal
|
||
layout like this:
|
||
|
||
+------------+
|
||
|PdoExtension|
|
||
+------------+
|
||
| +-----------+ +-----------+
|
||
+----------|SocketDataA|----------|SocketDataB|----0
|
||
+-----------+ +-----------+
|
||
| |
|
||
+------------+ +------------+
|
||
|ConfigDataA1| |ConfigDataB1|
|
||
+------------+ +------------+
|
||
| |
|
||
+------------+ +------------+
|
||
|ConfigDataA2| |ConfigDataB2|
|
||
+------------+ +------------+
|
||
| |
|
||
0 +------------+
|
||
|ConfigDataB3|
|
||
+------------+
|
||
|
|
||
0
|
||
|
||
This example shows that function A has two resource requirement alternatives,
|
||
and function B has three. What we do is make permutations of each alternative,
|
||
e.g.:
|
||
A1-B1, A1-B2, A1-B3, A2-B1, A2-B2, A2-B3
|
||
|
||
The permutations are built with recursive calls to PcmciaMfEnumerateConfigurations().
|
||
In this example, the result of this enumeration will be six independent
|
||
IoResLists. Each IoResList will be a merge of the particular permutation. When
|
||
PcmciaMfEnumerateConfigurations() returns to this routine, these IoResLists will
|
||
be chained together through the pointer MfResListChain. The rest of the routine
|
||
builds a single "six-member" IoResList from the chain.
|
||
|
||
Finally the support structure and lists for performing the operation are freed, and
|
||
the single conglomerate list is returned.
|
||
|
||
|
||
Arguments:
|
||
|
||
PdoExtension - Pointer to the device extension for the PDO of the pc-card
|
||
Information - Pointer to an allocated resource requirements list is stored in this
|
||
argument. Caller's responsibility to free the list
|
||
|
||
Return value:
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES Could not allocate the list
|
||
STATUS_SUCCES Obtained resource requirements, Information contains the pointer
|
||
to the IO_RESOURCE_REQUIREMENTS list
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PFDO_EXTENSION fdoExtension = PdoExtension->Socket->DeviceExtension;
|
||
ULONG MaxDepth = 0;
|
||
PSOCKET_DATA socketData;
|
||
PCONFIG_LIST ConfigList;
|
||
PPCMCIA_RESOURCE_CHAIN MfResListChain = NULL;
|
||
PIO_RESOURCE_REQUIREMENTS_LIST ioResourceRequirementsList;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT (IsDeviceMultifunction(PdoExtension));
|
||
|
||
//
|
||
// Find out how deep the enumeration will be.
|
||
// Should be the same as Socket->NumberOfFunctions, but just to be paranoid...
|
||
//
|
||
for (socketData = PdoExtension->SocketData; socketData != NULL; socketData = socketData->Next) {
|
||
MaxDepth++;
|
||
}
|
||
|
||
if (!MaxDepth) {
|
||
ASSERT (PdoExtension->SocketData);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
ConfigList = ExAllocatePool(PagedPool, MaxDepth*sizeof(CONFIG_LIST));
|
||
|
||
if (!ConfigList) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
PcmciaMfBuildResourceMapInfo(PdoExtension, ConfigList, MaxDepth);
|
||
|
||
|
||
status = PcmciaMfEnumerateConfigurations(PdoExtension,
|
||
PdoExtension->SocketData,
|
||
ConfigList,
|
||
0,
|
||
&MfResListChain);
|
||
|
||
ExFreePool(ConfigList);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Now merge everything that EnumerateConfigurations built into a single list
|
||
//
|
||
status = PcmciaMergeResourceChainToList(MfResListChain, &ioResourceRequirementsList);
|
||
}
|
||
|
||
if (NT_SUCCESS(status) && (ioResourceRequirementsList != NULL)) {
|
||
ioResourceRequirementsList->InterfaceType = Isa;
|
||
ioResourceRequirementsList->BusNumber = fdoExtension->Configuration.BusNumber;
|
||
ioResourceRequirementsList->SlotNumber = 0; // Need to revisit this..
|
||
*Information = (ULONG_PTR) ioResourceRequirementsList;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "pdo %08x mf returning req list %08x, %d alternatives\n",
|
||
PdoExtension->DeviceObject, ioResourceRequirementsList,
|
||
ioResourceRequirementsList->AlternativeLists
|
||
));
|
||
}
|
||
|
||
PcmciaFreeResourceChain(MfResListChain);
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
PcmciaMfBuildResourceMapInfo(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
PCONFIG_LIST ConfigList,
|
||
ULONG ConfigCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes variables in the SocketData structures to allow
|
||
PcmciaMfEnumerateChild() to correctly build ChildInfo ResourceMaps for MF.SYS.
|
||
|
||
It needs to calculate the base index for a particular resource of a particular
|
||
function. So for the example of a 2-function MF R2 card, the resulting CmResList
|
||
will be layed out positionally like:
|
||
|
||
CmResList
|
||
IRQ (Shared)
|
||
I/O (Function A)
|
||
I/O (Function B)
|
||
Mem (Function A)
|
||
Mem (Function B)
|
||
|
||
The reason for this is this is simply how PcmciaConfigEntriesToResourceList()
|
||
happens to lay out the requirements. So in order to generate a valid resource
|
||
map, this routine has to calculate, for example, the Memory Base for function B
|
||
by adding together:
|
||
1 (if there will be an IRQ in the cmreslist)
|
||
# of I/O port resources for A
|
||
# of I/O port resources for B
|
||
# of Mem resource for A
|
||
This sum will give you the position in the CmReslist for the first memory resource
|
||
that B would use.
|
||
|
||
These calculations are stored in the socket data structures for each corresponding
|
||
function so that PcmciaMfEnumerateChild() can simply fill in the maps for MF.
|
||
|
||
Arguments:
|
||
|
||
PdoExtension - Pointer to the device extension for the PDO of the pc-card
|
||
ConfigList - config list array holds a permutation of configdata's
|
||
ConfigCount - # of card functions
|
||
|
||
Return value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PSOCKET_DATA socketData;
|
||
PCONFIG_ENTRY configEntry;
|
||
ULONG index;
|
||
USHORT count;
|
||
UCHAR currentResourceMapIndex = 0;
|
||
BOOLEAN needsIRQ = FALSE;
|
||
|
||
for (index = 0, socketData = PdoExtension->SocketData; socketData != NULL; socketData = socketData->Next) {
|
||
|
||
//
|
||
// In the current implementation we assume that all the alternative lists in the
|
||
// io resource requirements for the multifunction parent pc-card have the same number
|
||
// and types of resource requirements. i.e. it's currently illegal to request
|
||
// one configuration in which only IRQ and I/O are requested, for example, and an
|
||
// alternative configuration in which MEMORY is also specified.
|
||
// This is because of the limitation in the MF enumerator - (which in turn relied
|
||
// on the Win 9x implementation).
|
||
// So we currently look at only the first valid configuration - that is representative
|
||
// of all the other configurations.
|
||
//
|
||
for (configEntry = socketData->ConfigEntryChain; (configEntry != NULL) &&
|
||
(configEntry->Flags & PCMCIA_INVALID_CONFIGURATION);
|
||
configEntry = configEntry->NextEntry);
|
||
|
||
if (configEntry == NULL) {
|
||
return;
|
||
}
|
||
|
||
ASSERT(index < ConfigCount);
|
||
|
||
ConfigList[index].SocketData = socketData;
|
||
ConfigList[index].ConfigEntry = configEntry;
|
||
index++;
|
||
}
|
||
|
||
//
|
||
// IRQ is unique because it is the only shared resource. So if the card needs an IRQ, then
|
||
// all devices point to the same resource
|
||
|
||
for (index = 0; index < ConfigCount; index++) {
|
||
if (ConfigList[index].ConfigEntry->IrqMask) {
|
||
//
|
||
// Index always maps to zero since PcmciaConfigEntriesToResourceList
|
||
// builds IRQs first.
|
||
//
|
||
ConfigList[index].SocketData->MfIrqResourceMapIndex = currentResourceMapIndex;
|
||
ConfigList[index].SocketData->MfNeedsIrq = TRUE;
|
||
needsIRQ = TRUE;
|
||
}
|
||
}
|
||
|
||
if (needsIRQ) {
|
||
currentResourceMapIndex++;
|
||
}
|
||
|
||
//
|
||
// fill in the bases of the I/O port ranges
|
||
//
|
||
for (index = 0; index < ConfigCount; index++) {
|
||
ConfigList[index].SocketData->MfIoPortResourceMapIndex = currentResourceMapIndex;
|
||
|
||
count = ConfigList[index].ConfigEntry->NumberOfIoPortRanges;
|
||
|
||
ConfigList[index].SocketData->MfIoPortCount = count;
|
||
currentResourceMapIndex += count;
|
||
}
|
||
|
||
//
|
||
// fill in the bases of the memory ranges
|
||
//
|
||
for (index = 0; index < ConfigCount; index++) {
|
||
ConfigList[index].SocketData->MfMemoryResourceMapIndex = currentResourceMapIndex;
|
||
|
||
count = ConfigList[index].ConfigEntry->NumberOfMemoryRanges;
|
||
|
||
ConfigList[index].SocketData->MfMemoryCount = count;
|
||
currentResourceMapIndex += count;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
PcmciaMfCheckForOverlappingRanges(
|
||
PCONFIG_LIST ConfigList,
|
||
LONG ConfigCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans through the current config list to see if the set of configurations
|
||
overlap. For example, if the MF R2 card is a dual-serial card, then each serial device
|
||
may want to have one of the standard com addresses (e.g. 3f8, 2f8, etc.). But now
|
||
that we are merging configurations, we need to weed out any overlapping ranges so
|
||
we don't produce a congolmerate IoResList that contains the same range for different
|
||
functions.
|
||
|
||
Arguments:
|
||
|
||
ConfigList - config list array holds a permutation of configdata's
|
||
ConfigCount - # of card functions
|
||
|
||
Return value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PCONFIG_ENTRY configEntry1, configEntry2;
|
||
LONG configIndex1, configIndex2;
|
||
LONG configCount1, configCount2;
|
||
LONG rangeIndex1, rangeIndex2;
|
||
LONG rangeCount1, rangeCount2;
|
||
ULONG rangeStart1, rangeStart2;
|
||
ULONG rangeEnd1, rangeEnd2;
|
||
BOOLEAN rangesOverlap = FALSE;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Range Check--------------\n"));
|
||
//
|
||
// Check for overlap in the I/O port ranges
|
||
//
|
||
try {
|
||
for (configIndex1 = 0; configIndex1 < ConfigCount; configIndex1++) {
|
||
|
||
configEntry1 = ConfigList[configIndex1].ConfigEntry;
|
||
rangeCount1 = configEntry1->NumberOfIoPortRanges;
|
||
|
||
for (rangeIndex1 = 0; rangeIndex1 < rangeCount1; rangeIndex1++) {
|
||
//
|
||
// Get the current range we will compare
|
||
//
|
||
rangeStart1 = configEntry1->IoPortBase[rangeIndex1];
|
||
rangeEnd1 = rangeStart1 + configEntry1->IoPortLength[rangeIndex1];
|
||
|
||
if (rangeStart1 == 0) {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck I/O: skip unrestricted range %x.%x\n",
|
||
configIndex1, rangeIndex1));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Now start comparing this against the rest of the ranges by
|
||
// starting at then end and working backwards.
|
||
//
|
||
for (configIndex2 = ConfigCount-1; configIndex2 >= 0; configIndex2--) {
|
||
configEntry2 = ConfigList[configIndex2].ConfigEntry;
|
||
rangeCount2 = configEntry2->NumberOfIoPortRanges;
|
||
|
||
for (rangeIndex2 = rangeCount2-1; rangeIndex2 >= 0; rangeIndex2--) {
|
||
|
||
if ((configEntry1 == configEntry2) && (rangeIndex1 == rangeIndex2)) {
|
||
leave;
|
||
}
|
||
|
||
rangeStart2 = configEntry2->IoPortBase[rangeIndex2];
|
||
rangeEnd2 = rangeStart2 + configEntry2->IoPortLength[rangeIndex2];
|
||
|
||
if (rangeStart2 == 0) {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck I/O: skip unrestricted range %x.%x\n",
|
||
configIndex2, rangeIndex2));
|
||
continue;
|
||
}
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck I/O: %x.%x %04x-%04x :: %x.%x %04x-%04x\n",
|
||
configIndex1, rangeIndex1, rangeStart1, rangeEnd1,
|
||
configIndex2, rangeIndex2, rangeStart2, rangeEnd2));
|
||
|
||
if (((rangeStart1 >= rangeStart2) && (rangeStart1 <= rangeEnd2)) ||
|
||
((rangeEnd1 >= rangeStart2) && (rangeEnd1 <= rangeEnd2))) {
|
||
rangesOverlap = TRUE;
|
||
leave;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} finally {
|
||
}
|
||
|
||
if (rangesOverlap) {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Overlap Detected---------\n"));
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Check for overlap in the memory ranges
|
||
//
|
||
try {
|
||
for (configIndex1 = 0; configIndex1 < ConfigCount; configIndex1++) {
|
||
|
||
configEntry1 = ConfigList[configIndex1].ConfigEntry;
|
||
rangeCount1 = configEntry1->NumberOfMemoryRanges;
|
||
|
||
for (rangeIndex1 = 0; rangeIndex1 < rangeCount1; rangeIndex1++) {
|
||
//
|
||
// Get the current range we will compare
|
||
//
|
||
rangeStart1 = configEntry1->MemoryHostBase[rangeIndex1];
|
||
rangeEnd1 = rangeStart1 + configEntry1->MemoryLength[rangeIndex1] - 1;
|
||
|
||
if (rangeStart1 == 0) {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck MEM: skip unrestricted range %x.%x\n",
|
||
configIndex1, rangeIndex1));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Now start comparing this against the rest of the ranges by
|
||
// starting at then end and working backwards.
|
||
//
|
||
for (configIndex2 = ConfigCount-1; configIndex2 >= 0; configIndex2--) {
|
||
configEntry2 = ConfigList[configIndex2].ConfigEntry;
|
||
rangeCount2 = configEntry2->NumberOfMemoryRanges;
|
||
|
||
for (rangeIndex2 = rangeCount2-1; rangeIndex2 >= 0; rangeIndex2--) {
|
||
|
||
if ((configEntry1 == configEntry2) && (rangeIndex1 == rangeIndex2)) {
|
||
leave;
|
||
}
|
||
|
||
rangeStart2 = configEntry2->MemoryHostBase[rangeIndex2];
|
||
rangeEnd2 = rangeStart2 + configEntry2->MemoryLength[rangeIndex2] - 1;
|
||
|
||
if (rangeStart2 == 0) {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck MEM: skip unrestricted range %x.%x\n",
|
||
configIndex2, rangeIndex2));
|
||
continue;
|
||
}
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "RangeCheck MEM: %x.%x %08x-%08x :: %x.%x %08x-%08x\n",
|
||
configIndex1, rangeIndex1, rangeStart1, rangeEnd1,
|
||
configIndex2, rangeIndex2, rangeStart2, rangeEnd2));
|
||
|
||
if (((rangeStart1 >= rangeStart2) && (rangeStart1 <= rangeEnd2)) ||
|
||
((rangeEnd1 >= rangeStart2) && (rangeEnd1 <= rangeEnd2))) {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Overlap Detected---------\n"));
|
||
rangesOverlap = TRUE;
|
||
leave;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} finally {
|
||
}
|
||
|
||
#if DBG
|
||
if (rangesOverlap) {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Overlap Detected---------\n"));
|
||
} else {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "-------Generate IoResList-------\n"));
|
||
}
|
||
#endif
|
||
|
||
return rangesOverlap;
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaStartPcCard(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PCM_RESOURCE_LIST ResourceList,
|
||
IN OUT PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine attempts to start the PC-Card by configuring it with the supplied resources.
|
||
|
||
|
||
Arguments:
|
||
|
||
Pdo - Pointer to the device object representing the PC-Card which needs to be started
|
||
ResourceList - Pointer the list of assigned resources for the PC-Card
|
||
|
||
Return value:
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Not sufficient resources supplied to start device/
|
||
could not allocate memory
|
||
STATUS_UNSUCCESSFUL - Supplied resources are invalid for this PC-Card
|
||
STATUS_SUCCESS - Configured and started the card successfully
|
||
|
||
--*/
|
||
{
|
||
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
|
||
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
|
||
ULONG fullResourceDescCount, partialResourceDescCount, i, index;
|
||
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
||
PSOCKET socket = pdoExtension->Socket;
|
||
PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
|
||
PSOCKET_DATA socketData = pdoExtension->SocketData;
|
||
PSOCKET_CONFIGURATION socketConfig;
|
||
PCONFIG_ENTRY currentConfig;
|
||
PFUNCTION_CONFIGURATION fnConfig;
|
||
NTSTATUS status;
|
||
ULONG scIoIndex = 0, scMemIndex = 0;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (IsDeviceStarted(pdoExtension)) {
|
||
//
|
||
// Already started..
|
||
//
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
if (IsDevicePhysicallyRemoved(pdoExtension)) {
|
||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||
}
|
||
|
||
if ( ResourceList == NULL ) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
PcmciaCleanupSocketConfiguration(pdoExtension);
|
||
|
||
socketConfig = ExAllocatePool(NonPagedPool, sizeof(SOCKET_CONFIGURATION));
|
||
if (!socketConfig) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(socketConfig, sizeof(SOCKET_CONFIGURATION));
|
||
|
||
fullResourceDescCount = ResourceList->Count;
|
||
|
||
ASSERT(fullResourceDescCount == 1);
|
||
|
||
fullResourceDesc = &ResourceList->List[0];
|
||
partialResourceList = &fullResourceDesc->PartialResourceList;
|
||
partialResourceDesc = partialResourceList->PartialDescriptors;
|
||
partialResourceDescCount = partialResourceList->Count;
|
||
|
||
socketConfig->NumberOfIoPortRanges =
|
||
socketConfig->NumberOfMemoryRanges = 0;
|
||
|
||
for (i=0; i< partialResourceList->Count; i++, partialResourceDesc++) {
|
||
switch (partialResourceDesc->Type) {
|
||
case CmResourceTypePort: {
|
||
index = socketConfig->NumberOfIoPortRanges;
|
||
socketConfig->Io[index].Base = partialResourceDesc->u.Port.Start.LowPart;
|
||
socketConfig->Io[index].Length = (USHORT) partialResourceDesc->u.Port.Length-1;
|
||
socketConfig->NumberOfIoPortRanges++;
|
||
break;
|
||
}
|
||
|
||
case CmResourceTypeMemory: {
|
||
index = socketConfig->NumberOfMemoryRanges;
|
||
socketConfig->Memory[index].HostBase = partialResourceDesc->u.Memory.Start.LowPart;
|
||
socketConfig->Memory[index].Length = partialResourceDesc->u.Memory.Length;
|
||
socketConfig->NumberOfMemoryRanges++;
|
||
break;
|
||
}
|
||
|
||
case CmResourceTypeInterrupt: {
|
||
socketConfig->Irq = partialResourceDesc->u.Interrupt.Level;
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Assigned Irq: 0x%x for socket register offset %d\n",
|
||
socketConfig->Irq, socket->RegisterOffset));
|
||
break;
|
||
}
|
||
|
||
case CmResourceTypePcCardConfig:
|
||
case CmResourceTypeMfCardConfig:
|
||
case CmResourceTypeDevicePrivate: {
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "DevicePrivate received, Data= %08x %08x %08x\n",
|
||
partialResourceDesc->u.DevicePrivate.Data[0],
|
||
partialResourceDesc->u.DevicePrivate.Data[1],
|
||
partialResourceDesc->u.DevicePrivate.Data[2]));
|
||
|
||
if (PCMRES_GET_DESCRIPTOR_TYPE (partialResourceDesc) == DPTYPE_PCMCIA_CONFIGURATION) {
|
||
//
|
||
// Single function configuration private
|
||
//
|
||
socketConfig->IndexForCurrentConfiguration = PCMRES_GET_CONFIG_INDEX(partialResourceDesc);
|
||
socketConfig->ConfigRegisterBase = socketData->ConfigRegisterBase;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "Pccard config resource\n"));
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, " Index %x\n", socketConfig->IndexForCurrentConfiguration));
|
||
|
||
for (index = 0; index < PCMRES_PCMCIA_MAX_IO; index++) {
|
||
|
||
if (scIoIndex >= MAX_NUMBER_OF_IO_RANGES) {
|
||
break;
|
||
}
|
||
|
||
socketConfig->Io[scIoIndex].Width16 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_16BIT_ACCESS);
|
||
socketConfig->Io[scIoIndex].WaitState16 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_WAIT_16);
|
||
socketConfig->Io[scIoIndex].Source16 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_SOURCE_16);
|
||
socketConfig->Io[scIoIndex].ZeroWait8 = PCMRES_GET_IO_FLAG(partialResourceDesc, index, PCMRESF_IO_ZERO_WAIT_8);
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "PcCardConfig IO%d - Width:%d, Wait16:%d, Source16:%d, ZeroWait8:%d\n", scIoIndex,
|
||
socketConfig->Io[scIoIndex].Width16,
|
||
socketConfig->Io[scIoIndex].WaitState16,
|
||
socketConfig->Io[scIoIndex].Source16,
|
||
socketConfig->Io[scIoIndex].ZeroWait8));
|
||
|
||
scIoIndex++;
|
||
}
|
||
|
||
for (index = 0; index < PCMRES_PCMCIA_MAX_MEM; index++) {
|
||
|
||
if (scMemIndex >= MAX_NUMBER_OF_MEMORY_RANGES) {
|
||
break;
|
||
}
|
||
|
||
socketConfig->Memory[scMemIndex].Width16 = PCMRES_GET_MEMORY_FLAG(partialResourceDesc, index, PCMRESF_MEM_16BIT_ACCESS);
|
||
socketConfig->Memory[scMemIndex].WaitState = PCMRES_GET_MEMORY_WAITSTATES(partialResourceDesc, index);
|
||
socketConfig->Memory[scMemIndex].IsAttribute = PCMRES_GET_MEMORY_FLAG(partialResourceDesc, index, PCMRESF_MEM_ATTRIBUTE);
|
||
socketConfig->Memory[scMemIndex].CardBase = PCMRES_GET_MEMORY_CARDBASE(partialResourceDesc, index);
|
||
|
||
DebugPrint((PCMCIA_DEBUG_RESOURCES, "PcCardConfig MEM%d - Width:%d, Wait:%d, IsAttr:%d, CardBase:%x\n", scMemIndex,
|
||
socketConfig->Memory[scMemIndex].Width16,
|
||
socketConfig->Memory[scMemIndex].WaitState,
|
||
socketConfig->Memory[scMemIndex].IsAttribute,
|
||
socketConfig->Memory[scMemIndex].CardBase));
|
||
|
||
scMemIndex++;
|
||
}
|
||
|
||
|
||
|
||
} else if (PCMRES_GET_DESCRIPTOR_TYPE (partialResourceDesc) == DPTYPE_PCMCIA_MF_CONFIGURATION) {
|
||
//
|
||
// Multifunction configuration private
|
||
//
|
||
UCHAR IoResourceIndex;
|
||
|
||
fnConfig = ExAllocatePool(NonPagedPool, sizeof(FUNCTION_CONFIGURATION));
|
||
if (!fnConfig) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(fnConfig, sizeof(FUNCTION_CONFIGURATION));
|
||
|
||
fnConfig->ConfigRegisterBase = PCMRES_GET_CONFIG_REGISTER_BASE(partialResourceDesc);
|
||
fnConfig->ConfigOptions = PCMRES_GET_CONFIG_OPTIONS(partialResourceDesc);
|
||
if (PCMRES_GET_AUDIO_ENABLE(partialResourceDesc)) {
|
||
fnConfig->ConfigFlags = 0x08;
|
||
}
|
||
|
||
if (fnConfig->ConfigOptions & 0x02) {
|
||
IoResourceIndex = PCMRES_GET_PORT_RESOURCE_INDEX(partialResourceDesc);
|
||
if ((IoResourceIndex < partialResourceList->Count) &&
|
||
(partialResourceList->PartialDescriptors[IoResourceIndex].Type == CmResourceTypePort)) {
|
||
|
||
fnConfig->IoLimit = (UCHAR) (partialResourceList->PartialDescriptors[IoResourceIndex].u.Port.Length-1);
|
||
fnConfig->IoBase = partialResourceList->PartialDescriptors[IoResourceIndex].u.Port.Start.LowPart;
|
||
}
|
||
}
|
||
|
||
if (socketConfig->FunctionConfiguration == NULL) {
|
||
//
|
||
// This is the first MfConfig
|
||
//
|
||
socketConfig->FunctionConfiguration = fnConfig;
|
||
} else {
|
||
//
|
||
// Chain it on the end so it is fifo
|
||
//
|
||
PFUNCTION_CONFIGURATION mfTmp = socketConfig->FunctionConfiguration;
|
||
while (mfTmp->Next != NULL) {
|
||
mfTmp = mfTmp->Next;
|
||
}
|
||
mfTmp->Next = fnConfig;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
default: {
|
||
DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaStartPcCard:Unknown resource type %d handed down",
|
||
(ULONG) partialResourceDesc->Type));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Power up the card if it isn't already..
|
||
//
|
||
status = PcmciaRequestSocketPower(pdoExtension, NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
ASSERT(NT_SUCCESS(status));
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Turn on ZV for this card, if it needs it
|
||
//
|
||
if (socketData->Flags & SDF_ZV) {
|
||
PcmciaSetZV(fdoExtension, socket, TRUE);
|
||
SetSocketFlag(socket, SOCKET_CUSTOM_INTERFACE);
|
||
} else if (IsSocketFlagSet(socket, SOCKET_CUSTOM_INTERFACE)) {
|
||
PcmciaSetZV(fdoExtension, socket, FALSE);
|
||
ResetSocketFlag(socket, SOCKET_CUSTOM_INTERFACE);
|
||
}
|
||
|
||
PcmciaSetAudio(fdoExtension, socket, IsDeviceFlagSet(pdoExtension, PCMCIA_PDO_ENABLE_AUDIO));
|
||
|
||
pdoExtension->SocketConfiguration = socketConfig;
|
||
if (!NT_SUCCESS(PcmciaConfigurePcCard(pdoExtension, NULL))) {
|
||
//
|
||
// Problems in configuring the card: could be the card
|
||
// was removed while configuring it
|
||
//
|
||
pdoExtension->SocketConfiguration = NULL;
|
||
ExFreePool(socketConfig);
|
||
return STATUS_DEVICE_NOT_READY;
|
||
}
|
||
|
||
MarkDeviceStarted(pdoExtension);
|
||
MarkDeviceLogicallyInserted(pdoExtension);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaStopPcCard(
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine stops and deconfigures the given PC-Card
|
||
|
||
Arguments:
|
||
|
||
Pdo - Pointer to the device object representing the PC-Card which needs to be stopped
|
||
|
||
Return value:
|
||
|
||
STATUS_SUCCESS - PC-Card was already stopped, or stopped and deconfigured now successfully
|
||
|
||
--*/
|
||
{
|
||
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
||
PSOCKET socket = pdoExtension->Socket;
|
||
PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
|
||
CARD_REQUEST cardRequest;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!IsDeviceStarted(pdoExtension)) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
//
|
||
// Need to deconfigure the controller
|
||
//
|
||
PcmciaSocketDeconfigure(socket);
|
||
(socket->SocketFnPtr->PCBInitializePcmciaSocket)(socket);
|
||
|
||
MarkDeviceNotStarted(pdoExtension);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaRemovePcCard(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return value:
|
||
|
||
--*/
|
||
{
|
||
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
||
PSOCKET socket = pdoExtension->Socket;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
if (socket == NULL) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
PcmciaStopPcCard(Pdo);
|
||
PcmciaReleaseSocketPower(pdoExtension, NULL);
|
||
|
||
if (IsDevicePhysicallyRemoved(pdoExtension)) {
|
||
PFDO_EXTENSION fdoExtension = socket->DeviceExtension;
|
||
PDEVICE_OBJECT curPdo, prevPdo;
|
||
PPDO_EXTENSION curPdoExt;
|
||
ULONG waitCount = 0;
|
||
|
||
//
|
||
// Synchronize with power routines
|
||
// LATER: make these values adjustable
|
||
//
|
||
while(!PCMCIA_TEST_AND_SET(&pdoExtension->DeletionLock)) {
|
||
PcmciaWait(1000000);
|
||
if (waitCount++ > 20) {
|
||
ASSERT(waitCount <= 20);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Delink this Pdo from the FDO list.
|
||
//
|
||
for (curPdo = fdoExtension->PdoList, prevPdo = NULL; curPdo!=NULL; prevPdo = curPdo, curPdo=curPdoExt->NextPdoInFdoChain) {
|
||
curPdoExt = curPdo->DeviceExtension;
|
||
|
||
if (curPdo == Pdo) {
|
||
if (prevPdo) {
|
||
((PPDO_EXTENSION)prevPdo->DeviceExtension)->NextPdoInFdoChain = pdoExtension->NextPdoInFdoChain;
|
||
} else {
|
||
fdoExtension->PdoList = pdoExtension->NextPdoInFdoChain;
|
||
}
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
for (curPdo = socket->PdoList, prevPdo = NULL; curPdo!=NULL; prevPdo = curPdo, curPdo=curPdoExt->NextPdoInSocket) {
|
||
curPdoExt = curPdo->DeviceExtension;
|
||
|
||
if (curPdo == Pdo) {
|
||
//
|
||
// Delink this Pdo from the socket list.
|
||
//
|
||
if (prevPdo) {
|
||
((PPDO_EXTENSION)prevPdo->DeviceExtension)->NextPdoInSocket = pdoExtension->NextPdoInSocket;
|
||
} else {
|
||
socket->PdoList = pdoExtension->NextPdoInSocket;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
PcmciaCleanupSocketConfiguration(pdoExtension);
|
||
PcmciaCleanupPdo(Pdo);
|
||
//
|
||
// Delete..
|
||
//
|
||
if (!IsDeviceDeleted(pdoExtension)) {
|
||
MarkDeviceDeleted(pdoExtension);
|
||
IoDeleteDevice(Pdo);
|
||
}
|
||
|
||
ResetSocketFlag(socket, SOCKET_CLEANUP_PENDING);
|
||
//
|
||
// If a query_device_relations came in after a card was inserted, but before
|
||
// we have removed the previous card configuration, the enumeration would have been
|
||
// postponed. Here, we start it up again
|
||
//
|
||
if (IsSocketFlagSet(socket, SOCKET_ENUMERATE_PENDING)) {
|
||
ResetSocketFlag(socket, SOCKET_ENUMERATE_PENDING);
|
||
SetSocketFlag(socket, SOCKET_CARD_STATUS_CHANGE);
|
||
IoInvalidateDeviceRelations(fdoExtension->Pdo, BusRelations);
|
||
}
|
||
|
||
} else {
|
||
//
|
||
// We will keep this Pdo around, since this is not physically ejected.
|
||
//
|
||
MarkDeviceLogicallyRemoved(pdoExtension);
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
PcmciaCleanupPdo(
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return value:
|
||
|
||
--*/
|
||
{
|
||
PPDO_EXTENSION pdoExtension;
|
||
PSOCKET_DATA socketData, tmpSocketData;
|
||
|
||
ASSERT (Pdo != NULL);
|
||
|
||
pdoExtension = Pdo->DeviceExtension;
|
||
|
||
ASSERT(pdoExtension->WaitWakeIrp == NULL);
|
||
|
||
if (pdoExtension->LowerDevice!=NULL) {
|
||
//
|
||
// Detach our filter device
|
||
//
|
||
IoDetachDevice(pdoExtension->LowerDevice);
|
||
pdoExtension->LowerDevice = NULL;
|
||
}
|
||
|
||
socketData = pdoExtension->SocketData;
|
||
pdoExtension->SocketData = NULL;
|
||
while (socketData != NULL) {
|
||
tmpSocketData = socketData;
|
||
socketData = socketData->Next;
|
||
PcmciaCleanupSocketData(tmpSocketData);
|
||
}
|
||
|
||
PcmciaCleanupSocketConfiguration(pdoExtension);
|
||
|
||
//
|
||
// Cleanup device id
|
||
//
|
||
if (pdoExtension->DeviceId) {
|
||
ExFreePool(pdoExtension->DeviceId);
|
||
pdoExtension->DeviceId = NULL;
|
||
}
|
||
|
||
if (pdoExtension->CisCache) {
|
||
ExFreePool(pdoExtension->CisCache);
|
||
pdoExtension->CisCache = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
PcmciaCleanupSocketData(
|
||
IN PSOCKET_DATA SocketData
|
||
)
|
||
/*++
|
||
|
||
Routine Descrption
|
||
|
||
Frees up the passed in SocketData structure & any
|
||
structures it might point to
|
||
|
||
Arguments
|
||
|
||
SocketData - Pointer to the SOCKET_DATA structure
|
||
|
||
Return Value
|
||
|
||
none
|
||
|
||
|
||
--*/
|
||
{
|
||
PCONFIG_ENTRY configEntry, nextConfigEntry;
|
||
|
||
if (SocketData == NULL) {
|
||
return;
|
||
}
|
||
//
|
||
// Free up the config entry descriptors
|
||
//
|
||
configEntry = SocketData->ConfigEntryChain;
|
||
SocketData->ConfigEntryChain = NULL;
|
||
while (configEntry) {
|
||
nextConfigEntry = configEntry->NextEntry;
|
||
ExFreePool(configEntry);
|
||
configEntry = nextConfigEntry;
|
||
}
|
||
|
||
//
|
||
// Free up socket data
|
||
//
|
||
ExFreePool(SocketData);
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
PcmciaCleanupSocketConfiguration(
|
||
PPDO_EXTENSION pdoExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Frees up the linked list of function configuration, as well as
|
||
the base socket configuration structure itself.
|
||
|
||
Arguments:
|
||
|
||
Return value:
|
||
|
||
--*/
|
||
{
|
||
PSOCKET_CONFIGURATION socketConfig = pdoExtension->SocketConfiguration;
|
||
PFUNCTION_CONFIGURATION fnConfig, fnConfigNext;
|
||
|
||
if (socketConfig == NULL) {
|
||
return;
|
||
}
|
||
|
||
fnConfig = socketConfig->FunctionConfiguration;
|
||
while(fnConfig) {
|
||
fnConfigNext = fnConfig->Next;
|
||
ExFreePool(fnConfig);
|
||
fnConfig = fnConfigNext;
|
||
}
|
||
|
||
ExFreePool(pdoExtension->SocketConfiguration);
|
||
pdoExtension->SocketConfiguration = NULL;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaPdoDeviceControl(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return value:
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// No IOCTLs handled currently
|
||
//
|
||
UNREFERENCED_PARAMETER(Pdo);
|
||
|
||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaPdoDeviceCapabilities(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtains the device capabilities of the given pc-card.
|
||
|
||
If the pc-card is an R2 card (16-bit pc-card), the capabilities
|
||
are constructed from the parent PCMCIA controller's capabilities.
|
||
Finally the obtained capabilities are cached in the pc-card's device
|
||
extension for use in power management of the card.
|
||
|
||
Arguments:
|
||
|
||
Pdo - Pointer to the device object for the pc-card
|
||
Irp - Pointer to the query device capabilities Irp
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Capabilities obtained and recorded in the passed in pointer
|
||
STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory to cache the capabilities
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PDEVICE_CAPABILITIES capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
|
||
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
|
||
PDEVICE_CAPABILITIES busCapabilities = &pdoExtension->Socket->DeviceExtension->DeviceCapabilities;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// R2 card. Fill in the capabilities ourselves..
|
||
//
|
||
|
||
capabilities->Removable = TRUE;
|
||
capabilities->UniqueID = TRUE;
|
||
capabilities->EjectSupported = FALSE;
|
||
|
||
capabilities->Address = pdoExtension->Socket->RegisterOffset;
|
||
// Don't know the UINumber, just leave it alone
|
||
|
||
|
||
if (busCapabilities->DeviceState[PowerSystemWorking] != PowerDeviceUnspecified) {
|
||
capabilities->DeviceState[PowerSystemWorking] = busCapabilities->DeviceState[PowerSystemWorking];
|
||
capabilities->DeviceState[PowerSystemSleeping1] = busCapabilities->DeviceState[PowerSystemSleeping1];
|
||
capabilities->DeviceState[PowerSystemSleeping2] = busCapabilities->DeviceState[PowerSystemSleeping2];
|
||
capabilities->DeviceState[PowerSystemSleeping3] = busCapabilities->DeviceState[PowerSystemSleeping3];
|
||
capabilities->DeviceState[PowerSystemHibernate] = busCapabilities->DeviceState[PowerSystemHibernate];
|
||
capabilities->DeviceState[PowerSystemShutdown] = busCapabilities->DeviceState[PowerSystemShutdown];
|
||
|
||
capabilities->SystemWake = MIN(PowerSystemSleeping3, busCapabilities->SystemWake);
|
||
capabilities->DeviceWake = PowerDeviceD0; // don't rely on FDO mungeing in the right thing for r2 cards
|
||
capabilities->D1Latency = busCapabilities->D1Latency;
|
||
capabilities->D2Latency = busCapabilities->D2Latency;
|
||
capabilities->D3Latency = busCapabilities->D3Latency;
|
||
} else {
|
||
capabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
|
||
capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
|
||
capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
|
||
capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
|
||
capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
|
||
capabilities->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
|
||
|
||
capabilities->SystemWake = PowerSystemUnspecified;
|
||
capabilities->DeviceWake = PowerDeviceD0; // don't rely on FDO mungeing in the right thing for r2 cards
|
||
capabilities->D1Latency = 0; // No latency - since we do nothing
|
||
capabilities->D2Latency = 0; //
|
||
capabilities->D3Latency = 100;
|
||
}
|
||
//
|
||
// Store these capabilities away..
|
||
//
|
||
|
||
RtlCopyMemory(&pdoExtension->DeviceCapabilities,
|
||
capabilities,
|
||
sizeof(DEVICE_CAPABILITIES));
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|