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