📄 tuple.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
tuple.c
Abstract:
This file implements the PCMCIA model device driver CIS tuple parsing
functions. This is provided as a sample to platform writers and is
expected to be able to be used without modification on most (if not
all) hardware platforms.
Functions:
CheckTupleOffset
I_ReadAttrByte()
I_ReadAttrWord()
I_TupleMapWindow()
I_TupleGetWindow()
I_ReadLink()
I_CheckNextTuple()
I_CheckNextLink()
I_GetNextTuple()
I_GetDesiredTuple()
CardGetNextTuple()
CardGetFirstTuple()
CardGetTupleData()
VarToFixed()
ParseConfig()
ConvertVoltage()
ParseVoltageDescr()
ParseCfTable()
CardGetParsedTuple()
Notes:
--*/
#include <windows.h>
#include <types.h>
#include <cardserv.h>
#include <sockserv.h>
#include <pcmcia.h>
#include <tuple.h>
#include <extern.h>
#define MAX_TUPLE_MISSES 500
#define LINK_TARGET_SIG ('C'+('I'<<8)+('S'<<16))
#define TUPLE_WINDOW_SIZE 8192
//#define TUPLE_WINDOW_SIZE 16384
#define TUPLE_OFFSET_LIMIT 65536
//
// Check if the tuple offset fits in the current window and try to remap
// the window if it doesn't.
//
STATUS
CheckTupleOffset(
UINT Address,
PCARD_TUPLE_PARMS pParms
)
{
PLOG_WINDOW pWin;
PPHYS_WINDOW pPhys;
PDCARD_WINDOW_STATE WinState;
STATUS status;
UINT CardOffset;
UINT8 attr;
if (pParms->fFlags & TUPLE_FLAG_COMMON) {
pWin = v_Sockets[pParms->hSocket.uSocket].pCmnWin;
CardOffset = Address;
attr = 0;
} else {
pWin = v_Sockets[pParms->hSocket.uSocket].pAttrWin;
CardOffset = Address*2;
attr = WIN_STATE_ATTRIBUTE;
}
pPhys = pWin->pPhys;
//
// If we can't change the window offset, then just do a static check
//
if (!(pPhys->fOtherCaps & MEM_CAP_PRG_BASE)) {
if (CardOffset >= TUPLE_WINDOW_SIZE) {
return CERR_READ_FAILURE;
}
return CERR_SUCCESS;
}
if ((CardOffset < (pWin->uReqOffset + pWin->uReqSize)) &&
(CardOffset >= pWin->uReqOffset)) {
return CERR_SUCCESS;
}
if (CardOffset > TUPLE_OFFSET_LIMIT) {
return CERR_READ_FAILURE;
}
DEBUGMSG(ZONE_PDD,
(TEXT("CheckTupleOffset remapping for CardOffset = 0x%x\r\n"),
CardOffset));
//
// We need to remap!
//
status = PDCardGetWindow(pPhys->uWindow, &WinState);
if (status != CERR_SUCCESS) {
return CERR_READ_FAILURE;
}
pWin->uReqOffset = CardOffset & ~(TUPLE_WINDOW_SIZE - 1);
pPhys->uOffset = WinState.uOffset = pWin->uReqOffset;
pPhys->uSize = WinState.uSize = TUPLE_WINDOW_SIZE;
WinState.fState &= ~WIN_STATE_ATTRIBUTE;
WinState.fState |= attr;
if (attr) {
pPhys->fFlags |= PHYS_WIN_FLAG_ATTR_MODE;
} else {
pPhys->fFlags &= ~PHYS_WIN_FLAG_ATTR_MODE;
}
status = PDCardSetWindow(pPhys->uWindow, &WinState);
if (status != CERR_SUCCESS) {
return CERR_READ_FAILURE;
}
return CERR_SUCCESS;
}
//
// Read next byte from CIS (may be either in common or attribute space).
//
STATUS
I_ReadAttrByte(
PCHAR * pAttr,
PCARD_TUPLE_PARMS pParms,
UINT32 uOffset,
UINT8 * pByte
)
{
PLOG_WINDOW pWin;
STATUS status;
UINT Address = pParms->uCISOffset+uOffset;
status = CheckTupleOffset(Address, pParms);
if (status != CERR_SUCCESS) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,(
TEXT("I_ReadAttrByte returning %d (offset = %d)\r\n"),
status, Address));
return status;
}
if (pParms->fFlags & TUPLE_FLAG_COMMON) {
pWin = v_Sockets[pParms->hSocket.uSocket].pCmnWin;
return CardReadCmnByte(*pAttr, Address - pWin->uReqOffset, pByte);
} else {
pWin = v_Sockets[pParms->hSocket.uSocket].pAttrWin;
return CardReadAttrByte(*pAttr, Address - pWin->uReqOffset/2, pByte);
}
} // I_ReadAttrByte
//
// Read a 4 byte chunk of the CIS as a little endian word.
//
STATUS
I_ReadAttrWord(
PCHAR *pAttr,
PCARD_TUPLE_PARMS pParms,
UINT32 uOffset,
UINT * pWord
)
{
PLOG_WINDOW pWin;
UINT uTmp = 0;
UINT i = pParms->uCISOffset+uOffset+3; // start with high order byte
UINT j = 4;
STATUS status;
UINT8 uByte;
status = CheckTupleOffset(i, pParms);
if (status != CERR_SUCCESS) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,(
TEXT("I_ReadAttrWord returning %d (offset = %d)\r\n"), status, i));
return status;
}
if (pParms->fFlags & TUPLE_FLAG_COMMON) {
pWin = v_Sockets[pParms->hSocket.uSocket].pCmnWin;
i -= pWin->uReqOffset;
} else {
pWin = v_Sockets[pParms->hSocket.uSocket].pAttrWin;
i -= pWin->uReqOffset/2;
}
while (j) {
uTmp <<= 8;
if (pParms->fFlags & TUPLE_FLAG_COMMON) {
status = CardReadCmnByte(*pAttr, i, &uByte);
} else {
status = CardReadAttrByte(*pAttr, i, &uByte);
}
if (status) {
return status;
}
uTmp += (UINT)uByte;
j--;
i--;
}
*pWord = uTmp;
return CERR_SUCCESS;
} // I_ReadAttrWord
//
// I_TupleMapWindow maps a logical window associated with a socket to a
// virtual memory region.
//
PVOID
I_TupleMapWindow(
PPHYS_WINDOW pPhys,
PCARD_TUPLE_PARMS pParms
)
{
PDCARD_WINDOW_STATE WinState;
PLOG_WINDOW pWin;
STATUS status;
UINT addr = 0; // Beginning of attribute space.
//
// If we can't change the window offset, then just do a static check
//
if (pPhys->fOtherCaps & MEM_CAP_PRG_BASE) {
DEBUGMSG(ZONE_PDD, (TEXT("I_TupleMapWindow remapping for CardOffset = 0x0\r\n")));
//
// We need to remap!
//
status = PDCardGetWindow(pPhys->uWindow, &WinState);
if (status != CERR_SUCCESS) {
return NULL;
}
//
// We'll set the attribute bit later on if necessary
//
pPhys->uOffset = WinState.uOffset = 0;
pPhys->uSize = WinState.uSize = TUPLE_WINDOW_SIZE;
status = PDCardSetWindow(pPhys->uWindow, &WinState);
if (status != CERR_SUCCESS) {
return NULL;
}
}
pWin = I_MapWindow(
pPhys,
&addr,
(TUPLE_WINDOW_SIZE > pPhys->uMaxSize) ?
pPhys->uMaxSize : TUPLE_WINDOW_SIZE,
(pParms->fFlags & TUPLE_FLAG_COMMON) ? FALSE : TRUE
);
if (pWin == NULL) {
return NULL;
}
PDCardGetWindow(pPhys->uWindow, &WinState);
if (pParms->fFlags & TUPLE_FLAG_COMMON) {
v_Sockets[pPhys->uSock].pCmnWin = pWin;
WinState.fState &= ~WIN_STATE_ATTRIBUTE;
pPhys->fFlags &= ~PHYS_WIN_FLAG_ATTR_MODE;
} else {
v_Sockets[pPhys->uSock].pAttrWin = pWin;
WinState.fState |= WIN_STATE_ATTRIBUTE;
pPhys->fFlags |= PHYS_WIN_FLAG_ATTR_MODE;
}
PDCardSetWindow(pPhys->uWindow, &WinState);
return pWin->pVirtMem;
} // I_TupleMapWindow
//
// I_TupleGetWindow is called by CardGetFirstTuple to allocate a virtual memory
// window to access the specified socket. If there is already a window, then
// that will be returned.
//
// hSock is the socket to access
// fFlag specifies whether the CIS is in attribute or common memory.
//
PVOID
I_TupleGetWindow(
PCARD_TUPLE_PARMS pParms
)
{
PPHYS_WINDOW pPhys;
PLOG_WINDOW pWin;
if (pParms->fFlags & TUPLE_FLAG_COMMON) {
pWin = v_Sockets[pParms->hSocket.uSocket].pCmnWin;
} else {
pWin = v_Sockets[pParms->hSocket.uSocket].pAttrWin;
}
if (pWin != NULL) {
if (pWin->pVirtMem == NULL) {
DEBUGMSG(ZONE_TUPLE|ZONE_WARNING,(
TEXT("I_TupleGetWindow: Window allocated but not mapped!\r\n")));
}
return pWin->pVirtMem;
}
//
// Find a physical memory window associated with this socket.
//
EnterCriticalSection(&v_WindowCrit);
pPhys = v_pWinList;
while (pPhys) {
if (pPhys->uSock == pParms->hSocket.uSocket) {
if ((((pParms->fFlags & TUPLE_FLAG_COMMON) == 0) && (pPhys->fWindowCaps & WIN_CAP_ATTRIBUTE)) ||
((pParms->fFlags & TUPLE_FLAG_COMMON) && (pPhys->fWindowCaps & WIN_CAP_COMMON))) {
LeaveCriticalSection(&v_WindowCrit);
return(I_TupleMapWindow(pPhys, pParms));
}
}
pPhys = pPhys->Next;
}
LeaveCriticalSection(&v_WindowCrit);
return NULL;
} // I_TupleGetWindow
//
// Remember info from current link tuple.
//
STATUS
I_ReadLink(
PCHAR * pAttr,
PCARD_TUPLE_PARMS pParms
)
{
STATUS status;
UINT8 byte;
switch (pParms->uTupleCode) {
case CISTPL_LONGLINK_A:
case CISTPL_LONGLINK_C:
status = I_ReadAttrWord(pAttr, pParms, 2, &(pParms->uLinkOffset));
if (status != CERR_SUCCESS) {
return status;
}
pParms->fFlags &= TUPLE_FLAG_COMMON; // clear all but mem mode.
if (pParms->uTupleCode == CISTPL_LONGLINK_A) {
pParms->fFlags |= TUPLE_FLAG_LINK_TO_A;
pParms->uLinkOffset *= 2;
} else {
pParms->fFlags |= TUPLE_FLAG_LINK_TO_C;
}
break;
case CISTPL_LONGLINK_MFC:
//
// Make sure the requested function number exists
//
status = I_ReadAttrByte(pAttr, pParms, 2, &byte);
if (status != CERR_SUCCESS) {
return status;
}
if (byte <= pParms->hSocket.uFunction) {
break;
}
//
// Also verify that the link shows enough room for the requested function
//
status = I_ReadAttrByte(pAttr, pParms, 1, &byte);
if (status != CERR_SUCCESS) {
return status;
}
if (byte < (pParms->hSocket.uFunction * 5) + 1) {
DEBUGMSG(ZONE_CALLBACK|ZONE_TUPLE,
(TEXT("I_ReadLink: CISTPL_LONGLINK_MFC length=%d, expecting at least %d\r\n"),
byte, pParms->hSocket.uFunction * 5 + 1));
break;
}
status = I_ReadAttrWord(pAttr, pParms, (pParms->hSocket.uFunction * 5) + 4, &(pParms->uLinkOffset));
if (status != CERR_SUCCESS) {
return status;
}
//
// Check which memory space the link goes to
//
status = I_ReadAttrByte(pAttr, pParms, (pParms->hSocket.uFunction * 5) + 3, &byte);
if (status != CERR_SUCCESS) {
return status;
}
if (byte == 0) {
pParms->fFlags |= TUPLE_FLAG_LINK_TO_A;
pParms->uLinkOffset *= 2;
} else {
pParms->fFlags |= TUPLE_FLAG_LINK_TO_C;
}
break;
case CISTPL_NO_LINK:
//
// CISTPL_NO_LINK means that all long links in this chain
// should be ignored.
//
pParms->fFlags &= TUPLE_FLAG_COMMON; // clear all but mem mode.
pParms->fFlags |= TUPLE_FLAG_NO_LINK;
break;
}
return CERR_SUCCESS;
} // I_ReadLink
//
// Examine the next tuple in the chain
//
STATUS
I_CheckNextTuple(
PCHAR * pAttr,
PCARD_TUPLE_PARMS pParms
)
{
UINT8 tuple;
STATUS status;
status = I_ReadAttrByte(pAttr, pParms, 0, &tuple);
if (status != CERR_SUCCESS) {
return status;
}
if (tuple == CISTPL_END) {
return CERR_NO_MORE_ITEMS;
}
//
// CISTPL_NULL is a one byte tuple with no info so it is skipped.
//
if (tuple == CISTPL_NULL) {
pParms->uCISOffset += 1; // skip to next tuple
} else {
status = I_ReadAttrByte(pAttr, pParms, 1, &tuple);
if (status != CERR_SUCCESS) {
return status;
}
if (tuple == CISTPL_END) {
DEBUGMSG(ZONE_TUPLE, (TEXT("I_CheckNextTuple: TupleLink == CISTPL_END, assuming end\r\n")));
return CERR_NO_MORE_ITEMS;
}
pParms->uCISOffset += tuple+2; // skip to next tuple
}
return CERR_SUCCESS;
} // I_CheckNextTuple
//
// Check and follow the link at the current CIS offset
//
// pAttr may get changed to a pointer to common memory if the CIS is in common
// memory.
//
STATUS
I_CheckNextLink(
PCHAR * pAttr,
PCARD_TUPLE_PARMS pParms
)
{
UINT uSig; // link target signature.
UINT8 tuple;
STATUS status;
if (pParms->fFlags & TUPLE_FLAG_LINK_TO_C) {
//
// Process a link to common memory.
//
pParms->fFlags |= TUPLE_FLAG_COMMON;
DEBUGMSG(ZONE_TUPLE,
(TEXT("I_CheckNextLink: processing CISTPL_LONGLINK_TO_C\r\n")));
} else if (pParms->fFlags & TUPLE_FLAG_LINK_TO_A) {
//
// Process a link to attribute memory.
//
pParms->fFlags &= ~TUPLE_FLAG_COMMON;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -