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);
|
||
}
|
||
}
|