Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2857 lines
80 KiB

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
pcicsup.c
Abstract:
This module supplies functions that control the 82365SL chip. In turn,
these functions are abstracted out to the main PCMCIA support module.
Author(s):
Bob Rinne (BobRi) 3-Aug-1994
Jeff McLeman ([email protected])
Neil Sandlin (neilsa) June 1 1999
Revisions:
6-Apr-95
Modified for databook support changes - John Keys Databook
1-Nov-96
Complete overhaul for plug'n'play support,
flash interfaces, power support etc.
- Ravisankar Pudipeddi (ravisp)
--*/
#include "pch.h"
#ifdef POOL_TAGGING
#undef ExAllocatePool
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'cicP')
#endif
//
// Internal References
//
NTSTATUS
PcicResetCard(
IN PSOCKET Socket,
OUT PULONG pDelayTime
);
BOOLEAN
PcicInitializePcmciaSocket(
IN PSOCKET Socket
);
UCHAR
PcicReadController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR PcicRegister
);
VOID
PcicWriteController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR PcicRegister,
IN UCHAR DataByte
);
NTSTATUS
PcicDetect(
IN PFDO_EXTENSION DeviceExtension,
IN INTERFACE_TYPE InterfaceType,
IN ULONG IoPortBase
);
BOOLEAN
PcicDetectCardInSocket(
IN PSOCKET Socket
);
BOOLEAN
PcicDetectCardChanged(
IN PSOCKET Socket
);
BOOLEAN
PcicPCCardReady(
IN PSOCKET Socket
);
BOOLEAN
PcicDetectReadyChanged(
IN PSOCKET Socket
);
BOOLEAN
PcicProcessConfigureRequest(
IN PSOCKET Socket,
IN PCARD_REQUEST ConfigRequest,
IN PUCHAR Base
);
VOID
PcicEnableDisableWakeupEvent(
IN PSOCKET Socket,
IN PPDO_EXTENSION PdoExtension,
IN BOOLEAN Enable
);
VOID
PcicEnableDisableMemory(
IN PSOCKET Socket,
IN MEMORY_SPACE MemorySpace,
IN ULONG CardBase,
IN UCHAR Mem16BitWindow,
IN BOOLEAN Enable
);
BOOLEAN
PcicEnableDisableCardDetectEvent(
IN PSOCKET Socket,
IN BOOLEAN Enable
);
UCHAR
PcicReadExtendedCirrusController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR Register
);
VOID
PcicWriteExtendedCirrusController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR PcicRegister,
IN UCHAR DataByte
);
ULONG
PcicWriteCardMemory(
IN PPDO_EXTENSION PdoExtension,
IN MEMORY_SPACE MemorySpace,
IN ULONG Offset,
IN PUCHAR Buffer,
IN ULONG Length
);
ULONG
PcicReadCardMemory(
IN PPDO_EXTENSION PdoExtension,
IN MEMORY_SPACE MemorySpace,
IN ULONG Offset,
IN PUCHAR Buffer,
IN ULONG Length
);
BOOLEAN
PcicModifyMemoryWindow(
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
PcicSetVpp(
IN PDEVICE_OBJECT Pdo,
IN UCHAR VppLevel
);
BOOLEAN
PcicIsWriteProtected(
IN PDEVICE_OBJECT Pdo
);
ULONG
PcicGetIrqMask(
IN PFDO_EXTENSION deviceExtension
);
NTSTATUS
PcicConvertSpeedToWait(
IN UCHAR Speed,
OUT PUCHAR WaitIndex
);
//
// Internal Data
//
ULONG PcicStallCounter = 4000; //4ms
UCHAR WaitToSpeedTable[4] = {
0x42, //350ns
0x52, //450ns
0x62, //600ns
0x72 //700ns
};
UCHAR DevSpeedTable[8] = {
0xff, // speed 0: invalid
0x32, // speed 1: 250ns
0x2a, // speed 2: 200ns
0x22, // speed 3: 150ns
0x0a, // speed 4: 100ns
0xff, // speed 5: reserved
0xff, // speed 6: reserved
0xff // speed 7: invalid
};
PCMCIA_CTRL_BLOCK PcicSupportFns = {
PcicInitializePcmciaSocket,
PcicResetCard,
PcicDetectCardInSocket,
PcicDetectCardChanged,
NULL, // PcicDetectCardStatus
PcicDetectReadyChanged,
NULL, // GetPowerRequirements
PcicProcessConfigureRequest,
PcicEnableDisableCardDetectEvent,
PcicEnableDisableWakeupEvent,
PcicGetIrqMask,
PcicReadCardMemory,
PcicWriteCardMemory,
PcicModifyMemoryWindow,
PcicSetVpp,
PcicIsWriteProtected
};
#define MEM_16BIT 1
#define MEM_8BIT 0
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,PcicIsaDetect)
#pragma alloc_text(INIT,PcicDetect)
#pragma alloc_text(PAGE,PcicBuildSocketList)
#endif
ULONG
PcicGetIrqMask(
IN PFDO_EXTENSION DeviceExtension
)
/*++
Routine Description:
Arguments:
Return value:
--*/
{
//
// Return the set of supported IRQs for the controller
// and PcCards
//
if (CLPD6729(DeviceExtension->SocketList)) {
return CL_SUPPORTED_INTERRUPTS;
} else {
return PCIC_SUPPORTED_INTERRUPTS;
}
}
BOOLEAN
PcicEnableDisableCardDetectEvent(
IN PSOCKET Socket,
IN BOOLEAN Enable
)
/*++
Routine Description:
Enable card detect interrupt.
Arguments:
Socket - socket information
Irq - the interrupt value to set.
Enable - if TRUE, CSC interrupt is enabled,
if FALSE, it is disabled
Return Value:
None
--*/
{
PFDO_EXTENSION deviceExtension = Socket->DeviceExtension;
INTERFACE_TYPE interface;
UCHAR byte;
ULONG Irq = Socket->FdoIrq;
switch (Enable) {
case TRUE: {
if (CLPD6729(Socket)) {
//
// For Cirrus Logic PCI controller we need to know the interrupt pin
// (INTA, INTB etc.) corresponding to the level passed in. Hence the
// passed in Irq is discarded. Actually the Irq parameter is redundant
// since it can be fetched from the device extension itself.
// If we remove the Irq param from this routine, the following is
// not so inelegant..
//
interface = PCIBus;
switch (deviceExtension->Configuration.InterruptPin) {
case 0: {
//
// This is what tells us that ISA interrupts are being used...
//
interface = Isa;
break;
}
case 1: {
Irq = PCIC_CIRRUS_INTA;
break;
}
case 2: {
Irq = PCIC_CIRRUS_INTB;
break;
}
case 3: {
Irq = PCIC_CIRRUS_INTC;
break;
}
case 4: {
Irq = PCIC_CIRRUS_INTD;
break;
}
}
//
// Set the Cirrus Logic controller for PCI style interrupts
//
byte = PcicReadExtendedCirrusController(Socket->AddressPort,
Socket->RegisterOffset,
PCIC_CIRRUS_EXTENSION_CTRL_1);
if (interface == PCIBus) {
byte |= 0x10; // PCI style interrupt
} else {
byte &= ~0x10; // Isa style interrupt
}
PcicWriteExtendedCirrusController(Socket->AddressPort,
Socket->RegisterOffset,
PCIC_CIRRUS_EXTENSION_CTRL_1,
byte);
PcmciaWait(100);
}
byte=PcicReadSocket(Socket, PCIC_CARD_INT_CONFIG);
byte = byte & CSCFG_BATT_MASK; // Don't nuke any other enables
byte = byte | (UCHAR) ((Irq << 4) & 0x00ff); // Put IRQ in upper nibble
byte |= CSCFG_CD_ENABLE;
PcicWriteSocket(Socket, PCIC_CARD_INT_CONFIG, byte);
break;
}
case FALSE: {
//
// Clear pending interrupt (for now)
//
byte = PcicReadSocket(Socket, PCIC_CARD_CHANGE);
DebugPrint((PCMCIA_DEBUG_INFO, "PcicDisableInterrupt:Status Change %x\n", byte));
PcicWriteSocket(Socket,
PCIC_CARD_INT_CONFIG,
0x0);
break;
}
}
return TRUE;
}
NTSTATUS
PcicSetPower(
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;
UCHAR tmp, vcc;
//
// Turn on the power - then turn on output - this is two operations
// per the Intel 82365SL documentation.
//
if (Enable) {
switch(Socket->PowerPhase) {
case 1:
tmp = PcicReadSocket(Socket, PCIC_PWR_RST);
//
// 5V for R2 cards..
//
vcc = PC_CARDPWR_ENABLE;
if (Elc(Socket)) {
tmp = PC_VPP_SETTO_VCC | vcc; // vpp1 = vcc
} else {
//
// Apparently we need to set bit 2 also for some obscure reason
//
tmp = 0x4 | PC_VPP_SETTO_VCC | vcc; // vpp1 = vpp2 = vcc
}
PcicWriteSocket(Socket, PCIC_PWR_RST, tmp);
//
// OUTPUT_ENABLE & AUTOPWR_ENABLE..
// Disable RESETDRV also..
//
tmp |= PC_OUTPUT_ENABLE | PC_AUTOPWR_ENABLE | PC_RESETDRV_DISABLE;
PcicWriteSocket(Socket, PCIC_PWR_RST, tmp);
//
// When power is enabled always stall to give the PCCARD
// a chance to react.
//
*pDelayTime = PCMCIA_PCIC_STALL_POWER;
status = STATUS_MORE_PROCESSING_REQUIRED;
break;
case 2:
//
// Check for an as yet unexplained condition on Dell Latitude XPi's
//
tmp = PcicReadSocket(Socket, PCIC_STATUS);
if (!(tmp & 0x40)) {
//
// power hasn't come on, flip the mystery bit
//
tmp = PcicReadSocket(Socket, 0x2f);
if (tmp == 0x42) {
PcicWriteSocket(Socket, 0x2f, 0x40);
*pDelayTime = PCMCIA_PCIC_STALL_POWER;
}
}
status = STATUS_SUCCESS;
break;
default:
ASSERT(FALSE);
status = STATUS_UNSUCCESSFUL;
}
} else {
PcicWriteSocket(Socket, PCIC_PWR_RST, 0x00);
status = STATUS_SUCCESS;
}
return status;
}
NTSTATUS
PcicConvertSpeedToWait(
IN UCHAR Speed,
OUT PUCHAR WaitIndex
)
{
NTSTATUS status = STATUS_INVALID_PARAMETER;
UCHAR exponent, exponent2, mantissa, index;
if (Speed & SPEED_EXT_MASK) {
return status;
}
exponent = Speed & SPEED_EXPONENT_MASK;
mantissa = Speed & SPEED_MANTISSA_MASK;
if (mantissa == 0) {
mantissa = DevSpeedTable[exponent] & SPEED_MANTISSA_MASK;
exponent = DevSpeedTable[exponent] & SPEED_EXPONENT_MASK;
}
for (index = 0; index < sizeof(WaitToSpeedTable); index++) {
exponent2= WaitToSpeedTable[index] & SPEED_EXPONENT_MASK;
if ((exponent < exponent2) ||
((exponent == exponent2) &&
(mantissa < (WaitToSpeedTable[index] & SPEED_MANTISSA_MASK)))) {
*WaitIndex = index;
status = STATUS_SUCCESS;
break;
}
}
return status;
}
BOOLEAN
PcicSetVpp(
IN PDEVICE_OBJECT Pdo,
IN UCHAR Vpp
)
/*++
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
--*/
{
PSOCKET socketPtr = ((PPDO_EXTENSION) Pdo->DeviceExtension)->Socket;
UCHAR tmp;
ASSERT ( socketPtr != NULL );
tmp = PcicReadSocket(socketPtr, PCIC_PWR_RST);
if ((tmp & 0x10) == 0) {
//
// Vcc not set.
//
return FALSE;
}
//
// Turn off Vpp bits
//
tmp &= ~0x3;
switch (Vpp) {
case PCMCIA_VPP_IS_VCC: {
tmp |= 0x1;
break;
}
case PCMCIA_VPP_12V: {
tmp |= 0x2;
break;
}
case PCMCIA_VPP_0V: {
tmp |= 0x0;
break;
}
}
PcicWriteSocket(socketPtr, PCIC_PWR_RST, tmp);
if (Vpp != PCMCIA_VPP_0V) {
//
// When power is enabled always stall to give the PCCARD
// a chance to react.
//
PcmciaWait(PCMCIA_PCIC_STALL_POWER);
}
return TRUE;
}
BOOLEAN
PcicModifyMemoryWindow(
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
)
/*++
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 = Pdo->DeviceExtension;
PFDO_EXTENSION fdoExtension;
PSOCKET socketPtr;
PSOCKET_CONFIGURATION socketConfig;
USHORT index;
UCHAR registerOffset;
UCHAR regl;
UCHAR regh;
UCHAR tmp, waitIndex;
socketConfig = pdoExtension->SocketConfiguration;
if (!socketConfig) {
// doesn't look like we are started.
return FALSE;
}
socketPtr = pdoExtension->Socket;
ASSERT ( socketPtr != NULL );
fdoExtension = socketPtr->DeviceExtension;
for (index = 0 ; index < socketConfig->NumberOfMemoryRanges; index++) {
if (socketConfig->Memory[index].HostBase == HostBase) {
break;
}
}
if (index >= socketConfig->NumberOfMemoryRanges) {
//
// Unknown hostbase
//
return FALSE;
}
//
// Make sure caller isn't asking a bigger window
// than he is permitted to
//
if (WindowSize > socketConfig->Memory[index].Length) {
return FALSE;
}
if (WindowSize == 0) {
//
// WindowSize not provided. Default to
// the largest size permitted for this pc-card
//
WindowSize = socketConfig->Memory[index].Length;
}
//
// Determine offset in registers.
//
registerOffset = (index * 8);
//
// Disable the window first (this has to be done regardless
// of whether we want to enable/disable the window ultimately)
//
PCMCIA_ACQUIRE_DEVICE_LOCK(socketPtr->DeviceExtension);
tmp = PcicReadSocket(socketPtr, PCIC_ADD_WIN_ENA);
tmp &= ~(1 << index);
PcicWriteSocket(socketPtr, PCIC_ADD_WIN_ENA, tmp);
if (!Enable) {
//
// We're done.. Just write zeroes to the window registers anyway
// before returning
//
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_L+registerOffset),
0);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_H+registerOffset),
0);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STRT_L+registerOffset),
0);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STRT_H+registerOffset),
0);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STOP_L+registerOffset),
0);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STOP_H+registerOffset),
0);
PcmciaSetWindowPage(fdoExtension, socketPtr, index, 0);
PCMCIA_RELEASE_DEVICE_LOCK(socketPtr->DeviceExtension);
return TRUE;
}
if (AccessSpeed) {
if (!NT_SUCCESS(PcicConvertSpeedToWait(AccessSpeed, &waitIndex))) {
PCMCIA_RELEASE_DEVICE_LOCK(socketPtr->DeviceExtension);
return FALSE;
}
}
//
// Calculate and set card base addresses.
// This is the 2's complement of the host address and
// the card offset.
//
CardBase = (CardBase - (HostBase & OFFSETCALC_BASE_MASK)) & OFFSETCALC_OFFSET_MASK;
regl = (UCHAR) (CardBase >> 12);
regh = (UCHAR) ((CardBase >> 20) & 0x003f);
if (IsAttributeMemory) {
regh |= 0x40;
}
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_L + registerOffset),
regl);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_H + registerOffset),
regh);
//
// Calculate and set host window.
//
if (!PcmciaSetWindowPage(fdoExtension, socketPtr, index, (UCHAR) ((ULONG) HostBase >> 24))) {
if ((HostBase + WindowSize) > 0xFFFFFF) {
DebugPrint((PCMCIA_DEBUG_FAIL, "PcicModifyMemorywindow: HostBase %x specified: doesn't fit in 24 bits!\n", (ULONG) HostBase));
PCMCIA_RELEASE_DEVICE_LOCK(socketPtr->DeviceExtension);
return FALSE;
}
}
regl = (UCHAR) (HostBase >> 12);
regh = (UCHAR) (HostBase >> 20) & 0xF;
if (BusWidth == PCMCIA_MEMORY_16BIT_ACCESS) {
regh |= 0x80; // 16-bit access
#if 0
//
// If this is not a revision 1 part (0x82), then set
// the work around register for 16-bit windows.
//
// This bit is not used on any chip that I have
// documentation for. I have no idea why it is here, it is
// not in win9x.
// In any case it looks like a NOOP for the vast majority of
// chips, but since it uses a NOT, then it is invoked on all
// new controllers. REMOVE after next major release
//
if (socketPtr->Revision != PCIC_REVISION) {
tmp = PcicReadSocket(socketPtr,
PCIC_CARD_DETECT);
tmp |= 0x01;
PcicWriteSocket(socketPtr,
PCIC_CARD_DETECT,
tmp);
}
#endif
}
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STRT_L + registerOffset),
regl);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STRT_H + registerOffset),
regh);
//
// Set stop address.
//
HostBase += WindowSize - 1;
regl = (UCHAR) (HostBase >> 12);
regh = (UCHAR) (HostBase >> 20) & 0xF;
//
// Set the wait states
//
if (AccessSpeed) {
//
// New access speed specified, use it
//
regh |= (waitIndex << 6);
} else {
//
// Use existing access speed
//
regh |= (PcicReadSocket(socketPtr, (UCHAR)(PCIC_MEM_ADD0_STOP_H + registerOffset)) & 0xC0);
}
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STOP_L + registerOffset),
regl);
PcicWriteSocket(socketPtr,
(UCHAR)(PCIC_MEM_ADD0_STOP_H + registerOffset),
regh);
//
// Memory window set up now enable it
//
tmp = (1 << index);
tmp |= PcicReadSocket(socketPtr, PCIC_ADD_WIN_ENA);
PcicWriteSocket(socketPtr, PCIC_ADD_WIN_ENA, tmp);
//
// Allow the window to settle
//
(VOID) PcicPCCardReady(socketPtr);
PCMCIA_RELEASE_DEVICE_LOCK(socketPtr->DeviceExtension);
return TRUE;
}
BOOLEAN
PcicIsWriteProtected(
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
--*/
{
PSOCKET socketPtr = ((PPDO_EXTENSION) Pdo->DeviceExtension)->Socket;
ASSERT ( socketPtr != NULL );
return ((PcicReadSocket(socketPtr, PCIC_STATUS) & 0x10) != 0);
}
VOID
PcicEnableDisableWakeupEvent(
IN PSOCKET Socket,
IN PPDO_EXTENSION PdoExtension,
IN BOOLEAN Enable
)
/*++
Routine Description
This routine sets/resets the Ring Indicate enable bit for the given socket,
enabling a PC-Card in the socket to assert/not assert wake through the RingIndicate
pin.
Arguments
Socket - Pointer to the socket
Enable - TRUE : set ring indicate enable
FALSE: turn off ring indicate, i.e. system cannot be woken up through
a pc-card in this socket
Return Value
None
--*/
{
UCHAR byte;
byte = PcicReadSocket(Socket, PCIC_INTERRUPT);
if (Enable) {
byte |= IGC_RINGIND_ENABLE;
} else {
byte &= ~IGC_RINGIND_ENABLE;
}
PcicWriteSocket(Socket, PCIC_INTERRUPT, byte);
}
BOOLEAN
PcicInitializePcmciaSocket(
PSOCKET Socket
)
/*++
Routine Description:
This routine will setup the 82365 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 byte;
UCHAR reg;
//
// Initialize the EXCA registers
//
//
for (index = 0; index < 0xFF; index++) {
reg = (UCHAR) PcicRegisterInitTable[index].Register;
if (reg == 0xFF) {
//
// End of table
//
break;
}
byte = (UCHAR) PcicRegisterInitTable[index].Value;
if (reg == PCIC_INTERRUPT) {
//
// Don't clobber the Ring Enable bit
// NOTE: this entire if statement should be removed
// when WAIT_WAKE support is done for modems
// also don't clobber the interrupt enable bit
//
byte |= (PcicReadSocket(Socket, reg) & (IGC_RINGIND_ENABLE | IGC_INTR_ENABLE));
}
PcicWriteSocket(Socket, reg, byte);
}
if (CLPD6729(Socket)) {
//
// Need to program the chip per code in
// Windows 95. This will turn on the
// audio support bit.
// NOTE: This used to be done in PcicDetect
//
byte = PcicReadSocket(Socket, PCIC_CL_MISC_CTRL1);
byte |= CL_MC1_SPKR_ENABLE;
PcicWriteSocket(Socket, PCIC_CL_MISC_CTRL1, byte);
//
// Set the Cirrus Logic controller for ISA style interrupts
//
byte = PcicReadExtendedCirrusController(Socket->AddressPort,
Socket->RegisterOffset,
PCIC_CIRRUS_EXTENSION_CTRL_1);
byte &= ~0x08; // Isa style interrupt
PcicWriteExtendedCirrusController(Socket->AddressPort,
Socket->RegisterOffset,
PCIC_CIRRUS_EXTENSION_CTRL_1,
byte);
}
return TRUE;
}
NTSTATUS
PcicResetCard (
IN 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;
UCHAR byte;
switch(Socket->CardResetPhase) {
case 1:
//
// Set interface mode to memory to begin with
//
byte = PcicReadSocket(Socket, PCIC_INTERRUPT);
byte &= ~IGC_PCCARD_IO;
PcicWriteSocket(Socket, PCIC_INTERRUPT, byte);
//
// Start reset
//
byte = PcicReadSocket(Socket, PCIC_INTERRUPT);
byte = byte & ~IGC_PCCARD_RESETLO;
PcicWriteSocket(Socket, PCIC_INTERRUPT, byte);
*pDelayTime = PCMCIA_PCIC_RESET_WIDTH_DELAY;
status = STATUS_MORE_PROCESSING_REQUIRED;
break;
case 2:
//
// Stop reset
//
byte = PcicReadSocket(Socket, PCIC_INTERRUPT);
byte |= IGC_PCCARD_RESETLO;
PcicWriteSocket(Socket, PCIC_INTERRUPT, byte);
*pDelayTime = PCMCIA_PCIC_RESET_SETUP_DELAY;
status = STATUS_MORE_PROCESSING_REQUIRED;
break;
case 3:
//
// Wait for the card to settle
//
PcicPCCardReady(Socket);
status = STATUS_SUCCESS;
break;
default:
ASSERT(FALSE);
status = STATUS_UNSUCCESSFUL;
}
return status;
}
UCHAR
PcicReadSocket(
IN PSOCKET Socket,
IN ULONG Register
)
/*++
Routine Description:
This routine will read a byte from the specified socket EXCA register
Arguments:
Socket -- Pointer to the socket from which we should read
Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{
UCHAR byte;
if (CardBus(Socket)) {
//
// Sanity check in case controller wasn't started
//
if (Socket->DeviceExtension->CardBusSocketRegisterBase) {
byte = READ_REGISTER_UCHAR((PUCHAR) (Socket->DeviceExtension->CardBusSocketRegisterBase + Register
+ CARDBUS_EXCA_REGISTER_BASE));
} else {
byte = 0xff;
}
} else {
byte = PcicReadController(Socket->AddressPort, Socket->RegisterOffset,
(UCHAR) Register);
}
return byte;
}
VOID
PcicWriteSocket(
IN PSOCKET Socket,
IN ULONG Register,
IN UCHAR DataByte
)
/*++
Routine Description:
This routine will write a byte to the specified socket EXCA register
Arguments:
Socket -- Pointer to the socket to which we write
Register -- The register to be read
DataByte -- Data to be written
Return Value:
None
--*/
{
if (CardBus(Socket)) {
//
// Sanity check in case controller wasn't started
//
if (Socket->DeviceExtension->CardBusSocketRegisterBase) {
WRITE_REGISTER_UCHAR((PUCHAR) (Socket->DeviceExtension->CardBusSocketRegisterBase+Register+CARDBUS_EXCA_REGISTER_BASE), DataByte);
}
} else {
PcicWriteController(Socket->AddressPort, Socket->RegisterOffset, (UCHAR)Register, DataByte);
}
}
UCHAR
PcicReadController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR Register
)
/*++
Routine Description:
This routine will read a byte from the controller data port
Arguments:
Base -- The I/O port for the controller
Socket -- The socket in for the card being read
Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{
UCHAR dataByte = 0;
WRITE_PORT_UCHAR(Base, (UCHAR)(Socket+Register));
dataByte = READ_PORT_UCHAR((PUCHAR)Base + 1);
return dataByte;
}
VOID
PcicWriteController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR Register,
IN UCHAR DataByte
)
/*++
Routine Description:
This routine will write a byte to the controller data port
Arguments:
Base -- The I/O port for the controller
Socket -- The socket in for the card being read
Register -- The register to be read
DataByte -- Data to be written
Return Value:
None
--*/
{
WRITE_PORT_UCHAR(Base, (UCHAR)(Socket+Register));
WRITE_PORT_UCHAR((PUCHAR)Base + 1, DataByte);
}
UCHAR
PcicReadExtendedCirrusController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR Register
)
/*++
Routine Description:
This routine will read a byte from the Cirrus
logic extended registers
Arguments:
Base -- The I/O port for the controller
Socket -- The socket in for the card being read
Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{
UCHAR dataByte = 0;
PcicWriteController(Base, Socket, PCIC_CIRRUS_EXTENDED_INDEX, Register);
dataByte = PcicReadController(Base, Socket, PCIC_CIRRUS_INDEX_REG);
return dataByte;
}
VOID
PcicWriteExtendedCirrusController(
IN PUCHAR Base,
IN USHORT Socket,
IN UCHAR Register,
IN UCHAR DataByte
)
/*++
Routine Description:
This routine will write a byte to one of the
Cirrus Logic extended registers
Arguments:
Base -- The I/O port for the controller
Socket -- The socket in for the card being read
Register -- The register to be read
DataByte -- Data to be written
Return Value:
None
--*/
{
//
// Register needs to be written out to the extended index register
//
PcicWriteController(Base, Socket, PCIC_CIRRUS_EXTENDED_INDEX, Register);
PcicWriteController(Base, Socket, PCIC_CIRRUS_INDEX_REG, DataByte);
}
ULONG
PcicReadWriteCardMemory(
IN PSOCKET Socket,
IN MEMORY_SPACE MemorySpace,
IN ULONG Offset,
IN PUCHAR Buffer,
IN ULONG Length,
IN CONST BOOLEAN Read
)
/*++
Routine Description:
This routine will read or write into the configuration memory on the card
with the supplied buffer. This is provided as a service to certain
client drivers (netcard) which need to write to the attribute memory
(say) to set parameters etc.
Arguments:
Socket -- The socket info in for the card being written to
MemorySpace -- indicates which space - attribute or common memory
Offset -- Offset in the memory to write to
Buffer -- Buffer contents being dumped to the card
Length -- Length of the buffer being written out
Read -- boolean indicating read or write
--*/
{
PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
PUCHAR memoryPtr, memoryPtrMax;
PUCHAR bufferPtr;
ULONG index, adjustedOffset, adjustedBase;
UCHAR memGran;
UCHAR memWidth;
//
// NOTE: memGran HAS to be a integral divisor of AttributeMemorySize for
// the rest of the code to work!
//
memGran = (MemorySpace == PCCARD_ATTRIBUTE_MEMORY) ? 2 : 1;
memWidth = (MemorySpace == PCCARD_ATTRIBUTE_MEMORY) ? MEM_8BIT : MEM_16BIT;
//
// Adjust for offsets > size of attribute memory window.
//
adjustedOffset = (Offset*memGran) % fdoExtension->AttributeMemorySize;
//
// Adjusted base is: |_ Offset _| mod AttrributeMemorySize
//
adjustedBase = ((Offset*memGran) / fdoExtension->AttributeMemorySize) *
fdoExtension->AttributeMemorySize;
bufferPtr = Buffer;
PcicEnableDisableMemory(Socket, MemorySpace, adjustedBase, memWidth, TRUE);
//
// Now read the memory contents into the user buffer
//
memoryPtr = fdoExtension->AttributeMemoryBase + adjustedOffset;
memoryPtrMax = fdoExtension->AttributeMemoryBase + fdoExtension->AttributeMemorySize;
for (index = 0; index < Length; index++) {
if (memoryPtr >= memoryPtrMax) {
//
// Skip to next page of attribute memory
// (size of page = fdoExtension->AttributeMemorySize)
//
adjustedBase += fdoExtension->AttributeMemorySize;
//
// Remap window at new base
//
PcicEnableDisableMemory(Socket, MemorySpace, adjustedBase, memWidth, TRUE);
memoryPtr = fdoExtension->AttributeMemoryBase;
}
if (Read) {
*bufferPtr++ = READ_REGISTER_UCHAR(memoryPtr);
} else {
WRITE_REGISTER_UCHAR(memoryPtr, *bufferPtr++);
}
memoryPtr += memGran;
}
PcicEnableDisableMemory(Socket, 0,0,0, FALSE);
return Length;
}
ULONG
PcicReadWriteCardMemoryIndirect(
IN PSOCKET Socket,
IN MEMORY_SPACE MemorySpace,
IN ULONG Offset,
IN PUCHAR Buffer,
IN ULONG Length,
IN CONST BOOLEAN Read
)
/*++
Routine Description:
This routine will read or write the memory space of a pcmcia card
using the indirect access method.
Arguments:
Socket -- The socket info in for the card being written to
MemorySpace -- indicates which space - attribute or common memory
Offset -- Offset in the memory to write to
Buffer -- Buffer contents being dumped to the card
Length -- Length of the buffer being written out
Read -- boolean indicating read or write
--*/
{
PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
ULONG index, adjustedOffset;
PUCHAR pMem;
UCHAR Control = 0;
UCHAR memGran;
PcicEnableDisableMemory(Socket, PCCARD_COMMON_MEMORY, 0, MEM_8BIT, TRUE);
pMem = (PUCHAR) ((ULONG_PTR)(fdoExtension->AttributeMemoryBase) + IAR_CONTROL_LOW);
Control = (MemorySpace == PCCARD_ATTRIBUTE_MEMORY_INDIRECT) ? IARF_AUTO_INC :
IARF_AUTO_INC | IARF_COMMON | IARF_BYTE_GRAN;
WRITE_REGISTER_UCHAR(pMem, Control);
memGran = (MemorySpace == PCCARD_ATTRIBUTE_MEMORY_INDIRECT) ? 2 : 1;
adjustedOffset = Offset*memGran;
pMem = (PUCHAR) ((ULONG_PTR)(fdoExtension->AttributeMemoryBase) + IAR_ADDRESS);
for (index = 0; index < sizeof(ULONG); index++) {
WRITE_REGISTER_UCHAR(pMem++, (UCHAR)(adjustedOffset>>(index*8)));
}
PcicEnableDisableMemory(Socket, PCCARD_COMMON_MEMORY, 0, MEM_16BIT, TRUE);
for (index = 0; index < Length; index++) {
// Note that pMem should be pointing to IAR_DATA, and is NOT
// supposed to be incremented
if (Read) {
Buffer[index] = READ_REGISTER_UCHAR(pMem);
} else {
WRITE_REGISTER_UCHAR(pMem, Buffer[index]);
}
}
PcicEnableDisableMemory(Socket, 0,0,0, FALSE);
return Length;
}
ULONG
PcicWriteCardMemory(
IN PPDO_EXTENSION PdoExtension,
IN MEMORY_SPACE MemorySpace,
IN ULONG Offset,
IN PUCHAR Buffer,
IN ULONG Length
)
/*++
Routine Description:
This routine will write into the configuration memory on the card
with the supplied buffer. This is provided as a service to certain
client drivers (netcard) which need to write to the attribute memory
(say) to set parameters etc.
Arguments:
PdoExtension-- The extension of the device being written to
MemorySpace -- indicates which space - attribute or common memory
Offset -- Offset in the memory to write to
Buffer -- Buffer contents being dumped to the card
Length -- Length of the buffer being written out
--*/
{
PSOCKET Socket = PdoExtension->Socket;
ULONG retLength;
ASSERT (IsSocketFlagSet(Socket, SOCKET_CARD_POWERED_UP));
switch(MemorySpace) {
case PCCARD_ATTRIBUTE_MEMORY_INDIRECT:
case PCCARD_COMMON_MEMORY_INDIRECT:
retLength = PcicReadWriteCardMemoryIndirect(Socket, MemorySpace, Offset, Buffer, Length, FALSE);
break;
case PCCARD_ATTRIBUTE_MEMORY:
case PCCARD_COMMON_MEMORY:
retLength = PcicReadWriteCardMemory(Socket, MemorySpace, Offset, Buffer, Length, FALSE);
break;
default:
retLength = 0;
ASSERT(FALSE);
}
return retLength;
}
ULONG
PcicReadCardMemory(
IN PPDO_EXTENSION PdoExtension,
IN MEMORY_SPACE MemorySpace,
IN ULONG Offset,
IN PUCHAR Buffer,
IN ULONG Length
)
/*++
Routine Description:
This routine will read the configuration memory on the card
Arguments:
PdoExtension-- The extension of the device being read
MemorySpace -- indicates which space - attribute or common memory
Offset -- Offset in the memory to read
Buffer -- pointer to pointer for tuple information.
Length -- maximum size of the buffer area for tuple information.
Return Value:
--*/
{
PSOCKET Socket = PdoExtension->Socket;
ULONG retLength;
ASSERT (IsSocketFlagSet(Socket, SOCKET_CARD_POWERED_UP));
switch(MemorySpace) {
case PCCARD_ATTRIBUTE_MEMORY_INDIRECT:
case PCCARD_COMMON_MEMORY_INDIRECT:
retLength = PcicReadWriteCardMemoryIndirect(Socket, MemorySpace, Offset, Buffer, Length, TRUE);
break;
case PCCARD_ATTRIBUTE_MEMORY:
case PCCARD_COMMON_MEMORY:
retLength = PcicReadWriteCardMemory(Socket, MemorySpace, Offset, Buffer, Length, TRUE);
DebugPrint((PCMCIA_DEBUG_INFO,"PcicReadCardMemory: "
"%.02X %.02X %.02X %.02X %.02X %.02X %.02X %.02X-%.02X %.02X %.02X %.02X %.02X %.02X %.02X %.02X\n",
Buffer[0], Buffer[1], Buffer[2], Buffer[3], Buffer[4], Buffer[5], Buffer[6], Buffer[7],
Buffer[8], Buffer[9], Buffer[10], Buffer[11], Buffer[12], Buffer[13], Buffer[14], Buffer[15]));
break;
default:
retLength = 0;
ASSERT(FALSE);
}
return retLength;
}
BOOLEAN
PcicProcessConfigureRequest(
IN PSOCKET Socket,
IN PCARD_REQUEST request,
IN PUCHAR Base
)
/*++
Routine Description:
Processes a configure or IRQ setup request.
Arguments:
ConfigRequest -- Socket config structure
Base - the I/O port base
Return Value:
None
--*/
{
USHORT index;
UCHAR tmp;
//
// Since all first entries in the config structure is a RequestType,
// cast the pointer comming in as a PREQUEST_CONFIG to get the proper
// RequestType
//
switch (request->RequestType) {
case IO_REQUEST: {
UCHAR ioControl = 0;
if (!request->u.Io.IoEntry[0].BasePort) {
break;
}
for (index = 0; index < request->u.Io.NumberOfRanges; index++) {
UCHAR registerOffset;
registerOffset = (index * 4);
if (request->u.Io.IoEntry[index].BasePort) {
PcicWriteSocket( Socket,
PCIC_IO_ADD0_STRT_L + registerOffset,
(UCHAR) (request->u.Io.IoEntry[index].BasePort & 0xff));
PcicWriteSocket( Socket,
PCIC_IO_ADD0_STRT_H + registerOffset,
(UCHAR) (request->u.Io.IoEntry[index].BasePort >> 8));
PcicWriteSocket(Socket,
PCIC_IO_ADD0_STOP_L + registerOffset,
(UCHAR) ((request->u.Io.IoEntry[index].BasePort +
request->u.Io.IoEntry[index].NumPorts) & 0xff));
PcicWriteSocket(Socket,
PCIC_IO_ADD0_STOP_H + registerOffset,
(UCHAR) ((request->u.Io.IoEntry[index].BasePort +
request->u.Io.IoEntry[index].NumPorts) >> 8));
}
//
// set up the io control register
//
tmp = 0;
if (request->u.Io.IoEntry[index].Attributes & IO_DATA_PATH_WIDTH) {
tmp |= IOC_IO0_DATASIZE;
}
if ((request->u.Io.IoEntry[index].Attributes & IO_WAIT_STATE_16) &&
!((Elc(Socket) || CLPD6729(Socket)))) {
tmp |= IOC_IO0_WAITSTATE;
}
if (request->u.Io.IoEntry[index].Attributes & IO_SOURCE_16) {
tmp |= IOC_IO0_IOCS16;
}
if (request->u.Io.IoEntry[index].Attributes & IO_ZERO_WAIT_8) {
tmp |= IOC_IO0_ZEROWS;
}
ioControl |= tmp << registerOffset;
}
PcicWriteSocket(Socket, PCIC_IO_CONTROL, ioControl);
tmp = PcicReadSocket( Socket, PCIC_ADD_WIN_ENA);
tmp &= ~(WE_IO0_ENABLE | WE_IO1_ENABLE);
switch(request->u.Io.NumberOfRanges) {
case 1:
tmp |= WE_IO0_ENABLE;
break;
case 2:
tmp |= (WE_IO0_ENABLE | WE_IO1_ENABLE);
break;
}
PcicWriteSocket(Socket, PCIC_ADD_WIN_ENA, tmp);
break;
}
case IRQ_REQUEST: {
//
// Do not nuke the reset and cardtype bits.
//
tmp = PcicReadSocket(Socket, PCIC_INTERRUPT);
tmp &= ~IGC_IRQ_MASK;
tmp |= request->u.Irq.AssignedIRQ;
DebugPrint((PCMCIA_DEBUG_INFO, "PcicProcessConfigureRequest: Assigned IRQ %x programming IRQ %x\n", request->u.Irq.AssignedIRQ,tmp));
PcicWriteSocket(Socket, PCIC_INTERRUPT, tmp);
if (tmp = request->u.Irq.ReadyIRQ) {
tmp = (tmp << 4) | 0x04;
PcicWriteSocket(Socket, PCIC_CARD_INT_CONFIG, tmp);
}
break;
}
case DECONFIGURE_REQUEST: {
//
// Deregister the interrupt, re-init to memory interface
//
tmp = PcicReadSocket(Socket, PCIC_INTERRUPT);
tmp &= ~(IGC_PCCARD_IO | IGC_IRQ_MASK);
PcicWriteSocket(Socket, PCIC_INTERRUPT, tmp);
//
// Disable memory/io windows
// Don't touch the memory window which is
// is used by the controller for reading attribute memory
//
if (IsSocketFlagSet(Socket, SOCKET_MEMORY_WINDOW_ENABLED)) {
UCHAR enableMask;
enableMask = WE_MEM0_ENABLE << Socket->CurrentMemWindow;
tmp = PcicReadSocket(Socket, PCIC_ADD_WIN_ENA);
tmp &= enableMask;
} else {
//
// no attribute window enabled, just turn off everything
//
tmp = 0;
}
PcicWriteSocket(Socket, PCIC_ADD_WIN_ENA, tmp);
//
// Zero out the I/O windows
//
for (index = PCIC_IO_ADD0_STRT_L; index <= PCIC_IO_ADD1_STOP_H; index++) {
PcicWriteSocket(Socket,
(ULONG) index,
0);
}
break;
}
case CONFIGURE_REQUEST:{
//
// Tell the socket controller we are an I/O card if InterfaceType says so
//
if (request->u.Config.InterfaceType == CONFIG_INTERFACE_IO_MEM) {
tmp = PcicReadSocket(Socket, PCIC_INTERRUPT);
tmp |= IGC_PCCARD_IO;
PcicWriteSocket(Socket, PCIC_INTERRUPT, tmp);
} else {
tmp = PcicReadSocket(Socket, PCIC_INTERRUPT);
tmp &= ~IGC_PCCARD_IO;
PcicWriteSocket(Socket, PCIC_INTERRUPT, tmp);
}
if (request->u.Config.RegisterWriteMask & (REGISTER_WRITE_CONFIGURATION_INDEX |
REGISTER_WRITE_CARD_CONFIGURATION |
REGISTER_WRITE_IO_BASE)) {
//
// This is where we setup the card and get it ready for operation
//
ULONG configRegisterBase = request->u.Config.ConfigBase / 2;
PDEVICE_OBJECT Pdo = Socket->PdoList;
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
MEMORY_SPACE memorySpace = IsPdoFlagSet(pdoExtension, PCMCIA_PDO_INDIRECT_CIS) ? PCCARD_ATTRIBUTE_MEMORY_INDIRECT :
PCCARD_ATTRIBUTE_MEMORY;
if (request->u.Config.RegisterWriteMask & REGISTER_WRITE_IO_BASE) {
UCHAR ioHigh = (UCHAR)(request->u.Config.IoBaseRegister>>8);
UCHAR ioLow = (UCHAR) request->u.Config.IoBaseRegister;
PcicWriteCardMemory(pdoExtension, memorySpace, configRegisterBase + 5, &ioLow, 1);
PcmciaWait(PcicStallCounter);
PcicWriteCardMemory(pdoExtension, memorySpace, configRegisterBase + 6, &ioHigh, 1);
PcmciaWait(PcicStallCounter);
}
if (request->u.Config.RegisterWriteMask & REGISTER_WRITE_IO_LIMIT) {
PcicWriteCardMemory(pdoExtension, memorySpace, configRegisterBase + 9, (PUCHAR)&request->u.Config.IoLimitRegister, 1);
PcmciaWait(PcicStallCounter);
}
if (request->u.Config.RegisterWriteMask & REGISTER_WRITE_CONFIGURATION_INDEX) {
UCHAR configIndex = request->u.Config.ConfigIndex;
PcicWriteCardMemory(pdoExtension, memorySpace, configRegisterBase, &configIndex, 1);
PcmciaWait(PcicStallCounter);
configIndex |= 0x40;
PcicWriteCardMemory(pdoExtension, memorySpace, configRegisterBase, &configIndex, 1);
PcmciaWait(PcicStallCounter);
}
if (request->u.Config.RegisterWriteMask & REGISTER_WRITE_CARD_CONFIGURATION) {
PcicReadCardMemory(pdoExtension, memorySpace, configRegisterBase + 1, &tmp, 1);
PcmciaWait(PcicStallCounter);
tmp |= request->u.Config.CardConfiguration;
//
// turn off power control bit
//
tmp &= ~0x04;
PcicWriteCardMemory(pdoExtension, memorySpace, configRegisterBase + 1, &tmp, 1);
PcmciaWait(PcicStallCounter);
}
}
break;
}
case MEM_REQUEST: {
//
// Set up memory ranges on the controller.
//
PFDO_EXTENSION deviceExtension = Socket->DeviceExtension;
for (index = 0; index < request->u.Memory.NumberOfRanges; index++) {
UCHAR registerOffset;
UCHAR regl;
UCHAR regh;
ULONG cardBase = request->u.Memory.MemoryEntry[index].BaseAddress;
ULONG base = request->u.Memory.MemoryEntry[index].HostAddress;
ULONG size = request->u.Memory.MemoryEntry[index].WindowSize;
//
// Determine offset in registers.
//
registerOffset = (index * 8);
//
// Calculate and set card base addresses.
// This is the 2's complement of the host address and
// the card offset.
//
cardBase = (cardBase - (base & OFFSETCALC_BASE_MASK)) & OFFSETCALC_OFFSET_MASK;
regl = (UCHAR) (cardBase >> 12);
regh = (UCHAR) (cardBase >> 20);
if (request->u.Memory.MemoryEntry[index].AttributeMemory) {
regh |= 0x40;
}
PcicWriteSocket(Socket,
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_L + registerOffset),
regl);
PcicWriteSocket(Socket,
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_H + registerOffset),
regh);
//
// Calculate and set host window.
//
if (!PcmciaSetWindowPage(deviceExtension, Socket, index, (UCHAR) (base >> 24))) {
ASSERT (base <= 0xFFFFFF);
}
base &= 0xFFFFFF; // only 24bit host base allowed
regl = (UCHAR) (base >> 12);
regh = (UCHAR) (base >> 20);
if (request->u.Memory.MemoryEntry[index].WindowDataSize16) {
//
// This memory window is for a 16-bit data path
// to the card. Enable appropriately.
//
regh |= (MEMBASE_16BIT >> 8);
#if 0
//
// If this is not a revision 1 part (0x82), then set
// the work around register for 16-bit windows.
//
// This bit is not used on any chip that I have
// documentation for. I have no idea why it is here, it is
// not in win9x.
// In any case it looks like a NOOP for the vast majority of
// chips, but since it uses a NOT, then it is invoked on all
// new controllers. REMOVE after next major release
//
if (Socket->Revision != PCIC_REVISION) {
tmp = PcicReadSocket(Socket,
PCIC_CARD_DETECT);
tmp |= 0x01;
PcicWriteSocket(Socket,
PCIC_CARD_DETECT,
tmp);
}
#endif
}
PcicWriteSocket(Socket,
(UCHAR)(PCIC_MEM_ADD0_STRT_L + registerOffset),
regl);
PcicWriteSocket(Socket,
(UCHAR)(PCIC_MEM_ADD0_STRT_H + registerOffset),
regh);
//
// Set stop address.
//
base += size - 1;
regl = (UCHAR) (base >> 12);
regh = (UCHAR) (base >> 20);
//
// Add specified wait states
//
regh |= (request->u.Memory.MemoryEntry[index].WaitStates << 6);
PcicWriteSocket(Socket,
(UCHAR)(PCIC_MEM_ADD0_STOP_L + registerOffset),
regl);
PcicWriteSocket(Socket,
(UCHAR)(PCIC_MEM_ADD0_STOP_H + registerOffset),
regh);
}
//
// Memory windows are set up now enable them.
//
tmp = 0;
for (index = 0; index < request->u.Memory.NumberOfRanges; index++) {
tmp |= (1 << index);
}
tmp |= PcicReadSocket(Socket, PCIC_ADD_WIN_ENA);
PcicWriteSocket(Socket, PCIC_ADD_WIN_ENA, tmp);
break;
}
default: {
DebugPrint((PCMCIA_DEBUG_FAIL, "ConfigRequest is INVALID!\n"));
}
}
return TRUE;
}
BOOLEAN
PcicDetectCardInSocket(
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.
--*/
{
UCHAR tmp;
BOOLEAN cardPresent=FALSE;
//
// Read the PCIC status register to see if the card is in there.
//
tmp = PcicReadSocket(Socket, PCIC_STATUS);
tmp &= (CARD_DETECT_1 | CARD_DETECT_2);
if (tmp == (CARD_DETECT_1 | CARD_DETECT_2)) {
cardPresent = TRUE;
}
return cardPresent;
}
BOOLEAN
PcicDetectCardChanged(
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.
--*/
{
//
// Read the PCIC CardStatusChange register to see if CD's have changed.
//
return (BOOLEAN) (PcicReadSocket(Socket, PCIC_CARD_CHANGE) & CSC_CD_CHANGE);
}
BOOLEAN
PcicDetectReadyChanged(
IN PSOCKET Socket
)
/*++
Routine Description:
This routine will determine if socket's card ready status has changed
Arguments:
Socket -- Socket info.
Return Value:
TRUE if card ready enable has changed.
--*/
{
//
// Read the PCIC Card status change register to see if ready has changed
//
return (PcicReadSocket(Socket, PCIC_CARD_CHANGE) & CSC_READY_CHANGE
?TRUE :FALSE);
}
VOID
PcicEnableDisableMemory(
IN PSOCKET Socket,
IN MEMORY_SPACE MemorySpace,
IN ULONG CardBase,
IN UCHAR memWidth,
IN BOOLEAN Enable
)
/*++
Routine Description:
This routine will enable or disable attribute/common memory.
It searches for a free window first to avoid using a window already
in use. Repeated 'enable' calls to this routine without a disable
(in order to remap the base) is allowed.
Arguments:
Socket -- Socket information
MemorySpace -- Indicates which space - ATTRIBUTE_MEMORY/COMMON_MEMORY
CardBase -- card offset (base) for the attribute memory window
Enable -- If TRUE, enable, if FALSE, disable
Return Value:
None
--*/
{
ULONG location;
PUCHAR cisBufferPointer;
PFDO_EXTENSION deviceExtension= Socket->DeviceExtension;
PUCHAR PcicCisBufferBase = (PUCHAR) deviceExtension->AttributeMemoryBase;
ULONG PcicPhysicalBase = deviceExtension->PhysicalBase.LowPart;
BOOLEAN memoryInterface;
UCHAR tmp;
UCHAR index;
UCHAR registerOffset;
UCHAR enableMask;
USHORT word;
ASSERT (IsSocketFlagSet(Socket, SOCKET_CARD_POWERED_UP));
if (Enable) {
tmp = PcicReadSocket(Socket, PCIC_INTERRUPT);
if (tmp & IGC_PCCARD_IO) {
//
// Card configured for i/o interface
//
memoryInterface = FALSE;
} else {
//
// Card configured for Memory interface
//
memoryInterface = TRUE;
}
//
// Find a window to use.
//
tmp = PcicReadSocket(Socket, PCIC_ADD_WIN_ENA);
if (IsSocketFlagSet(Socket, SOCKET_MEMORY_WINDOW_ENABLED)) {
index = Socket->CurrentMemWindow;
enableMask = WE_MEM0_ENABLE << index;
} else {
for (index = 0, enableMask = WE_MEM0_ENABLE; index < 5; index++, enableMask <<= 1) {
if (!(tmp & enableMask)) {
break;
}
if (index==4) {
//
// If we are here, we didn't find an available window. Just use the last
// one anyway, it is likely a pcmcia.sys bug.
//
// ASSERT(FALSE); // hits docked thinkpads
break;
}
}
Socket->CurrentMemWindow = index;
SetSocketFlag(Socket, SOCKET_MEMORY_WINDOW_ENABLED);
}
registerOffset = (index * 8);
//
// First turn the window off
//
tmp &= ~enableMask;
tmp &= ~WE_MEMCS16_DECODE;
PcicWriteSocket(Socket, PCIC_ADD_WIN_ENA, tmp);
//
// Calculate and set the memory windows start and stop locations.
//
//
// Only 24 bit addresses programmed
// For cardbus controllers, 32 bit addresses are supported,
// but the higher 8 bits are written to the page register (see below)
location = PcicPhysicalBase & 0xFFFFFF;
word = (USHORT) ((location >> 12) & MEMBASE_ADDR_MASK);
//
// typically run attribute memory with 8-bit window, common with 16-bit
// (except for writing the registers for attribute_indirect)
//
if (memWidth == MEM_16BIT) {
word |= MEMBASE_16BIT;
}
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STRT_L+registerOffset), (UCHAR)(word));
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STRT_H+registerOffset), (UCHAR)(word >> 8));
location += (deviceExtension->AttributeMemorySize - 1);
word = (USHORT) ((location >> 12) & MEMEND_ADDR_MASK);
//
// Impose 3 wait states..lessons learnt from win9x implementations
//
word |= MEMEND_WS_MASK;
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STOP_L+registerOffset), (UCHAR)(word));
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STOP_H+registerOffset), (UCHAR)(word >> 8));
//
// Set up the 2's complement card offset to zero
//
location = (CardBase - (PcicPhysicalBase & OFFSETCALC_BASE_MASK)) & OFFSETCALC_OFFSET_MASK;
word = (USHORT) ((location >> 12) & MEMOFF_ADDR_MASK);
if (MemorySpace == PCCARD_ATTRIBUTE_MEMORY) {
word |= MEMOFF_REG_ACTIVE;
}
PcicWriteSocket(Socket, (UCHAR)(PCIC_CRDMEM_OFF_ADD0_L+registerOffset), (UCHAR)(word));
PcicWriteSocket(Socket, (UCHAR)(PCIC_CRDMEM_OFF_ADD0_H+registerOffset), (UCHAR)(word >> 8));
//
// Set the page register
// (this routine is called only for R2 cards)
// Use mem4 window explicitly
//
if (!PcmciaSetWindowPage(deviceExtension, Socket, (USHORT)index, (UCHAR) (PcicPhysicalBase >> 24))) {
ASSERT (PcicPhysicalBase <= 0xFFFFFF);
}
//
// Enable the address window
//
tmp = PcicReadSocket(Socket, PCIC_ADD_WIN_ENA);
tmp |= enableMask | WE_MEMCS16_DECODE;
PcicWriteSocket(Socket, PCIC_ADD_WIN_ENA, tmp);
cisBufferPointer = PcicCisBufferBase;
if (memoryInterface) {
//
// Only wait for card ready if the memory window does not appear
//
(VOID) PcicPCCardReady(Socket);
} else {
//
// Wait a little bit for the window to appear
//
PcmciaWait(PCMCIA_PCIC_MEMORY_WINDOW_DELAY);
}
DebugPrint((PCMCIA_DEBUG_INFO, "skt %08x memory window %d enabled %x\n", Socket, index, PcicPhysicalBase));
} else {
if (IsSocketFlagSet(Socket, SOCKET_MEMORY_WINDOW_ENABLED)) {
enableMask = WE_MEM0_ENABLE << Socket->CurrentMemWindow;
registerOffset = (Socket->CurrentMemWindow * 8);
//
// Disable the Address window
//
tmp = PcicReadSocket(Socket, PCIC_ADD_WIN_ENA);
tmp &= ~enableMask;
PcicWriteSocket(Socket, PCIC_ADD_WIN_ENA, tmp);
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STRT_L+registerOffset), 0xFF);
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STRT_H+registerOffset), 0x0F);
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STOP_L+registerOffset), 0xFF);
PcicWriteSocket(Socket, (UCHAR)(PCIC_MEM_ADD0_STOP_H+registerOffset), 0x0F);
PcicWriteSocket(Socket, (UCHAR)(PCIC_CRDMEM_OFF_ADD0_L+registerOffset), 0x00);
PcicWriteSocket(Socket, (UCHAR)(PCIC_CRDMEM_OFF_ADD0_H+registerOffset), 0x00);
PcmciaSetWindowPage(deviceExtension, Socket, Socket->CurrentMemWindow, 0);
DebugPrint((PCMCIA_DEBUG_INFO, "skt %08x memory window %d disabled\n", Socket, Socket->CurrentMemWindow));
ResetSocketFlag(Socket, SOCKET_MEMORY_WINDOW_ENABLED);
}
}
return;
}
BOOLEAN
PcicPCCardReady(
IN PSOCKET Socket
)
/*++
Routine Description:
Loop for a reasonable amount of time waiting for the card status to
return ready.
Arguments:
Socket - the socket to check.
Return Value:
TRUE - the card is ready.
FALSE - after a reasonable delay the card is still not ready.
--*/
{
ULONG index;
UCHAR byte;
PFDO_EXTENSION fdoExtension = Socket->DeviceExtension;
NTSTATUS status;
LARGE_INTEGER timeout;
#ifdef READY_ENABLE
if (fdoExtension->PcmciaInterruptObject) {
byte = PcicReadSocket(Socket, PCIC_STATUS);
if (byte & 0x20) {
return TRUE;
}
//
// Enable ready enable controller interrupt
//
PcicEnableDisableControllerInterrupt(
Socket,
fdoExtension->Configuration.Interrupt.u.Interrupt.Level,
TRUE,
TRUE);
RtlConvertLongToLargeInteger(-PCMCIA_READY_WAIT_INTERVAL);
status = KeWaitForSingleObject(&Socket->PCCardReadyEvent,
Executive,
KernelMode,
FALSE,
&timeout
);
if (status != STATUS_TIMEOUT) {
return TRUE;
}
return FALSE;
}
#endif
for (index = 0; index < PCMCIA_READY_DELAY_ITER; index++) {
byte = PcicReadSocket(Socket, PCIC_STATUS);
if (byte & 0x20) {
break;
}
PcmciaWait(PCMCIA_READY_STALL);
}
if (index < PCMCIA_READY_DELAY_ITER) {
DebugPrint((PCMCIA_COUNTERS, "PcicPCCardReady: %d\n", index));
return TRUE;
}
return FALSE;
}
NTSTATUS
PcicIsaDetect(
IN PFDO_EXTENSION DeviceExtension
)
/*++
Routine Description:
Locate any PCMCIA sockets supported by this driver. This routine
will find the 82365SL and compatible parts and construct SOCKET
structures to represent all sockets found
Arguments:
DeviceExtension - the root for the SocketList.
Return Value:
STATUS_SUCCESS if a controller is found: also indicates this might be called
again to locate another controller
STATUS_UNSUCCESSFUL if something failed/no controllers found.
STATUS_NO_MORE_ENTRIES if no more pcic controllers can be found.
Stop calling this routine.
--*/
{
#define PCMCIA_NUMBER_ISA_PORT_ADDRESSES 3
static ULONG isaIndex=0;
ULONG index;
ULONG ioPortBases[PCMCIA_NUMBER_ISA_PORT_ADDRESSES] = { 0x3e0, 0x3e2, 0x3e4};
NTSTATUS status=STATUS_NO_MORE_ENTRIES;
PAGED_CODE();
DeviceExtension->Configuration.InterfaceType = Isa;
DeviceExtension->Configuration.BusNumber = 0x0;
for (index = isaIndex; !NT_SUCCESS(status) && (index < PCMCIA_NUMBER_ISA_PORT_ADDRESSES); index++) {
status = PcicDetect(DeviceExtension,Isa, ioPortBases[index]);
}
//
// Set index for next search
//
isaIndex = index;
return status;
}
NTSTATUS
PcicDetect(
IN PFDO_EXTENSION DeviceExtension,
IN INTERFACE_TYPE InterfaceType,
IN ULONG IoPortBase
)
/*++
Routine Description:
This routine is used for legacy detecting PCIC-compatible
PCMCIA controllers.
This attempts to sniff the standard PCMCIA controller ports
to check if anything resembling the PCMCIA revisions exists,
and if so obtain and initialize socket information for the controller.
Arguments:
DeviceExtension - pointer to the already allocated device extension
for the yet-to-be-detected pcmcia controller.
InterfaceType - Bus interface type on which the pcmcia
controller is expected to reside. Currently
we legacy detect only ISA based controllers
IoPortBase - IoPort address we need to sniff at for finding
the controller
Return value:
STATUS_SUCCESS PCMCIA controller was found
STATUS_UNSUCCESSFUL otherwise
--*/
{
ULONG addressSpace;
NTSTATUS status;
PUCHAR port;
PUCHAR elcPort;
PHYSICAL_ADDRESS cardAddress;
PHYSICAL_ADDRESS portAddress;
PCM_RESOURCE_LIST cmResourceList = NULL;
PCM_PARTIAL_RESOURCE_LIST cmPartialResourceList;
UCHAR saveBytes[2];
UCHAR dataByte;
UCHAR revisionByte;
USHORT socket;
UCHAR socketNumber = 0;
BOOLEAN translated;
BOOLEAN mapped = FALSE;
BOOLEAN conflict = TRUE;
BOOLEAN resourcesAllocated = FALSE;
PAGED_CODE();
portAddress.LowPart = IoPortBase;
portAddress.u.HighPart = 0;
//
// Get the resources used for detection
//
cmResourceList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST));
if (!cmResourceList) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
RtlZeroMemory(cmResourceList, sizeof(CM_RESOURCE_LIST));
cmResourceList->Count = 1;
cmResourceList->List[0].InterfaceType = Isa;
cmPartialResourceList = &(cmResourceList->List[0].PartialResourceList);
cmPartialResourceList->Version = 1;
cmPartialResourceList->Revision = 1;
cmPartialResourceList->Count = 1;
cmPartialResourceList->PartialDescriptors[0].Type = CmResourceTypePort;
cmPartialResourceList->PartialDescriptors[0].ShareDisposition = CmResourceShareDeviceExclusive;
cmPartialResourceList->PartialDescriptors[0].Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE;
cmPartialResourceList->PartialDescriptors[0].u.Port.Start = portAddress;
cmPartialResourceList->PartialDescriptors[0].u.Port.Length = 2;
status=IoReportResourceForDetection(
DeviceExtension->DriverObject,
cmResourceList,
sizeof(CM_RESOURCE_LIST),
NULL,
NULL,
0,
&conflict);
if (!NT_SUCCESS(status) || conflict) {
goto Exit;
}
resourcesAllocated = TRUE;
addressSpace = 1; // port space
translated = HalTranslateBusAddress(InterfaceType,
0,
portAddress,
&addressSpace,
&cardAddress);
if (!translated) {
//
// HAL would not translate the address.
//
status = STATUS_UNSUCCESSFUL;
goto Exit;
}
if (addressSpace) {
//
// I/O port space
//
port = (PUCHAR)(cardAddress.QuadPart);
} else {
//
// Memory space.. we need to map this into memory
//
port = MmMapIoSpace(cardAddress,
2,
FALSE);
mapped = TRUE;
}
status = STATUS_UNSUCCESSFUL;
socket = 0;
dataByte = PcicReadController(port, socket, PCIC_IDENT);
revisionByte = dataByte;
switch (dataByte) {
case PCIC_REVISION:
case PCIC_REVISION2:
case PCIC_REVISION3: {
//
// The cirrus logic controller will toggle top 2 lines from the chip info
// register on the chip. Read from thelocation 3 times and verify that the top two
// lines are changing. We do this for NEC 98 also..
//
ULONG i;
UCHAR data[4];
WRITE_PORT_UCHAR(port, (UCHAR)(socket + PCIC_CL_CHIP_INFO));
for (i = 0; i < 3; i++) {
data[i] = READ_PORT_UCHAR(port+1);
if (i) {
dataByte = data[i - 1] ^ data[i];
if (dataByte != 0xc0) {
break;
}
}
}
if (i == 3) {
//
// Ah. this is a cirrus logic controller
//
PcmciaSetControllerType(DeviceExtension, PcmciaCLPD6729);
}
dataByte = PcicReadController(port, socket, PCIC_CARD_CHANGE);
if (dataByte & 0xf0) {
//
// Not a socket.
//
break;
}
//
// Map and try to locate the Compaq Elite controller
// This code is a rough approximation of the code in
// the Windows 95 detection module for the PCIC part.
//
addressSpace = 1; // port space
portAddress.LowPart = IoPortBase + 0x8000;
portAddress.HighPart = 0;
translated = HalTranslateBusAddress(Isa,
0,
portAddress,
&addressSpace,
&cardAddress);
if (translated) {
if (!addressSpace) {
elcPort = MmMapIoSpace(cardAddress,
2,
FALSE);
} else {
elcPort = (PUCHAR)(cardAddress.QuadPart);
}
//
// Save current index value.
//
saveBytes[0] = READ_PORT_UCHAR(elcPort);
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + PCIC_IDENT));
//
// Save data byte for the location that will be used
// for the test.
//
saveBytes[1] = READ_PORT_UCHAR(elcPort + 1);
//
// Check for an ELC
//
WRITE_PORT_UCHAR(elcPort+1, 0x55);
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + PCIC_IDENT));
dataByte = READ_PORT_UCHAR(elcPort+1);
if (dataByte == 0x55) {
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + PCIC_IDENT));
WRITE_PORT_UCHAR(elcPort+1, 0xaa);
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + PCIC_IDENT));
dataByte = READ_PORT_UCHAR(elcPort+1);
if (dataByte == 0xaa) {
//
// ELC found - initialize eaddr registers
//
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + 0));
WRITE_PORT_UCHAR(elcPort+1, 0);
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + 1));
WRITE_PORT_UCHAR(elcPort+1, 0);
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + 2));
WRITE_PORT_UCHAR(elcPort+1, 0x10);
PcmciaSetControllerType(DeviceExtension, PcmciaElcController);
}
}
//
// Restore the original values.
//
WRITE_PORT_UCHAR(elcPort, (UCHAR)(socket + PCIC_IDENT));
WRITE_PORT_UCHAR(elcPort+1, saveBytes[1]);
WRITE_PORT_UCHAR(elcPort, saveBytes[0]);
if (!addressSpace) {
MmUnmapIoSpace(elcPort, 2);
}
}
DeviceExtension->Configuration.UntranslatedPortAddress = (USHORT)IoPortBase;
DeviceExtension->Configuration.PortSize = 2;
DebugPrint((PCMCIA_DEBUG_DETECT, "Port %x Offset %x\n", port, socket));
status = STATUS_SUCCESS;
break;
}
default: {
DebugPrint((PCMCIA_DEBUG_DETECT,
"controller at (0x%x:0x%x) not found, returns %x\n",
portAddress.LowPart, socket, dataByte));
break;
}
}
Exit:
if (!NT_SUCCESS(status) && mapped) {
MmUnmapIoSpace(port, 2);
}
//
// Free up the allocated resources if any
//
if (resourcesAllocated) {
IoReportResourceForDetection(DeviceExtension->DriverObject,
NULL,
0,
NULL,
NULL,
0,
&conflict);
}
//
// Free up allocated memory if any
//
if (cmResourceList) {
ExFreePool(cmResourceList);
}
return status;
}
NTSTATUS
PcicBuildSocketList(
IN PFDO_EXTENSION DeviceExtension
)
/*++
Routine Description:
This routine looks out at the registers of the controller to see how
many sockets there are. For each socket, a SOCKET structure is allocated
and chained onto the SocketList pointer of the device extension.
Arguments:
DeviceExtension - pointer to the device extension
enumerated PDO
Return value:
STATUS_SUCCESS PCMCIA controller was found and socket structures were
succesfully initialized
STATUS_UNSUCCESSFUL otherwise
--*/
{
ULONG addressSpace;
NTSTATUS status;
PUCHAR port;
PSOCKET socketPtr;
PSOCKET previousSocket;
UCHAR dataByte;
UCHAR revisionByte;
USHORT socket;
UCHAR socketNumber = 0;
PAGED_CODE();
previousSocket = DeviceExtension->SocketList;
port = (PUCHAR)DeviceExtension->Configuration.UntranslatedPortAddress;
status = STATUS_UNSUCCESSFUL;
for (socket = 0; socket < 0xFF; socket += 0x40) {
dataByte = PcicReadController(port, socket, PCIC_IDENT);
revisionByte = dataByte;
switch (dataByte) {
case PCIC_REVISION:
case PCIC_REVISION2:
case PCIC_REVISION3: {
dataByte = PcicReadController(port, socket, PCIC_CARD_CHANGE);
if (dataByte & 0xf0) {
//
// Not a socket.
//
continue;
}
//
// Check for IBM 750
//
if (socket & 0x80) {
ULONG i;
UCHAR tmp;
//
// See if this socket shadows the socket without
// the sign bit.
//
tmp = PcicReadController(port, socket, PCIC_MEM_ADD4_STRT_L);
for (i = 0; i < 8; i++) {
//
// See if memory window 4 is the same on both sockets
//
if (PcicReadController(port, socket, (UCHAR) (PCIC_MEM_ADD4_STRT_L + i)) !=
PcicReadController(port, (USHORT) (socket & 0x7f), (UCHAR) (PCIC_MEM_ADD4_STRT_L + i))) {
break;
}
}
if (i == 8) {
//
// Currently window is the same - change the
// window at one of the socket offsets.
//
PcicWriteController(port, (USHORT) (socket & 0x7f), PCIC_MEM_ADD4_STRT_L, (UCHAR) ~tmp);
if (PcicReadController(port, socket, PCIC_MEM_ADD4_STRT_L) == (UCHAR) ~tmp) {
//
// The sockets are the same.
//
continue;
} else {
PcicWriteController(port, (USHORT) (socket & 0x7f), PCIC_MEM_ADD4_STRT_L, tmp);
}
}
}
socketPtr = ExAllocatePool(NonPagedPool, sizeof(SOCKET));
if (!socketPtr) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(socketPtr, sizeof(SOCKET));
socketPtr->DeviceExtension = DeviceExtension;
socketPtr->SocketFnPtr = &PcicSupportFns;
socketPtr->RegisterOffset = socket;
socketPtr->AddressPort = port;
socketPtr->Revision = revisionByte;
socketPtr->SocketNumber = socketNumber++;
if (previousSocket) {
previousSocket->NextSocket = socketPtr;
} else {
DeviceExtension->SocketList = socketPtr;
}
previousSocket = socketPtr;
status = STATUS_SUCCESS;
break;
}
default: {
break;
}
}
}
return status;
}