kernel/eka/drivers/pbus/pccard/socket.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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);
	}