--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/pbus/pccard/spccard.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1076 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\drivers\pbus\pccard\spccard.cpp
+//
+//
+
+#include <pccard.h>
+#include "cis.h"
+
+LOCAL_D const TPccdAccessSpeed CisDevSpeedTable[8] =
+ {EAcSpeedInValid,EAcSpeed250nS,EAcSpeed200nS,EAcSpeed150nS,
+ EAcSpeed100nS,EAcSpeedInValid,EAcSpeedInValid,EAcSpeedInValid};
+LOCAL_D const TUint32 CisDevSizeInBytesTable[8] =
+ {0x00000200,0x00000800,0x00002000,0x00008000,0x00020000,0x00080000,0x00200000,0};
+LOCAL_D const TInt CisMantisaTable[0x10] =
+ {10,12,13,15,20,25,30,35,40,45,50,55,60,70,80,90};
+LOCAL_D const TInt CisSpeedExponentTable[8] =
+ {0,1,10,100,1000,10000,100000,1000000};
+
+GLDEF_C void PcCardPanic(TPcCardPanic aPanic)
+ {
+ Kern::Fault("PCCARD",aPanic);
+ }
+
+LOCAL_C TPccdAccessSpeed DevSpeedFromExtended(TInt aSpeedInNanoSecs)
+ {
+
+ if (aSpeedInNanoSecs<=100) return(EAcSpeed100nS);
+ if (aSpeedInNanoSecs<=150) return(EAcSpeed150nS);
+ if (aSpeedInNanoSecs<=200) return(EAcSpeed200nS);
+ if (aSpeedInNanoSecs<=250) return(EAcSpeed250nS);
+ if (aSpeedInNanoSecs<=300) return(EAcSpeed300nS);
+ if (aSpeedInNanoSecs<=450) return(EAcSpeed450nS);
+ if (aSpeedInNanoSecs<=600) return(EAcSpeed600nS);
+ if (aSpeedInNanoSecs<=750) return(EAcSpeed750nS);
+ return(EAcSpeedExtended);
+ }
+
+LOCAL_C TMemDeviceType DevType(TInt aTypeCode)
+ {
+ if ( aTypeCode>=KTpDiDTypeNull && aTypeCode<=KTpDiDTypeDram )
+ return( (TMemDeviceType)aTypeCode );
+ else if (aTypeCode>=KTpDiDTypeFuncSpec)
+ return(EDeviceFunSpec);
+ else
+ return(EDeviceInvalid);
+ }
+
+LOCAL_C TInt ExtendedSpeedToNanoSeconds(TUint8 aVal)
+//
+// Converts extended device speed field to speed in nS.
+//
+ {
+
+ TInt mant=(aVal&KCisTplMantM)>>KCisTplMantFO;
+ TInt s=(mant==0)?0:CisMantisaTable[mant-1];
+ s*=CisSpeedExponentTable[aVal&KCisTplExponM];
+ return(s);
+ }
+
+LOCAL_C TInt PwrTplToMicroAmps(TUint aVal,TUint anExt)
+//
+// Converts a power tuple into an integer value - units uA.
+//
+ {
+ TInt p=CisMantisaTable[(aVal&KCisTplMantM)>>KCisTplMantFO];
+ p*=10;
+ if (anExt<=99)
+ p+=anExt; // Add on the extension
+ switch ( aVal&KCisTplExponM )
+ {
+ case 7: return(p*=10000); case 6: return(p*=1000);
+ case 5: return(p*=100); case 4: return(p*=10);
+ case 3: return(p); case 2: return(p/=10);
+ case 1: return(p/=100);
+ default: return(0); // Anything else is too small to worry about
+ }
+ }
+
+LOCAL_C TInt PwrTplToMilliVolts(TUint aVal,TUint anExt)
+//
+// Converts a power tuple into a integer value - units mV.
+//
+ {
+ return(PwrTplToMicroAmps(aVal,anExt)/10);
+ }
+
+LOCAL_C TInt ParseConfigTuple(TDes8 &configTpl,TPcCardConfig &anInfo,TInt &aLastEntry)
+//
+// Parse a KCisTplConfig tuple.
+// (Always alters iConfigBaseAddr and iRegPresent).
+//
+ {
+
+ anInfo.iConfigBaseAddr=0;
+ anInfo.iRegPresent=0;
+
+ // Get the sizes of the ConfReg base addr & ConfReg present fields
+ TInt rasz=((configTpl[2]&KTpCcRaszM)>>KTpCcRaszFO)+1;
+ TInt rmsz=((configTpl[2]&KTpCcRmszM)>>KTpCcRmszFO)+1;
+ if ( (configTpl.Size()-4) < (rasz+rmsz) )
+ return(KErrNotSupported); // Size of fields longer than tuple length.
+ aLastEntry=configTpl[3];
+
+ // Read Config. Reg. base address.
+ TInt i;
+ for (i=0;i<rasz;i++)
+ anInfo.iConfigBaseAddr += (configTpl[4+i]<<(8*i));
+
+ // Read Config. Reg. present mask
+ if (rmsz>4) rmsz=4; // We only have 32bit field
+ for (i=0;i<rmsz;i++)
+ anInfo.iRegPresent += (configTpl[4+rasz+i]<<(8*i));
+ return(KErrNone); // Ignore custom interface subtuples
+ }
+
+LOCAL_C TInt ParsePowerEntry(const TUint8 *aTplPtr,TInt *aVMax,TInt *aVMin,TInt *aPeakI,TInt *aPdwnI)
+//
+// Parse a Power descriptor in a KCisTplCfTableEntry tuple. Returns the
+// number of bytes we have parsed.
+//
+ {
+ const TUint8 *initPtr = aTplPtr;
+ TUint8 present = *aTplPtr++;
+ TBuf8<16> pwr;
+ pwr.FillZ(16); // Important
+
+ TInt i;
+ for (i=0;i<16;i+=2,present>>=1)
+ {
+ if (present&0x01)
+ {
+ pwr[i]=(TUint8)((*aTplPtr)&(~KCisTplExt));
+ if (*aTplPtr++ & KCisTplExt)
+ {
+ pwr[i+1]=(TUint8)((*aTplPtr)&(~KCisTplExt)); // Extension tuple
+ while( *aTplPtr++ & KCisTplExt ); // Jump past any more extensions
+ }
+ }
+ }
+
+ if (aVMin && aVMax)
+ {
+ if (pwr[0]) // NomV (assume +/-5%)
+ {
+ (*aVMin)=(*aVMax)=PwrTplToMilliVolts(pwr[0],pwr[1]);
+ (*aVMin) = ((*aVMin)*95)/100;
+ (*aVMax) = ((*aVMax)*105)/100;
+ }
+ if (pwr[2]) // MinV
+ *aVMin=PwrTplToMilliVolts(pwr[2],pwr[3]);
+ if (pwr[4]) // MaxV
+ *aVMax=PwrTplToMilliVolts(pwr[4],pwr[5]);
+ }
+ // We'll settle for average/static if no peak.
+ if (aPeakI && (pwr[10]||pwr[8]||pwr[6]) )
+ {
+ if (pwr[6])
+ *aPeakI = PwrTplToMicroAmps(pwr[6],pwr[7]);
+ if (pwr[8])
+ *aPeakI = PwrTplToMicroAmps(pwr[8],pwr[9]);
+ if (pwr[10])
+ *aPeakI = PwrTplToMicroAmps(pwr[10],pwr[11]); // Last one overides others
+ }
+ if (aPdwnI && pwr[12])
+ *aPdwnI = PwrTplToMicroAmps(pwr[12],pwr[13]);
+
+ return(aTplPtr-initPtr);
+ }
+
+LOCAL_C TInt ParseTimingEntry(const TUint8 *aTplPtr)
+//
+// Parse a timing descriptor in a KCisTplCfTableEntry tuple. Returns the
+// number of bytes we have parsed.
+//
+ {
+ // We ignore this information - just jump past this field
+ const TUint8 *initPtr=aTplPtr;
+
+ TUint8 present=*aTplPtr++; // First the timing present field
+
+ if ((present & KTpCeTimWaitM) != KTpCeTimWaitM)
+ while( *aTplPtr++ & KCisTplExt ); // Wait time (jump past any extensions)
+ if ((present & KTpCeTimRdyM) != KTpCeTimRdyM)
+ while( *aTplPtr++ & KCisTplExt ); // Ready time (jump past any extensions)
+ if ((present & KTpCeTimResM) != KTpCeTimResM)
+ while( *aTplPtr++ & KCisTplExt ); // Reserved time (jump past any extensions)
+ return(aTplPtr-initPtr);
+ }
+
+LOCAL_C TInt ParseIoEntry(const TUint8 *aTplPtr,TPccdChnk *aChnk,TInt &aNextChnkNum)
+//
+// Parse an IO space descriptor in a KCisTplCfTableEntry tuple. Returns the
+// number of bytes we have parsed (or a negative error value). Also returns the
+// number of config chunk entries used ('aNextChunkNum').
+//
+ {
+ TPccdMemType memType;
+ TInt bytesParsed = 1; // Must be a minimum of a single byte descriptor here.
+
+ // Always at least one I/O space descriptor
+ switch( (*aTplPtr & KTpCeBus16_8M) >> KTpCeBus16_8FO )
+ {
+ case 1: case 2:
+ memType = EPccdIo8Mem; // Card supports 8bit I/O only.
+ break;
+ case 3:
+ memType = EPccdIo16Mem; // Card supports 8 & 16 bit I/O.
+ break;
+ default:
+ return(KErrCorrupt);
+ }
+ TUint ioLines = (*aTplPtr & KTpCeIoLinesM) >> KTpCeIoLinesFO;
+
+ TInt ranges=1; // We always specify one chunk even if no range descriptors follow
+ TInt addrInBytes=0;
+ TInt lenInBytes=0;
+ // Are there any IO Range description bytes to follow
+ if (*aTplPtr++ & KTpCeRangePresM)
+ {
+ ranges = ((*aTplPtr & KTpCeIoRangesM) >> KTpCeIoRangesFO)+1;
+ addrInBytes = (*aTplPtr & KTpCeIoAddrSzM) >> KTpCeIoAddrSzFO;
+ lenInBytes = (*aTplPtr & KTpCeIoAddrLenM) >> KTpCeIoAddrLenFO;
+ aTplPtr++;
+
+ // There could be multiple range descriptors
+ if ((ranges+aNextChnkNum)<=KMaxChunksPerConfig)
+ bytesParsed += (ranges * (addrInBytes + lenInBytes))+1;
+ else
+ return(KErrNotSupported); // Too many descriptors for us
+ }
+
+ aChnk+=aNextChnkNum;
+ for (;ranges>0;ranges--,aChnk++,aNextChnkNum++)
+ {
+ TInt j;
+ aChnk->iMemType=memType; // I/O memory type
+
+ // Lets get the IO start address
+ aChnk->iMemBaseAddr=0;
+ if (addrInBytes)
+ {
+ for (j=0;j<addrInBytes;j++)
+ aChnk->iMemBaseAddr += (*aTplPtr++) << (8*j);
+ }
+
+ // Finally, lets get the IO length
+ if (lenInBytes)
+ {
+ for (j=0,aChnk->iMemLen=0;j<lenInBytes;j++)
+ aChnk->iMemLen += (*aTplPtr++) << (8*j);
+ (aChnk->iMemLen)++;
+ }
+ else
+ {
+ if (ioLines)
+ aChnk->iMemLen = 0x01<<ioLines;
+ else
+ return(KErrCorrupt); // No ioLines and no length, it's invalid.
+ }
+ }
+ return(bytesParsed);
+ }
+
+LOCAL_C TInt ParseMemEntry(const TUint8 *aTplPtr,TInt aFeatureVal,TPccdChnk *aChnk,TInt &aNextChnkNum)
+//
+// Parse a memory space descriptor in a KCisTplCfTableEntry tuple. Returns
+// the number of bytes we have parsed (or a negative error value). Also returns the
+// number of config chunk entries used ('aNextChunkNum').
+//
+ {
+
+ const TUint8 *initPtr=aTplPtr;
+ TInt windows=0;
+ TInt lenInBytes=0;
+ TInt addrInBytes=0;
+ TBool hostAddr=EFalse;
+ switch (aFeatureVal)
+ {
+ case 3: // Memory space descriptor
+ windows=(*aTplPtr & KTpCeMemWindowsM)+1;
+ lenInBytes=(*aTplPtr & KTpCeMemLenSzM) >> KTpCeMemLenSzFO;
+ addrInBytes=(*aTplPtr & KTpCeMemAddrSzM) >> KTpCeMemAddrSzFO;
+ hostAddr=(*aTplPtr & KTpCeMemHostAddrM);
+ aTplPtr++;
+ break;
+ case 2: // Length(2byte) and base address(2byte) specified.
+ addrInBytes=2;
+ case 1: // Single 2-byte length specified.
+ lenInBytes=2;
+ windows=1;
+ break;
+ }
+
+ if ((windows+aNextChnkNum)>KMaxChunksPerConfig)
+ return(KErrNotSupported); // Too many descriptors for us
+
+ aChnk+=aNextChnkNum;
+ TInt i;
+ for (;windows>0;windows--,aChnk++,aNextChnkNum++)
+ {
+ aChnk->iMemType=EPccdCommon16Mem;
+ aChnk->iMemLen=0;
+ if (lenInBytes)
+ {
+ for (i=0;i<lenInBytes;i++)
+ aChnk->iMemLen += (*aTplPtr++) << ((8*i)+8); // in 256 byte pages
+ }
+ aChnk->iMemBaseAddr=0;
+ if (addrInBytes)
+ {
+ for (i=0;i<addrInBytes;i++)
+ aChnk->iMemBaseAddr += (*aTplPtr++) << ((8*i)+8);// in 256 byte pages
+ }
+ if (hostAddr)
+ {
+ for (i=0;i<addrInBytes;i++)
+ aTplPtr++; // Dont record this, just advance the tuple pointer
+ }
+ }
+ return(aTplPtr-initPtr);
+ }
+
+LOCAL_C TInt ParseMiscEntry(const TUint8 *aTplPtr, TBool &aPwrDown)
+//
+// Parse a miscellaneous features field in a KCisTplCfTableEntry tuple.
+// Returns the number of bytes we have parsed.
+//
+ {
+ aPwrDown=(*aTplPtr&KTpCePwrDownM);
+
+ TInt i;
+ for (i=1;*aTplPtr & KCisTplExt;i++,aTplPtr++);
+ return(i);
+ }
+
+LOCAL_C TInt ParseConfigEntTuple(TDes8 &cTpl,TPcCardConfig &anInfo)
+//
+// Parse a KCisTplCfTableEntry tuple. anInfo contains default values on
+// entry so this routine only adds data it finds in the tuple.
+//
+ {
+
+ // Parse the Index byte.
+ const TUint8 *tplPtr=cTpl.Ptr()+2; // First tuple after link
+ anInfo.iConfigOption=(*tplPtr & KTpCeOptionM);
+ anInfo.iIsDefault=(*tplPtr & KTpCeIsDefaultM);
+
+ // Check if there is an interface description field to follow
+ if (*tplPtr++ & KTpCeIntfPresM)
+ {
+ anInfo.iIsIoAndMem=(*tplPtr&KTpCeIntfTypeM);
+ anInfo.iActiveSignals=*tplPtr&(KTpCeBvdM|KTpCeWpM|KTpCeReadyM|KTpCeWaitM);
+ tplPtr++;
+ }
+
+ // Next byte should be the feature selection byte.
+ TUint8 features=*tplPtr++;
+
+ // Next might be 0-3 power description structures. 1st one is always VCC info.
+ TInt entry=(features & KTpCePwrPresM)>>KTpCePwrPresFO;
+ if (entry)
+ {
+ tplPtr += ParsePowerEntry(tplPtr,&anInfo.iVccMaxInMilliVolts,&anInfo.iVccMinInMilliVolts,
+ &anInfo.iOperCurrentInMicroAmps,&anInfo.iPwrDwnCurrentInMicroAmps);
+ entry--;
+ }
+
+ // We only support a single Vpp supply. However we need to parse both (Vpp1+Vpp2)
+ // in order to advance the tuple pointer.
+ while ( entry-- )
+ tplPtr += ParsePowerEntry(tplPtr,&anInfo.iVppMaxInMilliVolts,&anInfo.iVppMinInMilliVolts,NULL,NULL);
+
+ // Next might be timing info.
+ if (features & KTpCeTimPresM)
+ tplPtr += ParseTimingEntry(tplPtr);
+
+ // Next might be IO space description.
+ TInt ret;
+ TInt nextFreeChunk=0;
+ if (features & KTpCeIoPresM)
+ {
+ if((ret=ParseIoEntry(tplPtr,&(anInfo.iChnk[0]),nextFreeChunk))<0)
+ return(ret);
+ anInfo.iValidChunks=nextFreeChunk;
+ tplPtr += ret;
+ }
+
+ // Next might be IRQ description.
+ if (features & KTpCeIrqPresM)
+ {
+ anInfo.iInterruptInfo=*tplPtr&(KPccdIntShare|KPccdIntPulse|KPccdIntLevel);
+ tplPtr+=(*tplPtr&KTpCeIrqMaskM)?3:1; // Ignore mask bytes if present
+ }
+
+ // Next might be memory space description.
+ entry=((features & KTpCeMemPresM) >> KTpCeMemPresFO);
+ if (entry)
+ {
+ if ((ret=ParseMemEntry(tplPtr,entry,&(anInfo.iChnk[0]),nextFreeChunk))<0)
+ return(ret);
+ anInfo.iValidChunks=nextFreeChunk;
+ tplPtr+=ret;
+ }
+
+ // And finally there might be a miscellaneous features field
+ if (features & KTpCeMiscPresM)
+ tplPtr+=ParseMiscEntry(tplPtr,anInfo.iPwrDown);
+
+ // Check that we haven't been reading beyond the tuple.
+ if ((tplPtr-cTpl.Ptr()) > (cTpl[1]+2))
+ return(KErrCorrupt);
+
+ return(KErrNone);
+ }
+
+LOCAL_C TInt ParseDeviceInfo(const TUint8 *aTplPtr,TPcCardRegion &anInfo)
+//
+// Parse a device info field in a KCisTplDeviceX tuple.
+// Returns the number of bytes we have parsed (or a negative error value).
+//
+ {
+
+ const TUint8 *initPtr=aTplPtr;
+ TInt val;
+ // Device ID - device type field
+ val=((*aTplPtr & KTpDiDTypeM) >> KTpDiDTypeFO);
+ if (val==KTpDiDTypeExtend)
+ return(KErrNotSupported); // Don't support extended device type
+ anInfo.iDeviceType=DevType(val);
+
+ // Device ID - write protect field
+ if (!(*aTplPtr&KTpDiWpsM))
+ anInfo.iActiveSignals|=KSigWpActive;
+
+ // Device ID - device speed field
+ val=(*aTplPtr & KTpDiDSpeedM);
+ if (val==KTpDiDSpeedExt)
+ {
+ aTplPtr++;
+ anInfo.iExtendedAccSpeedInNanoSecs=ExtendedSpeedToNanoSeconds(*aTplPtr);
+ anInfo.iAccessSpeed=DevSpeedFromExtended(anInfo.iExtendedAccSpeedInNanoSecs);
+ while(*aTplPtr++ & KCisTplExt); // Jump past any (further) extended speed fields
+ }
+ else
+ {
+ anInfo.iExtendedAccSpeedInNanoSecs=0;
+ anInfo.iAccessSpeed=CisDevSpeedTable[val];
+ aTplPtr++;
+ }
+
+ // Now the Device size
+ TInt size,numUnits;
+ size=((*aTplPtr & KTpDiDSizeM) >> KTpDiDSizeFO);
+ numUnits=((*aTplPtr++ & KTpDiDUnitsM) >> KTpDiDUnitsFO)+1;
+ if (size>KTpDiDSize2M)
+ return(KErrCorrupt);
+ anInfo.iChnk.iMemLen=numUnits*CisDevSizeInBytesTable[size];
+ return(aTplPtr-initPtr);
+ }
+/*
+LOCAL_C TInt SocketIsInRange(TSocket aSocket)
+//
+// Check socket is valid for this machine
+//
+ {
+
+// return(aSocket>=0&&aSocket<ThePcCardController->TotalSupportedBuses());
+ return (aSocket>=0 && aSocket<KMaxPBusSockets && TheSockets[aSocket]!=NULL);
+ }
+*/
+EXPORT_C TCisReader::TCisReader()
+//
+// Constructor.
+//
+ : iFunc(0),iCisOffset(0),iLinkOffset(0),iMemType(EPccdAttribMem),
+ iLinkFlags(0),iRestarted(EFalse),iRegionCount(0),
+ iConfigCount(0)
+ {
+ iSocket=NULL;
+ }
+
+EXPORT_C TInt TCisReader::SelectCis(TSocket aSocket,TInt aCardFunc)
+//
+// Assign the CIS reader to a socket and function.
+//
+ {
+ // We need to have read the CIS format
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:SelectCis(S:%d F:%d)",aSocket,aCardFunc));
+ DPcCardSocket* pS=(DPcCardSocket*)TheSockets[aSocket];
+ if (pS->CardIsReadyAndVerified()!=KErrNone)
+ return KErrNotReady;
+ iSocket=pS;
+ return(DoSelectCis(aCardFunc));
+ }
+
+TInt TCisReader::DoSelectCis(TInt aCardFunc)
+//
+// Actually assign the CIS reader to a socket and function.
+//
+ {
+
+ // Check that the function is valid
+ TInt r;
+ if (!iSocket->IsValidCardFunc(aCardFunc))
+ {
+ iSocket=NULL;
+ r=KErrNotFound;
+ }
+ else
+ {
+ iFunc=aCardFunc;
+ DoRestart();
+ iConfigCount=0;
+ r=KErrNone;
+ }
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<CisReader:DoSelectCis(F:%d)-%d",aCardFunc,r));
+ return(r);
+ }
+
+EXPORT_C TInt TCisReader::Restart()
+//
+// Restart the CIS reader back to the start of the CIS, and re-initialise
+// config entry parsing.
+//
+ {
+ if (iSocket==NULL)
+ return(KErrGeneral);
+ DoRestart();
+ iConfigCount=0;
+ return(KErrNone);
+ }
+
+void TCisReader::DoRestart()
+//
+// Restart the CIS reader back to the start of the CIS
+//
+ {
+
+ TPcCardFunction *func=iSocket->CardFunc(iFunc);
+ iCisOffset=func->InitCisOffset();
+ iLinkOffset=0;
+ iMemType=func->InitCisMemType();
+ iLinkFlags=0;
+ iRestarted=ETrue;
+ iRegionCount=0;
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<CisReader:DoRestart"));
+ }
+
+EXPORT_C TInt TCisReader::FindReadTuple(TUint8 aDesiredTpl,TDes8 &aDes,TUint aFlag)
+//
+// Find a specified tuple from the CIS and read it.
+//
+ {
+ __ASSERT_ALWAYS(iSocket!=NULL,PcCardPanic(EPcCardCisReaderUnInit));
+
+ // We're going to read the card itself so it must be ready.
+ if ( iSocket->CardIsReadyAndVerified()!=KErrNone )
+ return(KErrNotReady);
+
+ return(DoFindReadTuple(aDesiredTpl,aDes,aFlag));
+ }
+
+TInt TCisReader::DoFindReadTuple(TUint8 aDesiredTpl,TDes8 &aDes,TUint aFlag)
+//
+// Actually find a specified tuple from the CIS and read it.
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:DoFindReadTuple(T:%xH)",aDesiredTpl));
+
+ TBuf8<KSmallTplBufSize> tpl;
+ TBuf8<KSmallTplBufSize> linkAddr;
+ TInt i,j,err;
+
+ // Read the previous tuple
+ if ((err=iSocket->ReadCis(iMemType,iCisOffset,tpl,2))!=KErrNone)
+ return(err);
+
+ for (j=0;j<KMaxTuplesPerCis;j++)
+ {
+ // Adjust CIS offset beyond last tuple read (unless we've just restarted)
+ if (iRestarted)
+ iRestarted=EFalse;
+ else
+ {
+ if (tpl[0]!=KCisTplEnd && tpl[1]!=0xff)
+ iCisOffset+=(tpl[0]==KCisTplNull)?1:(tpl[1]+2); // A null tuple has no link field
+ else
+ {
+ // End of chain tuple
+ if ((err=FollowLink(aFlag&KPccdReportErrors))!=KErrNone)
+ return(err);
+ }
+ }
+
+ // Read the next tuple
+ if ((err=iSocket->ReadCis(iMemType,iCisOffset,tpl,2))!=KErrNone)
+ return(err);
+
+ // Check for a link tuple (need to store next chain addr. for later)
+ switch(tpl[0])
+ {
+ case KCisTplLongLinkA:
+ iLinkFlags |= KPccdLinkA;
+ if ((err= iSocket->ReadCis(iMemType,iCisOffset+2,linkAddr,4)) != KErrNone)
+ return(err);
+ for (iLinkOffset=0,i=0 ; i<4 ; i++)
+ iLinkOffset += linkAddr[i] << (8*i);
+ break;
+ case KCisTplLongLinkC:
+ iLinkFlags |= KPccdLinkC;
+ if ((err= iSocket->ReadCis(iMemType,iCisOffset+2,linkAddr,4)) != KErrNone)
+ return(err);
+ for (iLinkOffset=0,i=0 ; i<4 ; i++)
+ iLinkOffset += linkAddr[i] << (8*i);
+ break;
+ case KCisTplLongLinkMfc:
+ iLinkFlags |= KPccdLinkMFC;
+ break;
+ case KCisTplNoLink:
+ iLinkFlags |= KPccdNoLink;
+ default:
+ break;
+ }
+
+ // Check if we have found the specified tuple
+ if (aDesiredTpl==KPccdNonSpecificTpl || aDesiredTpl==tpl[0])
+ {
+ // The following are ignored unless KPccdReturnLinkTpl is set.
+ if ((tpl[0]==KCisTplNull)||
+ (tpl[0]==KCisTplEnd)||
+ (tpl[0]==KCisTplLongLinkA)||
+ (tpl[0]==KCisTplLongLinkC)||
+ (tpl[0]==KCisTplLongLinkMfc)||
+ (tpl[0]==KCisTplNoLink)||
+ (tpl[0]==KCisTplLinkTarget))
+ {
+ if (aFlag&KPccdReturnLinkTpl)
+ break;
+ }
+ else
+ break;
+ }
+ }
+
+ // We got a result (or we've wandered off into the weeds)
+ if (j>=KMaxTuplesPerCis)
+ return( (aFlag&KPccdReportErrors)?KErrCorrupt:KErrNotFound );
+ else
+ return((aFlag&KPccdFindOnly)?KErrNone:DoReadTuple(aDes));
+ }
+
+EXPORT_C TInt TCisReader::ReadTuple(TDes8 &aDes)
+//
+// Read the tuple at the current CIS offset.
+//
+ {
+ __ASSERT_ALWAYS(iSocket!=NULL,PcCardPanic(EPcCardCisReaderUnInit));
+
+ // We're going to read the card itself so it must be ready.
+ if ( iSocket->CardIsReadyAndVerified()!=KErrNone )
+ return(KErrNotReady);
+
+ return(DoReadTuple(aDes));
+ }
+
+TInt TCisReader::DoReadTuple(TDes8 &aDes)
+//
+// Actually read the tuple at the current CIS offset.
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:DoReadTuple"));
+ TInt err;
+
+ // Read the tuple type and link
+ TBuf8<KSmallTplBufSize> tpl;
+ if ((err= iSocket->ReadCis(iMemType,iCisOffset,tpl,2)) != KErrNone)
+ return(err);
+
+ TInt tplLen ;
+ if ((tpl[0] == KCisTplNull) || (tpl[0] == KCisTplEnd))
+ tplLen = 1 ; // These tuples dont have a link.
+ else
+ tplLen = (tpl[1]+2) ;
+ if ( tplLen>aDes.MaxLength() ) // We dont want a panic if aDes too small
+ return(KErrArgument);
+
+ // Lets copy the tuple
+ if ((err= iSocket->ReadCis(iMemType,iCisOffset,aDes,tplLen)) != KErrNone)
+ return(err);
+ else
+ return(KErrNone);
+ }
+
+TInt TCisReader::FollowLink(TUint aFullErrorReport)
+//
+// Called at the end of a tuple chain, this moves CIS pointer to the next
+// CIS chain if a long link has been detected.
+//
+ {
+
+ TInt err;
+ switch (iLinkFlags)
+ {
+ case 0: // Haven't found anything so assume longlink to 0 in common.
+ iLinkOffset=0;
+ case KPccdLinkC:
+ iCisOffset=iLinkOffset;
+ iMemType=EPccdCommon8Mem;
+ iLinkOffset=0;
+ if ((err=VerifyLinkTarget())!=KErrNone)
+ {
+ DoRestart(); // Leave pointers somewhere safe.
+ if (iLinkFlags==0||!aFullErrorReport)
+ err=KErrNotFound; // Above assumption wrong
+ }
+ break;
+ case KPccdLinkA:
+ iCisOffset=iLinkOffset;
+ iMemType=EPccdAttribMem;
+ iLinkOffset=0;
+ if ((err=VerifyLinkTarget())!=KErrNone)
+ {
+ iCisOffset>>=1; // Check if the link offset is wrong
+ if (VerifyLinkTarget()!=KErrNone)
+ {
+ DoRestart(); // Leave pointers somewhere safe.
+ if (!aFullErrorReport)
+ err=KErrNotFound;
+ }
+ else
+ err=KErrNone;
+ }
+ break;
+ case KPccdNoLink:
+ case KPccdLinkMFC: // Can't follow a multi-function link
+ DoRestart(); // Leave pointers somewhere safe.
+ err=KErrNotFound;
+ break;
+ default: // Shouldn't have more than 1 link per chain
+ DoRestart(); // Leave pointers somewhere safe.
+ err=(aFullErrorReport)?KErrCorrupt:KErrNotFound;
+ }
+ iLinkFlags=0;
+ return(err);
+ }
+
+TInt TCisReader::VerifyLinkTarget()
+//
+// Verify a new tuple chain starts with a valid link target tuple
+//
+ {
+ TBuf8<KSmallTplBufSize> tpl;
+ TInt err;
+ if ((err=iSocket->ReadCis(iMemType,iCisOffset,tpl,5))!=KErrNone)
+ return(err);
+ if ( (tpl[0]!=KCisTplLinkTarget) || (tpl[1]<3) || (tpl.Find(_L8("CIS"))!=2) )
+ return(KErrCorrupt);
+ return(KErrNone);
+ }
+
+EXPORT_C TInt TCisReader::FindReadRegion(TPccdSocketVcc aSocketVcc,TPcCardRegion &anInfo,TUint8 aDesiredTpl)
+//
+// Read region info from the CIS on the specified Socket/Function. Can
+// be called multiple times to read all regions (eventually
+// returns KErrNotFound).
+// If the function returns an error value then ignore anInfo.
+//
+ {
+
+ if (!aDesiredTpl)
+ aDesiredTpl=(aSocketVcc==EPccdSocket_5V0)?KCisTplDevice:KCisTplDeviceOC;
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:FindReadRegion(TPL:%xH)",aDesiredTpl));
+
+ TInt ret;
+ TBuf8<KLargeTplBufSize> devTpl;
+ if (!iRegionCount) // Count of regions processed in tuple
+ ret=FindReadTuple(aDesiredTpl,devTpl);
+ else
+ ret=ReadTuple(devTpl);
+ if (ret!=KErrNone)
+ return(ret);
+ const TUint8 *tplPtr=devTpl.Ptr();
+ const TUint8 *tplE=tplPtr+devTpl.Length();
+ tplPtr+=2; // First tuple after link
+
+ if (aDesiredTpl==KCisTplDeviceOC||aDesiredTpl==KCisTplDeviceOA)
+ {
+ // Process the Other Conditions info.
+ anInfo.iChnk.iMemType=(aDesiredTpl==KCisTplDeviceOA)?EPccdAttribMem:EPccdCommon16Mem;
+ anInfo.iActiveSignals=(*tplPtr & KTpDoMWaitM)?KSigWaitRequired:0;
+ switch( (*tplPtr & KTpDoVccUsedM) >> KTpDoVccUsedFO )
+ {
+ case 3: anInfo.iVcc=EPccdSocket_yVy; break;
+ case 2: anInfo.iVcc=EPccdSocket_xVx; break;
+ case 1: anInfo.iVcc=EPccdSocket_3V3; break;
+ default: anInfo.iVcc=EPccdSocket_5V0; break;
+ }
+ while (*tplPtr++ & KCisTplExt); // Ignore any extensions
+ }
+ else
+ { // KCisTplDevice
+ anInfo.iChnk.iMemType=(aDesiredTpl==KCisTplDeviceA)?EPccdAttribMem:EPccdCommon16Mem;
+ anInfo.iVcc=EPccdSocket_5V0;
+ anInfo.iActiveSignals=0;
+ }
+
+ // Now start on the Device Info fields
+ anInfo.iAccessSpeed=EAcSpeedInValid;
+ anInfo.iChnk.iMemBaseAddr = anInfo.iChnk.iMemLen = 0;
+ for (TInt regions=1;*tplPtr!=0xFF&&tplPtr<tplE;tplPtr+=ret,regions++)
+ {
+ // Add length of previous region to give new base address.
+ anInfo.iChnk.iMemBaseAddr+=anInfo.iChnk.iMemLen;
+
+ if ((ret=ParseDeviceInfo(tplPtr,anInfo)) < 0)
+ return(ret);
+
+ // Check if we have new region to report (dont report null regions)
+ if (anInfo.iDeviceType!=EDeviceNull && regions>iRegionCount)
+ {
+ iRegionCount=regions; // Save for next time
+ return(KErrNone);
+ }
+ }
+ return(KErrNotFound);
+ }
+
+EXPORT_C TInt TCisReader::FindReadConfig(TPcCardConfig &anInfo)
+//
+// Read configuration info from the CIS on the specified Socket/Function. Can
+// be called multiple times to read all configuration options (eventually
+// returns KErrNotFound). Uses previous configuration option value to mark
+// where we are in a configuration table.
+// If the function returns an error value then ignore anInfo.
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:FindReadConfig(%d)",iConfigCount));
+ __ASSERT_ALWAYS(iSocket!=NULL,PcCardPanic(EPcCardCisReaderUnInit));
+
+ DoRestart(); // Start from beginning of CIS each time (dont reset iConfigCount though).
+
+ // Create an initial default configuration
+ TPcCardConfig defaultConfInfo;
+ defaultConfInfo.iVccMaxInMilliVolts=5250; // 5V+5%
+ defaultConfInfo.iVccMinInMilliVolts=4750; // 5V-5%
+ defaultConfInfo.iAccessSpeed=DEF_IO_ACSPEED;
+ defaultConfInfo.iActiveSignals=0;
+
+ TBuf8<KLargeTplBufSize> configTpl;
+ TInt lastEntryIndex;
+ TBool foundLast=EFalse;
+ TInt err;
+ TInt i=0;
+ if (
+ (err=FindReadTuple(KCisTplConfig,configTpl))==KErrNone &&
+ (err=ParseConfigTuple(configTpl,defaultConfInfo,lastEntryIndex))==KErrNone
+ )
+ {
+ // Start of new configuration table
+ for (; (err=FindReadTuple(KCisTplCfTableEntry,configTpl))==KErrNone && i<KMaxCfEntriesPerCis ; i++)
+ {
+ anInfo=defaultConfInfo; // Entries assume values from last default entry
+ err=ParseConfigEntTuple(configTpl,anInfo);
+ if (anInfo.iConfigOption==lastEntryIndex)
+ foundLast=ETrue;
+ else
+ {
+ if (foundLast)
+ {
+ err=KErrNotFound; // We've passed the last entry
+ break;
+ }
+ }
+ if (iConfigCount==i)
+ break;
+ if (err==KErrNone && anInfo.iIsDefault)
+ defaultConfInfo=anInfo;
+ }
+ }
+ if (i>=KMaxCfEntriesPerCis)
+ err=KErrCorrupt;
+ if (err==KErrNone)
+ iConfigCount++;
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<CisReader:FindReadConfig-%d",err));
+ return(err);
+ }
+
+TPcCardFunction::TPcCardFunction(TUint32 anOffset,TPccdMemType aMemType)
+//
+// Constructor
+//
+ : iFuncType(EUnknownCard),iInitCisOffset(anOffset),iInitCisMemType(aMemType),
+ iConfigBaseAddr(0),iConfigRegMask(0),iConfigIndex(KInvalidConfOpt),iConfigFlags(0)
+ {
+ iClientID=NULL;
+ }
+
+void TPcCardFunction::SetConfigOption(TInt anIndex,DBase *aClientID,TUint aConfigFlags)
+//
+// Save configuration index and client ID
+//
+ {
+
+ iConfigIndex=anIndex;
+ iClientID=aClientID;
+ iConfigFlags=aConfigFlags;
+ }
+
+TInt TPcCardFunction::ConfigRegAddress(TInt aRegOffset,TInt &anAddr)
+//
+// Provide the specified configuration register address.
+//
+ {
+
+ // Must be configured or we wont have the ConfigReg base address
+ if (!IsConfigured())
+ return(KErrGeneral);
+ anAddr=(iConfigBaseAddr + (aRegOffset<<1));
+
+ // Return an error if the register isn't present
+ if ( !(iConfigRegMask & (0x01<<aRegOffset)) )
+ return(KErrNotSupported);
+ else
+ return(KErrNone);
+ }
+
+EXPORT_C TPccdChnk::TPccdChnk()
+//
+// Constructor
+//
+ : iMemType(EPccdAttribMem),iMemBaseAddr(0),iMemLen(0)
+ {}
+
+EXPORT_C TPccdChnk::TPccdChnk(TPccdMemType aType,TUint32 aBaseAddr,TUint32 aLen)
+//
+// Constructor
+//
+ : iMemType(aType),iMemBaseAddr(aBaseAddr),iMemLen(aLen)
+ {}
+
+EXPORT_C TPcCardConfig::TPcCardConfig()
+//
+// Constructor (iConfigOption to KInvalidConfOpt guarentees that we start with
+// 1st configuration entry).
+//
+ : iAccessSpeed(EAcSpeedInValid),iActiveSignals(0),iVccMaxInMilliVolts(0),
+ iVccMinInMilliVolts(0),iValidChunks(0),iIsIoAndMem(FALSE),iIsDefault(FALSE),
+ iPwrDown(FALSE),iVppMaxInMilliVolts(0),iVppMinInMilliVolts(0),iOperCurrentInMicroAmps(0),
+ iPwrDwnCurrentInMicroAmps(0),iInterruptInfo(0),iConfigOption(KInvalidConfOpt),iConfigBaseAddr(0),
+ iRegPresent(0)
+ {}
+
+EXPORT_C TBool TPcCardConfig::IsMachineCompatible(TSocket aSocket,TInt aFlag)
+//
+// Return ETrue if this configuration is compatible with this machine
+//
+ {
+
+ DPcCardSocket* pS=(DPcCardSocket*)TheSockets[aSocket];
+ DPcCardVcc* pV=(DPcCardVcc*)pS->iVcc;
+ TInt nomSocketVcc=DPcCardVcc::SocketVccToMilliVolts(pV->VoltageSetting());
+ if (!(aFlag&KPccdCompatNoVccCheck))
+ {
+ // Check Vcc level compatibility
+ if (iVccMaxInMilliVolts<nomSocketVcc||iVccMinInMilliVolts>nomSocketVcc)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Vcc"));
+ return(EFalse);
+ }
+ }
+
+ TPcCardSocketInfo si;
+ pS->SocketInfo(si);
+ if (!(aFlag&KPccdCompatNoVppCheck))
+ {
+ // Check Vpp level compatibility
+ if (iVppMaxInMilliVolts<si.iNomVppInMilliVolts||iVppMinInMilliVolts>si.iNomVppInMilliVolts)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Vpp"));
+ return(EFalse);
+ }
+ }
+
+ if (!(aFlag&KPccdCompatNoPwrCheck))
+ {
+ // Check the configurations power requirements can be supported
+ if (iOperCurrentInMicroAmps>pV->MaxCurrentInMicroAmps())
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Pwr"));
+ return(EFalse);
+ }
+ }
+
+ // If wait requested then check its supported
+ if ((iActiveSignals&KSigWaitRequired)&&!(si.iSupportedSignals&KSigWaitSupported))
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Wait-sig"));
+ return(EFalse);
+ }
+ // Dealt with WAIT - mask out any other signls which aren't supported - not reason to reject though
+ iActiveSignals&=si.iSupportedSignals;
+ return(ETrue);
+ }
+
+EXPORT_C TPcCardRegion::TPcCardRegion()
+//
+// Constructor (iDeviceType to EDeviceInvalid guarentees that we start with
+// 1st device information entry).
+//
+ : iAccessSpeed(EAcSpeedInValid),iActiveSignals(0),iVcc(EPccdSocket_Invalid),
+ iDeviceType(EDeviceInvalid),iExtendedAccSpeedInNanoSecs(0)
+ {}
+
+EXPORT_C TBool TPcCardRegion::IsMachineCompatible(TSocket aSocket)
+//
+// Return ETrue if this configuration is compatible with this machine
+//
+ {
+
+ DPcCardSocket* pS=(DPcCardSocket*)TheSockets[aSocket];
+ TPccdSocketVcc vcc=pS->VccSetting();
+ // Check Vcc level compatibility
+ if (iVcc!=vcc)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Vcc"));
+ return(EFalse);
+ }
+
+ // If wait requested then check its supported
+ TPcCardSocketInfo si;
+ pS->SocketInfo(si);
+ TBool waitReq=(iActiveSignals&KSigWaitRequired);
+ if (waitReq&&!(si.iSupportedSignals&KSigWaitSupported))
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Wait-sig"));
+ return(EFalse);
+ }
+ // Dealt with WAIT - mask out any other signls which aren't supported - not reason to reject though
+ iActiveSignals&=si.iSupportedSignals;
+
+ // Check requested access speed (ie not too slow for us)
+ TPccdAccessSpeed as=__IS_ATTRIB_MEM(iChnk.iMemType)?si.iMaxAttribAccSpeed:si.iMaxCommonIoAccSpeed;
+ if (iAccessSpeed>as && !waitReq)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad speed"));
+ return(EFalse);
+ }
+ return(ETrue);
+ }
+
+EXPORT_C TPccdType::TPccdType()
+//
+// Constructor
+//
+ : iFuncCount(0)
+ {
+ for (TInt i=0;i<(TInt)KMaxFuncPerCard;i++)
+ iFuncType[i]=EUnknownCard;
+ }
+
+