You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1264 lines
27 KiB
1264 lines
27 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tuples.c
|
|
|
|
Abstract:
|
|
|
|
This program converses with the PCMCIA support driver to display
|
|
tuple and other information.
|
|
|
|
Author:
|
|
|
|
Bob Rinne
|
|
|
|
Environment:
|
|
|
|
User process.
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
Ravisankar Pudipeddi (ravisp) June 27 1997
|
|
- command line options & support for multiple controllers
|
|
Neil Sandlin (neilsa) Sept 20, 1998
|
|
- more commands
|
|
|
|
--*/
|
|
|
|
#include <pch.h>
|
|
|
|
//
|
|
// Tuple output strings
|
|
//
|
|
|
|
|
|
StringTable CommandCodes[] = {
|
|
|
|
"CISTPL_NULL", CISTPL_NULL,
|
|
"CISTPL_DEVICE", CISTPL_DEVICE,
|
|
"CISTPL_LONGLINK_MFC", CISTPL_LONGLINK_MFC,
|
|
"CISTPL_CHECKSUM", CISTPL_CHECKSUM,
|
|
"CISTPL_LONGLINK_A", CISTPL_LONGLINK_A,
|
|
"CISTPL_LONGLINK_C", CISTPL_LONGLINK_C,
|
|
"CISTPL_LINKTARGET", CISTPL_LINKTARGET,
|
|
"CISTPL_NO_LINK", CISTPL_NO_LINK,
|
|
"CISTPL_VERS_1", CISTPL_VERS_1,
|
|
"CISTPL_ALTSTR", CISTPL_ALTSTR,
|
|
"CISTPL_DEVICE_A", CISTPL_DEVICE_A,
|
|
"CISTPL_JEDEC_C", CISTPL_JEDEC_C,
|
|
"CISTPL_JEDEC_A", CISTPL_JEDEC_A,
|
|
"CISTPL_CONFIG", CISTPL_CONFIG,
|
|
"CISTPL_CFTABLE_ENTRY", CISTPL_CFTABLE_ENTRY,
|
|
"CISTPL_DEVICE_OC", CISTPL_DEVICE_OC,
|
|
"CISTPL_DEVICE_OA", CISTPL_DEVICE_OA,
|
|
"CISTPL_GEODEVICE", CISTPL_GEODEVICE,
|
|
"CISTPL_GEODEVICE_A", CISTPL_GEODEVICE_A,
|
|
"CISTPL_MANFID", CISTPL_MANFID,
|
|
"CISTPL_FUNCID", CISTPL_FUNCID,
|
|
"CISTPL_FUNCE", CISTPL_FUNCE,
|
|
"CISTPL_VERS_2", CISTPL_VERS_2,
|
|
"CISTPL_FORMAT", CISTPL_FORMAT,
|
|
"CISTPL_GEOMETRY", CISTPL_GEOMETRY,
|
|
"CISTPL_BYTEORDER", CISTPL_BYTEORDER,
|
|
"CISTPL_DATE", CISTPL_DATE,
|
|
"CISTPL_BATTERY", CISTPL_BATTERY,
|
|
"CISTPL_ORG", CISTPL_ORG,
|
|
|
|
//
|
|
// CISTPL_END must be the last one in the table.
|
|
//
|
|
|
|
"CISTPL_END", CISTPL_END
|
|
|
|
};
|
|
|
|
|
|
//
|
|
// Procedures
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
ReadTuple(
|
|
IN HANDLE Handle,
|
|
IN LONG SlotNumber,
|
|
IN PUCHAR Buffer,
|
|
IN LONG BufferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform the NT function to get the tuple data from the
|
|
pcmcia support driver.
|
|
|
|
Arguments:
|
|
|
|
Handle - an open handle to the driver.
|
|
SlotNumber - The socket offset
|
|
Buffer - return buffer for the data.
|
|
BufferSize - the size of the return buffer area.
|
|
|
|
Return Value:
|
|
|
|
The results of the NT call.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
TUPLE_REQUEST commandBlock;
|
|
|
|
commandBlock.Socket = (USHORT) SlotNumber;
|
|
|
|
status = NtDeviceIoControlFile(Handle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
IOCTL_GET_TUPLE_DATA,
|
|
&commandBlock,
|
|
sizeof(commandBlock),
|
|
Buffer,
|
|
BufferSize);
|
|
return status;
|
|
}
|
|
|
|
|
|
PUCHAR
|
|
FindTupleCodeName(
|
|
UCHAR TupleCode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return an ascii string that describes the tuple code provided.
|
|
|
|
Arguments:
|
|
|
|
TupleCode - what code to look up.
|
|
|
|
Return Value:
|
|
|
|
A string pointer - always.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG index;
|
|
|
|
for (index = 0; CommandCodes[index].CommandCode != CISTPL_END; index++) {
|
|
if (CommandCodes[index].CommandCode == TupleCode) {
|
|
return CommandCodes[index].CommandName;
|
|
}
|
|
}
|
|
|
|
return "Command Unknown";
|
|
}
|
|
|
|
|
|
PUCHAR DeviceTypeString[] = {
|
|
"DTYPE_NULL",
|
|
"DTYPE_ROM",
|
|
"DTYPE_OTPROM",
|
|
"DTYPE_EPROM",
|
|
"DTYPE_EEPROM",
|
|
"DTYPE_FLASH",
|
|
"DTYPE_SRAM",
|
|
"DTYPE_DRAM",
|
|
"Reserved8",
|
|
"Reserved9",
|
|
"Reserveda",
|
|
"Reservedb",
|
|
"Reservedc",
|
|
"DTYPE_FUNCSPEC",
|
|
"DTYPE_EXTEND"
|
|
"Reservedf",
|
|
};
|
|
|
|
PUCHAR DeviceSpeedString[] = {
|
|
"DSPEED_NULL",
|
|
"DSPEED_250NS",
|
|
"DSPEED_200NS",
|
|
"DSPEED_150NS",
|
|
"DSPEED_100NS",
|
|
"DSPEED_RES1",
|
|
"DSPEED_RES2",
|
|
"DSPEED_EXT"
|
|
};
|
|
|
|
VOID
|
|
DisplayDeviceTuple(
|
|
PUCHAR TupleBuffer,
|
|
UCHAR TupleSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display the data at the given pointer as a CISTPL_DEVICE structure.
|
|
|
|
Arguments:
|
|
|
|
TupleBuffer - the CISTPL_DEVICE to display.
|
|
TupleSize - the link value for the tuple.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR mantissa = MANTISSA_RES1;
|
|
UCHAR exponent;
|
|
UCHAR deviceTypeCode;
|
|
UCHAR wps;
|
|
UCHAR deviceSpeed;
|
|
UCHAR temp;
|
|
|
|
temp = *TupleBuffer;
|
|
deviceTypeCode = DeviceTypeCode(temp);
|
|
wps = DeviceWPS(temp);
|
|
deviceSpeed = DeviceSpeedField(temp);
|
|
|
|
temp = *(TupleBuffer + 1);
|
|
|
|
if (deviceSpeed == DSPEED_EXT) {
|
|
exponent = SpeedExponent(temp);
|
|
mantissa = SpeedMantissa(temp);
|
|
}
|
|
|
|
printf("DeviceType: %s DeviceSpeed: ", DeviceTypeString[deviceTypeCode]);
|
|
if (mantissa != MANTISSA_RES1) {
|
|
printf("Mantissa %.2x, Exponent %.2x\n", mantissa, exponent);
|
|
} else {
|
|
printf("%s\n", DeviceSpeedString[deviceSpeed]);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DisplayVers1(
|
|
PUCHAR TupleBuffer,
|
|
UCHAR TupleSize,
|
|
USHORT Crc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display the data as a Version tuple
|
|
|
|
Arguments:
|
|
|
|
TupleBuffer - the CISTPL_DEVICE to display.
|
|
TupleSize - the link value for the tuple.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR string;
|
|
PUCHAR cp;
|
|
|
|
//
|
|
// Step around the MAJOR and MINOR codes of 4/1 at
|
|
// the beginning of the tuple to get to the strings.
|
|
//
|
|
|
|
string = TupleBuffer;
|
|
string++;
|
|
string++;
|
|
|
|
printf("Manufacturer:\t%s\n", string);
|
|
while (*string++) {
|
|
}
|
|
|
|
printf("Product Name:\t%s\n", string);
|
|
printf("CRC: \t%.4x\n", Crc);
|
|
while (*string++) {
|
|
}
|
|
|
|
printf("Product Info:\t");
|
|
if (isprint(*string)) {
|
|
printf("%s", string);
|
|
} else {
|
|
while (*string) {
|
|
printf("%.2x ", *string);
|
|
string++;
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
VOID
|
|
DisplayConfigTuple(
|
|
PUCHAR TupleBuffer,
|
|
UCHAR TupleSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display the data at the given pointer as a CISTPL_CONFIG tuple.
|
|
|
|
Arguments:
|
|
|
|
TupleBuffer - the CISTPL_DEVICE to display.
|
|
TupleSize - the link value for the tuple.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR sizeField;
|
|
UCHAR tpccRfsz;
|
|
UCHAR tpccRmsz;
|
|
UCHAR tpccRasz;
|
|
UCHAR last;
|
|
ULONG baseAddress;
|
|
PUCHAR ptr;
|
|
|
|
sizeField = *TupleBuffer;
|
|
last = *(TupleBuffer + 1);
|
|
tpccRfsz = TpccRfsz(sizeField);
|
|
tpccRmsz = TpccRmsz(sizeField);
|
|
tpccRasz = TpccRasz(sizeField);
|
|
|
|
printf("TPCC_SZ %.2x (%.2x/%.2x/%.2x) - Last %.2x\n",
|
|
sizeField,
|
|
tpccRasz,
|
|
tpccRmsz,
|
|
tpccRfsz,
|
|
last);
|
|
|
|
baseAddress = 0;
|
|
ptr = TupleBuffer + 2;
|
|
switch (tpccRasz) {
|
|
case 3:
|
|
baseAddress = *(ptr + 3) << 24;
|
|
case 2:
|
|
baseAddress |= *(ptr + 2) << 16;
|
|
case 1:
|
|
baseAddress |= *(ptr + 1) << 8;
|
|
default:
|
|
baseAddress |= *ptr;
|
|
}
|
|
printf("Base Address: %8x - ", baseAddress);
|
|
ptr += tpccRasz + 1;
|
|
|
|
baseAddress = 0;
|
|
switch (tpccRmsz) {
|
|
case 3:
|
|
baseAddress = *(ptr + 3) << 24;
|
|
case 2:
|
|
baseAddress |= *(ptr + 2) << 16;
|
|
case 1:
|
|
baseAddress |= *(ptr + 1) << 8;
|
|
default:
|
|
baseAddress |= *ptr;
|
|
}
|
|
printf("Register Presence Mask: %8x\n", baseAddress);
|
|
}
|
|
|
|
|
|
PUCHAR
|
|
ProcessMemSpace(
|
|
PUCHAR Buffer,
|
|
UCHAR MemSpace
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display and process memspace information
|
|
|
|
Arguments:
|
|
|
|
Buffer - start of memspace information
|
|
MemSpace - the memspace value from the feature byte.
|
|
|
|
Return Value:
|
|
|
|
location of byte after all memory space information
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR ptr = Buffer;
|
|
UCHAR item = *ptr++;
|
|
UCHAR lengthSize;
|
|
UCHAR addrSize;
|
|
UCHAR number;
|
|
UCHAR hasHostAddress;
|
|
ULONG cardAddress;
|
|
ULONG length;
|
|
ULONG hostAddress;
|
|
|
|
if (MemSpace == 3) {
|
|
|
|
lengthSize = (item & 0x18) >> 3;
|
|
addrSize = (item & 0x60) >> 5;
|
|
number = (item & 0x07) + 1;
|
|
hasHostAddress = item & 0x80;
|
|
printf("(0x%.2x) %s - %d entries - LengthSize %d - AddrSize %d\n",
|
|
item,
|
|
hasHostAddress ? "Host address" : "no host",
|
|
number,
|
|
lengthSize,
|
|
addrSize);
|
|
while (number) {
|
|
cardAddress = length = hostAddress = 0;
|
|
switch (lengthSize) {
|
|
case 3:
|
|
length |= (*(ptr + 2)) << 16;
|
|
case 2:
|
|
length |= (*(ptr + 1)) << 8;
|
|
case 1:
|
|
length |= *ptr;
|
|
}
|
|
ptr += lengthSize;
|
|
switch (addrSize) {
|
|
case 3:
|
|
cardAddress |= (*(ptr + 2)) << 16;
|
|
case 2:
|
|
cardAddress |= (*(ptr + 1)) << 8;
|
|
case 1:
|
|
cardAddress |= *ptr;
|
|
}
|
|
ptr += addrSize;
|
|
if (hasHostAddress) {
|
|
switch (addrSize) {
|
|
case 3:
|
|
hostAddress |= (*(ptr + 2)) << 16;
|
|
case 2:
|
|
hostAddress |= (*(ptr + 1)) << 8;
|
|
case 1:
|
|
hostAddress |= *ptr;
|
|
}
|
|
printf("\tHost 0x%.8x ", hostAddress * 256);
|
|
ptr += addrSize;
|
|
} else {
|
|
printf("\t");
|
|
}
|
|
printf("Card 0x%.8x Size 0x%.8x\n",
|
|
cardAddress * 256,
|
|
length * 256);
|
|
number--;
|
|
}
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
USHORT VoltageConversionTable[16] = {
|
|
10, 12, 13, 14, 20, 25, 30, 35,
|
|
40, 45, 50, 55, 60, 70, 80, 90
|
|
};
|
|
|
|
UCHAR
|
|
ConvertVoltage(
|
|
UCHAR MantissaExponentByte,
|
|
UCHAR ExtensionByte
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
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 PowerTypeTable[] = {
|
|
"Nominal",
|
|
"Minimum",
|
|
"Maximum",
|
|
"Static",
|
|
"Average",
|
|
"Peak",
|
|
"PwrDown"
|
|
};
|
|
|
|
PUCHAR VoltagePinTable[] = {
|
|
"Vcc",
|
|
"Vpp1",
|
|
"Vpp2"
|
|
};
|
|
|
|
PUCHAR
|
|
ProcessPower(
|
|
PUCHAR Buffer,
|
|
UCHAR FeatureByte
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display and process power information
|
|
|
|
Arguments:
|
|
|
|
Power - start of power information
|
|
|
|
Return Value:
|
|
|
|
location of byte after all power information
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR powerSelect;
|
|
UCHAR bit;
|
|
UCHAR item;
|
|
UCHAR entries;
|
|
PUCHAR ptr = Buffer;
|
|
UCHAR count = FeatureByte;
|
|
|
|
powerSelect = *ptr;
|
|
printf("Parameter Selection Byte = 0x%.2x\n", powerSelect);
|
|
|
|
entries = 0;
|
|
while (entries < count) {
|
|
powerSelect = *ptr++;
|
|
printf("\t%s \"%d%d%d%d%d%d%d%d\"\n",
|
|
VoltagePinTable[entries],
|
|
powerSelect & 0x80 ? 1 : 0,
|
|
powerSelect & 0x40 ? 1 : 0,
|
|
powerSelect & 0x20 ? 1 : 0,
|
|
powerSelect & 0x10 ? 1 : 0,
|
|
powerSelect & 0x08 ? 1 : 0,
|
|
powerSelect & 0x04 ? 1 : 0,
|
|
powerSelect & 0x02 ? 1 : 0,
|
|
powerSelect & 0x01 ? 1 : 0);
|
|
for (bit = 0; bit < 7; bit++) {
|
|
if (powerSelect & (1 << bit)) {
|
|
|
|
if (!bit) {
|
|
|
|
//
|
|
// Convert nominal power for output.
|
|
//
|
|
|
|
item = ConvertVoltage(*ptr,
|
|
(UCHAR) (*ptr & EXTENSION_BYTE_FOLLOWS ?
|
|
*(ptr + 1) :
|
|
(UCHAR) 0));
|
|
}
|
|
printf("\t\t%s power =\t%d/10 volts\n", PowerTypeTable[bit], item);
|
|
while (*ptr++ & EXTENSION_BYTE_FOLLOWS) {
|
|
}
|
|
}
|
|
}
|
|
entries++;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
PUCHAR
|
|
ProcessTiming(
|
|
PUCHAR Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR ptr = Buffer;
|
|
UCHAR item = *ptr++;
|
|
UCHAR reservedScale = (item & 0xe0) >> 5;
|
|
UCHAR readyBusyScale = (item & 0x1c) >> 2;
|
|
UCHAR waitScale = (item & 0x03);
|
|
|
|
printf("Timing (0x%.2x): reservedScale 0x%.2x, readyBusyScale 0x%.2x, waitScale 0x%.2x\n",
|
|
item,
|
|
reservedScale,
|
|
readyBusyScale,
|
|
waitScale);
|
|
|
|
if (waitScale != 3) {
|
|
printf("\tWaitSpeed 0x%.2x\n", *ptr);
|
|
ptr++;
|
|
while (*ptr & EXTENSION_BYTE_FOLLOWS) {
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
if (readyBusyScale != 7) {
|
|
printf("\tReadyBusySpeed 0x%.2x\n", *ptr);
|
|
ptr++;
|
|
while (*ptr & EXTENSION_BYTE_FOLLOWS) {
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
if (reservedScale != 7) {
|
|
printf("\tReservedSpeed 0x%.2x\n", *ptr);
|
|
ptr++;
|
|
while (*ptr & EXTENSION_BYTE_FOLLOWS) {
|
|
ptr++;
|
|
}
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
PUCHAR
|
|
ProcessIoSpace(
|
|
PUCHAR Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display and process iospace information
|
|
|
|
Arguments:
|
|
|
|
Buffer - start of IoSpace information
|
|
|
|
Return Value:
|
|
|
|
location of byte after all power information
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR item;
|
|
UCHAR ioAddrLines;
|
|
UCHAR bus8;
|
|
UCHAR bus16;
|
|
UCHAR ranges;
|
|
UCHAR lengthSize;
|
|
UCHAR addressSize;
|
|
ULONG address;
|
|
PUCHAR ptr = Buffer;
|
|
|
|
item = *ptr++;
|
|
ioAddrLines = item & IO_ADDRESS_LINES_MASK;
|
|
bus8 = Is8BitAccess(item);
|
|
bus16 = Is16BitAccess(item);
|
|
ranges = HasRanges(item);
|
|
|
|
printf("IoSpace (%.2x): IoAddressLines %.2d - %s/%s\n",
|
|
item,
|
|
ioAddrLines,
|
|
bus8 ? "8bit" : "",
|
|
bus16 ? "16bit" : "");
|
|
|
|
//
|
|
// This is what it looks like the IBM token ring card
|
|
// does. It is unclear in the specification if this
|
|
// is correct or not.
|
|
//
|
|
|
|
if ((!ranges) && (!ioAddrLines)) {
|
|
ranges = 0xFF;
|
|
}
|
|
|
|
if (ranges) {
|
|
|
|
if (ranges == 0xff) {
|
|
|
|
//
|
|
// This is based on the tuple data as given by
|
|
// the IBM token ring card. This is not the
|
|
// way I would interpret the specification.
|
|
//
|
|
|
|
addressSize = 2;
|
|
lengthSize = 1;
|
|
ranges = 1;
|
|
} else {
|
|
item = *ptr++;
|
|
ranges = item & 0x0f;
|
|
ranges++;
|
|
addressSize = GetAddressSize(item);
|
|
lengthSize = GetLengthSize(item);
|
|
}
|
|
|
|
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;
|
|
printf("\tStart %.8x - Length ", 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;
|
|
printf("%.8x\n", address);
|
|
|
|
ranges--;
|
|
}
|
|
} else {
|
|
printf("\tResponds to all ranges.\n");
|
|
}
|
|
return ptr;
|
|
}
|
|
PUCHAR
|
|
ProcessIrq(
|
|
PUCHAR Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display and process irq information
|
|
|
|
Arguments:
|
|
|
|
Buffer - start of irq information
|
|
|
|
Return Value:
|
|
|
|
location of byte after all irq information
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR ptr = Buffer;
|
|
UCHAR level;
|
|
USHORT mask;
|
|
ULONG irqNumber;
|
|
|
|
level = *ptr++;
|
|
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++;
|
|
}
|
|
if (level & 0x80) {
|
|
printf("Share ");
|
|
}
|
|
if (level & 0x40) {
|
|
printf("Pulse ");
|
|
}
|
|
if (level & 0x20) {
|
|
printf("Level ");
|
|
}
|
|
if (level & 0x10) {
|
|
mask = *ptr | (*(ptr + 1) << 8);
|
|
ptr += 2;
|
|
printf("mask = %.4x - ", mask);
|
|
for (irqNumber = 0; mask; irqNumber++, mask = mask >> 1) {
|
|
if (mask & 0x0001) {
|
|
printf("IRQ%d ", irqNumber);
|
|
}
|
|
}
|
|
printf("- ");
|
|
|
|
if (level & 0x08) {
|
|
printf("Vend ");
|
|
}
|
|
if (level & 0x04) {
|
|
printf("Berr ");
|
|
}
|
|
if (level & 0x02) {
|
|
printf("IOCK ");
|
|
}
|
|
if (level & 0x01) {
|
|
printf("NMI");
|
|
}
|
|
printf("\n");
|
|
} else {
|
|
printf("irq = %d\n", level & 0x0f);
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
|
|
PUCHAR InterfaceTypeStrings[] = {
|
|
"Memory",
|
|
"I/O",
|
|
"Reserved 2",
|
|
"Reserved 3",
|
|
"Custom 0",
|
|
"Custom 1",
|
|
"Custom 2",
|
|
"Custom 3",
|
|
"Reserved 8",
|
|
"Reserved 9",
|
|
"Reserved a",
|
|
"Reserved b",
|
|
"Reserved c",
|
|
"Reserved d",
|
|
"Reserved e",
|
|
"Reserved f",
|
|
};
|
|
|
|
VOID
|
|
DisplayCftableEntryTuple(
|
|
PUCHAR TupleBuffer,
|
|
UCHAR TupleSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display the data at the given pointer as a CISTPL_CFTABLE_ENTRY tuple.
|
|
|
|
Arguments:
|
|
|
|
TupleBuffer - the CISTPL_DEVICE to display.
|
|
TupleSize - the link value for the tuple.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR temp;
|
|
UCHAR item;
|
|
UCHAR defaultbit;
|
|
UCHAR memSpace;
|
|
UCHAR power;
|
|
PUCHAR ptr;
|
|
|
|
temp = *TupleBuffer;
|
|
item = IntFace(temp);
|
|
defaultbit = Default(temp);
|
|
temp = ConfigEntryNumber(temp);
|
|
|
|
printf("ConfigurationEntryNumber %.2x (%s/%s)\n",
|
|
temp,
|
|
item ? "intface" : "",
|
|
defaultbit ? "default" : "");
|
|
|
|
ptr = TupleBuffer + 1;
|
|
if (item) {
|
|
temp = *ptr++;
|
|
item = temp & 0x0F;
|
|
printf("InterfaceDescription (%.2x) %s (%s/%s/%s/%s)\n",
|
|
temp,
|
|
InterfaceTypeStrings[item],
|
|
temp & 0x80 ? "WaitReq" : "",
|
|
temp & 0x40 ? "RdyBsy" : "",
|
|
temp & 0x20 ? "WP" : "",
|
|
temp & 0x10 ? "BVD" : "");
|
|
}
|
|
item = *ptr++;
|
|
|
|
memSpace = MemSpaceInformation(item);
|
|
power = PowerInformation(item);
|
|
printf("The following structures are present:\n");
|
|
switch (power) {
|
|
case 3:
|
|
printf("Vcc, Vpp1, Vpp2; ");
|
|
break;
|
|
case 2:
|
|
printf("Vcc and Vpp; ");
|
|
break;
|
|
case 1:
|
|
printf("Vcc; ");
|
|
break;
|
|
case 0:
|
|
break;
|
|
}
|
|
if (power) {
|
|
ptr = ProcessPower(ptr, power);
|
|
}
|
|
if (TimingInformation(item)) {
|
|
ptr = ProcessTiming(ptr);
|
|
}
|
|
if (IoSpaceInformation(item)) {
|
|
ptr = ProcessIoSpace(ptr);
|
|
}
|
|
if (IRQInformation(item)) {
|
|
printf("IRQ: ");
|
|
ptr = ProcessIrq(ptr);
|
|
}
|
|
switch (memSpace) {
|
|
case 3:
|
|
printf("Memory selection: ");
|
|
break;
|
|
case 2:
|
|
printf("Length and Card Address: ");
|
|
break;
|
|
case 1:
|
|
printf("2-byte length: ");
|
|
break;
|
|
case 0:
|
|
break;
|
|
}
|
|
if (memSpace) {
|
|
ptr = ProcessMemSpace(ptr, memSpace);
|
|
}
|
|
|
|
if (MiscInformation(item)) {
|
|
printf("Misc fields present");
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
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;
|
|
printf("Calculating CRC ");
|
|
while (1) {
|
|
tupleData = tplBuffer + 2;
|
|
tupleCode = *tplBuffer++;
|
|
|
|
if (tupleCode == CISTPL_END) {
|
|
break;
|
|
}
|
|
|
|
linkValue = (tupleCode) ? *tplBuffer++ : 0;
|
|
length = linkValue;
|
|
|
|
printf("%x", tupleCode);
|
|
for (index = 0; TplList[index] != CISTPL_END; index++) {
|
|
|
|
if (tupleCode == TplList[index]) {
|
|
|
|
|
|
//
|
|
// This one is included in the CRC calculation
|
|
//
|
|
|
|
printf("*", tupleCode);
|
|
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 = (USHORT)(cp - tupleData);
|
|
}
|
|
|
|
for (cp = tupleData; length; length--, cp++) {
|
|
|
|
tmp = *cp ^ (UCHAR)crc;
|
|
crc = (crc >> 8) ^ crc16a[tmp & 0x0f] ^ crc16b[tmp >> 4];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
printf(" ");
|
|
tplBuffer = tplBuffer + linkValue;
|
|
}
|
|
printf("++\n");
|
|
return crc;
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpTuple(
|
|
PUCHAR Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Control routine to process the tuple data.
|
|
|
|
Arguments:
|
|
|
|
Buffer - the tuple data.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR tupleBuffer = Buffer;
|
|
PUCHAR tupleCodeName;
|
|
USHORT crc;
|
|
UCHAR index;
|
|
UCHAR tupleCode;
|
|
UCHAR linkValue;
|
|
|
|
crc = GetCRC(tupleBuffer);
|
|
while (1) {
|
|
tupleCode = *tupleBuffer++;
|
|
linkValue = (tupleCode) ? *tupleBuffer : 0;
|
|
|
|
if (tupleCode == CISTPL_END) {
|
|
break;
|
|
}
|
|
|
|
tupleCodeName = FindTupleCodeName(tupleCode);
|
|
|
|
printf("Tuple Code\t%s\t%.2x - Link %.2x:", tupleCodeName, tupleCode, linkValue);
|
|
|
|
if (linkValue) {
|
|
for (index = 0; index < linkValue; index++) {
|
|
if ((index & 0x0F) == 0) {
|
|
printf("\n");
|
|
}
|
|
printf(" %.2x", *(tupleBuffer + index + 1));
|
|
}
|
|
}
|
|
printf("\n");
|
|
|
|
tupleBuffer++;
|
|
switch (tupleCode) {
|
|
case CISTPL_DEVICE:
|
|
DisplayDeviceTuple(tupleBuffer, linkValue);
|
|
break;
|
|
case CISTPL_VERS_1:
|
|
DisplayVers1(tupleBuffer, linkValue, crc);
|
|
break;
|
|
case CISTPL_CONFIG:
|
|
DisplayConfigTuple(tupleBuffer, linkValue);
|
|
break;
|
|
case CISTPL_CFTABLE_ENTRY:
|
|
DisplayCftableEntryTuple(tupleBuffer, linkValue);
|
|
break;
|
|
case CISTPL_LONGLINK_MFC:
|
|
case CISTPL_LONGLINK_A:
|
|
case CISTPL_LONGLINK_C:
|
|
case CISTPL_LINKTARGET:
|
|
case CISTPL_NO_LINK:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
tupleBuffer = tupleBuffer + linkValue;
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
DumpCIS(
|
|
IN PHOST_INFO hostInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PUCHAR currentBufferPointer;
|
|
UCHAR hexBuffer[260];
|
|
UCHAR ascii[100];
|
|
ULONG i;
|
|
UCHAR c;
|
|
PUCHAR buffer;
|
|
HANDLE handle;
|
|
|
|
handle = GetHandleForIoctl(hostInfo);
|
|
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
return;
|
|
}
|
|
|
|
buffer = malloc(BUFFER_SIZE);
|
|
if (!buffer) {
|
|
printf("Unable to malloc\n");
|
|
NtClose(handle);
|
|
return;
|
|
}
|
|
|
|
memset(buffer, 0, BUFFER_SIZE);
|
|
|
|
status = ReadTuple(handle, hostInfo->SocketNumber, buffer, BUFFER_SIZE);
|
|
|
|
//
|
|
// Don't bother dumping tuples for cards that aren't there.
|
|
//
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
NtClose(handle);
|
|
return;
|
|
}
|
|
|
|
printf("\nCIS Tuples for Socket Number %d:\n\n", hostInfo->SocketNumber);
|
|
|
|
hexBuffer[0] = '\0';
|
|
ascii[0] = '\0';
|
|
currentBufferPointer = buffer;
|
|
for (i = 0; i < 512; i++) {
|
|
c = *currentBufferPointer;
|
|
sprintf(hexBuffer, "%s %.2x", hexBuffer, c);
|
|
c = isprint(c) ? c : '.';
|
|
sprintf(ascii, "%s%c", ascii, c);
|
|
currentBufferPointer++;
|
|
|
|
//
|
|
// Display the line every 16 bytes.
|
|
//
|
|
|
|
if ((i & 0x0f) == 0x0f) {
|
|
printf("%s", hexBuffer);
|
|
printf(" *%s*\n", ascii);
|
|
hexBuffer[0] = '\0';
|
|
ascii[0] = '\0';
|
|
}
|
|
}
|
|
printf("%s", hexBuffer);
|
|
printf("\t\t*%s*\n\n", ascii);
|
|
DumpTuple(buffer);
|
|
|
|
NtClose(handle);
|
|
}
|
|
|