You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1606 lines
52 KiB
1606 lines
52 KiB
/*++
|
|
|
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fdopnp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that handles PNP irps for pcmcia bus driver
|
|
targeted towards the FDO's (for the pcmcia controller object)
|
|
|
|
Author:
|
|
|
|
Ravisankar Pudipeddi (ravisp) Oct 15 1996
|
|
Neil Sandlin (neilsa) June 1 1999
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Internal References
|
|
//
|
|
|
|
NTSTATUS
|
|
PcmciaFdoFilterResourceRequirements(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaFdoGetHardwareIds(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
OUT PUNICODE_STRING HardwareIds
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaFdoStartDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
OUT BOOLEAN *PassedDown,
|
|
OUT BOOLEAN *NeedsRecompletion
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaFdoStopDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
OUT BOOLEAN *PassedDown,
|
|
OUT BOOLEAN *NeedsRecompletion
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaFdoRemoveDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
PcmciaCleanupFdo(
|
|
IN PFDO_EXTENSION FdoExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaFdoDeviceCapabilities(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
OUT BOOLEAN *PassedDown,
|
|
OUT BOOLEAN *NeedsRecompletion
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaAreCardBusCardsSupported(
|
|
IN PFDO_EXTENSION FdoExtension
|
|
);
|
|
|
|
NTSTATUS
|
|
PcmciaFdoGetAssignedResources(
|
|
IN PCM_RESOURCE_LIST ResourceList,
|
|
IN PCM_RESOURCE_LIST TranslatedResourceList,
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, PcmciaFdoPnpDispatch)
|
|
#pragma alloc_text(PAGE, PcmciaFdoGetHardwareIds)
|
|
#pragma alloc_text(PAGE, PcmciaFdoStartDevice)
|
|
#pragma alloc_text(PAGE, PcmciaFdoStopDevice)
|
|
#pragma alloc_text(PAGE, PcmciaFdoRemoveDevice)
|
|
#pragma alloc_text(PAGE, PcmciaFdoFilterResourceRequirements)
|
|
#pragma alloc_text(PAGE, PcmciaFdoGetAssignedResources)
|
|
#pragma alloc_text(PAGE, PcmciaFdoDeviceCapabilities)
|
|
#pragma alloc_text(PAGE, PcmciaAreCardBusCardsSupported)
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoPnpDispatch (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
PNP/Power IRPs dispatch routine for the PCMCIA bus controller
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object.
|
|
Irp - Pointer to the IRP
|
|
|
|
Return Value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
|
|
PIO_STACK_LOCATION nextIrpStack;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
NTSTATUS status = Irp->IoStatus.Status;
|
|
BOOLEAN PassedDown = FALSE;
|
|
BOOLEAN NeedsReCompletion = FALSE;
|
|
|
|
PAGED_CODE();
|
|
|
|
#if DBG
|
|
if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x - Unknown PNP irp\n",
|
|
DeviceObject, irpStack->MinorFunction));
|
|
} else {
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x --> %s\n",
|
|
DeviceObject, Irp, PNP_IRP_STRING(irpStack->MinorFunction)));
|
|
}
|
|
#endif
|
|
|
|
switch (irpStack->MinorFunction) {
|
|
|
|
case IRP_MN_START_DEVICE: {
|
|
status = PcmciaFdoStartDevice(DeviceObject,
|
|
Irp,
|
|
&PassedDown,
|
|
&NeedsReCompletion);
|
|
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 = PcmciaFdoStopDevice(DeviceObject,
|
|
Irp,
|
|
&PassedDown,
|
|
&NeedsReCompletion);
|
|
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS: {
|
|
|
|
//
|
|
// Return the list of devices on the bus
|
|
//
|
|
|
|
status = PcmciaDeviceRelations(
|
|
DeviceObject,
|
|
Irp,
|
|
irpStack->Parameters.QueryDeviceRelations.Type,
|
|
(PDEVICE_RELATIONS *) &Irp->IoStatus.Information
|
|
);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: {
|
|
status = PcmciaFdoFilterResourceRequirements(DeviceObject, Irp);
|
|
PassedDown = TRUE;
|
|
NeedsReCompletion = TRUE;
|
|
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 = PcmciaFdoRemoveDevice(DeviceObject, Irp);
|
|
PassedDown = TRUE ;
|
|
NeedsReCompletion = TRUE ;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_SURPRISE_REMOVAL: {
|
|
PcmciaFdoStopDevice(DeviceObject, NULL, NULL, NULL);
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_ID: {
|
|
|
|
UNICODE_STRING unicodeId;
|
|
|
|
if (deviceExtension->Flags & PCMCIA_DEVICE_LEGACY_DETECTED) {
|
|
|
|
RtlInitUnicodeString(&unicodeId, NULL);
|
|
|
|
switch (irpStack->Parameters.QueryId.IdType) {
|
|
|
|
case BusQueryHardwareIDs: {
|
|
|
|
DebugPrint((PCMCIA_DEBUG_INFO, " Hardware Ids for fdo %x\n", DeviceObject));
|
|
status = PcmciaFdoGetHardwareIds(DeviceObject, &unicodeId);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
Irp->IoStatus.Information = (ULONG_PTR) unicodeId.Buffer;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_CAPABILITIES: {
|
|
status = PcmciaFdoDeviceCapabilities(DeviceObject,
|
|
Irp,
|
|
&PassedDown,
|
|
&NeedsReCompletion);
|
|
break;
|
|
}
|
|
|
|
case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
|
|
//
|
|
// If this FDO represents a CardBus bridge, we pass this irp down
|
|
// to the PCI PDO which will fill in the PCI bus type and number,
|
|
// otherwise we fail the IRP.
|
|
//
|
|
|
|
if (!CardBusExtension(deviceExtension)) {
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
//
|
|
// if status is still STATUS_NOT_SUPPORTED, then later code will pass
|
|
// this irp down the stack.
|
|
//
|
|
break;
|
|
|
|
default: {
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x - Skipping unsupported irp\n", DeviceObject, Irp));
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (!PassedDown) {
|
|
//
|
|
// Set the IRP status only if we set it to something other than
|
|
// STATUS_NOT_SUPPORTED.
|
|
//
|
|
if (status != STATUS_NOT_SUPPORTED) {
|
|
|
|
Irp->IoStatus.Status = status ;
|
|
}
|
|
//
|
|
// Pass down if success or STATUS_NOT_SUPPORTED. Otherwise, Complete.
|
|
//
|
|
if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
|
|
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x pass %s %08x\n",
|
|
DeviceObject, Irp,
|
|
STATUS_STRING(Irp->IoStatus.Status), Irp->IoStatus.Status));
|
|
//
|
|
// Below macro fills status with return of IoCallDriver. It does
|
|
// not change the Irps status in any way.
|
|
//
|
|
PcmciaSkipCallLowerDriver(status, deviceExtension->LowerDevice, Irp);
|
|
|
|
} else {
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x comp %s %08x\n",
|
|
DeviceObject, Irp,
|
|
STATUS_STRING(status), status));
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
} else if (NeedsReCompletion) {
|
|
//
|
|
// Set the IRP status only if we set it to something other than
|
|
// STATUS_NOT_SUPPORTED.
|
|
//
|
|
if (status != STATUS_NOT_SUPPORTED) {
|
|
|
|
Irp->IoStatus.Status = status ;
|
|
}
|
|
|
|
status = Irp->IoStatus.Status ;
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x irp %08x comp %s %08x\n",
|
|
DeviceObject, Irp,
|
|
STATUS_STRING(status), status));
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
return status ;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoDeviceCapabilities(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
OUT BOOLEAN *PassedDown,
|
|
OUT BOOLEAN *NeedsRecompletion
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
Records the device capabilities of this pcmcia controller,
|
|
so 1. they can be used in the power management for the controller
|
|
and 2. they can be used for determining the capabilities of the
|
|
child pc-card PDO's of this pcmcia controller.
|
|
If this is legacy detected pcmcia controller (ISA-based), the pdo for
|
|
the pcmcia controller is a dummy madeup device - hence the capabilities
|
|
are filled in by ourselves.
|
|
Otherwise, the capabilities are obtained by sending down the Irp
|
|
to the parent bus.
|
|
In either case, the capabilities are cached in the device extension of
|
|
the pcmcia controller for future use.
|
|
|
|
Arguments
|
|
|
|
Fdo - Pointer to functional device object of the pcmcia
|
|
controller
|
|
Irp - Pointer to the i/o request packet
|
|
PassedDown - Contains FALSE on entry, which means caller must
|
|
complete or pass down irp based on status. If set
|
|
to TRUE, Irp may need to be re-completed...
|
|
NeedsRecompletion - ...In which case this parameter will be checked
|
|
|
|
Return Value
|
|
|
|
STATUS_SUCCESS Capabilities returned
|
|
STATUS_INSUFFICIENT_RESOURCES Could not allocate memory to cache the capabilities
|
|
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PDEVICE_CAPABILITIES capabilities;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
|
|
fdoExtension = Fdo->DeviceExtension;
|
|
|
|
if (fdoExtension->Flags & PCMCIA_DEVICE_LEGACY_DETECTED) {
|
|
|
|
//
|
|
// This is a madeup devnode (ISA based PCMCIA controller).
|
|
// Fill in the capabilities ourselves
|
|
//
|
|
RtlZeroMemory(capabilities,
|
|
sizeof(DEVICE_CAPABILITIES));
|
|
//
|
|
// Non removable, non ejectable
|
|
//
|
|
capabilities->Removable = FALSE;
|
|
capabilities->UniqueID = FALSE;
|
|
capabilities->EjectSupported = FALSE;
|
|
//
|
|
// Address & number need work..
|
|
//
|
|
capabilities->Address = -1;
|
|
capabilities->UINumber = -1;
|
|
//
|
|
// We cannot power down this controller
|
|
//
|
|
capabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD0;
|
|
capabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD0;
|
|
capabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD0;
|
|
capabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
|
|
//
|
|
// Obviously wake is not supported on this legacy detected
|
|
// piece of xxxx
|
|
//
|
|
capabilities->SystemWake = PowerSystemUnspecified;
|
|
capabilities->DeviceWake = PowerDeviceUnspecified;
|
|
capabilities->D1Latency = 0;
|
|
capabilities->D2Latency = 0;
|
|
capabilities->D3Latency = 0;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
|
|
//
|
|
// Either a PCI-PCMCIA bridge or PCI-Cardbus bridge
|
|
// Send this down the stack to obtain the capabilities
|
|
//
|
|
ASSERT (fdoExtension->LowerDevice != NULL);
|
|
|
|
status = PcmciaIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
|
|
*PassedDown = TRUE ;
|
|
*NeedsRecompletion = TRUE ;
|
|
}
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// NOTE: HACKHACK:
|
|
//
|
|
// Here we provide an option to override the device wake of the pcmcia controller.
|
|
// There are several controllers, notably TI 12xx controllers, which say they
|
|
// can wake from D3, but really can effectively only do WOL from D2. That's because they
|
|
// turn of socket power when put into D3. They fixed this on the TI 14xx line.
|
|
//
|
|
// So here we update the device wake field, and potentially the device states from the BIOS.
|
|
// Note that this has to be used carefully, and only override a particular BIOS's settings
|
|
// where it has been verified the device still works at the lower (more awake) device state.
|
|
//
|
|
if (PcmciaControllerDeviceWake) {
|
|
if (PcmciaControllerDeviceWake < capabilities->DeviceWake) {
|
|
capabilities->DeviceWake = PcmciaControllerDeviceWake;
|
|
}
|
|
if (PcmciaControllerDeviceWake < capabilities->DeviceState[PowerSystemSleeping1]) {
|
|
capabilities->DeviceState[PowerSystemSleeping1] = PcmciaControllerDeviceWake;
|
|
}
|
|
if (PcmciaControllerDeviceWake < capabilities->DeviceState[PowerSystemSleeping2]) {
|
|
capabilities->DeviceState[PowerSystemSleeping2] = PcmciaControllerDeviceWake;
|
|
}
|
|
if (PcmciaControllerDeviceWake < capabilities->DeviceState[PowerSystemSleeping3]) {
|
|
capabilities->DeviceState[PowerSystemSleeping3] = PcmciaControllerDeviceWake;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cache the device capabilities in the device extension
|
|
// for this pcmcia controller.
|
|
//
|
|
RtlCopyMemory(&fdoExtension->DeviceCapabilities,
|
|
capabilities,
|
|
sizeof(DEVICE_CAPABILITIES));
|
|
|
|
} else {
|
|
|
|
RtlZeroMemory(&fdoExtension->DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoFilterResourceRequirements(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Filters Resource requirements for PCMCIA controllers generated
|
|
by the bus driver controlling the PDO for the PCMCIA controller.
|
|
Currently adds memory range as an additional resource requirement
|
|
since the BAR doesn't specify this
|
|
|
|
Note for CardBus controllers:
|
|
It is necessary to request an attribute memory window here for
|
|
reading CIS of 16-bit PC-Cards - we need a 24 bit address for that,
|
|
and this is the most elegant way of doing it - instead of
|
|
special casing it in PCI driver
|
|
|
|
Arguments
|
|
|
|
DeviceExtension - Pointer to extension for the PCMCIA controller in question
|
|
IoReqList - Pointer the the original resource requiremnts ejected by
|
|
the bus driver
|
|
FilteredRequirements - Pointer to the filtered resource req. list will be returned
|
|
in this variable
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if filtering is successful
|
|
Any other status - could not filter
|
|
|
|
--*/
|
|
{
|
|
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST oldReqList;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
|
|
PIO_RESOURCE_LIST oldList, newList;
|
|
PIO_RESOURCE_DESCRIPTOR ioResourceDesc;
|
|
ULONG newReqSize;
|
|
ULONG oldlistSize, newlistSize, altListSize;
|
|
ULONG index;
|
|
ULONG IntCount = 0;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
status = PcmciaIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
if (Irp->IoStatus.Information == 0) {
|
|
|
|
oldReqList = irpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList;
|
|
|
|
if (oldReqList == NULL) {
|
|
//
|
|
// NULL List, nothing to do
|
|
//
|
|
return(Irp->IoStatus.Status);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Use the returned list
|
|
//
|
|
oldReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information;
|
|
}
|
|
|
|
|
|
//
|
|
// Add an alternative list without the IRQ requirement, if one exists. Model the
|
|
// new alternative list after the first list.
|
|
//
|
|
|
|
oldList = oldReqList->List;
|
|
ioResourceDesc = oldList->Descriptors;
|
|
altListSize = 0;
|
|
|
|
for (index = 0; index < oldList->Count; index++) {
|
|
// Count the descriptors, excluding any IRQ descriptors
|
|
if (ioResourceDesc->Type == CmResourceTypeInterrupt) {
|
|
IntCount++;
|
|
}
|
|
ioResourceDesc++;
|
|
}
|
|
|
|
if (IntCount) {
|
|
//
|
|
// "+1" because we are adding two later, but IO_RESOURCE_LIST already has 1
|
|
//
|
|
altListSize = sizeof(IO_RESOURCE_LIST) + ((oldList->Count+1)-IntCount)*sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
}
|
|
|
|
//
|
|
// Add a memory range requirement to what we already have..
|
|
//
|
|
newReqSize = oldReqList->ListSize +
|
|
oldReqList->AlternativeLists*2*sizeof(IO_RESOURCE_DESCRIPTOR) +
|
|
altListSize;
|
|
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;
|
|
|
|
for (index = 0; index < oldReqList->AlternativeLists; index++) {
|
|
//
|
|
// Compute the size of the current original list
|
|
//
|
|
oldlistSize = sizeof(IO_RESOURCE_LIST) + (oldList->Count-1) * sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
newlistSize = oldlistSize;
|
|
RtlCopyMemory(newList, oldList, newlistSize);
|
|
|
|
//
|
|
// Add memory requirement
|
|
//
|
|
ioResourceDesc = (PIO_RESOURCE_DESCRIPTOR) (((PUCHAR) newList) + newlistSize);
|
|
|
|
ioResourceDesc->Option = IO_RESOURCE_PREFERRED;
|
|
ioResourceDesc->Type = CmResourceTypeMemory;
|
|
ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
|
ioResourceDesc->u.Memory.MinimumAddress.QuadPart = fdoExtension->AttributeMemoryLow;
|
|
ioResourceDesc->u.Memory.MaximumAddress.QuadPart = fdoExtension->AttributeMemoryHigh;
|
|
ioResourceDesc->u.Memory.Length = fdoExtension->AttributeMemorySize;
|
|
ioResourceDesc->u.Memory.Alignment = fdoExtension->AttributeMemoryAlignment;
|
|
if (fdoExtension->Flags & PCMCIA_MEMORY_24BIT) {
|
|
ioResourceDesc->u.Memory.MaximumAddress.QuadPart &= 0xFFFFFF;
|
|
}
|
|
ioResourceDesc++;
|
|
//
|
|
// The other - less restrictive - alternative.
|
|
//
|
|
ioResourceDesc->Option = IO_RESOURCE_ALTERNATIVE;
|
|
ioResourceDesc->Type = CmResourceTypeMemory;
|
|
ioResourceDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
|
ioResourceDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
|
|
ioResourceDesc->u.Memory.MinimumAddress.QuadPart = 0;
|
|
ioResourceDesc->u.Memory.MaximumAddress.QuadPart = 0xFFFFFFFF;
|
|
ioResourceDesc->u.Memory.Length = fdoExtension->AttributeMemorySize;
|
|
ioResourceDesc->u.Memory.Alignment = fdoExtension->AttributeMemoryAlignment;
|
|
if (fdoExtension->Flags & PCMCIA_MEMORY_24BIT) {
|
|
ioResourceDesc->u.Memory.MaximumAddress.QuadPart &= 0xFFFFFF;
|
|
}
|
|
|
|
newList->Count += 2;
|
|
newlistSize += 2*sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
|
|
oldList = (PIO_RESOURCE_LIST) (((PUCHAR) oldList) + oldlistSize);
|
|
newList = (PIO_RESOURCE_LIST) (((PUCHAR) newList) + newlistSize);
|
|
}
|
|
|
|
if (altListSize != 0) {
|
|
PIO_RESOURCE_DESCRIPTOR oldResourceDesc;
|
|
//
|
|
// Here we add the alternate list which doesn't contain an IRQ requirement.
|
|
// Note that we use the first "new list" as the "old list". This way, we
|
|
// pick up the things we added in the previous loop. All we have to do is
|
|
// copy every descriptor except for the interrupt descriptor.
|
|
//
|
|
// Note: newList is still set from previous loop
|
|
//
|
|
oldList = newReqList->List;
|
|
|
|
//
|
|
// First copy the basic structure without the descriptors
|
|
//
|
|
RtlCopyMemory(newList, oldList, sizeof(IO_RESOURCE_LIST) - sizeof(IO_RESOURCE_DESCRIPTOR));
|
|
|
|
oldResourceDesc = oldList->Descriptors;
|
|
ioResourceDesc = newList->Descriptors;
|
|
|
|
for (index = 0; index < oldList->Count; index++) {
|
|
|
|
if (oldResourceDesc->Type != CmResourceTypeInterrupt) {
|
|
*ioResourceDesc = *oldResourceDesc;
|
|
ioResourceDesc++;
|
|
|
|
} else {
|
|
//
|
|
// We've deleted a descriptor
|
|
//
|
|
newList->Count--;
|
|
}
|
|
oldResourceDesc++;
|
|
}
|
|
newReqList->AlternativeLists++;
|
|
}
|
|
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR) newReqList;
|
|
irpStack->Parameters.FilterResourceRequirements.IoResourceRequirementList =
|
|
newReqList;
|
|
|
|
//
|
|
// Free up the old resource reqs
|
|
//
|
|
ExFreePool(oldReqList);
|
|
|
|
fdoExtension->Flags |= PCMCIA_FILTER_ADDED_MEMORY;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoGetHardwareIds(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
OUT PUNICODE_STRING HardwareIds
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine description:
|
|
|
|
This routine returns the hardware ids for the given 'legacy' pcmcia controller
|
|
NOTE: this routine is required only for pcmcia controllers detected by this driver
|
|
itself and registered via IoReportDetectedDevice.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Pointer to the functional device object representing the pcmcia controller
|
|
CompatibleIds - Pointer to the unicode string which would contain the hardware ids
|
|
as a multi-string on return
|
|
|
|
Return value:
|
|
|
|
STATUS_SUCCESS
|
|
Any other status - could not generate compatible ids
|
|
--*/
|
|
|
|
{
|
|
PCSTR strings[2];
|
|
PCMCIA_CONTROLLER_TYPE controllerType;
|
|
ULONG count, index;
|
|
BOOLEAN found;
|
|
|
|
PAGED_CODE();
|
|
|
|
controllerType = ((PFDO_EXTENSION)Fdo->DeviceExtension)->ControllerType;
|
|
found = FALSE;
|
|
|
|
for (index = 0; (PcmciaAdapterHardwareIds[index].ControllerType != PcmciaInvalidControllerType); index++) {
|
|
if (PcmciaAdapterHardwareIds[index].ControllerType == controllerType) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
strings[0] = PcmciaAdapterHardwareIds[index].Id;
|
|
} else {
|
|
DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaGetAdapterHardwareIds: Could not find find hardware id for %x, controllerType %x\n",
|
|
Fdo,
|
|
controllerType
|
|
));
|
|
|
|
strings[0] = "";
|
|
}
|
|
|
|
count = 1;
|
|
return PcmciaStringsToMultiString(strings,
|
|
count,
|
|
HardwareIds);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoStartDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp,
|
|
OUT BOOLEAN *PassedDown,
|
|
OUT BOOLEAN *NeedsRecompletion
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will start the PCMCIA controller with the supplied
|
|
resources. The IRP is sent down to the pdo first, so PCI or ISAPNP
|
|
or whoever sits underneath gets a chance to program the controller
|
|
to decode the resources.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Functional device object of the PCMCIA controller
|
|
Irp - Well, it's the start irp, yah?
|
|
PassedDown - Contains FALSE on entry, which means caller must
|
|
complete or pass down irp based on status. If set
|
|
to TRUE, Irp may need to be re-completed...
|
|
NeedsRecompletion - ...In which case this parameter will be checked
|
|
|
|
Return value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PCM_RESOURCE_LIST resList, translatedResList, newResList, newTranslatedResList;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (deviceExtension->Flags & PCMCIA_DEVICE_STARTED) {
|
|
//
|
|
// Start to already started device
|
|
//
|
|
DebugPrint((PCMCIA_DEBUG_FAIL,"PcmciaFdoStartDevice: Fdo %x already started\n",
|
|
Fdo));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Parse AllocatedResources & get IoPort/AttributeMemoryBase/IRQ info.
|
|
//
|
|
status = PcmciaFdoGetAssignedResources(irpStack->Parameters.StartDevice.AllocatedResources,
|
|
irpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
|
|
deviceExtension
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// Ha. This is most likely a START for a madeup devnode (report-detected legacy PCMCIA controller)
|
|
// which has been removed subsequently, hence not reported again with proper resources.
|
|
// We return an appropriate status
|
|
//
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "Pcmcia: No resources assigned to FDO, probably bogus START for"
|
|
"non-existent controller\n" ));
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x StartAdapter: AttrMem Base %x\n", Fdo, deviceExtension->PhysicalBase));
|
|
DebugPrint((PCMCIA_DEBUG_PNP, " VirtualBase %x AttrMem Size %x\n", deviceExtension->AttributeMemoryBase, deviceExtension->AttributeMemorySize));
|
|
|
|
if (deviceExtension->Flags & PCMCIA_FILTER_ADDED_MEMORY) {
|
|
ULONG newSize;
|
|
ULONG index;
|
|
PCM_PARTIAL_RESOURCE_LIST resPartialList, translatedResPartialList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc, translatedResDesc;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR newResDesc, newTranslatedResDesc;
|
|
//
|
|
// We need to remove the memory resource requirement
|
|
//
|
|
resList= irpStack->Parameters.StartDevice.AllocatedResources;
|
|
resPartialList = &resList->List[0].PartialResourceList;
|
|
translatedResList= irpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
|
|
translatedResPartialList = &translatedResList->List[0].PartialResourceList;
|
|
|
|
newSize = sizeof(CM_RESOURCE_LIST) + (resPartialList->Count-2)*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
newResList = ExAllocatePool(PagedPool,
|
|
newSize);
|
|
if (newResList == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
newTranslatedResList = ExAllocatePool(PagedPool,
|
|
newSize);
|
|
|
|
if (newTranslatedResList == NULL) {
|
|
ExFreePool(newResList);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
newResList->Count = newTranslatedResList->Count = 1;
|
|
newResList->List[0].InterfaceType = resList->List[0].InterfaceType;
|
|
newTranslatedResList->List[0].InterfaceType = translatedResList->List[0].InterfaceType;
|
|
newResList->List[0].BusNumber = resList->List[0].BusNumber;
|
|
newTranslatedResList->List[0].BusNumber = translatedResList->List[0].BusNumber;
|
|
|
|
newResList->List[0].PartialResourceList.Version = resPartialList->Version;
|
|
newResList->List[0].PartialResourceList.Revision = resPartialList->Revision;
|
|
newResList->List[0].PartialResourceList.Count = resPartialList->Count - 1;
|
|
|
|
newTranslatedResList->List[0].PartialResourceList.Version = translatedResPartialList->Version;
|
|
newTranslatedResList->List[0].PartialResourceList.Revision = translatedResPartialList->Revision;
|
|
newTranslatedResList->List[0].PartialResourceList.Count = translatedResPartialList->Count - 1;
|
|
|
|
|
|
resDesc = resPartialList->PartialDescriptors;
|
|
translatedResDesc = translatedResPartialList->PartialDescriptors;
|
|
newResDesc = newResList->List[0].PartialResourceList.PartialDescriptors;
|
|
newTranslatedResDesc = newTranslatedResList->List[0].PartialResourceList.PartialDescriptors;
|
|
|
|
if (CardBusExtension(deviceExtension)) {
|
|
//
|
|
// Remove last memory descriptor - which is what we added
|
|
//
|
|
RtlCopyMemory(newResDesc,
|
|
resDesc,
|
|
newResList->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
|
|
RtlCopyMemory(newTranslatedResDesc,
|
|
translatedResDesc,
|
|
newTranslatedResList->List[0].PartialResourceList.Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
|
|
} else {
|
|
//
|
|
// Remove the only memory descriptor..
|
|
//
|
|
for (index = 0; index < resPartialList->Count;
|
|
index++, resDesc++, translatedResDesc++, newResDesc++, newTranslatedResDesc++) {
|
|
if (resDesc->Type != CmResourceTypeMemory) {
|
|
*newResDesc = *resDesc;
|
|
*newTranslatedResDesc = *translatedResDesc;
|
|
}
|
|
}
|
|
}
|
|
|
|
irpStack->Parameters.StartDevice.AllocatedResources = newResList;
|
|
irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = newTranslatedResList;
|
|
}
|
|
|
|
//
|
|
// Send this down to the PDO first
|
|
//
|
|
|
|
status = PcmciaIoCallDriverSynchronous(deviceExtension->LowerDevice, Irp);
|
|
*PassedDown = TRUE ;
|
|
|
|
//
|
|
// We set this because the completion routine returns
|
|
// STATUS_MORE_PROCESSING_REQUIRED, which means it needs to be completed
|
|
// again.
|
|
//
|
|
*NeedsRecompletion = TRUE ;
|
|
|
|
if (deviceExtension->Flags & PCMCIA_FILTER_ADDED_MEMORY) {
|
|
ExFreePool(newResList);
|
|
ExFreePool(newTranslatedResList);
|
|
irpStack->Parameters.StartDevice.AllocatedResources = resList;
|
|
irpStack->Parameters.StartDevice.AllocatedResourcesTranslated = translatedResList;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Give the hardware some time to settle after returning from the pdo
|
|
//
|
|
PcmciaWait(256);
|
|
|
|
//
|
|
// Initialize the hardware
|
|
//
|
|
|
|
status = PcmciaStartPcmciaController(Fdo);
|
|
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
deviceExtension->Flags |= PCMCIA_DEVICE_STARTED;
|
|
}
|
|
//
|
|
// Remember if cardbus cards will be supported for this controller
|
|
//
|
|
if (CardBusExtension(deviceExtension) &&
|
|
!PcmciaAreCardBusCardsSupported(deviceExtension)) {
|
|
deviceExtension->Flags |= PCMCIA_CARDBUS_NOT_SUPPORTED;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoStopDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp OPTIONAL,
|
|
OUT BOOLEAN *PassedDown OPTIONAL,
|
|
OUT BOOLEAN *NeedsRecompletion OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IRP_MN_STOP_DEVICE handler for the given pcmcia controller.
|
|
If Irp is present, it'll send it down first to the PDO.
|
|
Unhooks the interrupt/cancels poll timer etc.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Pointer to functional device object for the pcmcia
|
|
controller
|
|
Irp - If present it's the pointer to the stop Irp initiated
|
|
by PnP
|
|
PassedDown - Contains FALSE on entry, which means caller must
|
|
complete or pass down irp based on status. If set
|
|
to TRUE, Irp may need to be re-completed...
|
|
NeedsRecompletion - ...In which case this parameter will be checked.
|
|
|
|
Note: PassedDown and NeedsCompletion are ignored and
|
|
optional only if Irp is NULL.
|
|
|
|
Return value:
|
|
|
|
STATUS_SUCCESS - Pcmcia controller successfully stopped
|
|
Other - Stop failed
|
|
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION deviceExtension = Fdo->DeviceExtension;
|
|
PSOCKET socket;
|
|
NTSTATUS status;
|
|
|
|
if (!(deviceExtension->Flags & PCMCIA_DEVICE_STARTED)) {
|
|
//
|
|
// Already stopped
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PcmciaFdoDisarmWake(deviceExtension);
|
|
|
|
//
|
|
// Disable the interrupt
|
|
//
|
|
if (deviceExtension->PcmciaInterruptObject) {
|
|
|
|
for (socket = deviceExtension->SocketList; socket; socket = socket->NextSocket) {
|
|
//
|
|
// Disable the controller interrupts
|
|
//
|
|
(*(socket->SocketFnPtr->PCBEnableDisableCardDetectEvent))(socket, FALSE);
|
|
(*(socket->SocketFnPtr->PCBEnableDisableWakeupEvent))(socket, NULL, FALSE);
|
|
//
|
|
// Apparently IBM ThinkPads like this
|
|
//
|
|
PcmciaWait(PCMCIA_ENABLE_DELAY);
|
|
}
|
|
}
|
|
|
|
//
|
|
// the bus driver below us will make us go offline
|
|
//
|
|
deviceExtension->Flags |= PCMCIA_FDO_OFFLINE;
|
|
|
|
//
|
|
// clear pending event
|
|
//
|
|
KeCancelTimer(&deviceExtension->EventTimer);
|
|
|
|
//
|
|
// Send this down to the PDO
|
|
//
|
|
if (ARGUMENT_PRESENT(Irp)) {
|
|
|
|
status = PcmciaIoCallDriverSynchronous(deviceExtension->LowerDevice, Irp);
|
|
|
|
*PassedDown = TRUE ;
|
|
*NeedsRecompletion = TRUE ;
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (deviceExtension->Flags & PCMCIA_USE_POLLED_CSC) {
|
|
//
|
|
// cancel the card status change poller
|
|
//
|
|
KeCancelTimer(&deviceExtension->PollTimer);
|
|
deviceExtension->Flags &= ~PCMCIA_USE_POLLED_CSC;
|
|
}
|
|
|
|
if (deviceExtension->PcmciaInterruptObject) {
|
|
//
|
|
// unhook the interrupt
|
|
//
|
|
IoDisconnectInterrupt(deviceExtension->PcmciaInterruptObject);
|
|
deviceExtension->PcmciaInterruptObject = NULL;
|
|
}
|
|
|
|
//
|
|
// Unmap any i/o space or memory we might have mapped
|
|
//
|
|
if (deviceExtension->Flags & PCMCIA_ATTRIBUTE_MEMORY_MAPPED) {
|
|
MmUnmapIoSpace(deviceExtension->AttributeMemoryBase,
|
|
deviceExtension->AttributeMemorySize);
|
|
deviceExtension->Flags &= ~PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
|
|
deviceExtension->AttributeMemoryBase = 0;
|
|
deviceExtension->AttributeMemorySize = 0;
|
|
}
|
|
|
|
if (deviceExtension->Flags & PCMCIA_SOCKET_REGISTER_BASE_MAPPED) {
|
|
MmUnmapIoSpace(deviceExtension->CardBusSocketRegisterBase,
|
|
deviceExtension->CardBusSocketRegisterSize);
|
|
deviceExtension->Flags &= ~PCMCIA_SOCKET_REGISTER_BASE_MAPPED;
|
|
deviceExtension->CardBusSocketRegisterBase = 0;
|
|
deviceExtension->CardBusSocketRegisterSize = 0;
|
|
}
|
|
|
|
deviceExtension->Flags &= ~PCMCIA_DEVICE_STARTED;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoRemoveDevice(
|
|
IN PDEVICE_OBJECT Fdo,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles IRP_MN_REMOVE for the pcmcia controller.
|
|
Stops the adapter if it isn't already, sends the IRP
|
|
to the PDO first & cleans up the Fdo for this controller
|
|
and detaches & deletes the device object.
|
|
|
|
Arguments:
|
|
|
|
Fdo - Pointer to functional device object for the controller
|
|
to be removed
|
|
|
|
Return value:
|
|
|
|
Status
|
|
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
|
|
PDEVICE_OBJECT pdo, nextPdo, fdo, prevFdo;
|
|
PPDO_EXTENSION pdoExtension;
|
|
NTSTATUS status;
|
|
ULONG waitCount = 0;
|
|
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
|
|
if (fdoExtension->Flags & PCMCIA_DEVICE_STARTED) {
|
|
//
|
|
// Stop the fdo first.
|
|
//
|
|
PcmciaFdoStopDevice(Fdo, NULL, NULL, NULL);
|
|
}
|
|
|
|
//
|
|
// Send this down to the PDO
|
|
//
|
|
|
|
status = PcmciaIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Synchronize with power routines
|
|
//
|
|
while(!PCMCIA_TEST_AND_SET(&fdoExtension->DeletionLock)) {
|
|
PcmciaWait(1000000);
|
|
if (waitCount++ > PCMCIA_DELETION_TIMEOUT) {
|
|
ASSERT(waitCount <= PCMCIA_DELETION_TIMEOUT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the PdoList in the fdoExtension is non-empty it means:
|
|
// that the PDOs in the list were not physically removed, but
|
|
// a soft REMOVE was issued, hence they are still hanging on
|
|
// and now this controller itself is being REMOVED.
|
|
// Hence we dispose of those PDOs now
|
|
//
|
|
|
|
for (pdo = fdoExtension->PdoList; pdo != NULL ; pdo = nextPdo) {
|
|
DebugPrint((PCMCIA_DEBUG_INFO,
|
|
"RemoveDevice: pdo %x child of fdo %x was not removed before fdo\n",
|
|
pdo, Fdo));
|
|
|
|
pdoExtension = pdo->DeviceExtension;
|
|
|
|
ASSERT (!IsDevicePhysicallyRemoved(pdoExtension));
|
|
//
|
|
// It's possible for this bit to be on, if the device was added,
|
|
// but never started (because of some other error.
|
|
//ASSERT (!IsDeviceAlive(pdoExtension));
|
|
|
|
nextPdo = pdoExtension->NextPdoInFdoChain;
|
|
if (!IsDeviceDeleted(pdoExtension)) {
|
|
MarkDeviceDeleted(pdoExtension);
|
|
PcmciaCleanupPdo(pdo);
|
|
IoDeleteDevice(pdo);
|
|
}
|
|
}
|
|
|
|
MarkDeviceDeleted(fdoExtension);
|
|
PcmciaCleanupFdo(fdoExtension);
|
|
|
|
//
|
|
// Remove this from the fdo list..
|
|
//
|
|
prevFdo = NULL;
|
|
for (fdo = FdoList; fdo != NULL; prevFdo = fdo, fdo = fdoExtension->NextFdo) {
|
|
fdoExtension = fdo->DeviceExtension;
|
|
if (fdo == Fdo) {
|
|
if (prevFdo) {
|
|
//
|
|
// Delink this fdo
|
|
//
|
|
((PFDO_EXTENSION)prevFdo->DeviceExtension)->NextFdo
|
|
= fdoExtension->NextFdo;
|
|
} else {
|
|
FdoList = fdoExtension->NextFdo;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
DebugPrint((PCMCIA_DEBUG_PNP, "fdo %08x Remove detach & delete\n", Fdo));
|
|
IoDetachDevice(((PFDO_EXTENSION)Fdo->DeviceExtension)->LowerDevice);
|
|
IoDeleteDevice(Fdo);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
PcmciaCleanupContext(
|
|
IN PPCMCIA_CONTEXT pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Frees up allocated pool associated with a specific controller
|
|
register context.
|
|
|
|
Arguments
|
|
|
|
pContext - pointer to a PCMCIA_CONTEXT structure
|
|
|
|
Return value
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
pContext->RangeCount = 0;
|
|
|
|
if (pContext->Range) {
|
|
ExFreePool(pContext->Range);
|
|
pContext->Range = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
PcmciaCleanupFdo(
|
|
IN PFDO_EXTENSION FdoExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Frees up allocated pool, deletes symbolic links etc. for the
|
|
associated FDO for the pcmcia controller which is to be removed.
|
|
|
|
Arguments
|
|
|
|
FdoExtension - Pointer to the device extension for the FDO of the pcmcia controller
|
|
which is being removed
|
|
|
|
Return value
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
PSOCKET socket, nextSocket;
|
|
|
|
//
|
|
// Free the controller register context
|
|
//
|
|
PcmciaCleanupContext(&FdoExtension->PciContext);
|
|
if (FdoExtension->PciContextBuffer) {
|
|
ExFreePool(FdoExtension->PciContextBuffer);
|
|
FdoExtension->PciContextBuffer = NULL;
|
|
}
|
|
|
|
PcmciaCleanupContext(&FdoExtension->CardbusContext);
|
|
PcmciaCleanupContext(&FdoExtension->ExcaContext);
|
|
|
|
//
|
|
// Delete symbolic links to this fdo
|
|
//
|
|
if (FdoExtension->LinkName.Buffer != NULL) {
|
|
IoDeleteSymbolicLink(&FdoExtension->LinkName);
|
|
RtlFreeUnicodeString(&FdoExtension->LinkName);
|
|
}
|
|
|
|
//
|
|
// Cleanup the socket structures
|
|
//
|
|
for (socket = FdoExtension->SocketList; socket != NULL; socket = nextSocket) {
|
|
|
|
if (socket->CardbusContextBuffer) {
|
|
ExFreePool(socket->CardbusContextBuffer);
|
|
socket->CardbusContextBuffer = NULL;
|
|
}
|
|
|
|
if (socket->ExcaContextBuffer) {
|
|
ExFreePool(socket->ExcaContextBuffer);
|
|
socket->ExcaContextBuffer = NULL;
|
|
}
|
|
|
|
nextSocket = socket->NextSocket;
|
|
ExFreePool(socket);
|
|
}
|
|
|
|
FdoExtension->SocketList = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaFdoGetAssignedResources(
|
|
IN PCM_RESOURCE_LIST ResourceList,
|
|
IN PCM_RESOURCE_LIST TranslatedResourceList,
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Extracts the assigned resources to the pcmcia controller
|
|
|
|
Arguments:
|
|
|
|
ResourceList - Raw resource list
|
|
TranslatedResourceList
|
|
DeviceExtension - Device extension of the PCMCIA controller
|
|
|
|
Return value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_UNSUCCESSFUL if resources are not right or enough.
|
|
|
|
--*/
|
|
{
|
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
|
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
|
|
ULONG addressSpace;
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
PHYSICAL_ADDRESS translatedAddress;
|
|
ULONG i;
|
|
ULONG attributeIndex;
|
|
PULONG devicePrivate;
|
|
BOOLEAN translated;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
if ((ResourceList == NULL) || (ResourceList->Count <=0) ) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
|
|
if (CardBusExtension(DeviceExtension)) {
|
|
|
|
fullResourceDesc=&TranslatedResourceList->List[0];
|
|
DeviceExtension->Configuration.InterfaceType = fullResourceDesc->InterfaceType;
|
|
DeviceExtension->Configuration.BusNumber = fullResourceDesc->BusNumber;
|
|
|
|
partialResourceList = &fullResourceDesc->PartialResourceList;
|
|
partialResourceDesc = partialResourceList->PartialDescriptors;
|
|
//
|
|
// We need just the exca register base
|
|
// According to PeterJ the first descriptor
|
|
// for us is the cardbus socket register base.
|
|
// We trust him.
|
|
for (i=0; (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeMemory);
|
|
i++, partialResourceDesc++);
|
|
if (i >= partialResourceList->Count) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
};
|
|
|
|
//
|
|
// This is memory. We need to map it
|
|
//
|
|
DeviceExtension->CardBusSocketRegisterBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
|
|
partialResourceDesc->u.Memory.Length,
|
|
FALSE);
|
|
DeviceExtension->CardBusSocketRegisterSize = partialResourceDesc->u.Memory.Length;
|
|
|
|
DeviceExtension->Flags |= PCMCIA_SOCKET_REGISTER_BASE_MAPPED;
|
|
|
|
//
|
|
// Last BAR is attribute memory window. This will be peeled off later.
|
|
// It might be a good idea to tack a device private on at the end to
|
|
// confirm this. However how do we guarantee our device private does
|
|
// not contain the same data as somebody else's? PnP is lacking here -
|
|
// we need some convention so that devices can set uniquely identifying stuff
|
|
// in there - like maybe the device object they own - to identify it is
|
|
// theirs. Till then this should do.
|
|
//
|
|
if (i > (partialResourceList->Count - 2)) {
|
|
//
|
|
// No more resources? Bail out.
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
for (i++, partialResourceDesc++; (i < (partialResourceList->Count - 1));i++,partialResourceDesc++);
|
|
//
|
|
// partialResourceDesc points to the last descriptor
|
|
//
|
|
ASSERT (partialResourceDesc->Type == CmResourceTypeMemory);
|
|
DeviceExtension->PhysicalBase = partialResourceDesc->u.Memory.Start;
|
|
//
|
|
// This is memory. We need to map it
|
|
//
|
|
DeviceExtension->AttributeMemoryBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
|
|
partialResourceDesc->u.Memory.Length,
|
|
FALSE);
|
|
DeviceExtension->AttributeMemorySize = partialResourceDesc->u.Memory.Length;
|
|
DeviceExtension->Flags |= PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
|
|
|
|
//
|
|
// Finally see if an IRQ is assigned
|
|
//
|
|
|
|
for (i = 0, partialResourceDesc = partialResourceList->PartialDescriptors;
|
|
(i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
|
|
i++,partialResourceDesc++);
|
|
|
|
|
|
if (i < partialResourceList->Count) {
|
|
//
|
|
// We have an interrupt to used for CSC
|
|
// PCI will ensure that this interrupt is exactly the
|
|
// same as the one assigned to the functional interrupt
|
|
// for a cardbus pc-card in this controller's socket
|
|
//
|
|
DebugPrint((PCMCIA_DEBUG_INFO, "PcmciaGetAssignedResources: Interrupt resource assigned\n"));
|
|
DeviceExtension->Configuration.TranslatedInterrupt = *partialResourceDesc;
|
|
//
|
|
// Get the raw interrupt resource - needed to enable the interrupt on the controller
|
|
//
|
|
fullResourceDesc=&ResourceList->List[0];
|
|
partialResourceList = &fullResourceDesc->PartialResourceList;
|
|
partialResourceDesc = partialResourceList->PartialDescriptors;
|
|
for (i=0; (i< partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
|
|
i++, partialResourceDesc++);
|
|
if (i < partialResourceList->Count) {
|
|
DeviceExtension->Configuration.Interrupt = *partialResourceDesc;
|
|
} else {
|
|
//
|
|
// Should not happen.. translated descriptor was present, but raw is missing!
|
|
// Just reset the translated interrupt and pretend no interrupt was assigned
|
|
//
|
|
RtlZeroMemory(&DeviceExtension->Configuration.TranslatedInterrupt, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// 16-bit pcmcia controller
|
|
//
|
|
fullResourceDesc=&ResourceList->List[0];
|
|
DeviceExtension->Configuration.InterfaceType = fullResourceDesc->InterfaceType;
|
|
DeviceExtension->Configuration.BusNumber = fullResourceDesc->BusNumber;
|
|
|
|
partialResourceList = &fullResourceDesc->PartialResourceList;
|
|
partialResourceDesc = partialResourceList->PartialDescriptors;
|
|
|
|
for (i=0; i<partialResourceList->Count; i++, partialResourceDesc++) {
|
|
|
|
devicePrivate = partialResourceDesc->u.DevicePrivate.Data;
|
|
|
|
switch (partialResourceDesc->Type) {
|
|
|
|
case CmResourceTypeInterrupt: {
|
|
if (DeviceExtension->ControllerType != PcmciaCLPD6729 &&
|
|
DeviceExtension->ControllerType != PcmciaPciPcmciaBridge &&
|
|
DeviceExtension->ControllerType != PcmciaNEC98 &&
|
|
DeviceExtension->ControllerType != PcmciaNEC98102) {
|
|
|
|
// We always poll for Cirrus Logic PCI to PCMCIA controllers
|
|
// and other PCI-PCMCIA bridges
|
|
//
|
|
|
|
DeviceExtension->Configuration.Interrupt = *partialResourceDesc;
|
|
}
|
|
break;
|
|
}
|
|
case CmResourceTypePort: {
|
|
DeviceExtension->Configuration.UntranslatedPortAddress = (USHORT) partialResourceDesc->u.Port.Start.QuadPart;
|
|
DeviceExtension->Configuration.PortSize = (USHORT) partialResourceDesc->u.Port.Length;
|
|
break;
|
|
}
|
|
case CmResourceTypeMemory: {
|
|
DeviceExtension->PhysicalBase = partialResourceDesc->u.Memory.Start;
|
|
DeviceExtension->AttributeMemorySize = partialResourceDesc->u.Memory.Length;
|
|
attributeIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((DeviceExtension->PhysicalBase.QuadPart == 0) ||
|
|
(DeviceExtension->Configuration.UntranslatedPortAddress == 0)) {
|
|
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "PcmciaGetAssignedResources: Need both memory and i/o for pcmcia controller 0x%X\n",
|
|
DeviceExtension->DeviceObject));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
fullResourceDesc=&TranslatedResourceList->List[0];
|
|
partialResourceList = &fullResourceDesc->PartialResourceList;
|
|
partialResourceDesc = &partialResourceList->PartialDescriptors[attributeIndex];
|
|
|
|
|
|
switch (partialResourceDesc->Type) {
|
|
|
|
case CmResourceTypeMemory:
|
|
DeviceExtension->AttributeMemoryBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
|
|
DeviceExtension->AttributeMemorySize,
|
|
FALSE);
|
|
DeviceExtension->Flags |= PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
|
|
break;
|
|
|
|
case CmResourceTypePort:
|
|
DeviceExtension->AttributeMemoryBase = (PUCHAR)(partialResourceDesc->u.Port.Start.QuadPart);
|
|
DeviceExtension->Flags &= ~PCMCIA_ATTRIBUTE_MEMORY_MAPPED;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PcmciaAreCardBusCardsSupported(
|
|
IN PFDO_EXTENSION FdoExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicates if cardbus cards will be supported on the given PCMCIA
|
|
controller on this system
|
|
Currently we support cardbus cards only on:
|
|
Machines on which BIOS programmed the bus numbers & IntLine
|
|
|
|
Arguments:
|
|
|
|
FdoExtension - Pointer to device extension for the pcmcia controller
|
|
|
|
Return Value:
|
|
|
|
TRUE - if cardbus cards are supported
|
|
FALSE - if not
|
|
|
|
--*/
|
|
{
|
|
UCHAR byte;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Check int line
|
|
//
|
|
GetPciConfigSpace(FdoExtension,
|
|
CFGSPACE_INT_LINE,
|
|
&byte,
|
|
1);
|
|
if (byte == 0xff) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check cardbus bus number
|
|
//
|
|
GetPciConfigSpace(FdoExtension,
|
|
CFGSPACE_CARDBUS_BUSNUM,
|
|
&byte,
|
|
1);
|
|
if (byte == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check subordinate bus number
|
|
//
|
|
GetPciConfigSpace(FdoExtension,
|
|
CFGSPACE_SUB_BUSNUM,
|
|
&byte,
|
|
1);
|
|
if (byte == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// All tests passed
|
|
//
|
|
return TRUE;
|
|
}
|