📄 tuple.c
字号:
pTuple->fAttributes = 0; // Not interested in links
status = CardGetFirstTuple(pTuple);
if (status) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,
(TEXT("ParseConfig: CardGetFirstTuple returned %d\r\n"), status));
*pnItems = 0;
return status;
}
status = CardGetNextTuple(pTuple);
if (status) {
status = CardGetFirstTuple(pTuple);
if (status) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,
(TEXT("ParseConfig: CardGetFirstTuple returned %d\r\n"), status));
*pnItems = 0;
return status;
}
}
pData = (PCARD_DATA_PARMS)buf;
pData->uBufLen = BUFFER_SIZE;
pData->uTupleOffset = 0;
status = CardGetTupleData(pData);
if (status) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,
(TEXT("ParseConfig: CardGetTupleData returned %d\r\n"), status));
*pnItems = 0;
return status;
}
if (pBuf == NULL) {
*pnItems = 1;
return CERR_SUCCESS;
}
if (*pnItems == 0) {
return CERR_BAD_ARG_LENGTH;
}
*pnItems = 1;
pCfg->ConfigBase = 0;
pCfg->RegMask = 0;
pCIS = buf + sizeof(CARD_DATA_PARMS);
AddrSz = (*pCIS & 0x03) + 1;
pCIS++;
pCfg->LastConfigIndex = *pCIS & 0x3f;
pCIS++;
//
// Read the configuration register offset address and leave it in real
// physical address units.
//
pCfg->ConfigBase = VarToFixed(
AddrSz,
pCIS); // pointer
//
// Now get the register presence mask (only the first byte)
//
pCfg->RegMask = pCIS[AddrSz];
DEBUGMSG(ZONE_TUPLE,
(TEXT("ParseConfig: Last configuration index = 0x%x\r\n"), pCfg->LastConfigIndex));
DEBUGMSG(ZONE_TUPLE,
(TEXT("ParseConfig: Config registers base = 0x%x\r\n"), pCfg->ConfigBase));
DEBUGMSG(ZONE_TUPLE,
(TEXT("ParseConfig: Register presence mask = 0x%x\r\n"), pCfg->RegMask));
return CERR_SUCCESS;
} // ParseConfig
BOOL
ValidPowerEntry(
UINT fSupply,
UINT16 uVoltage
)
{
UINT8 i;
PPDCARD_POWER_ENTRY pPwr = (PPDCARD_POWER_ENTRY)(((PCHAR)v_pAdapterInfo) +
sizeof(PDCARD_ADAPTER_INFO));
for (i = 0; i < v_pAdapterInfo->uPowerEntries; i++, pPwr++) {
if (((pPwr->uPowerLevel * 9 / 10) <= uVoltage) &&
(pPwr->uPowerLevel >= uVoltage) &&
(pPwr->fSupply & fSupply)) {
return TRUE;
}
}
return FALSE;
}
const USHORT VoltageConversionTable[16] = {
10, 12, 13, 15, 20, 25, 30, 35,
40, 45, 50, 55, 60, 70, 80, 90
};
//
// ConvertVoltage - normalize a single CISTPL_CFTABLE_ENTRY voltage entry and
// return its length in bytes
//
UINT
ConvertVoltage(
PUCHAR pCIS,
PUSHORT pDescr
)
{
UINT Length;
SHORT power;
USHORT value;
UCHAR MantissaExponentByte;
UCHAR ExtensionByte;
Length = 1;
power = 1;
MantissaExponentByte = pCIS[0];
ExtensionByte = pCIS[1];
value = VoltageConversionTable[(MantissaExponentByte >> 3) & 0x0f];
if ((MantissaExponentByte & TPCE_PD_EXT) &&
(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++;
}
*pDescr = value;
//
// Skip any subsequent extension bytes for now.
//
while (*pCIS & TPCE_PD_EXT) {
Length++;
pCIS++;
}
return Length;
} // ConvertVoltage
//
// ParseVoltageDescr - convert the variable length power description structure
// from a CISTPL_CFTABLE_ENTRY to a POWER_DESCR structure
// and normalize the values.
// Returns the length of the variable length power description structure.
//
// A typical call would be:
// if (pCfTable->VccDescr.ValidMask) {
// pCIS += ParseVoltageDescr(pCIS, &pCfTable->VccDescr);
// }
//
UINT
ParseVoltageDescr(
PUCHAR pVolt,
PPOWER_DESCR pDescr
)
{
UINT Length;
UINT Mask;
UINT i;
PUSHORT pDVolt;
Length = 1;
Mask = pDescr->ValidMask = (UINT)*pVolt;
pVolt++;
pDVolt = &(pDescr->NominalV);
while (Mask) {
if (Mask & 1) {
i = ConvertVoltage(pVolt, pDVolt);
Length += i;
pVolt += i;
} else {
*pDVolt = 0;
}
pDVolt++;
Mask >>= 1;
}
return Length;
} // ParseVoltageDescr
//
// ParseCfTable - Read the CISTPL_CFTABLE_ENTRY tuples from the CIS and format them into
// an array of PARSED_CFTABLE structures.
//
STATUS
ParseCfTable(
CARD_SOCKET_HANDLE hSocket,
PVOID pBuf,
PUINT pnItems
)
{
STATUS status;
UCHAR buf[BUFFER_SIZE + sizeof(CARD_DATA_PARMS)];
PCARD_DATA_PARMS pData;
PCARD_TUPLE_PARMS pTuple;
PUCHAR pCIS;
PUCHAR pTmp;
PPARSED_CFTABLE pCfTable = (PPARSED_CFTABLE)pBuf;
PPARSED_CFTABLE pCfDefault = NULL;
BOOL TimingPresent; // This tuple contains a description of the card's timing
BOOL IOPresent; // This tuple contains I/O descriptor bytes
DWORD bmPowerPresent; // This tuple has some power descriptors
int lastCFI = -1; // Configuration Index of the previous CFTABLE_ENTRY tuple
UINT i;
UINT nItems;
nItems = 0;
//
// Find the first CISTPL_CFTABLE_ENTRY tuple
//
pTuple = (PCARD_TUPLE_PARMS)buf;
pTuple->hSocket = hSocket;
pTuple->uDesiredTuple = CISTPL_CFTABLE_ENTRY;
pTuple->fAttributes = 0; // Not interested in links
status = CardGetFirstTuple(pTuple);
if (status) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,
(TEXT("ParseCfTable: CardGetFirstTuple returned %d\r\n"), status));
goto pcft_exit;
}
if (pBuf != NULL) {
if (*pnItems == 0) {
status = CERR_BAD_ARG_LENGTH;
} else {
memset(pBuf, 0, *pnItems * sizeof(PARSED_CFTABLE));
}
}
//
// Parse all the CISTPL_CFTABLE_ENTRYs or as many as fit in the user's buffer
//
while (status == CERR_SUCCESS) {
nItems++;
if (pBuf == NULL) {
goto pcft_next;
}
pData = (PCARD_DATA_PARMS)buf;
pData->uBufLen = BUFFER_SIZE;
pData->uTupleOffset = 0;
status = CardGetTupleData(pData);
if (status) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,
(TEXT("ParseCfTable: CardGetTupleData returned %d\r\n"), status));
goto pcft_exit;
}
//
// Parse this CISTPL_CFTABLE_ENTRY
//
pCIS = buf + sizeof(CARD_DATA_PARMS);
// Default all the fields of the current parsed entry if necessary
//
// !! The ContainsDefaults field is now deprecated and should be
// !! set to non-zero in every parsed entry.
//
pCfTable->ContainsDefaults = *pCIS & 0x40;
pCfTable->ConfigIndex = *pCIS & 0x3F;
if (pCfTable->ContainsDefaults)
pCfDefault = pCfTable;
else if (pCfTable->ConfigIndex == lastCFI) {
ASSERT(pCfTable != pBuf && lastCFI >= 0);
*pCfTable = *(pCfTable - 1);
pCfTable->ContainsDefaults = TRUE;
} else if (pCfDefault)
*pCfTable = *pCfDefault;
// Reset the ConfigIndex after defaulting
pCfTable->ConfigIndex = *pCIS & 0x3F;
lastCFI = pCfTable->ConfigIndex;
// lastCFI is not used beyond this point
//
// Parse the interface type byte if present
//
if (*pCIS & 0x80) {
pCIS++;
pCfTable->IFacePresent = TRUE;
pCfTable->IFaceType = *pCIS & 0x0F;
pCfTable->BVDActive = *pCIS & 0x10;
pCfTable->WPActive = *pCIS & 0x20;
pCfTable->ReadyActive = *pCIS & 0x40;
pCfTable->WaitRequired = *pCIS & 0x80;
} else {
//pCfTable->IFacePresent = FALSE;
}
pCIS++;
//
// Parse the feature select byte
//
//
// Power requirements present
//
bmPowerPresent = *pCIS & 0x03;
//
// Timing description present
//
TimingPresent = *pCIS & 0x04;
//
// I/O space descriptions present
//
IOPresent = *pCIS & 0x08;
pCIS++;
//
// Parse the power description structures if present
//
if (bmPowerPresent >= 1) {
pCfTable->VccDescr.ValidMask = 0xFF;
pCIS += ParseVoltageDescr(pCIS, &pCfTable->VccDescr);
for (i = 0; i < 3; i++) {
if ((PWR_DESCR_NOMINALV << i) & pCfTable->VccDescr.ValidMask &&
ValidPowerEntry(PWR_SUPPLY_VCC, (&pCfTable->VccDescr.NominalV)[i]))
pCfTable->VccDescr.ValidMask |= (PWR_AVAIL_NOMINALV << i);
}
}
if (bmPowerPresent >= 2) {
pCfTable->Vpp1Descr.ValidMask = 0xFF;
pCIS += ParseVoltageDescr(pCIS, &pCfTable->Vpp1Descr);
for (i = 0; i < 3; i++) {
if ((PWR_DESCR_NOMINALV << i) & pCfTable->Vpp1Descr.ValidMask &&
ValidPowerEntry(PWR_SUPPLY_VPP1, (&pCfTable->Vpp1Descr.NominalV)[i]))
pCfTable->Vpp1Descr.ValidMask |= (PWR_AVAIL_NOMINALV << i);
}
pCfTable->Vpp2Descr.ValidMask = 0xFF;
if (bmPowerPresent == 3) {
pCIS += ParseVoltageDescr(pCIS, &pCfTable->Vpp2Descr);
for (i = 0; i < 3; i++) {
if ((PWR_DESCR_NOMINALV << i) & pCfTable->Vpp1Descr.ValidMask &&
ValidPowerEntry(PWR_SUPPLY_VPP2, (&pCfTable->Vpp1Descr.NominalV)[i]))
pCfTable->Vpp2Descr.ValidMask |= (PWR_AVAIL_NOMINALV << i);
}
} else
pCfTable->Vpp2Descr = pCfTable->Vpp1Descr;
}
//
// Skip the timing information
//
if ( TimingPresent ) {
pTmp = pCIS;
pCIS++;
if ( (*pTmp & 0x03) != 0x03 ) {
while ( *pCIS++ & TPCE_PD_EXT ) ;
}
if ( (*pTmp & 0x1C) != 0x1C ) {
while ( *pCIS++ & TPCE_PD_EXT );
}
}
//
// Process the I/O address ranges (up to MAX_IO_RANGES)
//
if (IOPresent) {
pCfTable->NumIOAddrLines = *pCIS & 0x1F;
pCfTable->IOAccess = (*pCIS & 0x60) >> 5; // type of access allowed
if (*pCIS & 0x80) { // range present bit
UINT8 AddrSize, LengthSize;
pCIS++;
pCfTable->NumIOEntries = (*pCIS & 0x0F) + 1;
if (pCfTable->NumIOEntries > MAX_IO_RANGES) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,
(TEXT("PCMCIA ParseCfTable: too many I/O ranges; ignoring some.\n")));
pCfTable->NumIOEntries = MAX_IO_RANGES;
}
AddrSize = (*pCIS & 0x30) >> 4;
if (AddrSize == 3) {
AddrSize = 4;
}
LengthSize = (*pCIS & 0xC0) >> 6;
if (LengthSize == 3) {
LengthSize = 4;
}
pCIS++;
for (i = 0; i < pCfTable->NumIOEntries; i++) {
pCfTable->IOBase[i] = VarToFixed(AddrSize, pCIS);
pCIS += AddrSize;
pCfTable->IOLength[i] = VarToFixed(LengthSize, pCIS);
pCIS += LengthSize;
}
} else {
// NumIOEntries is a misnomer; it's really the number of IO ranges.
pCfTable->NumIOEntries = 0;
}
}
// else it has already been either defaulted or memset to zeros.
pCfTable++;
pcft_next:
if ((pBuf != NULL) && (nItems == *pnItems)) {
status = CERR_NO_MORE_ITEMS; // no more room in caller's buffer
} else {
//
// Get the next CISTPL_CFTABLE_ENTRY
//
status = CardGetNextTuple(pTuple);
}
} // while (status == CERR_SUCCESS)
pcft_exit:
*pnItems = nItems;
//
// If there were problems and no CFTABLE_ENTRYs found then return an error.
//
if (nItems) {
return CERR_SUCCESS;
}
return status;
} // ParseCfTable
//
// CardGetParsedTuple
//
// @func STATUS | CardGetParsedTuple | Reads and parses the specified tuple.
// @rdesc Returns one of CERR_SUCCESS, CERR_BAD_ARGS, CERR_BAD_SOCKET, CERR_READ_FAILURE,
// CERR_OUT_OF_RESOURCE, CERR_NO_MORE_ITEMS or CERR_BAD_ARG_LENGTH.
//
// @comm Reads the CIS data from the specified PC card of the specified tuple code and
// formats the encoded data into an easily accessed structure. CISTPL_CONFIG and
// CISTPL_CFTABLE_ENTRY are currently the only tuples parsed. When CardGetParsedTuple
// is called with CISTPL_CONFIG, it returns a PARSED_CONFIG structure. When it
// is called with CISTPLE_CFTABLE_ENTRY, it returns a PARSED_CFTABLE structure.
// On input, the value pointed to by pnItems is the number of items the buffer, pBuf
// can contain. On output, pnItems indicates the number items in pBuf.
// If pBuf is NULL, then pnItems indicates how many of the requested tuples there are.
//
// @xref <t PARSED_CONFIG> <t PARSED_CFTABLE> <t POWER_DESCR>
//
STATUS
CardGetParsedTuple(
CARD_SOCKET_HANDLE hSocket, // @parm Socket/function identifier
UINT8 DesiredTuple, // @parm Desired tuple to parse (only CISTPL_CONFIG and CISTPL_CFTABLE_ENTRY for now)
PVOID pBuf, // @parm Pointer to buffer to receive parsed data
PUINT pnItems // @parm Pointer to number of items in pBuf.
)
{
STATUS status;
DEBUGMSG(ZONE_FUNCTION|ZONE_TUPLE,
(TEXT("CardGetParsedTuple entered %d\r\n"), DesiredTuple));
if (pnItems == NULL) {
status = CERR_BAD_ARGS;
goto parsed_exit;
}
switch (DesiredTuple) {
case CISTPL_CONFIG:
status = ParseConfig(hSocket, pBuf, pnItems);
break;
case CISTPL_CFTABLE_ENTRY:
status = ParseCfTable(hSocket, pBuf, pnItems);
break;
default:
status = CERR_BAD_ARGS;
break;
}
parsed_exit:
#ifdef DEBUG
if (status) {
DEBUGMSG(ZONE_FUNCTION|ZONE_ERROR|ZONE_TUPLE,
(TEXT("CardGetParsedTuple failed %d\r\n"), status));
} else {
DEBUGMSG(ZONE_FUNCTION|ZONE_TUPLE,
(TEXT("CardGetParsedTuple succeeded\r\n")));
}
#endif
return status;
} // CardGetParsedTuple
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -