NT4/private/ntos/dd/pcmcia/tuples.c
2020-09-30 17:12:29 +02:00

1461 lines
34 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
pcmcia.c
Abstract:
This module contains the code that controls the PCMCIA slots.
Author:
Bob Rinne (BobRi) 3-Aug-1994
Jeff McLeman 12-Apr-1994
Environment:
Kernel mode
Revision History :
--*/
// #include <stddef.h>
#include "ntddk.h"
#include "string.h"
#include "pcmcia.h"
#include "card.h"
#include "extern.h"
#include <stdarg.h>
#include "stdio.h"
#include "tuple.h"
UCHAR
ConvertVoltage(
UCHAR MantissaExponentByte,
UCHAR ExtensionByte
);
PUCHAR
PcmciaProcessPower(
PSOCKET_DATA SocketData,
PUCHAR Data,
UCHAR FeatureByte
);
PUCHAR
PcmciaProcessIoSpace(
PCONFIG_ENTRY ConfigEntry,
PUCHAR Data
);
PUCHAR
PcmciaProcessIrq(
PSOCKET_DATA SocketData,
PCONFIG_ENTRY ConfigEntry,
PUCHAR Data
);
PUCHAR
PcmciaProcessTiming(
IN PCONFIG_ENTRY ConfigEntry,
IN PUCHAR Data
);
PUCHAR
PcmciaProcessMemSpace(
IN PCONFIG_ENTRY ConfigEntry,
IN PUCHAR Data,
IN UCHAR MemSpace
);
PUCHAR
PcmciaMiscFeatures(
PSOCKET_DATA SocketData,
PUCHAR Data
);
PCONFIG_ENTRY
PcmciaProcessConfigTable(
IN PUCHAR TupleData,
IN PSOCKET_DATA SocketData
);
VOID
ProcessConfig(
IN PUCHAR Tuple,
IN PSOCKET_DATA SocketData
);
VOID
PcmciaCheckForRecognizedDevice(
PSOCKET_DATA SocketData
);
PCONFIG_ENTRY
InitTertiaryATAConfigEntry(
PCONFIG_ENTRY ConfigEntryChain
);
VOID
PcmciaProcessFuncExtention(
IN PUCHAR Tuple,
IN PSOCKET_DATA SocketData
);
#ifdef POOL_TAGGING
#undef ExAllocatePool
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'cmcP')
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,ConvertVoltage)
#pragma alloc_text(INIT,PcmciaProcessPower)
#pragma alloc_text(INIT,PcmciaProcessIoSpace)
#pragma alloc_text(INIT,PcmciaProcessIrq)
#pragma alloc_text(INIT,PcmciaProcessTiming)
#pragma alloc_text(INIT,PcmciaProcessMemSpace)
#pragma alloc_text(INIT,PcmciaMiscFeatures)
#pragma alloc_text(INIT,PcmciaProcessConfigTable)
#pragma alloc_text(INIT,ProcessConfig)
#pragma alloc_text(INIT,PcmciaCheckForRecognizedDevice)
#pragma alloc_text(INIT,InitTertiaryATAConfigEntry)
#endif
USHORT VoltageConversionTable[16] = {
10, 12, 13, 14, 20, 25, 30, 35,
40, 45, 50, 55, 60, 70, 80, 90
};
UCHAR TplList[] = {
CISTPL_DEVICE,
CISTPL_VERS_1,
CISTPL_CONFIG,
CISTPL_CFTABLE_ENTRY,
CISTPL_MANFID,
CISTPL_END
};
static unsigned short crc16a[] = {
0000000, 0140301, 0140601, 0000500,
0141401, 0001700, 0001200, 0141101,
0143001, 0003300, 0003600, 0143501,
0002400, 0142701, 0142201, 0002100,
};
static unsigned short crc16b[] = {
0000000, 0146001, 0154001, 0012000,
0170001, 0036000, 0024000, 0162001,
0120001, 0066000, 0074000, 0132001,
0050000, 0116001, 0104001, 0043000,
};
USHORT
GetCRC(
PUCHAR TupleBuffer
)
/*++
Routine Description:
Using the same algorithm as Windows 95, calculate the CRC value
to be appended with the manufacturer name and device name to
obtain the unique identifier for the PCCARD.
Arguments:
TupleBuffer - the tuple data
Return Value:
A USHORT CRC value.
--*/
{
USHORT crc = 0;
USHORT index;
USHORT length;
PUCHAR tupleData;
PUCHAR cp;
PUCHAR tplBuffer;
UCHAR tupleCode;
UCHAR linkValue;
UCHAR tmp;
//
// Calculate CRC
//
tplBuffer = TupleBuffer;
while (1) {
tupleData = tplBuffer + 2;
tupleCode = *tplBuffer++;
if (tupleCode == CISTPL_END) {
break;
}
linkValue = (tupleCode) ? *tplBuffer++ : 0;
length = linkValue;
for (index = 0; TplList[index] != CISTPL_END; index++) {
if (tupleCode == TplList[index]) {
//
// This one is included in the CRC calculation
//
if (tupleCode == CISTPL_VERS_1) {
cp = tupleData + 2;
//
// Include all of the manufacturer name.
//
while (*cp) {
cp++;
}
//
// Include the product string
//
cp++;
while (*cp) {
cp++;
}
cp++;
length = cp - tupleData;
}
for (cp = tupleData; length; length--, cp++) {
tmp = *cp ^ (UCHAR)crc;
crc = (crc >> 8) ^ crc16a[tmp & 0x0f] ^ crc16b[tmp >> 4];
}
break;
}
}
tplBuffer = tplBuffer + linkValue;
}
return crc;
}
UCHAR
ConvertVoltage(
UCHAR MantissaExponentByte,
UCHAR ExtensionByte
)
/*++
Routine Description:
Convert the voltage requirements for the PCCARD based on the
mantissa and extension byte.
Arguments:
MantissaExponentByte
ExtensionByte
Return Value:
The voltage required.
--*/
{
USHORT power;
USHORT value;
value = VoltageConversionTable[(MantissaExponentByte >> 3) & 0x0f];
power = 1;
if ((MantissaExponentByte & EXTENSION_BYTE_FOLLOWS) &&
(ExtensionByte < 100)) {
value = (100 * value + (ExtensionByte & 0x7f));
power += 2;
}
power = (MantissaExponentByte & 0x07) - 4 - power;
while (power > 0) {
value *= 10;
power--;
}
while (power < 0) {
value /= 10;
power++;
}
return (UCHAR) value;
}
PUCHAR
PcmciaProcessPower(
PSOCKET_DATA SocketData,
PUCHAR Data,
UCHAR FeatureByte
)
/*++
Routine Description:
Process power information from CIS.
Arguments:
SocketData - the specific socket.
Data - the power information from CIS.
FeatureByte - the feature byte from the tuple containing power information.
Return Value:
The byte after the power information.
--*/
{
UCHAR powerSelect;
UCHAR bit;
UCHAR item;
UCHAR rawItem;
UCHAR index = 0;
PUCHAR ptr = Data;
UCHAR count = FeatureByte;
while (index < count) {
powerSelect = *ptr++;
for (bit = 0; bit < 7; bit++) {
if (powerSelect & (1 << bit)) {
if (!bit) {
//
// Convert nominal power for output.
//
rawItem = *ptr;
item = ConvertVoltage(*ptr,
(UCHAR)((*ptr & EXTENSION_BYTE_FOLLOWS) ?
*(ptr + 1) :
(UCHAR) 0));
}
while (*ptr++ & EXTENSION_BYTE_FOLLOWS) {
}
}
switch (index) {
case 0:
SocketData->Vcc = item;
case 1:
SocketData->Vpp2 = SocketData->Vpp1 = item;
case 2:
SocketData->Vpp2 = item;
}
}
index++;
}
return ptr;
}
PUCHAR
PcmciaProcessIoSpace(
PCONFIG_ENTRY ConfigEntry,
PUCHAR Data
)
/*++
Routine Description:
Process I/O space information from CIS.
Arguments:
ConfigEntry - a config entry structure in which to store the information.
Data - the I/O Space information pointer.
Return Value:
A pointer to the next byte after the end of the IoSpace structure.
--*/
{
PUCHAR ptr = Data;
UCHAR item = *ptr++;
UCHAR ioAddrLines = (item & IO_ADDRESS_LINES_MASK);
UCHAR ranges;
UCHAR addressSize;
UCHAR lengthSize;
ULONG address;
ULONG index;
ConfigEntry->Uses16BitAccess = Is16BitAccess(item);
ConfigEntry->Uses8BitAccess = Is8BitAccess(item);
ranges = HasRanges(item);
if ((!ranges) && (!ioAddrLines)) {
//
// The IBM token ring card has a slightly different interpretation
// of the tuple data here. It isn't clear it is incorrect.
//
ranges = 0xFF;
}
if (ranges) {
//
// Specific ranges listed in the tuple.
//
if (ranges == 0xFF) {
//
// Special processing for IBM token ring IoSpace layout.
//
addressSize = 2;
lengthSize = 1;
ranges = 1;
} else {
item = *ptr++;
ranges = item & RANGE_MASK;
ranges++;
addressSize = GetAddressSize(item);
lengthSize = GetLengthSize(item);
}
index = 0;
while (ranges) {
address = 0;
switch (addressSize) {
case 4:
address |= (*(ptr + 3)) << 24;
case 3:
address |= (*(ptr + 2)) << 16;
case 2:
address |= (*(ptr + 1)) << 8;
case 1:
address |= *ptr;
}
ptr += addressSize;
ConfigEntry->IoPortBase[index] = (USHORT) address;
address = 0;
switch (lengthSize) {
case 4:
address |= (*(ptr + 3)) << 24;
case 3:
address |= (*(ptr + 2)) << 16;
case 2:
address |= (*(ptr + 1)) << 8;
case 1:
address |= *ptr;
}
ptr += lengthSize;
ConfigEntry->IoPortLength[index] = (USHORT) address;
index++;
if (index == MAX_NUMBER_OF_IO_RANGES) {
break;
}
ranges--;
}
ConfigEntry->NumberOfIoPortRanges = (USHORT) index;
} else {
//
// Modulo case.
//
switch (ioAddrLines) {
case 1:
ConfigEntry->ModuloBase = 2;
break;
case 2:
ConfigEntry->ModuloBase = 4;
break;
case 3:
ConfigEntry->ModuloBase = 8;
break;
case 4:
ConfigEntry->ModuloBase = 16;
break;
case 5:
ConfigEntry->ModuloBase = 32;
break;
case 6:
ConfigEntry->ModuloBase = 64;
break;
default:
//
// Don't believe that the PCCARD wants 128 ports.
//
ConfigEntry->ModuloBase = 32;
break;
}
}
return ptr;
}
PUCHAR
PcmciaProcessIrq(
PSOCKET_DATA SocketData,
PCONFIG_ENTRY ConfigEntry,
PUCHAR Data
)
/*++
Routine Description:
Process IRQ from CIS.
Arguments:
SocketData - the socket with the PCCARD
ConfigEntry - a place to store the IRQ.
Data - the IRQ information from CIS.
Return Value:
A pointer to the next byte after the end of the IRQ structure.
--*/
{
PUCHAR ptr = Data;
UCHAR level = *ptr++;
USHORT mask;
if (!level) {
//
// NOTE: It looks like Future Domain messed up on this
// and puts an extra zero byte into the structure.
// skip it for now.
//
level = *ptr++;
}
SocketData->LevelIrq = level & 0x20;
SocketData->SharedIrq = level & 0x80;
if (level & 0x10) {
SocketData->IrqMask = *ptr | (*(ptr + 1) << 8);
ptr += 2;
} else {
SocketData->IrqMask = 1 << (*ptr & 0x0f);
ConfigEntry->Irq = (*ptr & 0x0f);
}
return ptr;
}
PUCHAR
PcmciaProcessTiming(
IN PCONFIG_ENTRY ConfigEntry,
IN PUCHAR Data
)
/*++
Routine Description:
Move the data pointer around the timing information structure.
No processing of this data occurs at this time.
Arguments:
ConfigEntry - currently unused.
Data - the first byte of the timing information structure.
Return Value:
A pointer to the next byte after the end of the timing structure.
--*/
{
PUCHAR ptr = Data;
UCHAR item = *ptr++;
UCHAR reservedScale = (item & 0xe0) >> 5;
UCHAR readyBusyScale = (item & 0x1c) >> 2;
UCHAR waitScale = (item & 0x03);
//
// NOTE: It looks like the processing of extension bytes is not
// coded correctly in this routine.
//
if (waitScale != 3) {
while (*ptr & EXTENSION_BYTE_FOLLOWS) {
ptr++;
}
ptr++;
}
if (readyBusyScale != 7) {
while (*ptr & EXTENSION_BYTE_FOLLOWS) {
ptr++;
}
ptr++;
}
if (reservedScale != 7) {
while (*ptr & EXTENSION_BYTE_FOLLOWS) {
ptr++;
}
ptr++;
}
return ptr;
}
PUCHAR
PcmciaProcessMemSpace(
IN PCONFIG_ENTRY ConfigEntry,
IN PUCHAR Data,
IN UCHAR MemSpace
)
/*++
Routine Description:
Process memory space requirements from CIS.
Arguments:
ConfigEntry - the socket configuration structure.
Data - the first byte of the memory space structure.
MemSpace - the memory space enumerator from the config table entry
structure.
Return Value:
A pointer to the next byte after the end of the memory space structure.
--*/
{
PUCHAR ptr = Data;
UCHAR item = *ptr++;
UCHAR lengthSize;
UCHAR addrSize;
UCHAR number;
UCHAR hasHostAddress;
ULONG longValue;
ULONG index;
if (MemSpace == 3) {
lengthSize = (item & 0x18) >> 3;
addrSize = (item & 0x60) >> 5;
number = (item & 0x07) + 1;
hasHostAddress = item & 0x80;
for (index = 0; index < (ULONG) number; index++) {
longValue = 0;
switch (lengthSize) {
case 3:
longValue |= (*(ptr + 2)) << 16;
case 2:
longValue |= (*(ptr + 1)) << 8;
case 1:
longValue |= *ptr;
}
ConfigEntry->MemoryLength[index] = longValue * 256;
ptr += lengthSize;
longValue = 0;
switch (addrSize) {
case 3:
longValue |= (*(ptr + 2)) << 16;
case 2:
longValue |= (*(ptr + 1)) << 8;
case 1:
longValue |= *ptr;
}
ConfigEntry->MemoryCardBase[index] = longValue * 256;
ptr += addrSize;
if (hasHostAddress) {
longValue = 0;
switch (addrSize) {
case 3:
longValue |= (*(ptr + 2)) << 16;
case 2:
longValue |= (*(ptr + 1)) << 8;
case 1:
longValue |= *ptr;
}
ConfigEntry->MemoryHostBase[index] = longValue * 256;
ptr += addrSize;
}
}
ConfigEntry->NumberOfMemoryRanges = (USHORT) number;
}
return ptr;
}
PCONFIG_ENTRY
PcmciaProcessConfigTable(
IN PUCHAR TupleData,
IN PSOCKET_DATA SocketData
)
/*++
Routine Description:
Arguments:
TupleData - pointer to the first byte of the CFTABLE tuple.
SocketData - The socket data and generic description of the PCCARD.
Return Value:
A pointer to a config entry structure if one is created.
--*/
{
PCONFIG_ENTRY configEntry;
PUCHAR ptr;
BOOLEAN returnEntry;
UCHAR item;
UCHAR defaultbit;
UCHAR memSpace;
UCHAR power;
UCHAR misc;
configEntry = ExAllocatePool(NonPagedPool, sizeof(CONFIG_ENTRY));
if (!configEntry) {
return NULL;
}
RtlZeroMemory(configEntry, sizeof(CONFIG_ENTRY));
//
// Only return a configuration entry if it describes I/O ports
// interrupts or memory map.
//
returnEntry = FALSE;
ptr = TupleData;
item = *ptr++;
configEntry->DefaultConfiguration = Default(item);
configEntry->IndexForThisConfiguration = ConfigEntryNumber(item);
if (IntFace(item)) {
//
// This byte indicates type of interface in tuple (i.e. io or memory)
// This could be processed, but for now is just skipped.
//
item = *ptr++;
}
item = *ptr++;
memSpace = MemSpaceInformation(item);
power = PowerInformation(item);
misc = MiscInformation(item);
if (power = PowerInformation(item)) {
ptr = PcmciaProcessPower(SocketData, ptr, power);
}
if (TimingInformation(item)) {
ptr = PcmciaProcessTiming(configEntry, ptr);
}
if (IoSpaceInformation(item)) {
ptr = PcmciaProcessIoSpace(configEntry, ptr);
returnEntry = TRUE;
}
if (IRQInformation(item)) {
ptr = PcmciaProcessIrq(SocketData, configEntry, ptr);
returnEntry = TRUE;
}
if (memSpace) {
ptr = PcmciaProcessMemSpace(configEntry, ptr, memSpace);
returnEntry = TRUE;
}
if (misc) {
ptr = PcmciaMiscFeatures(SocketData, ptr);
returnEntry = TRUE;
}
//
// NOTE - this may will throw away timing information.
//
if (!returnEntry) {
ExFreePool(configEntry);
configEntry = NULL;
}
return configEntry;
}
PUCHAR
PcmciaMiscFeatures(
PSOCKET_DATA SocketData,
PUCHAR Data
)
/*++
Routine Description:
Parse the miscellaneous features field and look for audio supported
bit.
Arguments:
SocketData - the informatin structure for the socket.
Data - the first byte of the miscellaneous features structure.
Return Value:
A pointer to the next byte after the end of the miscellaneous features structure.
--*/
{
DebugPrint((PCMCIA_DEBUG_TUPLES,
"TPCE_MS (%lx) is pressent in CISTPL_CFTABLE_ENTRY \n",
*Data));
//
// If the audio bit is set, remember this in the socket information
// structure.
//
if(*Data & 0x8) {
DebugPrint((PCMCIA_DEBUG_TUPLES,
"Audio bit set in TPCE_MS \n"));
SocketData->Audio = TRUE;
}
//
// Step around the miscellaneous features and its extension bytes.
//
while (*Data++ & EXTENSION_BYTE_FOLLOWS) {
//
// No action in the while
//
}
return Data;
}
VOID
ProcessConfig(
IN PUCHAR Tuple,
IN PSOCKET_DATA SocketData
)
/*++
Routine Description:
Parse the CISTPL_CONFIG to extract the last index value and the
configuration register base for the PCCARD.
Arguments:
Tuple - pointer to the config tuple
SocketData - structure to fill in.
Return Value:
None
--*/
{
PUCHAR localBufferPointer = Tuple + 2; // skip tuple code and link
ULONG base = 0;
UCHAR numberOfBytes;
UCHAR numberOfBytesInRegPresentMask;
numberOfBytes = (*localBufferPointer & 0x03) + 1;
numberOfBytesInRegPresentMask = (*localBufferPointer & TPCC_RMSZ_MASK) + 1;
localBufferPointer++;
SocketData->LastEntryInCardConfig = *localBufferPointer;
localBufferPointer++;
switch (numberOfBytes) {
case 4:
base = ((ULONG)(*(localBufferPointer + 3)) << 24);
case 3:
base |= ((ULONG)(*(localBufferPointer + 2)) << 16);
case 2:
base |= ((ULONG)(*(localBufferPointer + 1)) << 8);
case 1:
base |= *localBufferPointer;
break;
default:
DebugPrint((PCMCIA_DEBUG_FAIL,
"PCMCIA: ProcessConfig - bad number of bytes %d\n",
numberOfBytes));
break;
}
SocketData->u.ConfigRegisterBase = (PUCHAR) base;
DebugPrint((PCMCIA_DEBUG_TUPLES,
"PCMCIA: ConfigRegisterBase in attribute memory is %8x\n",
SocketData->u.ConfigRegisterBase));
//
// Save first byte of the registry present mask.
// I will throw away number of bytes used by the
// registry present mask.
//
DebugPrint((PCMCIA_DEBUG_TUPLES,
"PCMCIA: NumberOfBytesInRegPresentMask (%x)\n",
numberOfBytesInRegPresentMask));
SocketData->RegistersPresentMask = *(localBufferPointer + numberOfBytes);
DebugPrint((PCMCIA_DEBUG_TUPLES,
"PCMCIA: First Byte in present mask (%x)\n",
SocketData->RegistersPresentMask));
}
PSOCKET_DATA
PcmciaParseCardData(
IN PUCHAR TupleData
)
/*++
Routine Description:
Parses the CIS and builds a socket structure
Arguments:
TupleData -- Pointer to the CIS
Return Value:
SocketData -- Pointer to the socket data structure
--*/
{
UCHAR dataByte;
UCHAR link;
UCHAR lastIndex;
ULONG byteCount;
PUCHAR localBufferPointer;
PUCHAR tmp;
PSOCKET_DATA socketData;
PCONFIG_ENTRY configEntry;
PCONFIG_ENTRY prevEntry;
DebugPrint((PCMCIA_DEBUG_TUPLES, "PCMCIA: Parsing Card Data....\n"));
socketData = (PSOCKET_DATA)ExAllocatePool(NonPagedPool, sizeof(SOCKET_DATA));
if (!socketData) {
return NULL;
}
RtlZeroMemory(socketData, sizeof(SOCKET_DATA));
//
// Get the CIS checksum
//
socketData->CisCrc = GetCRC(TupleData);
//
// Get Mfg name and card name
//
localBufferPointer = TupleData;
dataByte = *localBufferPointer;
if (dataByte == CISTPL_END) {
DebugPrint((PCMCIA_DEBUG_TUPLES, "DataByte was -1 -- returning to caller\n"));
return socketData;
}
//
// Find the version tuple.
//
while ((dataByte != CISTPL_VERS_1) && (dataByte != CISTPL_END)) {
localBufferPointer++;
link = *localBufferPointer;
DebugPrint((PCMCIA_DEBUG_TUPLES, "DataByte %2x - Link %2x\n", dataByte, link));
localBufferPointer += (link+1);
dataByte = *localBufferPointer;
}
//
// Extract manufacturer name and card name.
//
localBufferPointer += 4; // To string fields
tmp = localBufferPointer;
byteCount = 0;
while ((*tmp != '\0') && (*tmp != (UCHAR)0xff)) {
byteCount += 1;
tmp += 1;
}
RtlMoveMemory((PUCHAR)&socketData->Mfg, localBufferPointer, byteCount + 1);
DebugPrint((PCMCIA_DEBUG_TUPLES, "Manufacturer: %s\n", &socketData->Mfg));
localBufferPointer += (byteCount);
localBufferPointer++;
tmp = localBufferPointer;
byteCount = 0;
while ((*tmp != '\0') && (*tmp != (UCHAR)0xff)) {
byteCount += 1;
tmp += 1;
}
RtlMoveMemory((PUCHAR)&socketData->Ident, localBufferPointer, byteCount + 1);
DebugPrint((PCMCIA_DEBUG_TUPLES, "Identifier: %s\n", &socketData->Ident));
DebugPrint((PCMCIA_DEBUG_TUPLES, "PCMCIA:SocketData address is %x\n", socketData));
//
// get the device configuration base
//
localBufferPointer = TupleData;
dataByte = *localBufferPointer;
while ((dataByte != CISTPL_CONFIG) && (dataByte != CISTPL_END)) {
localBufferPointer++;
link = *localBufferPointer;
DebugPrint((PCMCIA_DEBUG_TUPLES, "DataByte %2x - Link %2x\n", dataByte, link));
localBufferPointer += (link+1);
dataByte = *localBufferPointer;
}
if (dataByte == CISTPL_CONFIG) {
ProcessConfig(localBufferPointer, socketData);
}
//
// Get the possible configuations supported.
//
localBufferPointer = TupleData;
dataByte = *localBufferPointer;
prevEntry = NULL;
while (dataByte != CISTPL_END) {
localBufferPointer++;
link = *localBufferPointer;
if (dataByte == CISTPL_CFTABLE_ENTRY) {
//
// construct a possible configuration entry for this device
//
configEntry = PcmciaProcessConfigTable((localBufferPointer + 1),
socketData);
if (configEntry) {
DebugPrint((PCMCIA_DEBUG_PARSE,
"PCMCIA: link config 0x%4x->0x%4x\n",
configEntry,
socketData->ConfigEntryChain));
//
// Link configurations at the end of the list.
//
configEntry->NextEntry = NULL;
if (prevEntry) {
prevEntry->NextEntry = configEntry;
} else {
socketData->ConfigEntryChain = configEntry;
}
prevEntry = configEntry;
DebugPrint((PCMCIA_DUMP_CONFIG,
"PCMCIA dump: port 0x%2x length 0x%2x ccr 0x%2x index 0x%2x\n",
configEntry->IoPortBase[0],
configEntry->IoPortLength[0],
socketData->u.ConfigRegisterBase,
configEntry->IndexForThisConfiguration));
}
}
localBufferPointer += (link+1);
dataByte = *localBufferPointer;
}
return socketData;
}
PCONFIG_ENTRY
InitTertiaryATAConfigEntry(
PCONFIG_ENTRY ConfigEntryChain
)
/*++
Routine Description:
Make the configEntry for the continuous I/O mapping mode
the last entry in the ConfigEntryChain. This is done so that
PcmciaConstructConfiguration(..) doesn't use this entry unless
the primary and the secondary ATA locations are in use.
Order the primary and secondary ATA locations as the 1st two in
the list if present.
Arguments:
ConfigEntryChain - Config entry chain for a ATA PCMCIA device.
Return Value:
ConfigEntryChain - The new sorted and init config entry chain.
--*/
{
PCONFIG_ENTRY configEntry;
PCONFIG_ENTRY prevSourceChain;
PCONFIG_ENTRY currentNewChain;
PCONFIG_ENTRY chainBase;
PCONFIG_ENTRY tertiaryConfigEntry;
PCONFIG_ENTRY entryToFree;
ULONG currentPortBase = 0x1f0;
#if DBG
configEntry = ConfigEntryChain;
while (configEntry) {
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA IDE: chain %x - %x - %d\n",
configEntry,
configEntry->IoPortBase[0],
configEntry->IndexForThisConfiguration));
configEntry = configEntry->NextEntry;
}
#endif
//
// Pull out the primary and secondary entries into the new chain
// and place them on the new chain pointer.
//
chainBase = currentNewChain = NULL;
while (currentPortBase) {
prevSourceChain = NULL;
for (configEntry = ConfigEntryChain;
configEntry;
/* update of configEntry occurs in the loop */) {
if (configEntry->IoPortBase[0] == currentPortBase) {
//
// Place this in the new chain.
//
if (currentNewChain) {
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA ATA: cn %x -> %x\n",
currentNewChain->IoPortBase[0],
configEntry->IoPortBase[0]));
currentNewChain->NextEntry = configEntry;
currentNewChain = configEntry;
} else {
chainBase = currentNewChain = configEntry;
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA ATA: cb %x\n",
currentNewChain->IoPortBase[0]));
}
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA ATA: %x to new chain\n",
configEntry->IoPortBase[0]));
//
// remove this from the input chain.
//
if (prevSourceChain) {
prevSourceChain->NextEntry = configEntry->NextEntry;
} else {
ConfigEntryChain = configEntry->NextEntry;
}
//
// Move forward to the next entry in the source chain.
//
configEntry = configEntry->NextEntry;
//
// Insure that the destination chain is null terminated.
//
currentNewChain->NextEntry = NULL;
} else {
prevSourceChain = configEntry;
configEntry = configEntry->NextEntry;
}
}
#if DBG
configEntry = ConfigEntryChain;
while (configEntry) {
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA IDE: chain %x - %x - %d\n",
configEntry,
configEntry->IoPortBase[0],
configEntry->IndexForThisConfiguration));
configEntry = configEntry->NextEntry;
}
#endif
if (currentPortBase == 0x1f0) {
currentPortBase = 0x170;
} else {
currentPortBase = 0;
}
}
//
// Process the chain again, removing any configuration entries that
// do not provide value and holding the "any config" configuration
// for the end.
//
entryToFree = tertiaryConfigEntry = NULL;
for (configEntry = ConfigEntryChain;
configEntry;
configEntry = configEntry->NextEntry) {
if (entryToFree) {
ExFreePool(entryToFree);
entryToFree = NULL;
}
if (configEntry->IoPortBase[0] == 0) {
//
// Remove any config tuples that do not specify IoSpace
// These can only be freed the next time through the loop,
// not at this time because the NextEntry pointer is needed
// to continue the loop.
//
if (configEntry->ModuloBase == 0) {
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA tuples: removing entry %x - %d\n",
configEntry,
configEntry->IndexForThisConfiguration));
entryToFree = configEntry;
continue;
}
}
if (configEntry->ModuloBase) {
//
// This is the configEntry for the contiguous I/O mapping mode.
// Remove this entry from the chain and save it.
//
tertiaryConfigEntry = configEntry;
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA tuples: moving entry %x - %d to end of chain\n",
configEntry,
configEntry->IndexForThisConfiguration));
continue;
}
if (currentNewChain) {
currentNewChain->NextEntry = configEntry;
} else {
chainBase = configEntry;
}
currentNewChain = configEntry;
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA ATA: %x to new chain\n",
configEntry->IoPortBase[0]));
}
//
// Catch the case where the last item in the chain is one
// that is to be freed.
//
if (entryToFree) {
ExFreePool(entryToFree);
}
//
// If an entry was saved add it to the end of the list.
//
if (tertiaryConfigEntry) {
if (currentNewChain) {
currentNewChain->NextEntry = tertiaryConfigEntry;
} else {
chainBase = tertiaryConfigEntry;
}
tertiaryConfigEntry->NextEntry = NULL;
}
#if DBG
configEntry = chainBase;
while (configEntry) {
DebugPrint((PCMCIA_DEBUG_ENABLE,
"PCMCIA IDE: chain %x - %x - %d\n",
configEntry,
configEntry->IoPortBase[0],
configEntry->IndexForThisConfiguration));
configEntry = configEntry->NextEntry;
}
#endif
return chainBase;
}
VOID
PcmciaCheckForRecognizedDevice(
PSOCKET_DATA SocketData
)
/*++
Routine Description:
Look at the configuration options on the PCCARD to determine if
it is a serial port / modem card.
Arguments:
SocketData - the configuration information on the current PCCARD.
Return Value:
None - Modifications are made to the socket data structure.
--*/
{
ULONG modemPorts[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
ULONG ataPorts0[2] = { 0x1f0, 0x170 };
BOOLEAN found = FALSE;
UCHAR dataByte;
UCHAR link;
ULONG index;
PUCHAR localBufferPointer;
PCONFIG_ENTRY configEntry;
for (configEntry = SocketData->ConfigEntryChain; configEntry; configEntry = configEntry->NextEntry) {
for (index = 0; index < 4; index++) {
if (modemPorts[index] == configEntry->IoPortBase[0]) {
SocketData->DeviceType = PCCARD_TYPE_SERIAL;
found = TRUE;
break;
}
if (index < 2) {
if (ataPorts0[index] == configEntry->IoPortBase[0]) {
if (configEntry->IoPortBase[1] == 0x376) {
SocketData->DeviceType = PCCARD_TYPE_ATA;
//
// Order the configuration entries such that the contiguous
// I/O range entry is in the correct location.
//
SocketData->ConfigEntryChain =
InitTertiaryATAConfigEntry(SocketData->ConfigEntryChain);
found = TRUE;
break;
}
}
}
}
}
if (!found) {
SocketData->DeviceType = PCCARD_TYPE_RESERVED;
//
// Search for the CISTPL_FUNCID value
//
localBufferPointer = SocketData->TupleData;
dataByte = *localBufferPointer;
while (dataByte != CISTPL_END) {
localBufferPointer++;
link = *localBufferPointer;
if (dataByte == CISTPL_FUNCID) {
SocketData->DeviceType = *(localBufferPointer + 1);
}
localBufferPointer += (link+1);
dataByte = *localBufferPointer;
}
}
DebugPrint((PCMCIA_DUMP_CONFIG,
"PcmciaCheckForRecognizedDevice: DeviceType %2x\n",
SocketData->DeviceType));
}