--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/pbus/pccard/socket.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,994 @@
+// 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\socket.cpp
+//
+//
+
+#include <pccard.h>
+#include "cis.h"
+
+const TInt KFuncGranularity=(KMaxFuncPerCard+1);
+const TInt KMemGranularity=2;
+
+TPccdFuncType FuncType(TUint aFuncCode)
+ {
+
+ if (aFuncCode<=KCisTplFuncIdScsi)
+ return((TPccdFuncType)(aFuncCode+1));
+ else if (aFuncCode==KCisTplFuncIdVendorSpecific)
+ return(EVendorSpecificCard);
+ else
+ return(EUnknownCard);
+ }
+
+/********************************************
+ * PC card power supply
+ ********************************************/
+DPcCardVcc::DPcCardVcc(TInt aPsuNum, TInt aMediaChangeNum)
+ : DPBusPsuBase(aPsuNum, aMediaChangeNum)
+ {
+ }
+
+TInt DPcCardVcc::SocketVccToMilliVolts(TPccdSocketVcc aVcc)
+//
+// Converts a TPccdSocketVcc into a integer value - units mV.
+//
+ {
+ switch (aVcc)
+ {
+ case EPccdSocket_5V0: return(5000);
+ case EPccdSocket_3V3: return(3300);
+ default: return(0);
+ }
+ }
+
+TBool DPcCardVcc::IsLocked()
+ {
+/* TInt i;
+ Kern::EnterCS();
+ for (i=0; i<KMaxPccdSockets; i++)
+ {
+ DPcCardSocket* pS=(DPcCardSocket*)TheSockets[i];
+ if (pS && pS->iVcc==this)
+ {
+ if (pS->iClientWindows || pS->iActiveConfigs)
+ break;
+ }
+ }
+ Kern::LeaveCS();
+ return (i<KMaxPccdSockets);
+*/
+ DPcCardSocket* pS=(DPcCardSocket*)iSocket;
+ return (pS->iClientWindows || pS->iActiveConfigs);
+ }
+
+void DPcCardVcc::ReceiveVoltageCheckResult(TInt anError)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("DPcCardVcc(%d)::ReceiveVoltageCheckResult(%d)",iPsuNum,anError));
+ DPcCardSocket* pS=(DPcCardSocket*)iSocket;
+ TInt s=pS->iCardPowerUpState;
+ if (s==DPcCardSocket::EWaitForVccReading)
+ {
+ if (anError==KErrNone)
+ {
+ SetState(EPsuOnFull);
+ pS->iCardPowerUpState=DPcCardSocket::EWaitForReady;
+ }
+ else
+ pS->TerminatePowerUpSequence(KErrCorrupt);
+ }
+ else if (s!=DPcCardSocket::EInit && s!=DPcCardSocket::EApplyingReset && s!=DPcCardSocket::ECheckVcc)
+ DPBusPsuBase::ReceiveVoltageCheckResult(anError);
+ }
+
+/********************************************
+ * PC card media change
+ ********************************************/
+DPcCardMediaChange::DPcCardMediaChange(TInt aMediaChangeNum)
+ : DMediaChangeBase(aMediaChangeNum)
+ {
+ }
+
+TInt DPcCardMediaChange::Create()
+ {
+ return DMediaChangeBase::Create();
+ }
+
+/********************************************
+ * PC card socket
+ ********************************************/
+void cardPowerUpTick(TAny* aPtr)
+ {
+ ((DPcCardSocket*)aPtr)->iCardPowerUpDfc.Enque();
+ }
+
+void cardPowerUpDfc(TAny* aPtr)
+ {
+ ((DPcCardSocket*)aPtr)->CardPowerUpTick();
+ }
+
+DPcCardSocket::DPcCardSocket(TSocket aSocketNum)
+//
+// Constructor.
+//
+ : DPBusSocket(aSocketNum),
+ iCardFuncArray(KFuncGranularity),
+ iMemChunks(KMemGranularity),
+ iCardPowerUpDfc(cardPowerUpDfc, this, 1)
+ {
+
+ iType=EPBusTypePcCard;
+// iCardPowerUpState=EIdle;
+// iClientWindows=0;
+// iActiveConfigs=0;
+ }
+
+TInt DPcCardSocket::Create(const TDesC* aName)
+//
+// Create a new Socket. Only created once on kernel initialization so don't
+// worry about cleanup if it fails.
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):Create(%lS)",iSocketNumber,aName));
+
+ TInt r=DPBusSocket::Create(aName);
+ if (r!=KErrNone)
+ return r;
+ iCardPowerUpDfc.SetDfcQ(&iDfcQ);
+
+ // Create card function array - add and remove a dummy function to pre-allocate array memory.
+ // This way, adding new functions to array never causes any memory allocation.
+ r=AddNewFunc(0,EPccdAttribMem); // Add dummy function
+ if (r!=KErrNone)
+ return r;
+ delete iCardFuncArray[0]; // Destroy dummy function
+ iCardFuncArray.Remove(0); // Remove pointer to dummy from array
+
+ // Now allocate the permanent attribute memory chunk. Don't bother about what
+ // access speed we asign, it gets set each time we subsequently access the chunk.
+ TPccdChnk chnk(EPccdAttribMem,0,KDefaultAttribMemSize);
+ r=iAttribWin.Create(this,chnk,EAcSpeed300nS,KPccdChunkPermanent|KPccdChunkShared|KPccdChunkSystemOwned);
+ return r;
+ }
+
+void DPcCardSocket::ResetPowerUpState()
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):ResetPowerUpState",iSocketNumber));
+ if (iCardPowerUpState!=EIdle)
+ {
+ iCardPowerUpTimer.Cancel();
+ iCardPowerUpDfc.Cancel();
+ iCardPowerUpState=EIdle;
+ }
+ }
+
+void DPcCardSocket::Reset1()
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):Reset1",iSocketNumber));
+ ResetPowerUpState();
+ }
+
+void DPcCardSocket::Reset2()
+//
+// Reset the socket (called to remove any allocated memory following a
+// media change event).
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):Rst2",iSocketNumber));
+ // Destroy all the function objects
+ TInt i;
+ for (i=CardFuncCount()-1;i>=0;i--)
+ {
+ delete iCardFuncArray[i];
+ iCardFuncArray.Remove(i); // Now remove from array (doesn't cause memory dealloc).
+ }
+ iActiveConfigs=0;
+
+ // Destroy all the non-permanent Pc Card chunks
+ for (i=(iMemChunks.Count()-1);i>=0;i--)
+ {
+ if ( iMemChunks[i]->IsRemovable() )
+ iMemChunks[i]->Close();
+ }
+ iMemChunks.Compress();
+ }
+
+void DPcCardSocket::Restore()
+//
+// Restore the socket. Normally called when restoring a socket after it has been powered
+// down due to inactivity (but not media change)
+//
+ {
+ TInt i;
+ TPcCardFunction *cf;
+ for (i=CardFuncCount()-1;i>=0;i--)
+ {
+ cf=iCardFuncArray[i];
+
+ TUint8 index;
+ if ((index=(TUint8)cf->ConfigOption())!=KInvalidConfOpt && cf->IsRestorableConfig())
+ WriteConfigReg(i,KConfigOptionReg,index);
+ }
+ }
+
+void DPcCardSocket::RemoveChunk(DPccdChunkBase *aChunk)
+//
+// Remove a chunk from this socket.
+//
+ {
+ TInt i;
+ for (i=0;i<iMemChunks.Count();i++)
+ {
+ if (iMemChunks[i]==aChunk)
+ {
+ iMemChunks.Remove(i);
+ iMemChunks.Compress();
+ return;
+ }
+ }
+ }
+
+EXPORT_C TInt DPcCardSocket::RequestConfig(TInt aCardFunc,DBase *aClientID,TPcCardConfig &anInfo,TUint aFlag)
+//
+// Configure the card.
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):RequestConfig(F:%d O:%xH B:%xH L:%xH)",iSocketNumber,aCardFunc,\
+ anInfo.iConfigOption,anInfo.iConfigBaseAddr,anInfo.iRegPresent));
+ if (!IsValidCardFunc(aCardFunc))
+ return(KErrArgument);
+ // Check that this function isn't configured already
+ TPcCardFunction *cf=iCardFuncArray[aCardFunc];
+ if (cf->IsConfigured())
+ return(KErrInUse); // Its already configured.
+
+ // If configuration registers are within attribute chunk then configure the
+ // card (rather than use the registers present info, assume all registers are
+ // present - ie size of mask).
+ if (anInfo.iConfigBaseAddr+(sizeof(anInfo.iRegPresent)<<1)>KDefaultAttribMemSize)
+ return(KErrNotSupported);
+ anInfo.iConfigOption&=(KConfOptLevIReqM|KConfOptConfM); // Mustn't allow msb - KInvalidConfOpt
+ TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
+ iAttribWin.SetAccessSpeed(sp);
+ iAttribWin.SetupChunkHw();
+ iAttribWin.Write(anInfo.iConfigBaseAddr,(TUint8*)&anInfo.iConfigOption,1);
+
+ cf->SetConfigRegMask(anInfo.iRegPresent);
+ cf->SetConfigBaseAddr(anInfo.iConfigBaseAddr);
+ cf->SetConfigOption(anInfo.iConfigOption,aClientID,aFlag);
+ __e32_atomic_add_ord32(&iActiveConfigs, 1);
+ return(KErrNone);
+ }
+
+EXPORT_C void DPcCardSocket::ReleaseConfig(TInt aCardFunc,DBase *aClientID)
+//
+// Return card to memory only config.
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):ReleaseConfig(F:%d)",iSocketNumber,aCardFunc));
+ if (IsValidCardFunc(aCardFunc))
+ {
+ TPcCardFunction *cf=iCardFuncArray[aCardFunc];
+ if (cf->IsConfiguredByClient(aClientID))
+ {
+ if (iState==EPBusOn && Kern::PowerGood())
+ WriteConfigReg(aCardFunc,KConfigOptionReg,0); // Restore Config. Option register
+
+ cf->SetConfigRegMask(0);
+ cf->SetConfigBaseAddr(0);
+ cf->SetConfigOption(KInvalidConfOpt,NULL,0);
+ __e32_atomic_add_ord32(&iActiveConfigs, TUint32(-1));
+ }
+ }
+ }
+
+EXPORT_C TInt DPcCardSocket::ReadConfigReg(TInt aCardFunc,TInt aRegOffset,TUint8 &aVal)
+//
+// Read from a specified configuration register. (We return an error if the RegPres mask
+// indicates the register isn't present but still attempt the read).
+//
+ {
+ TInt offset, err;
+ if (!IsValidCardFunc(aCardFunc)|| iState!=EPBusOn || !Kern::PowerGood())
+ err=KErrArgument;
+ else
+ {
+ if ((err=iCardFuncArray[aCardFunc]->ConfigRegAddress(aRegOffset,offset))==KErrNone||err==KErrNotSupported)
+ {
+ TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
+ iAttribWin.SetAccessSpeed(sp);
+ iAttribWin.SetupChunkHw();
+ iAttribWin.Read(offset,&aVal,1);
+ }
+ }
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<Skt(%d):ReadConfigReg-%d",iSocketNumber,err));
+ return(err);
+ }
+
+EXPORT_C TInt DPcCardSocket::WriteConfigReg(TInt aCardFunc,TInt aRegOffset,const TUint8 aVal)
+//
+// Write to a specified configuration register. (We return an error if the RegPres mask
+// indicates the register isn't present but still attempt the write).
+//
+ {
+ TInt offset, err;
+ if (!IsValidCardFunc(aCardFunc)|| iState!=EPBusOn || !Kern::PowerGood())
+ err=KErrArgument;
+ else
+ {
+ if ((err=iCardFuncArray[aCardFunc]->ConfigRegAddress(aRegOffset,offset))==KErrNone||err==KErrNotSupported)
+ {
+ TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
+ iAttribWin.SetAccessSpeed(sp);
+ iAttribWin.SetupChunkHw();
+ iAttribWin.Write(offset,&aVal,1);
+ }
+ }
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<Skt(%d):WriteConfigReg-%d",iSocketNumber,err));
+ return(err);
+ }
+
+const TInt KReadCisBufferSize=0x80; // 128 Bytes
+TInt DPcCardSocket::ReadCis(TPccdMemType aMemType,TInt aPos,TDes8 &aDes,TInt aLen)
+//
+// Read from CIS
+//
+ {
+
+ __KTRACE_OPT(KPBUS2,Kern::Printf(">Skt(%d):ReadCis(LE:%xH PO:%d TY:%d)",iSocketNumber,aLen,aPos,aMemType));
+ RPccdWindow newWin;
+ RPccdWindow* win=&newWin;
+ TBool needNewChunk=ETrue;
+ TInt cisE=(aPos+aLen);
+ TInt incrm=1;
+ if (aMemType==EPccdAttribMem)
+ {
+ incrm=2; // Read every other byte
+ cisE<<=1;
+ aPos<<=1;
+ if (cisE<=(TInt)KDefaultAttribMemSize)
+ {
+ needNewChunk=EFalse;
+ win=&iAttribWin;
+ }
+ }
+
+ if (needNewChunk)
+ {
+ TPccdChnk chnk(aMemType,aPos,(cisE-aPos));
+ TInt r=newWin.Create(this,chnk,EAcSpeed300nS,KPccdChunkShared|KPccdChunkSystemOwned);
+ if (r!=KErrNone)
+ return(r);
+ cisE-=aPos;
+ aPos=0;
+ }
+
+ TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
+ win->SetAccessSpeed(sp);
+ win->SetupChunkHw();
+ aDes.Zero();
+ TText8 buf[KReadCisBufferSize];
+ TInt s;
+ for (;aPos<cisE;aPos+=s)
+ {
+ s=Min(KReadCisBufferSize,(cisE-aPos));
+ win->Read(aPos,&buf[0],s);
+ for (TInt i=0;i<s;i+=incrm)
+ aDes.Append((TChar)buf[i]);
+ }
+
+ if (needNewChunk)
+ newWin.Close();
+ return(KErrNone);
+ }
+
+TInt DPcCardSocket::AddNewFunc(TUint32 anOffset,TPccdMemType aMemType)
+//
+// Create a new card function and append it to the function array
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):AddNewFunc(T:%d)",iSocketNumber,aMemType));
+ TInt r=KErrNoMemory;
+ TPcCardFunction* cf=new TPcCardFunction(anOffset,aMemType);
+ if (cf)
+ {
+ r=iCardFuncArray.Append(cf);
+ if (r!=KErrNone)
+ delete cf;
+ }
+ return r;
+ }
+
+TPcCardFunction *DPcCardSocket::CardFunc(TInt aCardFunc)
+//
+// Get a reference to a specific card function from the function array
+//
+ {
+
+ __ASSERT_ALWAYS(IsValidCardFunc(aCardFunc),PcCardPanic(EPcCardBadFunctionNumber));
+ return iCardFuncArray[aCardFunc];
+ }
+
+TBool DPcCardSocket::IsConfigLocked()
+//
+// Returns ETrue if this socket contains a card function which is currently configured.
+//
+ {
+// TInt i;
+// for (i=CardFuncCount()-1;i>=0;i--)
+// {
+// if (iCardFuncArray[i]->IsConfigured())
+// return(ETrue);
+// }
+// return(EFalse);
+ return (iActiveConfigs!=0);
+ }
+
+TBool DPcCardSocket::IsMemoryLocked()
+//
+// Returns ETrue if any PC Card memory chunks are allocated on this socket.
+//
+ {
+
+// TInt i;
+// for (i=iMemChunks.Count()-1;i>=0;i--)
+// {
+// if ( iMemChunks[i]->IsLocked() )
+// return(ETrue);
+// }
+// return(EFalse);
+ return (iClientWindows!=0);
+ }
+
+TPccdSocketVcc DPcCardSocket::VccSetting()
+//
+// Return voltage setting that this socket is currently set for
+//
+ {
+
+ return ((DPcCardVcc*)iVcc)->VoltageSetting();
+ }
+
+EXPORT_C TInt DPcCardSocket::VerifyCard(TPccdType &aType)
+//
+// Return information about the type of card present
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">Cntrl:VerifyCard(S:%d)",iSocketNumber));
+ // The data we want is stored off-card, so it doesn't actually need to be
+ // powered but we need to have read CIS format.
+ TInt err=KErrNone;
+ if (CardIsReadyAndVerified()==KErrNone)
+ {
+ aType.iFuncCount=CardFuncCount();
+ for (TInt i=(aType.iFuncCount-1);i>=0;i--)
+ aType.iFuncType[i]=CardFunc(i)->FuncType();
+ }
+ else
+ err=KErrNotReady;
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<Cntrl:VerifyCard(S:%d T:%d)-%d",iSocketNumber,(TInt)aType.iFuncType[0],err));
+ return(err);
+ }
+
+TInt DPcCardSocket::CardIsReadyAndVerified()
+//
+// Returns KErrNone when specified card is powered and ready (ie has had h/w reset) and
+// a basic parsing of CIS has been performed (card functions detected).
+//
+ {
+
+ TInt r=KErrNotReady;
+ if (CardIsReady())
+ {
+ r=KErrNone;
+ // Check if card function(s) have been determined (there is always at
+ // least a global function record if basic parsing performed).
+ if (!IsVerified())
+ r=GetCisFormat();
+ }
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<Cntrl:CardRdyAndVerif(S:%d)-%xH",iSocketNumber,r));
+ return r;
+ }
+
+TBool DPcCardSocket::CardIsReady()
+ {
+ TBool r=(iState==EPBusOn && Kern::PowerGood());
+ __KTRACE_OPT(KPBUS1,Kern::Printf("CardIsReady: %d",r));
+ return r;
+ }
+
+TBool DPcCardSocket::CardIsPowered()
+ {
+ return !iVcc->IsOff();
+ }
+
+TInt DPcCardSocket::GetCisFormat()
+//
+// Determine the type of card present by parsing the entire CIS. If a
+// Multi-function card is present then parse each CIS.
+//
+ {
+
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">GetCisFormat (S:%d)",iSocketNumber));
+
+ TInt r=AddNewFunc(0,EPccdAttribMem); // We always have 1st CIS
+ if (r!=KErrNone)
+ return r;
+ if (ValidateCis(0)!=KErrNone) // Can't use this until func added
+ return KErrCorrupt;
+ TCisReader cisRd;
+ cisRd.iSocket=this;
+ cisRd.DoSelectCis(0);
+ TPccdFuncType firstFuncType;
+ // Check for a multi-function card, search the global CIS (attribute
+ // memory - addr 0) for a KCisTplLongLinkMfc tuple.
+ TBuf8<KLargeTplBufSize> tpl;
+ if (cisRd.DoFindReadTuple(KCisTplLongLinkMfc,tpl,KPccdReturnLinkTpl)==KErrNone)
+ {
+ // Multi-Function card
+ firstFuncType=EGlobalCard;
+ const TUint8 *tplPtr=tpl.Ptr()+2; // First tuple after link
+ TInt funcCount=*tplPtr++;
+
+ // Add a card function object to the socket for each entry in KCisTplLongLinkMfc tuple
+ TPccdMemType memType;
+ TUint32 lnkAdr;
+ TInt i;
+ for (i=0;i<funcCount;i++)
+ {
+ memType=(*tplPtr++)?EPccdCommon8Mem:EPccdAttribMem;
+ TInt j;
+ for (lnkAdr=0,j=0;j<4;j++) // Convert link address from string to unsigned long
+ lnkAdr += (*tplPtr++) << (8*j);
+ r=AddNewFunc(lnkAdr,memType);
+ if (r!=KErrNone)
+ return r;
+ if (ValidateCis(i+1)!=KErrNone) // Can't use this until func added
+ return KErrCorrupt;
+ }
+ // Parse the CIS of each card function looking for a KCisTplFuncId tuple
+ for (i=1;i<=funcCount;i++)
+ {
+ cisRd.DoSelectCis(i);
+ TPccdFuncType ft;
+ if (cisRd.DoFindReadTuple(KCisTplFuncId,tpl,0)==KErrNone)
+ ft=FuncType(tpl[2]);
+ else
+ ft=EUnknownCard;
+ CardFunc(i)->SetFuncType(ft);
+ }
+ }
+ else
+ {
+ // Single Function card
+ cisRd.Restart();
+ if (cisRd.DoFindReadTuple(KCisTplFuncId,tpl,0)==KErrNone)
+ firstFuncType=FuncType(tpl[2]);
+ else
+ firstFuncType=EUnknownCard;
+ }
+
+ CardFunc(0)->SetFuncType(firstFuncType);
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<GetCisFormat(T:%d)",firstFuncType));
+ return KErrNone;
+ }
+
+TInt DPcCardSocket::ValidateCis(TInt aCardFunc)
+//
+// Attempt to walk though entire CIS.
+//
+ {
+
+ TCisReader cisRd;
+ cisRd.iSocket=this;
+ TBuf8<KLargeTplBufSize> tpl;
+ TInt j=0,err;
+ if ((err=cisRd.DoSelectCis(aCardFunc))==KErrNone)
+ {
+ for (j=0;j<KMaxTuplesPerCis;j++)
+ {
+ err=cisRd.DoFindReadTuple(KPccdNonSpecificTpl,tpl,(KPccdFindOnly|KPccdReturnLinkTpl|KPccdReportErrors));
+ if (err!=KErrNone)
+ break;
+ }
+ if (j>=KMaxTuplesPerCis)
+ err=KErrCorrupt;
+ if (err==KErrNotFound)
+ err=KErrNone;
+ }
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<Skt:ValidateCis(S:%d F:%d Tuples:%d)-%d",iSocketNumber,aCardFunc,j,err));
+ return(err);
+ }
+
+void DPcCardSocket::InitiatePowerUpSequence()
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("DPcCardSocket(%d)::InitiatePowerUpSequence",iSocketNumber));
+ // Check if battery is too low
+// TSupplyStatus ss=(TSupplyStatus)iMachineInfo.iDisableOnLowBattery;
+// if (ss!=EZero)
+// {
+// TSupplyInfoV1 info;
+// Hal::SupplyInfo(info);
+// if (info.iMainBatteryStatus<ss && !info.iExternalPowerPresent)
+// {
+// iSocket[aSocket]->SetSocketStatus(ESocketBatTooLow);
+// rs=KErrBadPower;
+// break;
+// }
+// }
+
+ // Check the state of the Voltage sense line
+ TSocketIndicators ind;
+ Indicators(ind);
+ TUint v=(TUint)ind.iVoltSense & ((DPcCardVcc*)iVcc)->VoltageSupported();
+ if (v==0)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("InitiatePowerUpSequence(S:%d)-Voltage sense problem(%d)",iSocketNumber,ind.iVoltSense));
+ iVcc->SetCurrLimited(); // Not totally true but has effect.
+ PowerUpSequenceComplete(KErrCorrupt);
+ return;
+ }
+ TPccdSocketVcc sVcc=(v&KPccdVcc_3V3)?EPccdSocket_3V3:EPccdSocket_5V0; // ??? What about xVx / yVy
+ ((DPcCardVcc*)iVcc)->SetVoltage(sVcc);
+
+ // Power up card (current limited).
+ __KTRACE_OPT(KPBUS1,Kern::Printf("InitiatePowerUpSequence(S:%d)-Apply Vcc",iSocketNumber));
+ if (iVcc->SetState(EPsuOnCurLimit) != KErrNone)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("InitiatePowerUpSequence(S:%d)-Vcc problem",iSocketNumber));
+ iVcc->SetState(EPsuOff);
+ iVcc->SetCurrLimited();
+ PowerUpSequenceComplete(KErrGeneral);
+ return;
+ }
+ iCardPowerUpState=EInit;
+ iCardPowerUpTickCount=0;
+ iCardPowerUpResetLen=KResetOnDefaultLen;
+ iCardPowerUpPauseLen=KResetOffDefaultLen;
+ iCardPowerUpTimer.Periodic(KPccdPowerUpReqInterval,cardPowerUpTick,this);
+ }
+
+void DPcCardSocket::TerminatePowerUpSequence(TInt aResult)
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("DPcCardSocket(%d)::TerminatePowerUpSequence result %d",iSocketNumber,aResult));
+ ResetPowerUpState();
+ if (aResult==KErrNone)
+ Restore();
+ PowerUpSequenceComplete(aResult);
+ }
+
+void DPcCardSocket::CardPowerUpTick()
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf("CardPowerUpTick S:%d Elapsed %d State %d",iSocketNumber,iCardPowerUpTickCount,iCardPowerUpState));
+ if (++iCardPowerUpTickCount>KPwrUpTimeOut)
+ {
+ iVcc->SetState(EPsuOff); // should leave this to timeout
+ TerminatePowerUpSequence(KErrTimedOut);
+ return;
+ }
+ switch (iCardPowerUpState)
+ {
+ case EInit:
+ HwReset(ETrue); // Apply reset - Turns on interface
+ iCardPowerUpState=EApplyingReset;
+ break;
+ case EApplyingReset:
+ if (iCardPowerUpTickCount>iCardPowerUpResetLen)
+ {
+ HwReset(EFalse); // remove reset
+ iCardPowerUpState=ECheckVcc;
+ }
+ break;
+ case ECheckVcc:
+ {
+ iCardPowerUpState=EWaitForVccReading;
+ TInt cv=iVcc->CheckVoltage(KPsuChkOnPwrUp);
+ if (cv==KErrNotSupported)
+ iCardPowerUpState=EWaitForReady;
+ else if (cv!=KErrNone)
+ TerminatePowerUpSequence(cv);
+ break;
+ }
+ case EWaitForVccReading:
+ break;
+ case EWaitForReady:
+ if (Ready())
+ {
+ iCardPowerUpState=EPauseAfterReady; // Card is ready
+ // Its effectively powered up now so reset the elapsed time and use it
+ // to measure pause after reset (ie this is limited to KPwrUpTimeOut too).
+ iCardPowerUpTickCount=0;
+ }
+ break;
+ case EPauseAfterReady:
+ if (iCardPowerUpTickCount>=iCardPowerUpPauseLen)
+ {
+ // power-up sequence is complete
+ TerminatePowerUpSequence(KErrNone);
+ }
+ break;
+ }
+ }
+
+/********************************************
+ * PC card memory chunk
+ ********************************************/
+DPccdChunkBase::DPccdChunkBase()
+//
+// Constructor
+//
+ {
+// iSocket=NULL;
+// iCacheable=EFalse;
+ }
+
+TInt DPccdChunkBase::Create(DPcCardSocket* aSocket, TPccdChnk aChunk, TUint aFlag)
+//
+// Create a chunk of Pc Card h/w.
+//
+ {
+ iSocket=aSocket;
+ iChnk=aChunk;
+ iCacheable=(aFlag&KPccdChunkCacheable);
+ return DoCreate(aChunk,aFlag);
+ }
+
+DPccdChunkBase::~DPccdChunkBase()
+//
+// Destructor
+//
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">DPccdChunkBase destruct %08x",this));
+ }
+
+void DPccdChunkBase::Close()
+//
+// Destructor
+//
+ {
+ __KTRACE_OPT(KPBUS1,Kern::Printf(">DPccdChunkBase::Close() %08x",this));
+
+ // Disconnect all the Pc Card windows and then delete chunk
+ SDblQueLink* pW=iWindowQ.iA.iNext;
+ while (pW!=&iWindowQ.iA)
+ {
+ RPccdWindow& w=*(RPccdWindow*)pW;
+ pW=pW->iNext;
+ w.Close(); // closing last window deletes chunk
+ }
+ __KTRACE_OPT(KPBUS1,Kern::Printf("<DPccdChunkBase::Close() %08x",this));
+ }
+
+TBool DPccdChunkBase::IsRemovable()
+//
+// Check if this chunk has any permanent windows.
+//
+ {
+ return (iPermanentWindows==0);
+ }
+
+TBool DPccdChunkBase::IsLocked()
+//
+// Check if this chunk has any windows which are allocated to clients of the PC Card
+// Controller (as opposed to the Controller itself).
+//
+ {
+ return (iWindows>iSystemWindows);
+ }
+
+TInt DPccdChunkBase::AllocateWinCheck(TPccdChnk aWin,TUint aFlag)
+//
+// Check if it is possible to create the specified window from this chunk.
+//
+ {
+ // Check if they are of compatible type
+ if (!IsTypeCompatible(aWin.iMemType))
+ return(KErrNotFound);
+
+ // For a success, the requested window must lie entirely within this chunk.
+ TUint32 chnkEnd=(iChnk.iMemBaseAddr+iChnk.iMemLen-1);
+ TUint32 winEnd=(aWin.iMemBaseAddr+aWin.iMemLen-1);
+ TBool startIsInChnk=(aWin.iMemBaseAddr>=iChnk.iMemBaseAddr && aWin.iMemBaseAddr<=chnkEnd);
+ TBool endIsInChnk=(winEnd>=iChnk.iMemBaseAddr && winEnd<=chnkEnd);
+ if (startIsInChnk&&endIsInChnk)
+ {
+ // Possible success - first check the cache options are compatible
+ if (!(aFlag|KPccdChunkCacheable)&&iCacheable)
+ return(KErrAccessDenied);
+
+ // Now check that the requested window isn't already allocated
+ SDblQueLink* pW=iWindowQ.iA.iNext;
+ while (pW!=&iWindowQ.iA)
+ {
+ RPccdWindow& w=*(RPccdWindow*)pW;
+ pW=pW->iNext;
+ if (w.Overlap(aWin.iMemBaseAddr-iChnk.iMemBaseAddr,aWin.iMemLen) )
+ return(KErrAccessDenied);
+ }
+ return(KErrNone);
+ }
+ if (startIsInChnk||endIsInChnk)
+ return(KErrAccessDenied); // Requested window is partly in this chunk.
+ return(KErrNotFound);
+ }
+
+void DPccdChunkBase::AddWindow(RPccdWindow *aWindow)
+//
+// Add a window to this chunk.
+//
+ {
+ iWindowQ.Add(aWindow);
+// Kern::EnterCS(); Not needed since a single thread is used
+ iWindows++;
+ if (aWindow->IsPermanent())
+ iPermanentWindows++;
+ if (aWindow->IsShareable())
+ iShareableWindows++;
+ if (aWindow->IsSystemOwned())
+ iSystemWindows++;
+ else
+ iSocket->iClientWindows++;
+// Kern::LeaveCS();
+ aWindow->iChunk=this;
+ }
+
+void DPccdChunkBase::RemoveWindow(RPccdWindow *aWindow)
+//
+// Remove a window from this chunk (even if it's permanent).
+//
+ {
+
+ if (aWindow->iNext && aWindow->iChunk==this)
+ {
+ aWindow->Deque();
+ aWindow->iNext=NULL;
+// Kern::EnterCS(); Not needed since a single thread is used
+ iWindows--;
+ if (aWindow->IsPermanent())
+ iPermanentWindows--;
+ if (aWindow->IsShareable())
+ iShareableWindows--;
+ if (aWindow->IsSystemOwned())
+ iSystemWindows--;
+ else
+ iSocket->iClientWindows--;
+// Kern::LeaveCS();
+ if (iWindows==0)
+ {
+ iSocket->RemoveChunk(this);
+ delete this;
+ }
+ }
+ }
+
+/********************************************
+ * PC card memory window
+ ********************************************/
+EXPORT_C RPccdWindow::RPccdWindow()
+//
+// Constructor
+//
+ : iAccessSpeed(EAcSpeedInValid),iMemType(EPccdAttribMem),iOffset(0),iLen(0),iType(0)
+ {
+ iNext=NULL;
+ iChunk=NULL;
+ }
+
+EXPORT_C TInt RPccdWindow::Create(DPcCardSocket* aSocket, TPccdChnk aChnk, TPccdAccessSpeed aSpeed, TUint aFlag)
+//
+// Create a block of memory (IO, Common or Attribute memory).
+//
+ {
+
+ DPccdChunkBase *chunk=NULL;
+ TBool chunkExists=EFalse;
+ TInt r;
+
+ // See if requested window is actually part of a chunk already created
+ TInt i;
+ for (i=0;i<aSocket->iMemChunks.Count();i++)
+ {
+ if ((r=aSocket->iMemChunks[i]->AllocateWinCheck(aChnk,aFlag))==KErrNone)
+ {
+ chunk=aSocket->iMemChunks[i];
+ chunkExists=ETrue;
+ break;
+ }
+ if (r==KErrAccessDenied)
+ return r;
+ }
+
+ // If necesary, create a chunk
+ if (!chunkExists)
+ {
+ // Create the memory chunk
+ chunk=aSocket->NewPccdChunk(aChnk.iMemType);
+ if (!chunk)
+ return KErrNoMemory;
+ TInt r=chunk->Create(aSocket, aChnk, aFlag);
+ if (r==KErrNone)
+ r=aSocket->iMemChunks.Append(chunk);
+ if (r!=KErrNone)
+ {
+ delete chunk;
+ return r;
+ }
+ }
+ __KTRACE_OPT(KPBUS2,Kern::Printf("Skt:CreateMemWindowL-got chunk(existing-%d)",chunkExists));
+
+ // Create the memory window
+ iOffset=aChnk.iMemBaseAddr-chunk->BaseAddr();
+ iLen=aChnk.iMemLen;
+ iAccessSpeed=aSpeed;
+ iMemType=aChnk.iMemType;
+ iWaitSig=(aFlag&KPccdRequestWait);
+ iType=aFlag&(KPccdChunkShared|KPccdChunkPermanent|KPccdChunkSystemOwned); // Save flag settings
+ chunk->AddWindow(this);
+ __KTRACE_OPT(KPBUS2,Kern::Printf("Skt:CreateMemWindowL-created window"));
+ return KErrNone;
+ }
+
+EXPORT_C void RPccdWindow::Close()
+ {
+ if (iNext && iChunk)
+ iChunk->RemoveWindow(this);
+ }
+
+EXPORT_C TInt RPccdWindow::SetupChunkHw(TUint aFlag)
+//
+// Config h/w in preparation for accessing window. Flag is for platform dependant info.
+//
+ {
+
+ if (!iChunk)
+ return(KErrNotReady);
+ iChunk->SetupChunkHw(iAccessSpeed,iMemType,iWaitSig,aFlag);
+// iVcc->ResetInactivityTimer();
+ return(KErrNone);
+ }
+
+EXPORT_C TLinAddr RPccdWindow::LinearAddress()
+//
+// Return linear address of window
+//
+ {
+ return iChunk->LinearAddress()+iOffset;
+ }
+
+TBool RPccdWindow::Overlap(TUint32 anOffset,TUint aLen)
+//
+//
+//
+ {
+ // If this window is sharable then it doesn't matter if they overlap or not.
+ if (IsShareable())
+ return(EFalse);
+
+ TUint32 winEnd=(anOffset+aLen-1);
+ TUint32 thisEnd=(iOffset+iLen-1);
+ if ((anOffset>=iOffset && anOffset<=thisEnd) ||
+ (winEnd>=iOffset && winEnd<=thisEnd) )
+ return(ETrue);
+
+ return(EFalse);
+ }
+