kernel/eka/drivers/pbus/pccard/socket.cpp
changeset 0 a41df078684a
child 43 c1f20ce4abcf
--- /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);
+	}
+