diff -r 000000000000 -r a41df078684a kernel/eka/drivers/pbus/pccard/socket.cpp --- /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 +#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; iiVcc==this) + { + if (pS->iClientWindows || pS->iActiveConfigs) + break; + } + } + Kern::LeaveCS(); + return (iiClientWindows || 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;iSkt(%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("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):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 (;aPosRead(aPos,&buf[0],s); + for (TInt i=0;iSkt(%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("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 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;iSetFuncType(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(" tpl; + TInt j=0,err; + if ((err=cisRd.DoSelectCis(aCardFunc))==KErrNone) + { + for (j=0;j=KMaxTuplesPerCis) + err=KErrCorrupt; + if (err==KErrNotFound) + err=KErrNone; + } + __KTRACE_OPT(KPBUS1,Kern::Printf("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("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;iiMemChunks.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); + } +