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.
1273 lines
30 KiB
1273 lines
30 KiB
/*++
|
|
|
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cb.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code that contains
|
|
generic (Yenta compliant) cardbus controller
|
|
specific initialization and other dispatches
|
|
|
|
Author:
|
|
|
|
Ravisankar Pudipeddi (ravisp) 1-Nov-97
|
|
Neil Sandlin (neilsa) June 1 1999
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
Neil Sandlin (neilsa) 3-Mar-99
|
|
new setpower routine interface
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
|
|
BOOLEAN
|
|
CBInitializePcmciaSocket(
|
|
PSOCKET Socket
|
|
);
|
|
|
|
NTSTATUS
|
|
CBResetCard(
|
|
PSOCKET Socket,
|
|
PULONG pDelayTime
|
|
);
|
|
|
|
BOOLEAN
|
|
CBDetectCardInSocket(
|
|
IN PSOCKET Socket
|
|
);
|
|
|
|
BOOLEAN
|
|
CBDetectCardChanged(
|
|
IN PSOCKET Socket
|
|
);
|
|
|
|
BOOLEAN
|
|
CBDetectCardStatus(
|
|
IN PSOCKET Socket
|
|
);
|
|
|
|
BOOLEAN
|
|
CBDetectReadyChanged(
|
|
IN PSOCKET Socket
|
|
);
|
|
|
|
NTSTATUS
|
|
CBGetPowerRequirements(
|
|
IN PSOCKET Socket
|
|
);
|
|
|
|
BOOLEAN
|
|
CBProcessConfigureRequest(
|
|
IN PSOCKET Socket,
|
|
IN PVOID ConfigRequest,
|
|
IN PUCHAR Base
|
|
);
|
|
|
|
BOOLEAN
|
|
CBEnableDisableCardDetectEvent(
|
|
IN PSOCKET Socket,
|
|
IN BOOLEAN Enable
|
|
);
|
|
|
|
ULONG
|
|
CBGetIrqMask(
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
);
|
|
|
|
ULONG
|
|
CBReadCardMemory(
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN MEMORY_SPACE MemorySpace,
|
|
IN ULONG Offset,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
);
|
|
|
|
ULONG
|
|
CBWriteCardMemory(
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN MEMORY_SPACE MemorySpace,
|
|
IN ULONG Offset,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
);
|
|
|
|
VOID
|
|
CBEnableDisableWakeupEvent(
|
|
IN PSOCKET Socket,
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN BOOLEAN Enable
|
|
);
|
|
|
|
BOOLEAN
|
|
CBModifyMemoryWindow(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN ULONGLONG HostBase,
|
|
IN ULONGLONG CardBase OPTIONAL,
|
|
IN BOOLEAN Enable,
|
|
IN ULONG WindowSize OPTIONAL,
|
|
IN UCHAR AccessSpeed OPTIONAL,
|
|
IN UCHAR BusWidth OPTIONAL,
|
|
IN BOOLEAN IsAttributeMemory OPTIONAL
|
|
);
|
|
|
|
BOOLEAN
|
|
CBSetVpp(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN UCHAR Vpp
|
|
);
|
|
|
|
BOOLEAN
|
|
CBIsWriteProtected(
|
|
IN PDEVICE_OBJECT Pdo
|
|
);
|
|
|
|
//
|
|
// Function dispatch data block
|
|
//
|
|
|
|
PCMCIA_CTRL_BLOCK CBSupportFns = {
|
|
CBInitializePcmciaSocket,
|
|
CBResetCard,
|
|
CBDetectCardInSocket,
|
|
CBDetectCardChanged,
|
|
CBDetectCardStatus,
|
|
CBDetectReadyChanged,
|
|
CBGetPowerRequirements,
|
|
CBProcessConfigureRequest,
|
|
CBEnableDisableCardDetectEvent,
|
|
CBEnableDisableWakeupEvent,
|
|
CBGetIrqMask,
|
|
CBReadCardMemory,
|
|
CBWriteCardMemory,
|
|
CBModifyMemoryWindow,
|
|
CBSetVpp,
|
|
CBIsWriteProtected
|
|
};
|
|
|
|
extern PCMCIA_CTRL_BLOCK PcicSupportFns;
|
|
|
|
//
|
|
// Support functions
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
CBBuildSocketList(
|
|
IN PFDO_EXTENSION FdoExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds the socket list for the given FDO. This is very
|
|
simple for cardbus since there is always only 1 socket per controller.
|
|
|
|
Arguments:
|
|
|
|
FdoExtension - device extension for the controller
|
|
|
|
Return Value:
|
|
|
|
ntstatus
|
|
|
|
--*/
|
|
{
|
|
PSOCKET socket = NULL;
|
|
|
|
socket = ExAllocatePool(NonPagedPool, sizeof(SOCKET));
|
|
if (!socket) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(socket, sizeof(SOCKET));
|
|
|
|
FdoExtension->SocketList = socket;
|
|
|
|
socket->DeviceExtension = FdoExtension;
|
|
socket->SocketFnPtr = &CBSupportFns;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
CBInitializePcmciaSocket(
|
|
PSOCKET Socket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will setup the controller into a state where the pcmcia support
|
|
module will be able to issue commands to read device tuples from the
|
|
cards in the sockets.
|
|
|
|
Arguments:
|
|
|
|
Socket - socket specific information
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful
|
|
FALSE if not successful
|
|
|
|
--*/
|
|
{
|
|
UCHAR index;
|
|
UCHAR reg;
|
|
|
|
//
|
|
// Initialize exca registers
|
|
//
|
|
if (!PcicSupportFns.PCBInitializePcmciaSocket(Socket)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Clear pending events
|
|
//
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG, 0x0000000F);
|
|
|
|
//
|
|
// Since we may have just powered up, do a cvstest to make sure the socket registers
|
|
// are valid
|
|
//
|
|
|
|
if (CBDetectCardInSocket(Socket) &&
|
|
!IsDeviceFlagSet(Socket->DeviceExtension, PCMCIA_FDO_ON_DEBUG_PATH)) {
|
|
CBIssueCvsTest(Socket);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
CBIssueCvsTest(
|
|
IN PSOCKET Socket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine forces the controller to reinterrogate the card type and voltage
|
|
requirements. This is to insure correct values read from the socket registers.
|
|
|
|
Arguments:
|
|
|
|
Socket - socket specific information
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
ULONG dwSktMask;
|
|
|
|
//
|
|
// Issue CVSTEST to interrogate card
|
|
// Disable interrupt temporarily because TI 12xx could cause spurious
|
|
// interrupt when playing with SktForce register.
|
|
//
|
|
dwSktMask = CBReadSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG);
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, 0);
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_FORCE_EVENT_REG, SKTFORCE_CVSTEST);
|
|
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, dwSktMask);
|
|
|
|
// it would be nice to figure out a cleaner way to determine when interrogation is complete
|
|
PcmciaWait(300000);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
CBEnableDeviceInterruptRouting(
|
|
IN PSOCKET Socket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Socket - socket specific information
|
|
|
|
Return Value:
|
|
|
|
FALSE - irq to PCI
|
|
TRUE - route to ISA
|
|
|
|
--*/
|
|
{
|
|
USHORT word, orig_word;
|
|
|
|
//
|
|
// set up IRQ routing
|
|
//
|
|
|
|
GetPciConfigSpace(Socket->DeviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
orig_word = word;
|
|
|
|
if (IsCardBusCardInSocket(Socket) ||
|
|
(Is16BitCardInSocket(Socket) && IsSocketFlagSet(Socket, SOCKET_CB_ROUTE_R2_TO_PCI))) {
|
|
//
|
|
// route to PCI
|
|
//
|
|
word &= ~BCTRL_IRQROUTING_ENABLE;
|
|
} else {
|
|
//
|
|
// route to ISA
|
|
//
|
|
word |= BCTRL_IRQROUTING_ENABLE;
|
|
}
|
|
|
|
if (orig_word != word) {
|
|
SetPciConfigSpace(Socket->DeviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
}
|
|
|
|
// return TRUE for routing to ISA
|
|
return ((word & BCTRL_IRQROUTING_ENABLE) == BCTRL_IRQROUTING_ENABLE);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CBResetCard(
|
|
PSOCKET Socket,
|
|
OUT PULONG pDelayTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resets the pc-card in the given socket.
|
|
|
|
Arguments:
|
|
|
|
Socket - Pointer to the socket in which the pc-card resides
|
|
pDelayTime - specifies delay (msec) to occur after the current phase
|
|
|
|
Return value:
|
|
|
|
STATUS_MORE_PROCESSING_REQUIRED - increment phase, perform delay, recall
|
|
other status values terminate sequence
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
UCHAR byte;
|
|
USHORT word;
|
|
PFDO_EXTENSION deviceExtension=Socket->DeviceExtension;
|
|
|
|
|
|
if (Is16BitCardInSocket(Socket)) {
|
|
if (Socket->CardResetPhase == 2) {
|
|
GetPciConfigSpace(deviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
//
|
|
// R2 card. Turn off write posting
|
|
//
|
|
word &= ~BCTRL_WRITE_POSTING_ENABLE;
|
|
SetPciConfigSpace(deviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
}
|
|
|
|
status = PcicSupportFns.PCBResetCard(Socket, pDelayTime);
|
|
return status;
|
|
}
|
|
|
|
|
|
switch(Socket->CardResetPhase) {
|
|
case 1:
|
|
|
|
//
|
|
// Reset via bridge control
|
|
//
|
|
GetPciConfigSpace(deviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
word |= BCTRL_CRST;
|
|
SetPciConfigSpace(deviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
|
|
Socket->PowerData = (ULONG) word;
|
|
*pDelayTime = PCMCIA_CB_RESET_WIDTH_DELAY;
|
|
break;
|
|
|
|
case 2:
|
|
|
|
word = (USHORT)Socket->PowerData;
|
|
word &= ~BCTRL_CRST;
|
|
//
|
|
// CardBus card. Turn on write posting
|
|
//
|
|
word |= BCTRL_WRITE_POSTING_ENABLE;
|
|
word &= ~BCTRL_IRQROUTING_ENABLE;
|
|
//
|
|
// Hack: turn of write posting for topic95 to avoid hardware
|
|
// bug with intel NICs
|
|
//
|
|
if (deviceExtension->ControllerType == PcmciaTopic95) {
|
|
word &= ~BCTRL_WRITE_POSTING_ENABLE;
|
|
}
|
|
//
|
|
// Stop bridge control reset
|
|
//
|
|
SetPciConfigSpace(deviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
|
|
*pDelayTime = PCMCIA_CB_RESET_SETUP_DELAY;
|
|
break;
|
|
|
|
case 3:
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
CBDetectCardInSocket(
|
|
IN PSOCKET Socket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will determine if a card is in the socket
|
|
|
|
Arguments:
|
|
|
|
Socket -- Socket information
|
|
|
|
Return Value:
|
|
|
|
TRUE if card is present.
|
|
|
|
--*/
|
|
{
|
|
ULONG state;
|
|
BOOLEAN cardPresent=FALSE;
|
|
|
|
if (IsSocketFlagSet(Socket, SOCKET_DEVICE_HIDDEN)) {
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Read the CARDBUS status register to see if the card is in there.
|
|
//
|
|
state = CBReadSocketRegister(Socket, CARDBUS_SOCKET_PRESENT_STATE_REG);
|
|
if ((state & SKTSTATE_CCD_MASK) == 0) {
|
|
cardPresent = TRUE;
|
|
}
|
|
return(cardPresent);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CBDetectCardChanged(
|
|
IN PSOCKET Socket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will determine if socket's card insertion status has changed.
|
|
|
|
Arguments:
|
|
|
|
Socket -- Socket info.
|
|
|
|
Return Value:
|
|
|
|
TRUE if card insertion status has changed.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN retVal = FALSE;
|
|
ULONG tmp;
|
|
//
|
|
// Read SOCKET Event register to see if CD's changed
|
|
//
|
|
tmp = CBReadSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG);
|
|
if ((tmp & SKTEVENT_CCD_MASK) != 0) {
|
|
//
|
|
// Yes they did..
|
|
// first clear the interrupt
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG, SKTEVENT_CCD_MASK);
|
|
retVal = TRUE;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
CBDetectCardStatus(
|
|
IN PSOCKET Socket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will determine if socket's card insertion status has changed.
|
|
|
|
Arguments:
|
|
|
|
Socket -- Socket info.
|
|
|
|
Return Value:
|
|
|
|
TRUE if card insertion status has changed.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN retVal = FALSE;
|
|
ULONG tmp;
|
|
|
|
if (Is16BitCardInSocket(Socket)) {
|
|
// NOTE: UNIMPLEMENTED: may need to do something for 16-bit cards
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Read SOCKET Event register to see if CD's changed
|
|
//
|
|
tmp = CBReadSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG);
|
|
if ((tmp & SKTEVENT_CSTSCHG) != 0) {
|
|
//
|
|
// Yes they did..
|
|
// first clear the interrupt
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG, SKTEVENT_CSTSCHG);
|
|
retVal = TRUE;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
CBDetectReadyChanged(
|
|
IN PSOCKET Socket
|
|
)
|
|
{
|
|
return(PcicSupportFns.PCBDetectReadyChanged(Socket));
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CBProcessConfigureRequest(
|
|
IN PSOCKET Socket,
|
|
IN PCARD_REQUEST Request,
|
|
IN PUCHAR Base
|
|
)
|
|
{
|
|
BOOLEAN bStatus = TRUE;
|
|
USHORT word;
|
|
|
|
//
|
|
// Shouldn't this check for 16-bit cards?
|
|
//
|
|
|
|
switch (Request->RequestType) {
|
|
|
|
case IRQ_REQUEST:
|
|
|
|
if (CBEnableDeviceInterruptRouting(Socket)) {
|
|
bStatus = PcicSupportFns.PCBProcessConfigureRequest(Socket, Request, Base);
|
|
}
|
|
break;
|
|
|
|
case DECONFIGURE_REQUEST:
|
|
|
|
bStatus = PcicSupportFns.PCBProcessConfigureRequest(Socket, Request, Base);
|
|
GetPciConfigSpace(Socket->DeviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
word |= BCTRL_IRQROUTING_ENABLE;
|
|
SetPciConfigSpace(Socket->DeviceExtension, CFGSPACE_BRIDGE_CTRL, &word, 2);
|
|
break;
|
|
|
|
default:
|
|
bStatus = PcicSupportFns.PCBProcessConfigureRequest(Socket, Request, Base);
|
|
}
|
|
|
|
return bStatus;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CBEnableDisableCardDetectEvent(
|
|
IN PSOCKET Socket,
|
|
IN BOOLEAN Enable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enable card detect/card ready interrupt.
|
|
|
|
Arguments:
|
|
|
|
Socket - socket information
|
|
Enable - if TRUE, CSC interrupt is enabled,
|
|
if FALSE, it is disabled
|
|
Return Value:
|
|
|
|
TRUE if successful
|
|
FALSE if not successful
|
|
|
|
--*/
|
|
{
|
|
|
|
switch (Enable) {
|
|
|
|
case TRUE: {
|
|
UCHAR byte;
|
|
//
|
|
// Only if TI 1130/1250?
|
|
// Route through PCI interrupts
|
|
byte = PcicReadSocket(Socket, PCIC_INTERRUPT);
|
|
byte |= IGC_INTR_ENABLE;
|
|
PcicWriteSocket(Socket, PCIC_INTERRUPT, byte);
|
|
|
|
//
|
|
// Clear the bits in Socket Event Register
|
|
//
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG, 0xF);
|
|
|
|
//
|
|
// Enable card-detect interrupt in Socket Mask Register
|
|
//
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, SKTMSK_CCD);
|
|
break;
|
|
}
|
|
|
|
case FALSE: {
|
|
ULONG oldValue;
|
|
//
|
|
// Clear the bits in Socket Event Register
|
|
//
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG, 0xF);
|
|
|
|
//
|
|
// Disable card-detect interrupt in Socket Mask Register
|
|
//
|
|
oldValue = CBReadSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG);
|
|
oldValue &= ~SKTMSK_CCD;
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, oldValue);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
CBEnableDisableWakeupEvent(
|
|
IN PSOCKET Socket,
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN BOOLEAN Enable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
Socket - socket information
|
|
Enable - if TRUE, interrupt is enabled,
|
|
if FALSE, it is disabled
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
ULONG dwValue;
|
|
|
|
switch (Enable) {
|
|
|
|
case TRUE: {
|
|
|
|
if (PdoExtension && !IsCardBusCard(PdoExtension)) {
|
|
PcicSupportFns.PCBEnableDisableWakeupEvent(Socket, PdoExtension, Enable);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Enable card-status interrupt in Socket Mask Register
|
|
//
|
|
dwValue = CBReadSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG);
|
|
dwValue |= SKTMSK_CSTSCHG;
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, dwValue);
|
|
|
|
if (PdoExtension && IsCardBusCard(PdoExtension)) {
|
|
UCHAR capptr;
|
|
ULONG powercaps;
|
|
//
|
|
// HACK ALERT - should be handled by PCI.SYS
|
|
// Have a look to see if PME_ENABLE has been turned on by PCI. If not then we do it.
|
|
//
|
|
|
|
GetPciConfigSpace(PdoExtension, CBCFG_CAPPTR, &capptr, sizeof(capptr));
|
|
if (capptr) {
|
|
GetPciConfigSpace(PdoExtension, capptr, &powercaps, sizeof(powercaps));
|
|
if ((powercaps & 0xff) == 1) {
|
|
GetPciConfigSpace(PdoExtension, capptr+4, &powercaps, sizeof(powercaps));
|
|
if (!(powercaps & PME_EN)) {
|
|
powercaps |= PME_EN;
|
|
DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x setting PME_EN!\n", PdoExtension->DeviceObject));
|
|
SetPciConfigSpace(PdoExtension, capptr+4, &powercaps, sizeof(powercaps));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FALSE: {
|
|
|
|
PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
|
|
UCHAR capptr;
|
|
ULONG powercaps, newPowercaps;
|
|
|
|
//
|
|
// Check to see if PMESTAT is on... It shouldn't be. If it is, it probably means
|
|
// that the BIOS did not notify us that the device did the wake, and PCI didn't
|
|
// get a chance to clear the condition. This is really a BIOS bug.
|
|
//
|
|
if (PdoExtension) {
|
|
if (IsCardBusCard(PdoExtension)) {
|
|
|
|
GetPciConfigSpace(PdoExtension, CBCFG_CAPPTR, &capptr, sizeof(capptr));
|
|
if (capptr) {
|
|
GetPciConfigSpace(PdoExtension, capptr, &powercaps, sizeof(powercaps));
|
|
if ((powercaps & 0xff) == 1) {
|
|
GetPciConfigSpace(PdoExtension, capptr+4, &powercaps, sizeof(powercaps));
|
|
if (powercaps & (PME_STAT | PME_EN)) {
|
|
|
|
DebugPrint((PCMCIA_DEBUG_POWER, "pdo %08x PME bits still set! stat=%x en=%x\n",
|
|
PdoExtension->DeviceObject, ((powercaps&PME_STAT)!=0), ((powercaps&PME_EN)!=0)));
|
|
|
|
powercaps |= PME_STAT;
|
|
powercaps &= ~PME_EN;
|
|
SetPciConfigSpace(PdoExtension, capptr+4, &powercaps, sizeof(powercaps));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
PcicSupportFns.PCBEnableDisableWakeupEvent(Socket, PdoExtension, Enable);
|
|
}
|
|
}
|
|
|
|
GetPciConfigSpace(fdoExtension, CFGSPACE_CAPPTR, &capptr, sizeof(capptr));
|
|
if (capptr) {
|
|
GetPciConfigSpace(fdoExtension, capptr, &powercaps, sizeof(powercaps));
|
|
if ((powercaps & 0xff) == 1) {
|
|
|
|
//
|
|
// Clear PMESTAT, if on
|
|
//
|
|
GetPciConfigSpace(fdoExtension, capptr+4, &powercaps, sizeof(powercaps));
|
|
if (powercaps & PME_STAT) {
|
|
|
|
DebugPrint((PCMCIA_DEBUG_POWER, "fdo %08x PME_STAT still set!\n", fdoExtension->DeviceObject));
|
|
|
|
SetPciConfigSpace(fdoExtension, capptr+4, &powercaps, sizeof(powercaps));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PdoExtension && !IsCardBusCard(PdoExtension)) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Disable card-status interrupt in Socket Mask Register
|
|
//
|
|
dwValue = CBReadSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG);
|
|
dwValue &= ~SKTMSK_CSTSCHG;
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, dwValue);
|
|
|
|
//
|
|
// Clear the event in Socket Event Register
|
|
//
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_EVENT_REG, SKTEVENT_CSTSCHG);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
CBGetIrqMask(
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
)
|
|
{
|
|
return(PcicSupportFns.PCBGetIrqMask(DeviceExtension));
|
|
}
|
|
|
|
|
|
ULONG
|
|
CBReadCardMemory(
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN MEMORY_SPACE MemorySpace,
|
|
IN ULONG Offset,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
ULONG bytesCopied = 0;
|
|
|
|
if (!IsCardBusCard(PdoExtension)) {
|
|
return(PcicSupportFns.PCBReadCardMemory(PdoExtension,
|
|
MemorySpace,
|
|
Offset,
|
|
Buffer,
|
|
Length));
|
|
}
|
|
|
|
switch(MemorySpace){
|
|
|
|
case PCCARD_PCI_CONFIGURATION_SPACE:
|
|
bytesCopied = GetPciConfigSpace(PdoExtension, Offset, Buffer, Length);
|
|
break;
|
|
|
|
case PCCARD_CARDBUS_BAR0:
|
|
case PCCARD_CARDBUS_BAR1:
|
|
case PCCARD_CARDBUS_BAR2:
|
|
case PCCARD_CARDBUS_BAR3:
|
|
case PCCARD_CARDBUS_BAR4:
|
|
case PCCARD_CARDBUS_BAR5:
|
|
break;
|
|
|
|
case PCCARD_CARDBUS_ROM:
|
|
bytesCopied = PdoExtension->PciBusInterface.GetBusData(
|
|
PdoExtension->PciBusInterface.Context,
|
|
PCI_WHICHSPACE_ROM, Buffer, Offset, Length);
|
|
break;
|
|
|
|
}
|
|
return bytesCopied;
|
|
}
|
|
|
|
|
|
ULONG
|
|
CBWriteCardMemory(
|
|
IN PPDO_EXTENSION PdoExtension,
|
|
IN MEMORY_SPACE MemorySpace,
|
|
IN ULONG Offset,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
if (IsCardBusCard(PdoExtension)) {
|
|
return 0;
|
|
}
|
|
return(PcicSupportFns.PCBWriteCardMemory(PdoExtension,
|
|
MemorySpace,
|
|
Offset,
|
|
Buffer,
|
|
Length));
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CBModifyMemoryWindow(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN ULONGLONG HostBase,
|
|
IN ULONGLONG CardBase OPTIONAL,
|
|
IN BOOLEAN Enable,
|
|
IN ULONG WindowSize OPTIONAL,
|
|
IN UCHAR AccessSpeed OPTIONAL,
|
|
IN UCHAR BusWidth OPTIONAL,
|
|
IN BOOLEAN IsAttributeMemory OPTIONAL
|
|
)
|
|
{
|
|
return(PcicSupportFns.PCBModifyMemoryWindow(Pdo,
|
|
HostBase,
|
|
CardBase,
|
|
Enable,
|
|
WindowSize,
|
|
AccessSpeed,
|
|
BusWidth,
|
|
IsAttributeMemory));
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CBSetVpp(
|
|
IN PDEVICE_OBJECT Pdo,
|
|
IN UCHAR Vpp
|
|
)
|
|
{
|
|
return(PcicSupportFns.PCBSetVpp(Pdo, Vpp));
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CBIsWriteProtected(
|
|
IN PDEVICE_OBJECT Pdo
|
|
)
|
|
{
|
|
return(PcicSupportFns.PCBIsWriteProtected(Pdo));
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CBGetPowerRequirements(
|
|
IN PSOCKET Socket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Look at the hardware to see what it says the card needs, and update the
|
|
socket structure accordingly.
|
|
|
|
Arguments:
|
|
|
|
Socket - the socket to examine
|
|
|
|
Return Value:
|
|
|
|
n/a
|
|
|
|
--*/
|
|
{
|
|
ULONG state;
|
|
UCHAR voltage;
|
|
|
|
//
|
|
// Check what voltages are supported by this card
|
|
//
|
|
state = CBReadSocketRegister(Socket, CARDBUS_SOCKET_PRESENT_STATE_REG);
|
|
|
|
if (!(state & (SKTSTATE_5VCARD | SKTSTATE_3VCARD))) {
|
|
ULONG dwSktMask;
|
|
//
|
|
// neither 5v or 3v is set... try cvstest
|
|
// Disable interrupt temporarily because TI 12xx could cause spurious
|
|
// interrupt when playing with SktForce register.
|
|
//
|
|
dwSktMask = CBReadSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG);
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, 0);
|
|
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_FORCE_EVENT_REG, SKTFORCE_CVSTEST);
|
|
state = CBReadSocketRegister(Socket, CARDBUS_SOCKET_PRESENT_STATE_REG);
|
|
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_MASK_REG, dwSktMask);
|
|
}
|
|
|
|
state &= (SKTSTATE_5VCARD | SKTSTATE_3VCARD);
|
|
|
|
if (state == 0) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (state == (SKTSTATE_5VCARD | SKTSTATE_3VCARD)) {
|
|
//
|
|
// both are specified. Check for preference
|
|
//
|
|
voltage = IsDeviceFlagSet(Socket->DeviceExtension, PCMCIA_FDO_PREFER_3V) ? 33 : 50;
|
|
|
|
} else {
|
|
|
|
voltage = (state & SKTSTATE_5VCARD) ? 50 : 33;
|
|
|
|
}
|
|
|
|
Socket->Vcc = Socket->Vpp1 = Socket->Vpp2 = voltage;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
CBSetPower(
|
|
IN PSOCKET Socket,
|
|
IN BOOLEAN Enable,
|
|
OUT PULONG pDelayTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set power to the specified socket.
|
|
|
|
Arguments:
|
|
|
|
Socket - the socket to set
|
|
Enable - TRUE means to set power - FALSE is to turn it off.
|
|
pDelayTime - specifies delay (msec) to occur after the current phase
|
|
|
|
Return Value:
|
|
|
|
STATUS_MORE_PROCESSING_REQUIRED - increment phase, perform delay, recall
|
|
other status values terminate sequence
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
ULONG oldPower, state, newPower;
|
|
ULONG vcc, vpp;
|
|
UCHAR tmp;
|
|
USHORT word;
|
|
|
|
switch(Socket->PowerPhase) {
|
|
case 1:
|
|
|
|
if (Enable) {
|
|
|
|
//
|
|
// Turn on the power
|
|
//
|
|
|
|
switch(Socket->Vcc) {
|
|
|
|
case 50: vcc = SKTPOWER_VCC_050V; break;
|
|
case 33: vcc = SKTPOWER_VCC_033V; break;
|
|
default: vcc = SKTPOWER_VCC_OFF;
|
|
|
|
}
|
|
|
|
switch(Socket->Vpp1) {
|
|
|
|
case 120: vpp = SKTPOWER_VPP_120V; break;
|
|
case 50: vpp = SKTPOWER_VPP_050V; break;
|
|
case 33: vpp = SKTPOWER_VPP_033V; break;
|
|
default: vpp = SKTPOWER_VPP_OFF;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Power off
|
|
//
|
|
vcc = SKTPOWER_VCC_OFF;
|
|
vpp = SKTPOWER_VPP_OFF;
|
|
|
|
//
|
|
// Disable output before powering down to avoid spurious signals
|
|
// from reaching the card
|
|
//
|
|
if (Is16BitCardInSocket(Socket)) {
|
|
tmp = PcicReadSocket(Socket, PCIC_PWR_RST);
|
|
if (tmp & PC_OUTPUT_ENABLE) {
|
|
tmp &= ~PC_OUTPUT_ENABLE;
|
|
PcicWriteSocket(Socket, PCIC_PWR_RST, tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
oldPower = CBReadSocketRegister(Socket, CARDBUS_SOCKET_CONTROL_REG);
|
|
|
|
newPower = vcc | vpp;
|
|
newPower|= oldPower & ~(SKTPOWER_VPP_CONTROL |SKTPOWER_VCC_CONTROL);
|
|
|
|
if (newPower != oldPower) {
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_CONTROL_REG, newPower);
|
|
//
|
|
// When power is enabled always stall to give the PCCARD
|
|
// a chance to react.
|
|
//
|
|
*pDelayTime = PCMCIA_CB_STALL_POWER;
|
|
Socket->PowerData = newPower;
|
|
status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
} else {
|
|
//
|
|
// Indicate that nothing was done
|
|
//
|
|
status = STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
|
|
newPower = Socket->PowerData;
|
|
//
|
|
// Try to apply the required power setting a few times.
|
|
// We bail if it doesn't succeed after the given number of tries
|
|
//
|
|
state = CBReadSocketRegister(Socket, CARDBUS_SOCKET_PRESENT_STATE_REG);
|
|
|
|
if (state & SKTSTATE_BADVCCREQ) {
|
|
DebugPrint((PCMCIA_DEBUG_INFO, "skt %08 CBSetPower: Bad vcc request\n", Socket));
|
|
//
|
|
// Clear the status bits & try again
|
|
//
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_FORCE_EVENT_REG, 0);
|
|
CBWriteSocketRegister(Socket, CARDBUS_SOCKET_CONTROL_REG, newPower);
|
|
*pDelayTime = PCMCIA_CB_STALL_POWER;
|
|
status = STATUS_MORE_PROCESSING_REQUIRED;
|
|
|
|
} else {
|
|
status = STATUS_SUCCESS;
|
|
if (Is16BitCardInSocket(Socket)) {
|
|
tmp = PcicReadSocket(Socket, PCIC_PWR_RST);
|
|
if (newPower & SKTPOWER_VCC_CONTROL) {
|
|
//
|
|
// Vcc is on..
|
|
//
|
|
tmp |= PC_OUTPUT_ENABLE | PC_AUTOPWR_ENABLE;
|
|
PcicWriteSocket(Socket, PCIC_PWR_RST, tmp);
|
|
*pDelayTime = PCMCIA_CB_STALL_POWER;
|
|
} else {
|
|
//
|
|
// power off..
|
|
//
|
|
tmp &= ~(PC_OUTPUT_ENABLE | PC_AUTOPWR_ENABLE);
|
|
PcicWriteSocket(Socket, PCIC_PWR_RST, tmp);
|
|
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DebugPrint((PCMCIA_DEBUG_FAIL, "skt %08 CBSetPower: Final retry failed - bad vcc\n", Socket));
|
|
ASSERT(FALSE);
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CBSetWindowPage(
|
|
IN PSOCKET Socket,
|
|
USHORT Index,
|
|
UCHAR Page
|
|
)
|
|
{
|
|
ASSERT(Index <= 4);
|
|
|
|
PcicWriteSocket(Socket, (UCHAR) (PCIC_PAGE_REG + Index), Page);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG
|
|
CBReadSocketRegister(
|
|
IN PSOCKET Socket,
|
|
IN UCHAR Register
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Returns the contents of the specified Cardbus socket register for the
|
|
given socket
|
|
|
|
Arguments
|
|
|
|
Socket - Pointer to the socket
|
|
Register - Cardbus socket register
|
|
|
|
Return Value
|
|
|
|
Contents of the register
|
|
|
|
--*/
|
|
{
|
|
ULONG data = 0xFFFFFFFF;
|
|
PFDO_EXTENSION fdoExtension;
|
|
BOOLEAN dataWasRead = FALSE;
|
|
|
|
//
|
|
// Sanity check in case controller wasn't started
|
|
// or if the register is not dword aligned
|
|
//
|
|
if (Socket && IsSocket(Socket) && CardBus(Socket)) {
|
|
fdoExtension = Socket->DeviceExtension;
|
|
|
|
if (fdoExtension && IsFdoExtension(fdoExtension) &&
|
|
(fdoExtension->CardBusSocketRegisterBase) && ((Register&3) == 0)) {
|
|
|
|
data = READ_REGISTER_ULONG((PULONG) (Socket->DeviceExtension->CardBusSocketRegisterBase+Register));
|
|
dataWasRead = TRUE;
|
|
}
|
|
}
|
|
|
|
ASSERT(dataWasRead);
|
|
return data;
|
|
}
|
|
|
|
|
|
VOID
|
|
CBWriteSocketRegister(
|
|
IN PSOCKET Socket,
|
|
IN UCHAR Register,
|
|
IN ULONG Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Writes the supplied value to the Cardbus socket register for the
|
|
given socket
|
|
|
|
Arguments
|
|
|
|
Socket - Pointer to the socket
|
|
Register - Cardbus socket register
|
|
Data - Value to be written to the register
|
|
|
|
Return Value
|
|
|
|
--*/
|
|
{
|
|
PFDO_EXTENSION fdoExtension;
|
|
BOOLEAN dataWasWritten = FALSE;
|
|
|
|
//
|
|
// Sanity check in case controller wasn't started
|
|
// or if the register is not dword aligned
|
|
//
|
|
if (Socket && IsSocket(Socket) && CardBus(Socket)) {
|
|
fdoExtension = Socket->DeviceExtension;
|
|
|
|
if (fdoExtension && IsFdoExtension(fdoExtension) &&
|
|
(fdoExtension->CardBusSocketRegisterBase) && ((Register&3) == 0)) {
|
|
|
|
WRITE_REGISTER_ULONG((PULONG) (Socket->DeviceExtension->CardBusSocketRegisterBase+Register), Data);
|
|
dataWasWritten = TRUE;
|
|
}
|
|
}
|
|
|
|
ASSERT(dataWasWritten);
|
|
}
|