diff -r 000000000000 -r 96e5fb8b040d kernel/eka/drivers/pbus/pccard/spccard.cpp --- /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 +#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;i4) rmsz=4; // We only have 32bit field + for (i=0;i 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;jiMemBaseAddr += (*aTplPtr++) << (8*j); + } + + // Finally, lets get the IO length + if (lenInBytes) + { + for (j=0,aChnk->iMemLen=0;jiMemLen += (*aTplPtr++) << (8*j); + (aChnk->iMemLen)++; + } + else + { + if (ioLines) + aChnk->iMemLen = 0x01<> 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;iiMemLen += (*aTplPtr++) << ((8*i)+8); // in 256 byte pages + } + aChnk->iMemBaseAddr=0; + if (addrInBytes) + { + for (i=0;iiMemBaseAddr += (*aTplPtr++) << ((8*i)+8);// in 256 byte pages + } + if (hostAddr) + { + for (i=0;i>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&&aSocketTotalSupportedBuses()); + return (aSocket>=0 && aSocketCisReader: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("CardFunc(iFunc); + iCisOffset=func->InitCisOffset(); + iLinkOffset=0; + iMemType=func->InitCisMemType(); + iLinkFlags=0; + iRestarted=ETrue; + iRegionCount=0; + __KTRACE_OPT(KPBUS1,Kern::Printf("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 tpl; + TBuf8 linkAddr; + TInt i,j,err; + + // Read the previous tuple + if ((err=iSocket->ReadCis(iMemType,iCisOffset,tpl,2))!=KErrNone) + return(err); + + for (j=0;jReadCis(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 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 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 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&&tplPtriRegionCount) + { + 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 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) + err=KErrCorrupt; + if (err==KErrNone) + iConfigCount++; + __KTRACE_OPT(KPBUS1,Kern::Printf("iVcc; + TInt nomSocketVcc=DPcCardVcc::SocketVccToMilliVolts(pV->VoltageSetting()); + if (!(aFlag&KPccdCompatNoVccCheck)) + { + // Check Vcc level compatibility + if (iVccMaxInMilliVoltsnomSocketVcc) + { + __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Vcc")); + return(EFalse); + } + } + + TPcCardSocketInfo si; + pS->SocketInfo(si); + if (!(aFlag&KPccdCompatNoVppCheck)) + { + // Check Vpp level compatibility + if (iVppMaxInMilliVoltssi.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; + } + +