1026 lines
28 KiB
C
1026 lines
28 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
intrface.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the external interfaces of the
|
||
pcmcia driver
|
||
|
||
Author:
|
||
|
||
Neil Sandlin (neilsa) 3-Mar-1999
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History :
|
||
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
//
|
||
// Internal References
|
||
//
|
||
|
||
ULONG
|
||
PcmciaReadCardMemory(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN ULONG WhichSpace,
|
||
OUT PUCHAR Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
);
|
||
|
||
ULONG
|
||
PcmciaWriteCardMemory(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN ULONG WhichSpace,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
);
|
||
|
||
NTSTATUS
|
||
PcmciaMfEnumerateChild(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
IN ULONG Index,
|
||
OUT PMF_DEVICE_INFO ChildInfo
|
||
);
|
||
|
||
BOOLEAN
|
||
PcmciaModifyMemoryWindow(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN ULONGLONG HostBase,
|
||
IN ULONGLONG CardBase,
|
||
IN BOOLEAN Enable,
|
||
IN ULONG WindowSize OPTIONAL,
|
||
IN UCHAR AccessSpeed OPTIONAL,
|
||
IN UCHAR BusWidth OPTIONAL,
|
||
IN BOOLEAN IsAttributeMemory OPTIONAL
|
||
);
|
||
|
||
BOOLEAN
|
||
PcmciaSetVpp(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN UCHAR VppLevel
|
||
);
|
||
|
||
BOOLEAN
|
||
PcmciaIsWriteProtected(
|
||
IN PDEVICE_OBJECT Pdo
|
||
);
|
||
|
||
BOOLEAN
|
||
PcmciaTranslateBusAddress(
|
||
IN PVOID Context,
|
||
IN PHYSICAL_ADDRESS BusAddress,
|
||
IN ULONG Length,
|
||
IN OUT PULONG AddressSpace,
|
||
OUT PPHYSICAL_ADDRESS TranslatedAddress
|
||
);
|
||
|
||
PDMA_ADAPTER
|
||
PcmciaGetDmaAdapter(
|
||
IN PVOID Context,
|
||
IN struct _DEVICE_DESCRIPTION *DeviceDescriptor,
|
||
OUT PULONG NumberOfMapRegisters
|
||
);
|
||
|
||
VOID
|
||
PcmciaNop(
|
||
IN PVOID Context
|
||
);
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, PcmciaPdoQueryInterface)
|
||
#pragma alloc_text(PAGE, PcmciaMfEnumerateChild)
|
||
#pragma alloc_text(PAGE, PcmciaNop)
|
||
#pragma alloc_text(PAGE, PcmciaGetInterface)
|
||
#pragma alloc_text(PAGE, PcmciaUpdateInterruptLine)
|
||
#endif
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaPdoQueryInterface(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN OUT PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fills in the interface requested
|
||
|
||
|
||
Interfaces supported are:
|
||
|
||
GUID_PCMCIA_INTERFACE_STANDARD:
|
||
|
||
This returns a pointer to a PCMCIA_INTERFACE_STANDARD structure.
|
||
These interfaces are exported solely for flash memory card support as
|
||
a means for flash memory card drivers to slide memory windows,
|
||
set Vpp levels etc.
|
||
|
||
GUID_TRANSLATOR_INTERFACE_STANDARD:
|
||
|
||
This returns an interrupt translator for 16-bit pc-cards which is used
|
||
by PnP for translating raw IRQs. We simply return the Hal implemented
|
||
translator, since PCMCIA does not need any specific translation. We do not
|
||
return a translator if this is for a cardbus card
|
||
|
||
GUID_PCMCIA_BUS_INTERFACE_STANDARD:
|
||
|
||
This returns a pointer to a PCMCIA_BUS_INTERFACE_STANDARD structure.
|
||
This contains entry points to set/get PCMCIA config data for the pc-card
|
||
|
||
|
||
GUID_MF_ENUMERATION_INTERFACE
|
||
|
||
For 16-bit multifunction pc-cards returns a pointer to MF_ENUMERATION_INTERFACE
|
||
structure which contains entry points to enumerate multifunction children of
|
||
the pc-card
|
||
|
||
Completes the Passed in IRP before returning
|
||
|
||
Arguments
|
||
|
||
Pdo - Pointer to the device object
|
||
Irp - Pointer to the io request packet
|
||
|
||
Return Value
|
||
|
||
STATUS_SUCCESS
|
||
STATUS_INSUFFICIENT_RESOURCES - if supplied interface size is
|
||
not big enough to accomodate the interface
|
||
STATUS_INVALID_PARAMETER_1 - if the requested interface is not supported
|
||
by this driver
|
||
--*/
|
||
|
||
{
|
||
|
||
PIO_STACK_LOCATION irpStack;
|
||
PPCMCIA_INTERFACE_STANDARD pcmciaInterfaceStandard;
|
||
GUID *interfaceType;
|
||
PPDO_EXTENSION pdoExtension;
|
||
PFDO_EXTENSION fdoExtension;
|
||
PSOCKET socket;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
interfaceType = (GUID *) irpStack->Parameters.QueryInterface.InterfaceType;
|
||
pdoExtension = Pdo->DeviceExtension;
|
||
socket = pdoExtension->Socket;
|
||
fdoExtension = socket->DeviceExtension;
|
||
if (Is16BitCard(pdoExtension) && CompareGuid(interfaceType, (PVOID) &GUID_PCMCIA_INTERFACE_STANDARD)) {
|
||
|
||
if (irpStack->Parameters.QueryInterface.Size < sizeof(PCMCIA_INTERFACE_STANDARD)) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Ignore the version for the present
|
||
//
|
||
pcmciaInterfaceStandard = (PPCMCIA_INTERFACE_STANDARD) irpStack->Parameters.QueryInterface.Interface;
|
||
|
||
RtlZeroMemory(pcmciaInterfaceStandard, sizeof (PCMCIA_INTERFACE_STANDARD));
|
||
pcmciaInterfaceStandard->Size = sizeof(PCMCIA_INTERFACE_STANDARD);
|
||
pcmciaInterfaceStandard->Version = 1;
|
||
pcmciaInterfaceStandard->Context = Pdo;
|
||
//
|
||
// Fill in the exported functions
|
||
//
|
||
socket = pdoExtension->Socket;
|
||
|
||
ASSERT (socket != NULL);
|
||
pcmciaInterfaceStandard->InterfaceReference = (PINTERFACE_REFERENCE) PcmciaNop;
|
||
pcmciaInterfaceStandard->InterfaceDereference = (PINTERFACE_DEREFERENCE) PcmciaNop;
|
||
pcmciaInterfaceStandard->ModifyMemoryWindow = PcmciaModifyMemoryWindow;
|
||
pcmciaInterfaceStandard->SetVpp = PcmciaSetVpp;
|
||
pcmciaInterfaceStandard->IsWriteProtected = PcmciaIsWriteProtected;
|
||
Irp->IoStatus.Status = status = STATUS_SUCCESS;;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
} else if (CompareGuid(interfaceType, (PVOID) &GUID_TRANSLATOR_INTERFACE_STANDARD)
|
||
&& ((ULONG_PTR)irpStack->Parameters.QueryInterface.InterfaceSpecificData ==
|
||
CmResourceTypeInterrupt)) {
|
||
if ((Is16BitCard(pdoExtension) && !IsSocketFlagSet(pdoExtension->Socket, SOCKET_CB_ROUTE_R2_TO_PCI)) &&
|
||
//
|
||
// Eject a translator only if the controller is PCI enumerated
|
||
// (i.e. we are enumerated by PCI - so we eject a PCI-Isa translator)
|
||
//
|
||
(CardBusExtension(fdoExtension) || PciPcmciaBridgeExtension(fdoExtension))) {
|
||
|
||
PTRANSLATOR_INTERFACE translator;
|
||
ULONG busNumber;
|
||
//
|
||
// We need a translator for this PDO (16-bit pc-card) which uses
|
||
// ISA resources.
|
||
//
|
||
status = HalGetInterruptTranslator(
|
||
PCIBus,
|
||
0,
|
||
Isa,
|
||
irpStack->Parameters.QueryInterface.Size,
|
||
irpStack->Parameters.QueryInterface.Version,
|
||
(PTRANSLATOR_INTERFACE) irpStack->Parameters.QueryInterface.Interface,
|
||
&busNumber
|
||
);
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
} else {
|
||
//
|
||
// Translator interface not supported for this card/controller
|
||
//
|
||
if (pdoExtension->LowerDevice != NULL) {
|
||
PcmciaSkipCallLowerDriver(status, pdoExtension->LowerDevice, Irp);
|
||
} else {
|
||
status = Irp->IoStatus.Status;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
}
|
||
}
|
||
|
||
} else if (IsDeviceMultifunction(pdoExtension) && CompareGuid(interfaceType, (PVOID)&GUID_MF_ENUMERATION_INTERFACE)) {
|
||
//
|
||
// Multifunction enumeration interface
|
||
//
|
||
PMF_ENUMERATION_INTERFACE mfEnum;
|
||
|
||
mfEnum = (PMF_ENUMERATION_INTERFACE) irpStack->Parameters.QueryInterface.Interface;
|
||
mfEnum->Context = pdoExtension;
|
||
mfEnum->InterfaceReference = PcmciaNop;
|
||
mfEnum->InterfaceDereference = PcmciaNop;
|
||
mfEnum->EnumerateChild = (PMF_ENUMERATE_CHILD) PcmciaMfEnumerateChild;
|
||
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
} else if (CompareGuid(interfaceType, (PVOID)&GUID_PCMCIA_BUS_INTERFACE_STANDARD)) {
|
||
|
||
PPCMCIA_BUS_INTERFACE_STANDARD busInterface;
|
||
|
||
busInterface = (PPCMCIA_BUS_INTERFACE_STANDARD) irpStack->Parameters.QueryInterface.Interface;
|
||
busInterface->Context = Pdo;
|
||
busInterface->InterfaceReference = PcmciaNop;
|
||
busInterface->InterfaceDereference = PcmciaNop;
|
||
busInterface->ReadConfig = PcmciaReadCardMemory;
|
||
busInterface->WriteConfig = PcmciaWriteCardMemory;
|
||
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
} else if (Is16BitCard(pdoExtension) && CompareGuid(interfaceType, (PVOID) &GUID_BUS_INTERFACE_STANDARD)) {
|
||
PBUS_INTERFACE_STANDARD busInterface = (PBUS_INTERFACE_STANDARD)irpStack->Parameters.QueryInterface.Interface;
|
||
|
||
busInterface->Size = sizeof( BUS_INTERFACE_STANDARD );
|
||
busInterface->Version = 1;
|
||
busInterface->Context = Pdo;
|
||
busInterface->InterfaceReference = PcmciaNop;
|
||
busInterface->InterfaceDereference = PcmciaNop;
|
||
busInterface->TranslateBusAddress = PcmciaTranslateBusAddress;
|
||
busInterface->GetDmaAdapter = PcmciaGetDmaAdapter;
|
||
busInterface->GetBusData = PcmciaReadCardMemory;
|
||
busInterface->SetBusData = PcmciaWriteCardMemory;
|
||
status = Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
} else {
|
||
//
|
||
// Query Interface type not supported
|
||
//
|
||
if (pdoExtension->LowerDevice != NULL) {
|
||
PcmciaSkipCallLowerDriver(status, pdoExtension->LowerDevice, Irp);
|
||
} else {
|
||
status = Irp->IoStatus.Status;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
}
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
ULONG
|
||
PcmciaReadCardMemory(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN ULONG WhichSpace,
|
||
OUT PUCHAR Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Stub for reading card memory which is exported via
|
||
PCMCIA_BUS_INTERFACE_STANDARD. This just calls the
|
||
PcmciaReadWriteCardMemory which does the real work
|
||
|
||
Note: this has to be non-paged since it can be called by
|
||
clients at DISPATCH_LEVEL
|
||
|
||
Arguments:
|
||
|
||
Pdo - Device object representing the PC-CARD whose config memory needs to be read
|
||
WhichSpace - Indicates which memory space needs to be mapped: one of
|
||
PCCARD_COMMON_MEMORY_SPACE
|
||
PCCARD_ATTRIBUTE_MEMORY_SPACE
|
||
PCCARD_PCI_CONFIGURATION_MEMORY_SPACE (only for cardbus cards)
|
||
|
||
|
||
Buffer - Caller supplied buffer into which the memory contents are copied
|
||
Offset - Offset of the attribute memory at which we copy
|
||
Length - Number of bytes of attribute memory to be copied
|
||
|
||
Return value:
|
||
|
||
Count of bytes read
|
||
|
||
--*/
|
||
{
|
||
|
||
DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x read card memory\n", Pdo));
|
||
return NT_SUCCESS(PcmciaReadWriteCardMemory(Pdo, WhichSpace, Buffer, Offset, Length, TRUE)) ?
|
||
Length : 0;
|
||
}
|
||
|
||
|
||
|
||
ULONG
|
||
PcmciaWriteCardMemory(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN ULONG WhichSpace,
|
||
IN PUCHAR Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Stub for writing to card memory which is exported via
|
||
PCMCIA_BUS_INTERFACE_STANDARD. This just calls
|
||
PcmciaReadWriteCardMemory which does the real work
|
||
|
||
Note: this has to be non-paged since it can be called by
|
||
clients at DISPATCH_LEVEL
|
||
|
||
Arguments:
|
||
|
||
Pdo - Device object representing the PC-CARD whose config memory needs to be written to
|
||
WhichSpace - Indicates which memory space needs to be mapped: one of
|
||
PCCARD_COMMON_MEMORY_SPACE
|
||
PCCARD_ATTRIBUTE_MEMORY_SPACE
|
||
PCCARD_PCI_CONFIGURATION_MEMORY_SPACE (only for cardbus cards)
|
||
|
||
|
||
Buffer - Caller supplied buffer out of which the memory contents are copied
|
||
Offset - Offset of the attribute memory at which we copy
|
||
Length - Number of bytes of buffer to be copied
|
||
|
||
Return value:
|
||
|
||
Count of bytes written
|
||
|
||
--*/
|
||
{
|
||
|
||
DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x write card memory\n", Pdo));
|
||
return NT_SUCCESS(PcmciaReadWriteCardMemory(Pdo, WhichSpace, Buffer, Offset, Length, FALSE)) ?
|
||
Length : 0;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
PcmciaModifyMemoryWindow(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN ULONGLONG HostBase,
|
||
IN ULONGLONG CardBase,
|
||
IN BOOLEAN Enable,
|
||
IN ULONG WindowSize OPTIONAL,
|
||
IN UCHAR AccessSpeed OPTIONAL,
|
||
IN UCHAR BusWidth OPTIONAL,
|
||
IN BOOLEAN IsAttributeMemory OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Part of the interfaces originally developed to
|
||
support flash memory cards.
|
||
|
||
This routine enables the caller to 'slide' the supplied
|
||
host memory window across the given (16-bit)pc-card's card memory.
|
||
i.e. the host memory window will be modified to map
|
||
the pc-card at a new card memory offset
|
||
|
||
Arguments:
|
||
|
||
Pdo - Pointer to the device object for the PC-Card
|
||
|
||
HostBase - Host memory window base to be mapped
|
||
|
||
CardBase - Mandatory if Enable is TRUE
|
||
New card memory offset to map the host memory window
|
||
to
|
||
|
||
Enable - If this is FALSE - all the remaining arguments
|
||
are ignored and the host window will simply be
|
||
disabled
|
||
|
||
WindowSize - Specifies the size of the host memory window to
|
||
be mapped. Note this must be at the proper alignment
|
||
and must be less than or equal to the originally
|
||
allocated window size for the host base.
|
||
If this is zero, the originally allocated window
|
||
size will be used.
|
||
|
||
AccessSpeed - Mandatory if Enable is TRUE
|
||
Specifies the new access speed for the pc-card.
|
||
(AccessSpeed should be encoded as per the pc-card
|
||
standard, card/socket services spec)
|
||
|
||
BusWidth - Mandatory if Enable is TRUE
|
||
One of PCMCIA_MEMORY_8BIT_ACCESS
|
||
or PCMCIA_MEMORY_16BIT_ACCESS
|
||
|
||
IsAttributeMemory - Mandatory if Enable is TRUE
|
||
Specifies if the window should be mapped
|
||
to the pc-card's attribute or common memory
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE - Memory window was enabled/disabled as requested
|
||
FALSE - If not
|
||
|
||
--*/
|
||
{
|
||
PPDO_EXTENSION pdoExtension;
|
||
PSOCKET socket;
|
||
|
||
pdoExtension = Pdo->DeviceExtension;
|
||
socket = pdoExtension->Socket;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x modify memory window\n", Pdo));
|
||
if (socket->SocketFnPtr->PCBModifyMemoryWindow == NULL) {
|
||
return FALSE;
|
||
} else {
|
||
return (*(socket->SocketFnPtr->PCBModifyMemoryWindow))(Pdo, HostBase, CardBase, Enable,
|
||
WindowSize, AccessSpeed, BusWidth,
|
||
IsAttributeMemory);
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
PcmciaSetVpp(
|
||
IN PDEVICE_OBJECT Pdo,
|
||
IN UCHAR VppLevel
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
Part of the interfaces originally developed to
|
||
support flash memory cards.
|
||
Sets VPP1 to the required setting
|
||
|
||
Arguments
|
||
|
||
Pdo - Pointer to device object for the PC-Card
|
||
Vpp - Desired Vpp setting. This is currently one of
|
||
PCMCIA_VPP_12V (12 volts)
|
||
PCMCIA_VPP_0V (disable VPP)
|
||
PCMCIA_VPP_IS_VCC (route VCC to VPP)
|
||
|
||
Return
|
||
|
||
TRUE - if successful
|
||
FALSE - if not. This will be returned if the
|
||
PC-Card is not already powered up
|
||
--*/
|
||
{
|
||
PPDO_EXTENSION pdoExtension;
|
||
PSOCKET socket;
|
||
|
||
pdoExtension = Pdo->DeviceExtension;
|
||
socket = pdoExtension->Socket;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x set vpp\n", Pdo));
|
||
if (socket->SocketFnPtr->PCBSetVpp == NULL) {
|
||
return FALSE;
|
||
} else {
|
||
return (*(socket->SocketFnPtr->PCBSetVpp))(Pdo, VppLevel);
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
PcmciaIsWriteProtected(
|
||
IN PDEVICE_OBJECT Pdo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Part of the interfaces originally developed to
|
||
support flash memory cards.
|
||
|
||
Returns the status of the write protected pin
|
||
for the given PC-Card
|
||
|
||
Arguments:
|
||
|
||
Pdo - Pointer to the device object for the PC-Card
|
||
|
||
Return Value:
|
||
|
||
TRUE - if the PC-Card is write-protected
|
||
FALSE - if not
|
||
|
||
--*/
|
||
{
|
||
PPDO_EXTENSION pdoExtension;
|
||
PSOCKET socket;
|
||
|
||
pdoExtension = Pdo->DeviceExtension;
|
||
socket = pdoExtension->Socket;
|
||
|
||
DebugPrint((PCMCIA_DEBUG_INTERFACE, "pdo %08x is write protected \n", Pdo));
|
||
if (socket->SocketFnPtr->PCBIsWriteProtected == NULL) {
|
||
return FALSE;
|
||
} else {
|
||
return (*(socket->SocketFnPtr->PCBIsWriteProtected))(Pdo);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
PcmciaTranslateBusAddress(
|
||
IN PVOID Context,
|
||
IN PHYSICAL_ADDRESS BusAddress,
|
||
IN ULONG Length,
|
||
IN OUT PULONG AddressSpace,
|
||
OUT PPHYSICAL_ADDRESS TranslatedAddress
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
This function is used to translate bus addresses from legacy drivers.
|
||
|
||
Arguments
|
||
|
||
Context - Supplies a pointer to the interface context. This is actually
|
||
the PDO for the root bus.
|
||
|
||
BusAddress - Supplies the orginal address to be translated.
|
||
|
||
Length - Supplies the length of the range to be translated.
|
||
|
||
AddressSpace - Points to the location of of the address space type such as
|
||
memory or I/O port. This value is updated by the translation.
|
||
|
||
TranslatedAddress - Returns the translated address.
|
||
|
||
Return Value
|
||
|
||
Returns a boolean indicating if the operations was a success.
|
||
|
||
--*/
|
||
{
|
||
return HalTranslateBusAddress(Isa,
|
||
0,
|
||
BusAddress,
|
||
AddressSpace,
|
||
TranslatedAddress);
|
||
}
|
||
|
||
|
||
|
||
PDMA_ADAPTER
|
||
PcmciaGetDmaAdapter(
|
||
IN PVOID Context,
|
||
IN struct _DEVICE_DESCRIPTION *DeviceDescriptor,
|
||
OUT PULONG NumberOfMapRegisters
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
Passes IoGetDmaAdapter calls to the parent.
|
||
|
||
Arguments
|
||
|
||
Context - Supplies a pointer to the interface context. This is actually the PDO.
|
||
|
||
DeviceDescriptor - Supplies the device descriptor used to allocate the dma
|
||
adapter object.
|
||
|
||
NubmerOfMapRegisters - Returns the maximum number of map registers a device
|
||
can allocate at one time.
|
||
|
||
Return Value
|
||
|
||
Returns a DMA adapter or NULL.
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT Pdo = Context;
|
||
PPDO_EXTENSION pdoExtension;
|
||
PFDO_EXTENSION fdoExtension;
|
||
|
||
pdoExtension = Pdo->DeviceExtension;
|
||
|
||
if (!pdoExtension || !pdoExtension->Socket || !pdoExtension->Socket->DeviceExtension) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Get the parent FDO extension
|
||
//
|
||
fdoExtension = pdoExtension->Socket->DeviceExtension;
|
||
|
||
//
|
||
// Pass the call on to the parent
|
||
//
|
||
return IoGetDmaAdapter(fdoExtension->Pdo,
|
||
DeviceDescriptor,
|
||
NumberOfMapRegisters);
|
||
}
|
||
|
||
|
||
VOID
|
||
PcmciaNop(
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
Does nothing
|
||
|
||
Arguments
|
||
|
||
none
|
||
|
||
Return Value
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
UNREFERENCED_PARAMETER(Context);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaMfEnumerateChild(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
IN ULONG Index,
|
||
OUT PMF_DEVICE_INFO ChildInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description
|
||
|
||
Returns required enumeration information for the multifunction children
|
||
of the given pc-card. This fills in the required info. for the child
|
||
indicated, returing STATUS_NO_MORE_ENTRIES when there are no more
|
||
children to be enumerated
|
||
|
||
Arguments
|
||
|
||
PdoExtension - Pointer to the device extension for the multifunction parent pc-card
|
||
Index - Zero based index for the child to be enumerated
|
||
ChildInfo - Caller allocated buffer in which the info about the child is returned.
|
||
We may allocate additional buffers for each field in the supplied
|
||
structure. This will be freed by the caller when no longer needed
|
||
|
||
Return value
|
||
|
||
STATUS_SUCCESS - supplied child info filled in & returned
|
||
STATUS_NO_MORE_ENTRIES - No child of the given index exists. Caller is
|
||
assumed to iteratively call this routine with index incremented
|
||
from 0 upwards till this status value is returned
|
||
STATUS_NO_SUCH_DEVICE - if the pc-card no longer exists
|
||
--*/
|
||
{
|
||
PSOCKET socket;
|
||
PSOCKET_DATA socketData;
|
||
PCONFIG_ENTRY configEntry, mfConfigEntry;
|
||
ULONG i, currentIndex, count;
|
||
NTSTATUS status;
|
||
UCHAR iRes;
|
||
PUCHAR idString;
|
||
ANSI_STRING ansiString;
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugPrint((PCMCIA_DEBUG_INTERFACE,
|
||
"PcmciaMfEnumerateChild: parent ext %x child index %x\n",
|
||
PdoExtension,
|
||
Index
|
||
));
|
||
try {
|
||
if (IsDeviceDeleted(PdoExtension) ||
|
||
IsDeviceLogicallyRemoved(PdoExtension)) {
|
||
//
|
||
// This pdo is deleted or marked to be deleted
|
||
//
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
leave;
|
||
}
|
||
|
||
socket = PdoExtension->Socket;
|
||
ASSERT (socket != NULL);
|
||
|
||
RtlZeroMemory(ChildInfo, sizeof(MF_DEVICE_INFO));
|
||
|
||
if (Index >= socket->NumberOfFunctions) {
|
||
//
|
||
// info requested for a child which doesn't exist
|
||
//
|
||
status = STATUS_NO_MORE_ENTRIES;
|
||
leave;
|
||
}
|
||
|
||
//
|
||
// Fill in the name field
|
||
// This is of the form ChildXX
|
||
// where XX is the number of the function
|
||
// Examples: Child00, Child01 etc.
|
||
//
|
||
idString = (PUCHAR) ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
|
||
if (!idString) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
leave;
|
||
}
|
||
sprintf(idString, "Child%02x", Index);
|
||
RtlInitAnsiString(&ansiString, idString);
|
||
status = RtlAnsiStringToUnicodeString(&ChildInfo->Name,
|
||
&ansiString,
|
||
TRUE);
|
||
ExFreePool(idString);
|
||
if (!NT_SUCCESS(status)) {
|
||
leave;
|
||
}
|
||
|
||
//
|
||
// Get compatible ids
|
||
//
|
||
status = PcmciaGetCompatibleIds(PdoExtension->DeviceObject,
|
||
Index,
|
||
&ChildInfo->CompatibleID);
|
||
if (!NT_SUCCESS(status)) {
|
||
leave;
|
||
}
|
||
|
||
//
|
||
// Get hardware ids
|
||
//
|
||
status = PcmciaGetHardwareIds(PdoExtension->DeviceObject,
|
||
Index,
|
||
&ChildInfo->HardwareID);
|
||
if (!NT_SUCCESS(status)) {
|
||
leave;
|
||
}
|
||
|
||
//
|
||
// Fill in the resource map stuff
|
||
//
|
||
// Locate the socket data structure corresponding to this function
|
||
for (socketData = PdoExtension->SocketData, i=0; (socketData != NULL) && (i != Index); socketData=socketData->Next, i++);
|
||
|
||
if (!socketData) {
|
||
//
|
||
// this condition should never be encountered
|
||
//
|
||
ASSERT (FALSE);
|
||
status = STATUS_NO_MORE_ENTRIES;
|
||
leave;
|
||
}
|
||
|
||
if (!(socketData->NumberOfConfigEntries > 0)) {
|
||
//
|
||
// No resource map required
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
leave;
|
||
}
|
||
|
||
count = (socketData->MfNeedsIrq ? 1 : 0) + socketData->MfIoPortCount + socketData->MfMemoryCount;
|
||
if (count == 0) {
|
||
ASSERT(FALSE);
|
||
//
|
||
// No resource map required
|
||
//
|
||
status = STATUS_SUCCESS;
|
||
leave;
|
||
}
|
||
|
||
//
|
||
// Allocate resource map
|
||
//
|
||
ChildInfo->ResourceMap = ExAllocatePool(PagedPool,
|
||
sizeof(MF_RESOURCE_MAP) + (count-1) * sizeof(UCHAR));
|
||
if (!ChildInfo->ResourceMap) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
leave;
|
||
}
|
||
|
||
ChildInfo->ResourceMap->Count = count;
|
||
//
|
||
// Compute the resource map indices
|
||
// The config entry *already* contains fields (MfIrqResourceMapIndex, MfIoPortResourceMapIndex etc.)
|
||
// which indicate the relative index of the resource requested for this function within the resource type.
|
||
// We calculate the absolute index by adding up the number of instances of each resource type requested,
|
||
// preceding the current resource type, to this relative index.
|
||
//
|
||
currentIndex = 0;
|
||
//
|
||
// Fill the irq map if there's one
|
||
//
|
||
if (socketData->MfNeedsIrq) {
|
||
ChildInfo->ResourceMap->Resources[currentIndex++] = socketData->MfIrqResourceMapIndex;
|
||
}
|
||
//
|
||
// Fill the i/o port map if there's one
|
||
//
|
||
if (socketData->MfIoPortCount) {
|
||
for (iRes=0; iRes<socketData->MfIoPortCount; iRes++) {
|
||
|
||
ChildInfo->ResourceMap->Resources[currentIndex++] = socketData->MfIoPortResourceMapIndex + iRes;
|
||
|
||
}
|
||
}
|
||
//
|
||
// Fill the memory request map if there's one
|
||
//
|
||
if (socketData->MfMemoryCount) {
|
||
for (iRes=0; iRes<socketData->MfMemoryCount; iRes++) {
|
||
|
||
ChildInfo->ResourceMap->Resources[currentIndex++] = socketData->MfMemoryResourceMapIndex + iRes;
|
||
|
||
}
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
} finally {
|
||
if (!NT_SUCCESS(status)) {
|
||
//
|
||
// Free up all the allocated buffers
|
||
//
|
||
if (ChildInfo->Name.Buffer) {
|
||
ExFreePool(ChildInfo->Name.Buffer);
|
||
}
|
||
|
||
if (ChildInfo->CompatibleID.Buffer) {
|
||
ExFreePool(ChildInfo->CompatibleID.Buffer);
|
||
}
|
||
|
||
if (ChildInfo->HardwareID.Buffer) {
|
||
ExFreePool(ChildInfo->HardwareID.Buffer);
|
||
}
|
||
|
||
if (ChildInfo->ResourceMap) {
|
||
ExFreePool(ChildInfo->ResourceMap);
|
||
}
|
||
|
||
if (ChildInfo->VaryingResourceMap) {
|
||
ExFreePool(ChildInfo->ResourceMap);
|
||
}
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaGetInterface(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN CONST GUID *pGuid,
|
||
IN USHORT sizeofInterface,
|
||
OUT PINTERFACE pInterface
|
||
)
|
||
/*
|
||
|
||
Routine Description
|
||
|
||
Gets the interface exported by PCI for enumerating 32-bit cardbus cards, which
|
||
appear as regular PCI devices. This interface will be used to respond during
|
||
subsequent enumeration requests from PnP to invoke PCI to enumerate the cards.
|
||
|
||
Arguments
|
||
|
||
Pdo - Pointer to physical device object for the cardbus controller
|
||
PciCardBusInterface - Pointer to the PCI-Cardbus interface will be returned
|
||
in this variable
|
||
|
||
Return Value
|
||
|
||
Status
|
||
|
||
*/
|
||
|
||
{
|
||
KEVENT event;
|
||
PIRP irp;
|
||
NTSTATUS status;
|
||
IO_STATUS_BLOCK statusBlock;
|
||
PIO_STACK_LOCATION irpSp;
|
||
|
||
PAGED_CODE();
|
||
|
||
KeInitializeEvent (&event, NotificationEvent, FALSE);
|
||
irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
|
||
DeviceObject,
|
||
NULL,
|
||
0,
|
||
0,
|
||
&event,
|
||
&statusBlock
|
||
);
|
||
|
||
irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
|
||
irp->IoStatus.Information = 0;
|
||
|
||
irpSp = IoGetNextIrpStackLocation(irp);
|
||
|
||
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||
|
||
irpSp->Parameters.QueryInterface.InterfaceType= pGuid;
|
||
irpSp->Parameters.QueryInterface.Size = sizeofInterface;
|
||
irpSp->Parameters.QueryInterface.Version = 1;
|
||
irpSp->Parameters.QueryInterface.Interface = pInterface;
|
||
|
||
status = IoCallDriver(DeviceObject, irp);
|
||
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
|
||
status = statusBlock.Status;
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((PCMCIA_DEBUG_INFO, "GetInterface failed with status %x\n", status));
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PcmciaUpdateInterruptLine(
|
||
IN PPDO_EXTENSION PdoExtension,
|
||
IN PFDO_EXTENSION FdoExtension
|
||
)
|
||
/*
|
||
|
||
Routine Description
|
||
|
||
This routine uses the PCI Irq Routing interface to update the raw interrupt
|
||
line of a cardbus card. This is done in order to allow cardbus cards to run
|
||
on non-acpi machines without pci irq routing, as long as the bios supplies
|
||
the interrupt for the cardbus controller.
|
||
|
||
Arguments
|
||
|
||
PdoExtension - Pointer to the extension for the cardbus card
|
||
FdoExtension - Pointer to the extension for the cardbus controller
|
||
|
||
Return Value
|
||
|
||
Status
|
||
|
||
*/
|
||
|
||
{
|
||
|
||
PAGED_CODE();
|
||
|
||
if (!IsDeviceFlagSet(FdoExtension, PCMCIA_INT_ROUTE_INTERFACE)) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if (FdoExtension->Configuration.Interrupt.u.Interrupt.Vector == 0) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
(FdoExtension->PciIntRouteInterface.UpdateInterruptLine)(PdoExtension->PciPdo,
|
||
(UCHAR) FdoExtension->Configuration.Interrupt.u.Interrupt.Vector);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|