1827 lines
51 KiB
C
1827 lines
51 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1994 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 (mcleman@zso.dec.com)
|
|||
|
|
|||
|
Revisions:
|
|||
|
6-Apr-95
|
|||
|
Modified for databook support changes - John Keys Databook
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ntddk.h"
|
|||
|
#include "stdio.h"
|
|||
|
#include "pcmcia.h"
|
|||
|
#include "card.h"
|
|||
|
#include "extern.h"
|
|||
|
#include "tuple.h"
|
|||
|
|
|||
|
#ifdef POOL_TAGGING
|
|||
|
#undef ExAllocatePool
|
|||
|
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'cicP')
|
|||
|
#endif
|
|||
|
|
|||
|
PUCHAR PcicCisBufferBase;
|
|||
|
ULONG PcicPhysicalBase;
|
|||
|
ULONG PcicStallCounter = 5000;
|
|||
|
ULONG PcicStallPower = 20000;
|
|||
|
|
|||
|
PCMCIA_CTRL_BLOCK PcicSupportFns = {
|
|||
|
PcicInitializePcmciaSocket,
|
|||
|
PcicReadAttributeMemory,
|
|||
|
PcicDetectCardInSocket,
|
|||
|
PcicDetectCardChanged,
|
|||
|
PcicProcessConfigureRequest,
|
|||
|
PcicEnableControllerInterrupt,
|
|||
|
PcicPCCardReady,
|
|||
|
PcicSetPower,
|
|||
|
PcicGetRegisters
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// Routine definitions to satisfy INIT pragma statements.
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicSearchPci(
|
|||
|
PDEVICE_EXTENSION DeviceExtension,
|
|||
|
ULONG BusNumber,
|
|||
|
PULONG IoPortLocation
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT,PcicDetect)
|
|||
|
#pragma alloc_text(INIT,PcicInitializePcmciaSocket)
|
|||
|
#pragma alloc_text(INIT,PcicSearchPci)
|
|||
|
#endif
|
|||
|
|
|||
|
#if DBG
|
|||
|
VOID
|
|||
|
PcicDumpSocketState(
|
|||
|
IN PUCHAR Base,
|
|||
|
IN USHORT Socket
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Debug routine to print the registers to the debugger.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Base - the I/O port base.
|
|||
|
Socket - the socket offset
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR registers[0x40];
|
|||
|
ULONG longValue;
|
|||
|
UCHAR i;
|
|||
|
|
|||
|
for (i = 0; i < 0x40; i++) {
|
|||
|
registers[i] = PcicReadController(Base, Socket, i);
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DUMP_SOCKET,
|
|||
|
"%2x %2x %2x %2x %2x %2x %2x\n",
|
|||
|
registers[0],
|
|||
|
registers[1],
|
|||
|
registers[2],
|
|||
|
registers[3],
|
|||
|
registers[4],
|
|||
|
registers[5],
|
|||
|
registers[6]));
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DUMP_SOCKET, "Revision %2x, Interface %2x, Power %2x, Enable Window %2x\n",
|
|||
|
registers[0],
|
|||
|
registers[1],
|
|||
|
registers[2],
|
|||
|
registers[6]));
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DUMP_SOCKET,
|
|||
|
"I/O 0 Start - Stop %4x - %4x\n",
|
|||
|
(registers[9] << 8) | registers[8],
|
|||
|
(registers[0xb] << 8) | registers[0xa]));
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DUMP_SOCKET,
|
|||
|
"I/O 1 Start - Stop %4x - %4x\n",
|
|||
|
(registers[0xd] << 8) | registers[0xc],
|
|||
|
(registers[0xf] << 8) | registers[0xe]));
|
|||
|
|
|||
|
for (i = 0; i <= 4; i++) {
|
|||
|
DebugPrint((PCMCIA_DUMP_SOCKET,
|
|||
|
"Memory Address %d Stop/Start/Card %4x/%4x/%4x\n",
|
|||
|
i,
|
|||
|
(registers[(i*8)+0x11] << 8) | registers[(i*8)]+0x10,
|
|||
|
(registers[(i*8)+0x13] << 8) | registers[(i*8)]+0x12,
|
|||
|
(registers[(i*8)+0x15] << 8) | registers[(i*8)]+0x14));
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PcicEnableControllerInterrupt(
|
|||
|
IN PSOCKET SocketPtr,
|
|||
|
IN ULONG Irq
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Enable card detect/card ready interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketPtr - socket information
|
|||
|
Irq - the interrupt value to set.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR byte;
|
|||
|
|
|||
|
byte = (UCHAR) ((Irq << 4) & 0x00ff);
|
|||
|
byte |= 0x08; // Card detect & ready enable
|
|||
|
PcicWriteController(SocketPtr->AddressPort,
|
|||
|
SocketPtr->RegisterOffset,
|
|||
|
PCIC_CARD_INT_CONFIG,
|
|||
|
byte);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PcicSetPower(
|
|||
|
IN PSOCKET SocketPtr,
|
|||
|
IN BOOLEAN Enable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Set power to the specified socket.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketPtr - the socket to set
|
|||
|
Enable - TRUE means to set power - FALSE is to turn it off.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUCHAR base;
|
|||
|
UCHAR tmp;
|
|||
|
USHORT socket;
|
|||
|
|
|||
|
//
|
|||
|
// Turn on the power - then turn on output - this is two operations
|
|||
|
// per the Intel 82365SL documentation.
|
|||
|
//
|
|||
|
|
|||
|
base = SocketPtr->AddressPort;
|
|||
|
socket = SocketPtr->RegisterOffset;
|
|||
|
|
|||
|
if (Enable) {
|
|||
|
tmp = PcicReadController(base, socket, PCIC_PWR_RST);
|
|||
|
if (SocketPtr->ElcController) {
|
|||
|
tmp = 0x11; // vpp1 = vcc
|
|||
|
} else {
|
|||
|
tmp = 0x15; // vpp1 = vpp2 = vcc
|
|||
|
}
|
|||
|
PcicWriteController(base, socket, PCIC_PWR_RST, tmp);
|
|||
|
|
|||
|
if (SocketPtr->ElcController) {
|
|||
|
tmp = 0xf1; // vpp1 = vcc
|
|||
|
} else {
|
|||
|
tmp = 0xf5; // vpp1 = vpp2 = vcc
|
|||
|
}
|
|||
|
|
|||
|
PcicWriteController(base, socket, PCIC_PWR_RST, tmp);
|
|||
|
|
|||
|
//
|
|||
|
// When power is enabled always stall to give the PCCARD
|
|||
|
// a chance to react.
|
|||
|
//
|
|||
|
|
|||
|
KeStallExecutionProcessor(PcicStallPower);
|
|||
|
if (!PcicPCCardReady(SocketPtr)) {
|
|||
|
DebugPrint((PCMCIA_PCCARD_READY,
|
|||
|
"PCIC: PCCARD %x not ready after reset\n",
|
|||
|
socket));
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Disable IRQ
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_INTERRUPT);
|
|||
|
tmp = tmp & 0xf0;
|
|||
|
|
|||
|
PcicWriteController(base, socket, PCIC_INTERRUPT, tmp);
|
|||
|
|
|||
|
//
|
|||
|
// I/O windows were set up now disable them.
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_ADD_WIN_ENA);
|
|||
|
tmp &= 0x3f;
|
|||
|
PcicWriteController(base, socket, PCIC_ADD_WIN_ENA, tmp);
|
|||
|
|
|||
|
//
|
|||
|
// Memory windows were set up now disable them.
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base,
|
|||
|
socket,
|
|||
|
PCIC_ADD_WIN_ENA);
|
|||
|
tmp &= 0xe0;
|
|||
|
PcicWriteController(base, socket, PCIC_ADD_WIN_ENA, tmp);
|
|||
|
|
|||
|
|
|||
|
PcicWriteController(base, socket, PCIC_PWR_RST, 0x00);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
UCHAR SocketInitString[] = { 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, 0x00,
|
|||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|||
|
UCHAR SocketWindowInit[] = { 0xFF, 0x07, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x0f };
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicInitializePcmciaSocket(
|
|||
|
PSOCKET SocketPtr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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:
|
|||
|
|
|||
|
SocketPtr - socket specific information
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful
|
|||
|
FALSE if not successful
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension;
|
|||
|
PUCHAR base;
|
|||
|
UCHAR tmp;
|
|||
|
USHORT socket;
|
|||
|
PSOCKET socketPtr;
|
|||
|
UCHAR index;
|
|||
|
UCHAR length;
|
|||
|
UCHAR reg;
|
|||
|
|
|||
|
deviceExtension = SocketPtr->DeviceExtension;
|
|||
|
PcicCisBufferBase = (PUCHAR)deviceExtension->AttributeMemoryBase;
|
|||
|
PcicPhysicalBase = deviceExtension->PhysicalBase;
|
|||
|
|
|||
|
base = SocketPtr->AddressPort;
|
|||
|
socket = SocketPtr->RegisterOffset;
|
|||
|
|
|||
|
//
|
|||
|
// Starting from the POWER register, initialize this socket.
|
|||
|
//
|
|||
|
|
|||
|
for (index = 2; index < 16; index++) {
|
|||
|
tmp = SocketInitString[index];
|
|||
|
PcicWriteController(base, socket, index, tmp);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Do all of the memory windows.
|
|||
|
//
|
|||
|
|
|||
|
reg = PCIC_MEM_ADD0_STRT_L;
|
|||
|
for (length = 0; length < 5; length++) {
|
|||
|
for (index = 0; index < 6; index++) {
|
|||
|
tmp = SocketWindowInit[index];
|
|||
|
PcicWriteController(base, socket, reg, tmp);
|
|||
|
reg++;
|
|||
|
}
|
|||
|
reg += 2; // skip reserved registers.
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Say card is there
|
|||
|
//
|
|||
|
|
|||
|
if (PcicDetectCardInSocket(SocketPtr)) {
|
|||
|
|
|||
|
//
|
|||
|
// Turn on the power
|
|||
|
//
|
|||
|
|
|||
|
PcicSetPower(SocketPtr, TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// reset PCCARD
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_INTERRUPT);
|
|||
|
tmp &= 0xbf; // turn off bit 6 (start reset)
|
|||
|
PcicWriteController(base, socket, PCIC_INTERRUPT, tmp);
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
tmp |= 0x40; // turn on bit 6 (stop reset)
|
|||
|
PcicWriteController(base, socket, PCIC_INTERRUPT, tmp);
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
if (!PcicPCCardReady(SocketPtr)) {
|
|||
|
DebugPrint((PCMCIA_PCCARD_READY,
|
|||
|
"PCIC: PCCARD %x not ready after reset\n",
|
|||
|
socket));
|
|||
|
}
|
|||
|
|
|||
|
SocketPtr->CardInSocket = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
//
|
|||
|
// The stalls are needed by the IBM PPC systems. Do not
|
|||
|
// remove them.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR((PUCHAR)Base, (UCHAR)(Socket+Register));
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
dataByte = READ_PORT_UCHAR((PUCHAR)Base + 1);
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
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
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// The stalls are needed by the IBM PPC systems. Do not
|
|||
|
// remove them.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR((PUCHAR)Base, (UCHAR)(Socket+Register));
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
WRITE_PORT_UCHAR((PUCHAR)Base + 1, DataByte);
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicReadAttributeMemory(
|
|||
|
IN PSOCKET SocketPtr,
|
|||
|
IN PUCHAR *TupleBuffer,
|
|||
|
IN PULONG TupleBufferSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will set up the card to read attribute memory
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketPtr -- The socket info in for the card being read
|
|||
|
TupleBuffer -- pointer to pointer for tuple information.
|
|||
|
TupleBufferSize -- maximum size of the buffer area for tuple information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - if read was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOLEAN ret;
|
|||
|
|
|||
|
PcicEnableDisableAttributeMemory(SocketPtr, 0, TRUE);
|
|||
|
if (!PcicPCCardReady(SocketPtr)) {
|
|||
|
DebugPrint((PCMCIA_PCCARD_READY,
|
|||
|
"PCIC: PCCARD %x not ready for read attribute memory\n",
|
|||
|
SocketPtr->RegisterOffset));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now read the CIS into the user buffer
|
|||
|
//
|
|||
|
|
|||
|
ret = PcicReadCIS(SocketPtr->AddressPort,
|
|||
|
SocketPtr->RegisterOffset,
|
|||
|
TupleBuffer,
|
|||
|
TupleBufferSize);
|
|||
|
PcicEnableDisableAttributeMemory(SocketPtr, 0, FALSE);
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicReadCIS(
|
|||
|
IN PUCHAR Base,
|
|||
|
IN USHORT Socket,
|
|||
|
IN PUCHAR *TupleBuffer,
|
|||
|
IN PULONG TupleBufferSize
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will read the CIS - the INTEL FAX modem (and others)
|
|||
|
has a condition where it allows the attribute memory to be read only
|
|||
|
once. After that read it returns 0xff for everything - therefore
|
|||
|
the tuple data has to be transferred to a page buffer then the
|
|||
|
size can be calculated rather than calculating the size in place.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Socket -- Socket to read.
|
|||
|
TupleBuffer -- pointer to pointer for buffer to hold tuple Data.
|
|||
|
if pointer is NULL - allocate space.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if read was successful
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUCHAR holdBuffer;
|
|||
|
PUCHAR currentBufferPointer;
|
|||
|
PUCHAR cisBufferPointer;
|
|||
|
UCHAR tupleCode;
|
|||
|
UCHAR link;
|
|||
|
ULONG i;
|
|||
|
ULONG size;
|
|||
|
|
|||
|
cisBufferPointer = PcicCisBufferBase;
|
|||
|
currentBufferPointer = holdBuffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
|
|||
|
for (i = 0; i < (PAGE_SIZE / 4); i++) {
|
|||
|
|
|||
|
*currentBufferPointer++ = READ_REGISTER_UCHAR(cisBufferPointer);
|
|||
|
cisBufferPointer += 2;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the size of the tuple information and allocate
|
|||
|
// a user buffer.
|
|||
|
//
|
|||
|
|
|||
|
cisBufferPointer = holdBuffer;
|
|||
|
tupleCode = *cisBufferPointer++;
|
|||
|
link = *cisBufferPointer++;
|
|||
|
size = 2;
|
|||
|
while (tupleCode != CISTPL_END) {
|
|||
|
|
|||
|
DebugPrint((PCMCIA_READ_TUPLE,
|
|||
|
"PcmciaReadCIS: Code = %2x link = %2x\n",
|
|||
|
tupleCode,
|
|||
|
link));
|
|||
|
size += link + 2; // add in code and link size
|
|||
|
cisBufferPointer += link;
|
|||
|
tupleCode = *cisBufferPointer++;
|
|||
|
link = *cisBufferPointer++;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add in the end tuple.
|
|||
|
//
|
|||
|
|
|||
|
size++;
|
|||
|
size += link;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory to hold the tuple information.
|
|||
|
//
|
|||
|
|
|||
|
*TupleBuffer = currentBufferPointer = ExAllocatePool(NonPagedPool, size);
|
|||
|
*TupleBufferSize = size;
|
|||
|
if (!currentBufferPointer) {
|
|||
|
|
|||
|
//
|
|||
|
// Use the holding buffer. This is a waste of memory.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((PCMCIA_READ_TUPLE,
|
|||
|
"PcmciaReadCIS: using hold buffer size %d\n",
|
|||
|
size));
|
|||
|
*TupleBuffer = holdBuffer;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Copy the CIS information to a smaller buffer for the caller.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((PCMCIA_READ_TUPLE, "PcmciaReadCIS: size %d\n", size));
|
|||
|
RtlMoveMemory(currentBufferPointer, holdBuffer, size);
|
|||
|
ExFreePool(holdBuffer);
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PcicProcessConfigureRequest(
|
|||
|
IN PSOCKET SocketPtr,
|
|||
|
IN PVOID ConfigRequest,
|
|||
|
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
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCARD_REQUEST request = ConfigRequest;
|
|||
|
USHORT socket = request->Socket;
|
|||
|
USHORT index;
|
|||
|
UCHAR tmp;
|
|||
|
ULONG configRegisterBase;
|
|||
|
PCONFIG_QUERY_REQUEST query;
|
|||
|
|
|||
|
//
|
|||
|
// 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:
|
|||
|
|
|||
|
if (!request->u.Io.BasePort1) {
|
|||
|
DebugPrint((PCMCIA_DEBUG_FAIL,
|
|||
|
"PCMCIA: Got an IO Configure Request with an invalid Port\n"));
|
|||
|
break;
|
|||
|
} else {
|
|||
|
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD0_STRT_L,
|
|||
|
(UCHAR) (request->u.Io.BasePort1 & 0xff));
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD0_STRT_H,
|
|||
|
(UCHAR) (request->u.Io.BasePort1 >> 8));
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD0_STOP_L,
|
|||
|
(UCHAR) ((request->u.Io.BasePort1 +
|
|||
|
request->u.Io.NumPorts1) & 0xff));
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD0_STOP_H,
|
|||
|
(UCHAR) ((request->u.Io.BasePort1 +
|
|||
|
request->u.Io.NumPorts1) >> 8));
|
|||
|
}
|
|||
|
|
|||
|
if (request->u.Io.BasePort2 != 0) {
|
|||
|
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD1_STRT_L,
|
|||
|
(UCHAR) (request->u.Io.BasePort2 & 0xff));
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD1_STRT_H,
|
|||
|
(UCHAR) (request->u.Io.BasePort2 >> 8));
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD1_STOP_L,
|
|||
|
(UCHAR) ((request->u.Io.BasePort2 +
|
|||
|
request->u.Io.NumPorts2) & 0xff));
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_IO_ADD1_STOP_H,
|
|||
|
(UCHAR) ((request->u.Io.BasePort2 +
|
|||
|
request->u.Io.NumPorts2) >> 8));
|
|||
|
}
|
|||
|
|
|||
|
tmp = PcicReadController(Base,
|
|||
|
socket,
|
|||
|
PCIC_ADD_WIN_ENA);
|
|||
|
tmp |= request->u.Io.BasePort2 ? 0xc0 : 0x40;
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_ADD_WIN_ENA, tmp);
|
|||
|
|
|||
|
//
|
|||
|
// Now set up the datapath according to the attributes
|
|||
|
//
|
|||
|
|
|||
|
if (request->u.Io.Attributes1 & IO_DATA_PATH_WIDTH) {
|
|||
|
UCHAR waitState;
|
|||
|
|
|||
|
if (SocketPtr->ElcController || SocketPtr->CirrusLogic) {
|
|||
|
waitState = 0x03;
|
|||
|
} else {
|
|||
|
waitState = 0x0b;
|
|||
|
}
|
|||
|
tmp = 0;
|
|||
|
if (request->u.Io.BasePort2 != 0) {
|
|||
|
tmp |= waitState << 4;
|
|||
|
}
|
|||
|
tmp |= waitState;
|
|||
|
PcicWriteController(Base, socket, PCIC_IO_CONTROL, tmp);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IRQ_REQUEST:
|
|||
|
|
|||
|
//
|
|||
|
// Do not nuke the reset and cardtype bits.
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(Base, socket, PCIC_INTERRUPT);
|
|||
|
tmp |= request->u.Irq.AssignedIRQ;
|
|||
|
|
|||
|
PcicWriteController(Base, socket, PCIC_INTERRUPT, tmp);
|
|||
|
|
|||
|
if (tmp = request->u.Irq.ReadyIRQ) {
|
|||
|
tmp = (tmp << 4) | 0x04;
|
|||
|
PcicWriteController(Base, socket, PCIC_CARD_INT_CONFIG, tmp);
|
|||
|
}
|
|||
|
|
|||
|
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 = PcicReadController(Base, socket, PCIC_INTERRUPT);
|
|||
|
tmp |= 0x20;
|
|||
|
PcicWriteController(Base, socket, PCIC_INTERRUPT, tmp);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is where we setup the card and get it ready for operation
|
|||
|
//
|
|||
|
configRegisterBase = request->u.Config.ConfigBase;
|
|||
|
|
|||
|
if (configRegisterBase > (1 << 12)) {
|
|||
|
ULONG moduloBase;
|
|||
|
|
|||
|
moduloBase = configRegisterBase >> 12;
|
|||
|
moduloBase = moduloBase << 12;
|
|||
|
configRegisterBase &= 0x00000FFF;
|
|||
|
PcicEnableDisableAttributeMemory(SocketPtr, moduloBase, TRUE);
|
|||
|
} else {
|
|||
|
PcicEnableDisableAttributeMemory(SocketPtr, 0, TRUE);
|
|||
|
}
|
|||
|
if (!PcicPCCardReady(SocketPtr)) {
|
|||
|
DebugPrint((PCMCIA_PCCARD_READY,
|
|||
|
"PCIC: PCCARD %x not ready for configuration index\n",
|
|||
|
socket));
|
|||
|
}
|
|||
|
|
|||
|
if (request->u.Config.RegisterWriteMask & REGISTER_WRITE_CONFIGURATION_INDEX) {
|
|||
|
WRITE_REGISTER_UCHAR((PUCHAR)PcicCisBufferBase + configRegisterBase,
|
|||
|
request->u.Config.ConfigIndex);
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
WRITE_REGISTER_UCHAR((PUCHAR)PcicCisBufferBase + configRegisterBase,
|
|||
|
(UCHAR)(request->u.Config.ConfigIndex | 0x40));
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
}
|
|||
|
if (request->u.Config.RegisterWriteMask & REGISTER_WRITE_CARD_CONFIGURATION) {
|
|||
|
tmp = READ_REGISTER_UCHAR((PUCHAR)PcicCisBufferBase + configRegisterBase + 2);
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
|
|||
|
tmp |= request->u.Config.CardConfiguration;
|
|||
|
|
|||
|
//
|
|||
|
// turn off power control bit
|
|||
|
//
|
|||
|
|
|||
|
tmp &= ~0x04;
|
|||
|
WRITE_REGISTER_UCHAR((PUCHAR)PcicCisBufferBase + configRegisterBase + 2,
|
|||
|
tmp);
|
|||
|
KeStallExecutionProcessor(PcicStallCounter);
|
|||
|
}
|
|||
|
PcicEnableDisableAttributeMemory(SocketPtr, 0, FALSE);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case MEM_REQUEST:
|
|||
|
|
|||
|
//
|
|||
|
// Set up memory ranges on the controller.
|
|||
|
//
|
|||
|
|
|||
|
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);
|
|||
|
regl = (UCHAR) (cardBase >> 12);
|
|||
|
regh = (UCHAR) ((cardBase >> 20) & 0x003f);
|
|||
|
if (request->u.Memory.MemoryEntry[index].AttributeMemory) {
|
|||
|
regh |= 0x40;
|
|||
|
}
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_L + registerOffset),
|
|||
|
regl);
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
(UCHAR)(PCIC_CRDMEM_OFF_ADD0_H + registerOffset),
|
|||
|
regh);
|
|||
|
|
|||
|
//
|
|||
|
// Calculate and set host window.
|
|||
|
//
|
|||
|
|
|||
|
regl = (UCHAR) (base >> 12);
|
|||
|
regh = (UCHAR) (base >> 20);
|
|||
|
|
|||
|
if (request->u.Memory.MemoryEntry[index].WindowDataSize16) {
|
|||
|
regh |= 0x80; // 16-bit access
|
|||
|
|
|||
|
//
|
|||
|
// If this is not a revision 1 part (0x82), then set
|
|||
|
// the work around register for 16-bit windows.
|
|||
|
//
|
|||
|
|
|||
|
if (SocketPtr->Revision != PCIC_REVISION) {
|
|||
|
tmp = PcicReadController(Base,
|
|||
|
socket,
|
|||
|
PCIC_CARD_DETECT);
|
|||
|
tmp |= 0x01;
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
PCIC_CARD_DETECT,
|
|||
|
tmp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
(UCHAR)(PCIC_MEM_ADD0_STRT_L + registerOffset),
|
|||
|
regl);
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
(UCHAR)(PCIC_MEM_ADD0_STRT_H + registerOffset),
|
|||
|
regh);
|
|||
|
|
|||
|
//
|
|||
|
// Set stop address.
|
|||
|
//
|
|||
|
|
|||
|
base += size;
|
|||
|
regl = (UCHAR) (base >> 12);
|
|||
|
regh = (UCHAR) (base >> 20);
|
|||
|
PcicWriteController(Base,
|
|||
|
socket,
|
|||
|
(UCHAR)(PCIC_MEM_ADD0_STOP_L + registerOffset),
|
|||
|
regl);
|
|||
|
PcicWriteController(Base,
|
|||
|
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 |= PcicReadController(Base, socket, PCIC_ADD_WIN_ENA);
|
|||
|
PcicWriteController(Base, socket, PCIC_ADD_WIN_ENA, tmp);
|
|||
|
break;
|
|||
|
|
|||
|
case QUERY_REQUEST:
|
|||
|
|
|||
|
//
|
|||
|
// If the card has power collect its configuration. If it does not
|
|||
|
// have power, just return.
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(Base, socket, PCIC_PWR_RST);
|
|||
|
|
|||
|
if (tmp) {
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the query information structure.
|
|||
|
//
|
|||
|
|
|||
|
query = (PCONFIG_QUERY_REQUEST) request;
|
|||
|
RtlZeroMemory(query, sizeof(CONFIG_QUERY_REQUEST));
|
|||
|
|
|||
|
//
|
|||
|
// Process I/O port windows
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(Base, socket, PCIC_ADD_WIN_ENA);
|
|||
|
query->NumberOfIoPortRanges += (tmp & 0x80) ? 1 : 0;
|
|||
|
query->NumberOfIoPortRanges += (tmp & 0x40) ? 1 : 0;
|
|||
|
query->NumberOfMemoryRanges += (tmp & 0x01) ? 1 : 0;
|
|||
|
query->NumberOfMemoryRanges += (tmp & 0x02) ? 1 : 0;
|
|||
|
query->NumberOfMemoryRanges += (tmp & 0x04) ? 1 : 0;
|
|||
|
query->NumberOfMemoryRanges += (tmp & 0x08) ? 1 : 0;
|
|||
|
|
|||
|
query->IoPorts[0] =
|
|||
|
PcicReadController(Base, socket, PCIC_IO_ADD0_STRT_L) |
|
|||
|
(PcicReadController(Base, socket, PCIC_IO_ADD0_STRT_H) << 8);
|
|||
|
index = (PcicReadController(Base, socket, PCIC_IO_ADD0_STOP_L) |
|
|||
|
(PcicReadController(Base, socket, PCIC_IO_ADD0_STOP_H) << 8));
|
|||
|
query->IoPortLength[0] = index - query->IoPorts[0];
|
|||
|
|
|||
|
query->IoPorts[1] =
|
|||
|
PcicReadController(Base, socket, PCIC_IO_ADD1_STRT_L) |
|
|||
|
(PcicReadController(Base, socket, PCIC_IO_ADD1_STRT_H) << 8);
|
|||
|
index = (PcicReadController(Base, socket, PCIC_IO_ADD1_STOP_L) |
|
|||
|
(PcicReadController(Base, socket, PCIC_IO_ADD1_STOP_H) << 8));
|
|||
|
query->IoPortLength[1] = index - query->IoPorts[1];
|
|||
|
|
|||
|
tmp = PcicReadController(Base, socket, PCIC_IO_CONTROL);
|
|||
|
query->IoPort16[0] = tmp & 0x01;
|
|||
|
query->IoPort16[1] = tmp & 0x10;
|
|||
|
|
|||
|
//
|
|||
|
// Process Memory windows.
|
|||
|
//
|
|||
|
|
|||
|
for (index = 0; index < query->NumberOfMemoryRanges; index++) {
|
|||
|
ULONG host;
|
|||
|
ULONG card;
|
|||
|
ULONG length;
|
|||
|
|
|||
|
//
|
|||
|
// The the raw values
|
|||
|
//
|
|||
|
|
|||
|
tmp = (PcicReadController(Base,
|
|||
|
socket,
|
|||
|
(UCHAR) (PCIC_MEM_ADD0_STRT_H + (index * 8))) & 0x0f);
|
|||
|
host =
|
|||
|
(PcicReadController(Base, socket, (UCHAR) (PCIC_MEM_ADD0_STRT_L + (index * 8))) |
|
|||
|
((ULONG) tmp << 8));
|
|||
|
tmp = (PcicReadController(Base, socket, (UCHAR) (PCIC_MEM_ADD0_STOP_H + (index * 8))) & 0x0f);
|
|||
|
length =
|
|||
|
(PcicReadController(Base, socket, (UCHAR) (PCIC_MEM_ADD0_STOP_L + (index * 8))) |
|
|||
|
((ULONG) tmp << 8));
|
|||
|
tmp = PcicReadController(Base, socket, (UCHAR) (PCIC_CRDMEM_OFF_ADD0_H + (index * 8)));
|
|||
|
query->AttributeMemory[index] = (tmp & 0x40) ? 1 : 0;
|
|||
|
tmp &= 0x3f;
|
|||
|
card =
|
|||
|
(PcicReadController(Base, socket, (UCHAR) (PCIC_CRDMEM_OFF_ADD0_L + (index * 8))) |
|
|||
|
((ULONG) tmp << 8));
|
|||
|
|
|||
|
//
|
|||
|
// Convert the values into expected values
|
|||
|
//
|
|||
|
|
|||
|
length = length - host;
|
|||
|
card = (card + host) & 0x00003fff;
|
|||
|
host = host << 12;
|
|||
|
length = length << 12;
|
|||
|
card = card << 12;
|
|||
|
|
|||
|
query->HostMemoryWindow[index] = host;
|
|||
|
query->PCCARDMemoryWindow[index] = card;
|
|||
|
query->MemoryWindowLength[index] = length;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get IRQ
|
|||
|
//
|
|||
|
|
|||
|
query->DeviceIrq = PcicReadController(Base, socket, PCIC_INTERRUPT) & 0x0f;
|
|||
|
query->CardReadyIrq = (PcicReadController(Base, socket, PCIC_CARD_INT_CONFIG) & 0xf0) >> 8;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
DebugPrint((PCMCIA_DEBUG_FAIL, "PCMCIA: ConfigRequest is INVALID!\n"));
|
|||
|
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicDetectCardInSocket(
|
|||
|
IN PSOCKET SocketPtr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will determine if a card is in the socket
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketPtr -- Socket information
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if card is present.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR tmp;
|
|||
|
BOOLEAN cardPresent;
|
|||
|
PUCHAR base = SocketPtr->AddressPort;
|
|||
|
USHORT socket = SocketPtr->RegisterOffset;
|
|||
|
|
|||
|
//
|
|||
|
// Read the PCIC status register to see if the card is in there.
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_STATUS);
|
|||
|
tmp &= (CARD_DETECT_1 | CARD_DETECT_2);
|
|||
|
|
|||
|
if (tmp == (CARD_DETECT_1 | CARD_DETECT_2) ) {
|
|||
|
cardPresent = TRUE;
|
|||
|
} else {
|
|||
|
cardPresent = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return cardPresent;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicDetectCardChanged(
|
|||
|
IN PSOCKET SocketPtr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will determine if socket's card insertion status has changed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketPtr -- Socket info.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if card insertion status has changed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR tmp;
|
|||
|
PUCHAR Base = SocketPtr->AddressPort;
|
|||
|
USHORT Socket = SocketPtr->RegisterOffset;
|
|||
|
# define CARD_STATUS_CHANGE 8
|
|||
|
//
|
|||
|
// Read the PCIC CardStatusChange register to see if CD's have changed.
|
|||
|
//
|
|||
|
|
|||
|
return (PcicReadController(Base, Socket, PCIC_CARD_CHANGE) & CARD_STATUS_CHANGE
|
|||
|
?TRUE :FALSE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PcicEnableDisableAttributeMemory(
|
|||
|
IN PSOCKET SocketPtr,
|
|||
|
IN ULONG CardBase,
|
|||
|
IN BOOLEAN Enable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will enable or disable attribute memory. Use memory window
|
|||
|
four for the this function to avoid using any other memory windows that
|
|||
|
may already be programmed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketPtr -- Socket information
|
|||
|
CardBase -- card offset (base) for the attribute memory window
|
|||
|
Enable -- If TRUE, enable, if FALSE, disable
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
#define WINDOW_TO_USE 0x10
|
|||
|
UCHAR tmp;
|
|||
|
UCHAR low;
|
|||
|
UCHAR high;
|
|||
|
ULONG location;
|
|||
|
PUCHAR cisBufferPointer;
|
|||
|
PUCHAR base = SocketPtr->AddressPort;
|
|||
|
USHORT socket = SocketPtr->RegisterOffset;
|
|||
|
|
|||
|
if (Enable) {
|
|||
|
|
|||
|
//
|
|||
|
// Insure the window is off first.
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_ADD_WIN_ENA);
|
|||
|
tmp &= ~WINDOW_TO_USE;
|
|||
|
PcicWriteController(base, socket, PCIC_ADD_WIN_ENA, tmp);
|
|||
|
|
|||
|
//
|
|||
|
// Calculate and set the memory windows start and stop locations.
|
|||
|
//
|
|||
|
|
|||
|
location = PcicPhysicalBase;
|
|||
|
low = (UCHAR)(location >> 12);
|
|||
|
high = (UCHAR)(location >> 20);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STRT_L, low);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STRT_H, high);
|
|||
|
|
|||
|
location += 0x11000;
|
|||
|
low = (UCHAR)(location >> 12);
|
|||
|
high = (UCHAR)(location >> 20);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STOP_L, low);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STOP_H, high);
|
|||
|
|
|||
|
//
|
|||
|
// Set up the 2's complement card offset to zero
|
|||
|
//
|
|||
|
|
|||
|
location = CardBase - PcicPhysicalBase;
|
|||
|
low = (UCHAR)(location >> 12);
|
|||
|
high = (UCHAR)((location >> 20) & 0x3f);
|
|||
|
PcicWriteController(base, socket, PCIC_CRDMEM_OFF_ADD4_L, low);
|
|||
|
PcicWriteController(base, socket, PCIC_CRDMEM_OFF_ADD4_H, (UCHAR)(high | 0x40));
|
|||
|
|
|||
|
//
|
|||
|
// Insure that the pccard has power
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_PWR_RST);
|
|||
|
if ((tmp & 0x90) != 0x90) {
|
|||
|
tmp |= 0x10;
|
|||
|
PcicWriteController(base, socket, PCIC_PWR_RST, tmp);
|
|||
|
KeStallExecutionProcessor(PcicStallPower);
|
|||
|
|
|||
|
if (!PcicPCCardReady(SocketPtr)) {
|
|||
|
DebugPrint((PCMCIA_PCCARD_READY,
|
|||
|
"PCIC: PCCARD %x not ready for late power ON\n",
|
|||
|
socket));
|
|||
|
}
|
|||
|
|
|||
|
tmp |= 0x80;
|
|||
|
PcicWriteController(base, socket, PCIC_PWR_RST, tmp);
|
|||
|
KeStallExecutionProcessor(PcicStallPower);
|
|||
|
|
|||
|
if (!PcicPCCardReady(SocketPtr)) {
|
|||
|
DebugPrint((PCMCIA_PCCARD_READY,
|
|||
|
"PCIC: PCCARD %x not ready for late power on\n",
|
|||
|
socket));
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((PCMCIA_DEBUG_FAIL, "PCMCIA: Added power late\n"));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Enable the address window
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_ADD_WIN_ENA);
|
|||
|
tmp |= WINDOW_TO_USE | 0x20;
|
|||
|
PcicWriteController(base, socket, PCIC_ADD_WIN_ENA, tmp);
|
|||
|
KeStallExecutionProcessor(2000);
|
|||
|
|
|||
|
cisBufferPointer = PcicCisBufferBase;
|
|||
|
|
|||
|
if (READ_REGISTER_UCHAR(cisBufferPointer) == 0xff) {
|
|||
|
|
|||
|
//
|
|||
|
// Only wait for card ready if the memory window does not appear
|
|||
|
//
|
|||
|
|
|||
|
PcicPCCardReady(SocketPtr);
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Disable the Address window
|
|||
|
//
|
|||
|
|
|||
|
tmp = PcicReadController(base, socket, PCIC_ADD_WIN_ENA);
|
|||
|
tmp &= ~WINDOW_TO_USE;
|
|||
|
|
|||
|
PcicWriteController(base, socket, PCIC_ADD_WIN_ENA, tmp);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STRT_L, 0x00);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STRT_H, 0x00);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STOP_L, 0x00);
|
|||
|
PcicWriteController(base, socket, PCIC_MEM_ADD4_STOP_H, 0x00);
|
|||
|
PcicWriteController(base, socket, PCIC_CRDMEM_OFF_ADD4_L, 0x00);
|
|||
|
PcicWriteController(base, socket, PCIC_CRDMEM_OFF_ADD4_H, 0x00);
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicPCCardReady(
|
|||
|
IN PSOCKET SocketPtr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Loop for a reasonable amount of time waiting for the card status to
|
|||
|
return ready.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
SocketPtr - 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;
|
|||
|
PUCHAR base = SocketPtr->AddressPort;
|
|||
|
USHORT socket = SocketPtr->RegisterOffset;
|
|||
|
|
|||
|
for (index = 0; index < 500; index++) {
|
|||
|
|
|||
|
byte = PcicReadController(base, socket, PCIC_STATUS);
|
|||
|
if (byte & 0x20) {
|
|||
|
break;
|
|||
|
}
|
|||
|
KeStallExecutionProcessor(10);
|
|||
|
}
|
|||
|
|
|||
|
if (index < 500) {
|
|||
|
DebugPrint((PCMCIA_COUNTERS, "PcicPCCardReady: %d\n", index));
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PcicSearchPci(
|
|||
|
PDEVICE_EXTENSION DeviceExtension,
|
|||
|
ULONG BusNumber,
|
|||
|
PULONG IoPortLocation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Search all PCI bus slots for the given set of PCI controllers. This
|
|||
|
code will only find a SINGLE controller - it is not prepared to find
|
|||
|
multiple controllers at this time.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - a Cirrus Logic PCI part was found.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG pciBuffer;
|
|||
|
ULONG slotNumber;
|
|||
|
ULONG functionNumber;
|
|||
|
ULONG index;
|
|||
|
NTSTATUS status;
|
|||
|
PCI_SLOT_NUMBER pciSlotNumber;
|
|||
|
PPCI_COMMON_CONFIG pciData;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
PCM_RESOURCE_LIST resourceList;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialData;
|
|||
|
PCM_FULL_RESOURCE_DESCRIPTOR fullData;
|
|||
|
USHORT vendorID[] = { 0x1013, PCI_INVALID_VENDORID };
|
|||
|
USHORT deviceID[] = { 0x1100, PCI_INVALID_VENDORID };
|
|||
|
|
|||
|
|
|||
|
pciData = (PPCI_COMMON_CONFIG) &pciBuffer;
|
|||
|
pciSlotNumber.u.AsULONG = 0;
|
|||
|
|
|||
|
for (slotNumber = 0; slotNumber < 32; slotNumber++) {
|
|||
|
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI, "PcicSearchPci: slot %d\n", slotNumber));
|
|||
|
pciSlotNumber.u.bits.DeviceNumber = slotNumber;
|
|||
|
for (functionNumber = 0; functionNumber < 8; functionNumber++) {
|
|||
|
|
|||
|
pciSlotNumber.u.bits.FunctionNumber = functionNumber;
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicSearchPci: function %d\n",
|
|||
|
functionNumber));
|
|||
|
if (!HalGetBusData(PCIConfiguration,
|
|||
|
BusNumber,
|
|||
|
pciSlotNumber.u.AsULONG,
|
|||
|
pciData,
|
|||
|
sizeof(ULONG))) {
|
|||
|
|
|||
|
//
|
|||
|
// No PCI data.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI, "PcicSearchPci: No more HAL data\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (pciData->VendorID == PCI_INVALID_VENDORID) {
|
|||
|
|
|||
|
//
|
|||
|
// No more functions - move to next slot.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicSearchPci: checking %x:%x\n",
|
|||
|
pciData->VendorID,
|
|||
|
pciData->DeviceID));
|
|||
|
for (index = 0; vendorID[index] != PCI_INVALID_VENDORID; index++) {
|
|||
|
if (vendorID[index] == pciData->VendorID) {
|
|||
|
|
|||
|
if (deviceID[index] == pciData->DeviceID) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (vendorID[index] != PCI_INVALID_VENDORID) {
|
|||
|
|
|||
|
//
|
|||
|
// Found a controller - assign it slot resources and return.
|
|||
|
//
|
|||
|
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicSearchPci: FOUND %d:%d\n",
|
|||
|
slotNumber,
|
|||
|
functionNumber));
|
|||
|
RtlInitUnicodeString(&unicodeString, L"Pcmcia");
|
|||
|
status = HalAssignSlotResources(DeviceExtension->RegistryPath,
|
|||
|
&unicodeString,
|
|||
|
DeviceExtension->DriverObject,
|
|||
|
DeviceExtension->DeviceObject,
|
|||
|
PCIBus,
|
|||
|
BusNumber,
|
|||
|
pciSlotNumber.u.AsULONG,
|
|||
|
&resourceList);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI, "PcicSearchPci: No resources\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
fullData = resourceList->List;
|
|||
|
for (index = 0; index < fullData->PartialResourceList.Count; index++) {
|
|||
|
|
|||
|
partialData = &fullData->PartialResourceList.PartialDescriptors[index];
|
|||
|
switch (partialData->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicResource: Port %x:%x\n",
|
|||
|
partialData->u.Port.Start,
|
|||
|
partialData->u.Port.Length));
|
|||
|
*IoPortLocation = (ULONG)partialData->u.Port.Start.LowPart;
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicResource: Interrupt v=%d l=%d\n",
|
|||
|
partialData->u.Interrupt.Vector,
|
|||
|
partialData->u.Interrupt.Level));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicResource: Memory %x:%x\n",
|
|||
|
partialData->u.Memory.Start,
|
|||
|
partialData->u.Memory.Length));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicResource: Dma c=%x p=%x\n",
|
|||
|
partialData->u.Dma.Channel,
|
|||
|
partialData->u.Dma.Port));
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI,
|
|||
|
"PcicResource: Unknown resource\n"));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(resourceList);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DebugPrint((PCMCIA_SEARCH_PCI, "PcicSearchPci: All slots searched\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PcicDetect(
|
|||
|
IN PDEVICE_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 socket is found - failure status otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG ioPortBases[3] = { 0x3e0, 0x3e2, 0x3e4 };
|
|||
|
ULONG addressSpace;
|
|||
|
ULONG index;
|
|||
|
PUCHAR port;
|
|||
|
PUCHAR elcPort;
|
|||
|
UCHAR saveBytes[2];
|
|||
|
UCHAR dataByte;
|
|||
|
UCHAR revisionByte;
|
|||
|
USHORT socket;
|
|||
|
BOOLEAN translated;
|
|||
|
BOOLEAN isPci;
|
|||
|
BOOLEAN foundOne;
|
|||
|
BOOLEAN foundSomething;
|
|||
|
BOOLEAN mapped;
|
|||
|
BOOLEAN elcChip;
|
|||
|
BOOLEAN cirrusLogic;
|
|||
|
PSOCKET socketPtr;
|
|||
|
PSOCKET previousSocketPtr;
|
|||
|
PHYSICAL_ADDRESS cardAddress;
|
|||
|
PHYSICAL_ADDRESS portAddress;
|
|||
|
|
|||
|
previousSocketPtr = NULL;
|
|||
|
foundOne = FALSE;
|
|||
|
isPci = PcicSearchPci(DeviceExtension, 0, &ioPortBases[0]);
|
|||
|
|
|||
|
for (index = 0; index < 3; index++) {
|
|||
|
addressSpace = 1; // port space
|
|||
|
portAddress.LowPart = ioPortBases[index];
|
|||
|
portAddress.HighPart = 0;
|
|||
|
|
|||
|
translated = HalTranslateBusAddress(isPci ? PCIBus : Isa,
|
|||
|
0,
|
|||
|
portAddress,
|
|||
|
&addressSpace,
|
|||
|
&cardAddress);
|
|||
|
|
|||
|
if (!translated) {
|
|||
|
|
|||
|
//
|
|||
|
// HAL would not translate the address.
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (addressSpace) {
|
|||
|
mapped = FALSE;
|
|||
|
port = (PUCHAR)cardAddress.LowPart;
|
|||
|
} else {
|
|||
|
mapped = TRUE;
|
|||
|
port = MmMapIoSpace(cardAddress,
|
|||
|
2,
|
|||
|
FALSE);
|
|||
|
}
|
|||
|
|
|||
|
foundSomething = elcChip = cirrusLogic = FALSE;
|
|||
|
for (socket = 0; socket < 0xFF; socket += 0x40) {
|
|||
|
dataByte = PcicReadController(port, socket, PCIC_IDENT);
|
|||
|
revisionByte = dataByte;
|
|||
|
|
|||
|
switch (dataByte) {
|
|||
|
case PCIC_REVISION:
|
|||
|
cirrusLogic = TRUE;
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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 = ioPortBases[index] + 0x8000;
|
|||
|
portAddress.HighPart = 0;
|
|||
|
|
|||
|
translated = HalTranslateBusAddress(Isa,
|
|||
|
0,
|
|||
|
portAddress,
|
|||
|
&addressSpace,
|
|||
|
&cardAddress);
|
|||
|
|
|||
|
if (translated) {
|
|||
|
|
|||
|
if (!addressSpace) {
|
|||
|
elcPort = MmMapIoSpace(cardAddress,
|
|||
|
2,
|
|||
|
FALSE);
|
|||
|
} else {
|
|||
|
elcPort = (PUCHAR)cardAddress.LowPart;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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);
|
|||
|
elcChip = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (cirrusLogic) {
|
|||
|
ULONG i;
|
|||
|
UCHAR data[4];
|
|||
|
|
|||
|
//
|
|||
|
// The Cirrus Logic will toggle the top two lines
|
|||
|
// from the 0x1f register on the chip. Read this
|
|||
|
// location 3 times and verify that the top two
|
|||
|
// lines are changing.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(port, (UCHAR)(socket + 0x1f));
|
|||
|
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) {
|
|||
|
cirrusLogic = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Need to program the chip per code in
|
|||
|
// Windows 95. This will turn on the
|
|||
|
// audio support bit.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(port, (UCHAR)(socket + 0x16));
|
|||
|
dataByte = READ_PORT_UCHAR(port+1);
|
|||
|
dataByte |= 0x10;
|
|||
|
WRITE_PORT_UCHAR(port+1, dataByte);
|
|||
|
} else {
|
|||
|
cirrusLogic = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 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);
|
|||
|
}
|
|||
|
|
|||
|
socketPtr = ExAllocatePool(NonPagedPool, sizeof(SOCKET));
|
|||
|
if (!socketPtr) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
RtlZeroMemory(socketPtr, sizeof(SOCKET));
|
|||
|
|
|||
|
socketPtr->DeviceExtension = DeviceExtension;
|
|||
|
socketPtr->SocketFnPtr = &PcicSupportFns;
|
|||
|
socketPtr->RegisterOffset = socket;
|
|||
|
socketPtr->AddressPort = port;
|
|||
|
socketPtr->ElcController = elcChip;
|
|||
|
socketPtr->CirrusLogic = cirrusLogic;
|
|||
|
socketPtr->Revision = revisionByte;
|
|||
|
socketPtr->SocketConfigured = FALSE;
|
|||
|
|
|||
|
if (previousSocketPtr) {
|
|||
|
previousSocketPtr->NextSocket = socketPtr;
|
|||
|
} else {
|
|||
|
DeviceExtension->SocketList = socketPtr;
|
|||
|
}
|
|||
|
previousSocketPtr = socketPtr;
|
|||
|
foundOne = foundSomething = TRUE;
|
|||
|
DeviceExtension->Configuration.UntranslatedPortAddress = (USHORT)ioPortBases[index];
|
|||
|
DeviceExtension->Configuration.PortSize = 2;
|
|||
|
DebugPrint((PCMCIA_DEBUG_DETECT,
|
|||
|
"PCMCIA: Port %x Offset %x Elc %d\n",
|
|||
|
port,
|
|||
|
socket,
|
|||
|
elcChip));
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
DebugPrint((PCMCIA_DEBUG_FAIL,
|
|||
|
"PCMCIA: The controller (0x%x:0x%x) is either not present or it is an\n",
|
|||
|
portAddress.LowPart,
|
|||
|
socket));
|
|||
|
DebugPrint((PCMCIA_DEBUG_FAIL,
|
|||
|
"\tearlier revision of the controller. Return was %x\n",
|
|||
|
dataByte));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((!foundSomething) && mapped) {
|
|||
|
MmUnmapIoSpace(port, 2);
|
|||
|
}
|
|||
|
|
|||
|
if (isPci) {
|
|||
|
|
|||
|
//
|
|||
|
// The problem controller has been moved to a new location
|
|||
|
// search the remaining addresses.
|
|||
|
//
|
|||
|
|
|||
|
isPci = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return foundOne ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PcicGetRegisters(
|
|||
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|||
|
IN PSOCKET SocketPtr,
|
|||
|
IN PUCHAR Buffer
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Return the flat 82365SL register values. This routine is used
|
|||
|
for debugging.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceExtension - not used
|
|||
|
SocketPtr - socket information
|
|||
|
Buffer - the memory for receiving the values
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR index;
|
|||
|
PUCHAR port = SocketPtr->AddressPort;
|
|||
|
USHORT socket = SocketPtr->RegisterOffset;
|
|||
|
|
|||
|
for (index = 0; index < 0x40; index++) {
|
|||
|
Buffer[index] = PcicReadController(port, socket, index);
|
|||
|
}
|
|||
|
}
|