1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/pbus/pccard/socket.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,994 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\drivers\pbus\pccard\socket.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <pccard.h>
1.22 +#include "cis.h"
1.23 +
1.24 +const TInt KFuncGranularity=(KMaxFuncPerCard+1);
1.25 +const TInt KMemGranularity=2;
1.26 +
1.27 +TPccdFuncType FuncType(TUint aFuncCode)
1.28 + {
1.29 +
1.30 + if (aFuncCode<=KCisTplFuncIdScsi)
1.31 + return((TPccdFuncType)(aFuncCode+1));
1.32 + else if (aFuncCode==KCisTplFuncIdVendorSpecific)
1.33 + return(EVendorSpecificCard);
1.34 + else
1.35 + return(EUnknownCard);
1.36 + }
1.37 +
1.38 +/********************************************
1.39 + * PC card power supply
1.40 + ********************************************/
1.41 +DPcCardVcc::DPcCardVcc(TInt aPsuNum, TInt aMediaChangeNum)
1.42 + : DPBusPsuBase(aPsuNum, aMediaChangeNum)
1.43 + {
1.44 + }
1.45 +
1.46 +TInt DPcCardVcc::SocketVccToMilliVolts(TPccdSocketVcc aVcc)
1.47 +//
1.48 +// Converts a TPccdSocketVcc into a integer value - units mV.
1.49 +//
1.50 + {
1.51 + switch (aVcc)
1.52 + {
1.53 + case EPccdSocket_5V0: return(5000);
1.54 + case EPccdSocket_3V3: return(3300);
1.55 + default: return(0);
1.56 + }
1.57 + }
1.58 +
1.59 +TBool DPcCardVcc::IsLocked()
1.60 + {
1.61 +/* TInt i;
1.62 + Kern::EnterCS();
1.63 + for (i=0; i<KMaxPccdSockets; i++)
1.64 + {
1.65 + DPcCardSocket* pS=(DPcCardSocket*)TheSockets[i];
1.66 + if (pS && pS->iVcc==this)
1.67 + {
1.68 + if (pS->iClientWindows || pS->iActiveConfigs)
1.69 + break;
1.70 + }
1.71 + }
1.72 + Kern::LeaveCS();
1.73 + return (i<KMaxPccdSockets);
1.74 +*/
1.75 + DPcCardSocket* pS=(DPcCardSocket*)iSocket;
1.76 + return (pS->iClientWindows || pS->iActiveConfigs);
1.77 + }
1.78 +
1.79 +void DPcCardVcc::ReceiveVoltageCheckResult(TInt anError)
1.80 + {
1.81 + __KTRACE_OPT(KPBUS1,Kern::Printf("DPcCardVcc(%d)::ReceiveVoltageCheckResult(%d)",iPsuNum,anError));
1.82 + DPcCardSocket* pS=(DPcCardSocket*)iSocket;
1.83 + TInt s=pS->iCardPowerUpState;
1.84 + if (s==DPcCardSocket::EWaitForVccReading)
1.85 + {
1.86 + if (anError==KErrNone)
1.87 + {
1.88 + SetState(EPsuOnFull);
1.89 + pS->iCardPowerUpState=DPcCardSocket::EWaitForReady;
1.90 + }
1.91 + else
1.92 + pS->TerminatePowerUpSequence(KErrCorrupt);
1.93 + }
1.94 + else if (s!=DPcCardSocket::EInit && s!=DPcCardSocket::EApplyingReset && s!=DPcCardSocket::ECheckVcc)
1.95 + DPBusPsuBase::ReceiveVoltageCheckResult(anError);
1.96 + }
1.97 +
1.98 +/********************************************
1.99 + * PC card media change
1.100 + ********************************************/
1.101 +DPcCardMediaChange::DPcCardMediaChange(TInt aMediaChangeNum)
1.102 + : DMediaChangeBase(aMediaChangeNum)
1.103 + {
1.104 + }
1.105 +
1.106 +TInt DPcCardMediaChange::Create()
1.107 + {
1.108 + return DMediaChangeBase::Create();
1.109 + }
1.110 +
1.111 +/********************************************
1.112 + * PC card socket
1.113 + ********************************************/
1.114 +void cardPowerUpTick(TAny* aPtr)
1.115 + {
1.116 + ((DPcCardSocket*)aPtr)->iCardPowerUpDfc.Enque();
1.117 + }
1.118 +
1.119 +void cardPowerUpDfc(TAny* aPtr)
1.120 + {
1.121 + ((DPcCardSocket*)aPtr)->CardPowerUpTick();
1.122 + }
1.123 +
1.124 +DPcCardSocket::DPcCardSocket(TSocket aSocketNum)
1.125 +//
1.126 +// Constructor.
1.127 +//
1.128 + : DPBusSocket(aSocketNum),
1.129 + iCardFuncArray(KFuncGranularity),
1.130 + iMemChunks(KMemGranularity),
1.131 + iCardPowerUpDfc(cardPowerUpDfc, this, 1)
1.132 + {
1.133 +
1.134 + iType=EPBusTypePcCard;
1.135 +// iCardPowerUpState=EIdle;
1.136 +// iClientWindows=0;
1.137 +// iActiveConfigs=0;
1.138 + }
1.139 +
1.140 +TInt DPcCardSocket::Create(const TDesC* aName)
1.141 +//
1.142 +// Create a new Socket. Only created once on kernel initialization so don't
1.143 +// worry about cleanup if it fails.
1.144 +//
1.145 + {
1.146 +
1.147 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):Create(%lS)",iSocketNumber,aName));
1.148 +
1.149 + TInt r=DPBusSocket::Create(aName);
1.150 + if (r!=KErrNone)
1.151 + return r;
1.152 + iCardPowerUpDfc.SetDfcQ(&iDfcQ);
1.153 +
1.154 + // Create card function array - add and remove a dummy function to pre-allocate array memory.
1.155 + // This way, adding new functions to array never causes any memory allocation.
1.156 + r=AddNewFunc(0,EPccdAttribMem); // Add dummy function
1.157 + if (r!=KErrNone)
1.158 + return r;
1.159 + delete iCardFuncArray[0]; // Destroy dummy function
1.160 + iCardFuncArray.Remove(0); // Remove pointer to dummy from array
1.161 +
1.162 + // Now allocate the permanent attribute memory chunk. Don't bother about what
1.163 + // access speed we asign, it gets set each time we subsequently access the chunk.
1.164 + TPccdChnk chnk(EPccdAttribMem,0,KDefaultAttribMemSize);
1.165 + r=iAttribWin.Create(this,chnk,EAcSpeed300nS,KPccdChunkPermanent|KPccdChunkShared|KPccdChunkSystemOwned);
1.166 + return r;
1.167 + }
1.168 +
1.169 +void DPcCardSocket::ResetPowerUpState()
1.170 + {
1.171 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):ResetPowerUpState",iSocketNumber));
1.172 + if (iCardPowerUpState!=EIdle)
1.173 + {
1.174 + iCardPowerUpTimer.Cancel();
1.175 + iCardPowerUpDfc.Cancel();
1.176 + iCardPowerUpState=EIdle;
1.177 + }
1.178 + }
1.179 +
1.180 +void DPcCardSocket::Reset1()
1.181 + {
1.182 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):Reset1",iSocketNumber));
1.183 + ResetPowerUpState();
1.184 + }
1.185 +
1.186 +void DPcCardSocket::Reset2()
1.187 +//
1.188 +// Reset the socket (called to remove any allocated memory following a
1.189 +// media change event).
1.190 +//
1.191 + {
1.192 +
1.193 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):Rst2",iSocketNumber));
1.194 + // Destroy all the function objects
1.195 + TInt i;
1.196 + for (i=CardFuncCount()-1;i>=0;i--)
1.197 + {
1.198 + delete iCardFuncArray[i];
1.199 + iCardFuncArray.Remove(i); // Now remove from array (doesn't cause memory dealloc).
1.200 + }
1.201 + iActiveConfigs=0;
1.202 +
1.203 + // Destroy all the non-permanent Pc Card chunks
1.204 + for (i=(iMemChunks.Count()-1);i>=0;i--)
1.205 + {
1.206 + if ( iMemChunks[i]->IsRemovable() )
1.207 + iMemChunks[i]->Close();
1.208 + }
1.209 + iMemChunks.Compress();
1.210 + }
1.211 +
1.212 +void DPcCardSocket::Restore()
1.213 +//
1.214 +// Restore the socket. Normally called when restoring a socket after it has been powered
1.215 +// down due to inactivity (but not media change)
1.216 +//
1.217 + {
1.218 + TInt i;
1.219 + TPcCardFunction *cf;
1.220 + for (i=CardFuncCount()-1;i>=0;i--)
1.221 + {
1.222 + cf=iCardFuncArray[i];
1.223 +
1.224 + TUint8 index;
1.225 + if ((index=(TUint8)cf->ConfigOption())!=KInvalidConfOpt && cf->IsRestorableConfig())
1.226 + WriteConfigReg(i,KConfigOptionReg,index);
1.227 + }
1.228 + }
1.229 +
1.230 +void DPcCardSocket::RemoveChunk(DPccdChunkBase *aChunk)
1.231 +//
1.232 +// Remove a chunk from this socket.
1.233 +//
1.234 + {
1.235 + TInt i;
1.236 + for (i=0;i<iMemChunks.Count();i++)
1.237 + {
1.238 + if (iMemChunks[i]==aChunk)
1.239 + {
1.240 + iMemChunks.Remove(i);
1.241 + iMemChunks.Compress();
1.242 + return;
1.243 + }
1.244 + }
1.245 + }
1.246 +
1.247 +EXPORT_C TInt DPcCardSocket::RequestConfig(TInt aCardFunc,DBase *aClientID,TPcCardConfig &anInfo,TUint aFlag)
1.248 +//
1.249 +// Configure the card.
1.250 +//
1.251 + {
1.252 +
1.253 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):RequestConfig(F:%d O:%xH B:%xH L:%xH)",iSocketNumber,aCardFunc,\
1.254 + anInfo.iConfigOption,anInfo.iConfigBaseAddr,anInfo.iRegPresent));
1.255 + if (!IsValidCardFunc(aCardFunc))
1.256 + return(KErrArgument);
1.257 + // Check that this function isn't configured already
1.258 + TPcCardFunction *cf=iCardFuncArray[aCardFunc];
1.259 + if (cf->IsConfigured())
1.260 + return(KErrInUse); // Its already configured.
1.261 +
1.262 + // If configuration registers are within attribute chunk then configure the
1.263 + // card (rather than use the registers present info, assume all registers are
1.264 + // present - ie size of mask).
1.265 + if (anInfo.iConfigBaseAddr+(sizeof(anInfo.iRegPresent)<<1)>KDefaultAttribMemSize)
1.266 + return(KErrNotSupported);
1.267 + anInfo.iConfigOption&=(KConfOptLevIReqM|KConfOptConfM); // Mustn't allow msb - KInvalidConfOpt
1.268 + TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
1.269 + iAttribWin.SetAccessSpeed(sp);
1.270 + iAttribWin.SetupChunkHw();
1.271 + iAttribWin.Write(anInfo.iConfigBaseAddr,(TUint8*)&anInfo.iConfigOption,1);
1.272 +
1.273 + cf->SetConfigRegMask(anInfo.iRegPresent);
1.274 + cf->SetConfigBaseAddr(anInfo.iConfigBaseAddr);
1.275 + cf->SetConfigOption(anInfo.iConfigOption,aClientID,aFlag);
1.276 + __e32_atomic_add_ord32(&iActiveConfigs, 1);
1.277 + return(KErrNone);
1.278 + }
1.279 +
1.280 +EXPORT_C void DPcCardSocket::ReleaseConfig(TInt aCardFunc,DBase *aClientID)
1.281 +//
1.282 +// Return card to memory only config.
1.283 +//
1.284 + {
1.285 +
1.286 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):ReleaseConfig(F:%d)",iSocketNumber,aCardFunc));
1.287 + if (IsValidCardFunc(aCardFunc))
1.288 + {
1.289 + TPcCardFunction *cf=iCardFuncArray[aCardFunc];
1.290 + if (cf->IsConfiguredByClient(aClientID))
1.291 + {
1.292 + if (iState==EPBusOn && Kern::PowerGood())
1.293 + WriteConfigReg(aCardFunc,KConfigOptionReg,0); // Restore Config. Option register
1.294 +
1.295 + cf->SetConfigRegMask(0);
1.296 + cf->SetConfigBaseAddr(0);
1.297 + cf->SetConfigOption(KInvalidConfOpt,NULL,0);
1.298 + __e32_atomic_add_ord32(&iActiveConfigs, TUint32(-1));
1.299 + }
1.300 + }
1.301 + }
1.302 +
1.303 +EXPORT_C TInt DPcCardSocket::ReadConfigReg(TInt aCardFunc,TInt aRegOffset,TUint8 &aVal)
1.304 +//
1.305 +// Read from a specified configuration register. (We return an error if the RegPres mask
1.306 +// indicates the register isn't present but still attempt the read).
1.307 +//
1.308 + {
1.309 + TInt offset, err;
1.310 + if (!IsValidCardFunc(aCardFunc)|| iState!=EPBusOn || !Kern::PowerGood())
1.311 + err=KErrArgument;
1.312 + else
1.313 + {
1.314 + if ((err=iCardFuncArray[aCardFunc]->ConfigRegAddress(aRegOffset,offset))==KErrNone||err==KErrNotSupported)
1.315 + {
1.316 + TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
1.317 + iAttribWin.SetAccessSpeed(sp);
1.318 + iAttribWin.SetupChunkHw();
1.319 + iAttribWin.Read(offset,&aVal,1);
1.320 + }
1.321 + }
1.322 + __KTRACE_OPT(KPBUS1,Kern::Printf("<Skt(%d):ReadConfigReg-%d",iSocketNumber,err));
1.323 + return(err);
1.324 + }
1.325 +
1.326 +EXPORT_C TInt DPcCardSocket::WriteConfigReg(TInt aCardFunc,TInt aRegOffset,const TUint8 aVal)
1.327 +//
1.328 +// Write to a specified configuration register. (We return an error if the RegPres mask
1.329 +// indicates the register isn't present but still attempt the write).
1.330 +//
1.331 + {
1.332 + TInt offset, err;
1.333 + if (!IsValidCardFunc(aCardFunc)|| iState!=EPBusOn || !Kern::PowerGood())
1.334 + err=KErrArgument;
1.335 + else
1.336 + {
1.337 + if ((err=iCardFuncArray[aCardFunc]->ConfigRegAddress(aRegOffset,offset))==KErrNone||err==KErrNotSupported)
1.338 + {
1.339 + TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
1.340 + iAttribWin.SetAccessSpeed(sp);
1.341 + iAttribWin.SetupChunkHw();
1.342 + iAttribWin.Write(offset,&aVal,1);
1.343 + }
1.344 + }
1.345 + __KTRACE_OPT(KPBUS1,Kern::Printf("<Skt(%d):WriteConfigReg-%d",iSocketNumber,err));
1.346 + return(err);
1.347 + }
1.348 +
1.349 +const TInt KReadCisBufferSize=0x80; // 128 Bytes
1.350 +TInt DPcCardSocket::ReadCis(TPccdMemType aMemType,TInt aPos,TDes8 &aDes,TInt aLen)
1.351 +//
1.352 +// Read from CIS
1.353 +//
1.354 + {
1.355 +
1.356 + __KTRACE_OPT(KPBUS2,Kern::Printf(">Skt(%d):ReadCis(LE:%xH PO:%d TY:%d)",iSocketNumber,aLen,aPos,aMemType));
1.357 + RPccdWindow newWin;
1.358 + RPccdWindow* win=&newWin;
1.359 + TBool needNewChunk=ETrue;
1.360 + TInt cisE=(aPos+aLen);
1.361 + TInt incrm=1;
1.362 + if (aMemType==EPccdAttribMem)
1.363 + {
1.364 + incrm=2; // Read every other byte
1.365 + cisE<<=1;
1.366 + aPos<<=1;
1.367 + if (cisE<=(TInt)KDefaultAttribMemSize)
1.368 + {
1.369 + needNewChunk=EFalse;
1.370 + win=&iAttribWin;
1.371 + }
1.372 + }
1.373 +
1.374 + if (needNewChunk)
1.375 + {
1.376 + TPccdChnk chnk(aMemType,aPos,(cisE-aPos));
1.377 + TInt r=newWin.Create(this,chnk,EAcSpeed300nS,KPccdChunkShared|KPccdChunkSystemOwned);
1.378 + if (r!=KErrNone)
1.379 + return(r);
1.380 + cisE-=aPos;
1.381 + aPos=0;
1.382 + }
1.383 +
1.384 + TPccdAccessSpeed sp=(VccSetting()==EPccdSocket_3V3)?EAcSpeed600nS:EAcSpeed300nS;
1.385 + win->SetAccessSpeed(sp);
1.386 + win->SetupChunkHw();
1.387 + aDes.Zero();
1.388 + TText8 buf[KReadCisBufferSize];
1.389 + TInt s;
1.390 + for (;aPos<cisE;aPos+=s)
1.391 + {
1.392 + s=Min(KReadCisBufferSize,(cisE-aPos));
1.393 + win->Read(aPos,&buf[0],s);
1.394 + for (TInt i=0;i<s;i+=incrm)
1.395 + aDes.Append((TChar)buf[i]);
1.396 + }
1.397 +
1.398 + if (needNewChunk)
1.399 + newWin.Close();
1.400 + return(KErrNone);
1.401 + }
1.402 +
1.403 +TInt DPcCardSocket::AddNewFunc(TUint32 anOffset,TPccdMemType aMemType)
1.404 +//
1.405 +// Create a new card function and append it to the function array
1.406 +//
1.407 + {
1.408 +
1.409 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Skt(%d):AddNewFunc(T:%d)",iSocketNumber,aMemType));
1.410 + TInt r=KErrNoMemory;
1.411 + TPcCardFunction* cf=new TPcCardFunction(anOffset,aMemType);
1.412 + if (cf)
1.413 + {
1.414 + r=iCardFuncArray.Append(cf);
1.415 + if (r!=KErrNone)
1.416 + delete cf;
1.417 + }
1.418 + return r;
1.419 + }
1.420 +
1.421 +TPcCardFunction *DPcCardSocket::CardFunc(TInt aCardFunc)
1.422 +//
1.423 +// Get a reference to a specific card function from the function array
1.424 +//
1.425 + {
1.426 +
1.427 + __ASSERT_ALWAYS(IsValidCardFunc(aCardFunc),PcCardPanic(EPcCardBadFunctionNumber));
1.428 + return iCardFuncArray[aCardFunc];
1.429 + }
1.430 +
1.431 +TBool DPcCardSocket::IsConfigLocked()
1.432 +//
1.433 +// Returns ETrue if this socket contains a card function which is currently configured.
1.434 +//
1.435 + {
1.436 +// TInt i;
1.437 +// for (i=CardFuncCount()-1;i>=0;i--)
1.438 +// {
1.439 +// if (iCardFuncArray[i]->IsConfigured())
1.440 +// return(ETrue);
1.441 +// }
1.442 +// return(EFalse);
1.443 + return (iActiveConfigs!=0);
1.444 + }
1.445 +
1.446 +TBool DPcCardSocket::IsMemoryLocked()
1.447 +//
1.448 +// Returns ETrue if any PC Card memory chunks are allocated on this socket.
1.449 +//
1.450 + {
1.451 +
1.452 +// TInt i;
1.453 +// for (i=iMemChunks.Count()-1;i>=0;i--)
1.454 +// {
1.455 +// if ( iMemChunks[i]->IsLocked() )
1.456 +// return(ETrue);
1.457 +// }
1.458 +// return(EFalse);
1.459 + return (iClientWindows!=0);
1.460 + }
1.461 +
1.462 +TPccdSocketVcc DPcCardSocket::VccSetting()
1.463 +//
1.464 +// Return voltage setting that this socket is currently set for
1.465 +//
1.466 + {
1.467 +
1.468 + return ((DPcCardVcc*)iVcc)->VoltageSetting();
1.469 + }
1.470 +
1.471 +EXPORT_C TInt DPcCardSocket::VerifyCard(TPccdType &aType)
1.472 +//
1.473 +// Return information about the type of card present
1.474 +//
1.475 + {
1.476 +
1.477 + __KTRACE_OPT(KPBUS1,Kern::Printf(">Cntrl:VerifyCard(S:%d)",iSocketNumber));
1.478 + // The data we want is stored off-card, so it doesn't actually need to be
1.479 + // powered but we need to have read CIS format.
1.480 + TInt err=KErrNone;
1.481 + if (CardIsReadyAndVerified()==KErrNone)
1.482 + {
1.483 + aType.iFuncCount=CardFuncCount();
1.484 + for (TInt i=(aType.iFuncCount-1);i>=0;i--)
1.485 + aType.iFuncType[i]=CardFunc(i)->FuncType();
1.486 + }
1.487 + else
1.488 + err=KErrNotReady;
1.489 +
1.490 + __KTRACE_OPT(KPBUS1,Kern::Printf("<Cntrl:VerifyCard(S:%d T:%d)-%d",iSocketNumber,(TInt)aType.iFuncType[0],err));
1.491 + return(err);
1.492 + }
1.493 +
1.494 +TInt DPcCardSocket::CardIsReadyAndVerified()
1.495 +//
1.496 +// Returns KErrNone when specified card is powered and ready (ie has had h/w reset) and
1.497 +// a basic parsing of CIS has been performed (card functions detected).
1.498 +//
1.499 + {
1.500 +
1.501 + TInt r=KErrNotReady;
1.502 + if (CardIsReady())
1.503 + {
1.504 + r=KErrNone;
1.505 + // Check if card function(s) have been determined (there is always at
1.506 + // least a global function record if basic parsing performed).
1.507 + if (!IsVerified())
1.508 + r=GetCisFormat();
1.509 + }
1.510 +
1.511 + __KTRACE_OPT(KPBUS1,Kern::Printf("<Cntrl:CardRdyAndVerif(S:%d)-%xH",iSocketNumber,r));
1.512 + return r;
1.513 + }
1.514 +
1.515 +TBool DPcCardSocket::CardIsReady()
1.516 + {
1.517 + TBool r=(iState==EPBusOn && Kern::PowerGood());
1.518 + __KTRACE_OPT(KPBUS1,Kern::Printf("CardIsReady: %d",r));
1.519 + return r;
1.520 + }
1.521 +
1.522 +TBool DPcCardSocket::CardIsPowered()
1.523 + {
1.524 + return !iVcc->IsOff();
1.525 + }
1.526 +
1.527 +TInt DPcCardSocket::GetCisFormat()
1.528 +//
1.529 +// Determine the type of card present by parsing the entire CIS. If a
1.530 +// Multi-function card is present then parse each CIS.
1.531 +//
1.532 + {
1.533 +
1.534 + __KTRACE_OPT(KPBUS1,Kern::Printf(">GetCisFormat (S:%d)",iSocketNumber));
1.535 +
1.536 + TInt r=AddNewFunc(0,EPccdAttribMem); // We always have 1st CIS
1.537 + if (r!=KErrNone)
1.538 + return r;
1.539 + if (ValidateCis(0)!=KErrNone) // Can't use this until func added
1.540 + return KErrCorrupt;
1.541 + TCisReader cisRd;
1.542 + cisRd.iSocket=this;
1.543 + cisRd.DoSelectCis(0);
1.544 + TPccdFuncType firstFuncType;
1.545 + // Check for a multi-function card, search the global CIS (attribute
1.546 + // memory - addr 0) for a KCisTplLongLinkMfc tuple.
1.547 + TBuf8<KLargeTplBufSize> tpl;
1.548 + if (cisRd.DoFindReadTuple(KCisTplLongLinkMfc,tpl,KPccdReturnLinkTpl)==KErrNone)
1.549 + {
1.550 + // Multi-Function card
1.551 + firstFuncType=EGlobalCard;
1.552 + const TUint8 *tplPtr=tpl.Ptr()+2; // First tuple after link
1.553 + TInt funcCount=*tplPtr++;
1.554 +
1.555 + // Add a card function object to the socket for each entry in KCisTplLongLinkMfc tuple
1.556 + TPccdMemType memType;
1.557 + TUint32 lnkAdr;
1.558 + TInt i;
1.559 + for (i=0;i<funcCount;i++)
1.560 + {
1.561 + memType=(*tplPtr++)?EPccdCommon8Mem:EPccdAttribMem;
1.562 + TInt j;
1.563 + for (lnkAdr=0,j=0;j<4;j++) // Convert link address from string to unsigned long
1.564 + lnkAdr += (*tplPtr++) << (8*j);
1.565 + r=AddNewFunc(lnkAdr,memType);
1.566 + if (r!=KErrNone)
1.567 + return r;
1.568 + if (ValidateCis(i+1)!=KErrNone) // Can't use this until func added
1.569 + return KErrCorrupt;
1.570 + }
1.571 + // Parse the CIS of each card function looking for a KCisTplFuncId tuple
1.572 + for (i=1;i<=funcCount;i++)
1.573 + {
1.574 + cisRd.DoSelectCis(i);
1.575 + TPccdFuncType ft;
1.576 + if (cisRd.DoFindReadTuple(KCisTplFuncId,tpl,0)==KErrNone)
1.577 + ft=FuncType(tpl[2]);
1.578 + else
1.579 + ft=EUnknownCard;
1.580 + CardFunc(i)->SetFuncType(ft);
1.581 + }
1.582 + }
1.583 + else
1.584 + {
1.585 + // Single Function card
1.586 + cisRd.Restart();
1.587 + if (cisRd.DoFindReadTuple(KCisTplFuncId,tpl,0)==KErrNone)
1.588 + firstFuncType=FuncType(tpl[2]);
1.589 + else
1.590 + firstFuncType=EUnknownCard;
1.591 + }
1.592 +
1.593 + CardFunc(0)->SetFuncType(firstFuncType);
1.594 + __KTRACE_OPT(KPBUS1,Kern::Printf("<GetCisFormat(T:%d)",firstFuncType));
1.595 + return KErrNone;
1.596 + }
1.597 +
1.598 +TInt DPcCardSocket::ValidateCis(TInt aCardFunc)
1.599 +//
1.600 +// Attempt to walk though entire CIS.
1.601 +//
1.602 + {
1.603 +
1.604 + TCisReader cisRd;
1.605 + cisRd.iSocket=this;
1.606 + TBuf8<KLargeTplBufSize> tpl;
1.607 + TInt j=0,err;
1.608 + if ((err=cisRd.DoSelectCis(aCardFunc))==KErrNone)
1.609 + {
1.610 + for (j=0;j<KMaxTuplesPerCis;j++)
1.611 + {
1.612 + err=cisRd.DoFindReadTuple(KPccdNonSpecificTpl,tpl,(KPccdFindOnly|KPccdReturnLinkTpl|KPccdReportErrors));
1.613 + if (err!=KErrNone)
1.614 + break;
1.615 + }
1.616 + if (j>=KMaxTuplesPerCis)
1.617 + err=KErrCorrupt;
1.618 + if (err==KErrNotFound)
1.619 + err=KErrNone;
1.620 + }
1.621 + __KTRACE_OPT(KPBUS1,Kern::Printf("<Skt:ValidateCis(S:%d F:%d Tuples:%d)-%d",iSocketNumber,aCardFunc,j,err));
1.622 + return(err);
1.623 + }
1.624 +
1.625 +void DPcCardSocket::InitiatePowerUpSequence()
1.626 + {
1.627 + __KTRACE_OPT(KPBUS1,Kern::Printf("DPcCardSocket(%d)::InitiatePowerUpSequence",iSocketNumber));
1.628 + // Check if battery is too low
1.629 +// TSupplyStatus ss=(TSupplyStatus)iMachineInfo.iDisableOnLowBattery;
1.630 +// if (ss!=EZero)
1.631 +// {
1.632 +// TSupplyInfoV1 info;
1.633 +// Hal::SupplyInfo(info);
1.634 +// if (info.iMainBatteryStatus<ss && !info.iExternalPowerPresent)
1.635 +// {
1.636 +// iSocket[aSocket]->SetSocketStatus(ESocketBatTooLow);
1.637 +// rs=KErrBadPower;
1.638 +// break;
1.639 +// }
1.640 +// }
1.641 +
1.642 + // Check the state of the Voltage sense line
1.643 + TSocketIndicators ind;
1.644 + Indicators(ind);
1.645 + TUint v=(TUint)ind.iVoltSense & ((DPcCardVcc*)iVcc)->VoltageSupported();
1.646 + if (v==0)
1.647 + {
1.648 + __KTRACE_OPT(KPBUS1,Kern::Printf("InitiatePowerUpSequence(S:%d)-Voltage sense problem(%d)",iSocketNumber,ind.iVoltSense));
1.649 + iVcc->SetCurrLimited(); // Not totally true but has effect.
1.650 + PowerUpSequenceComplete(KErrCorrupt);
1.651 + return;
1.652 + }
1.653 + TPccdSocketVcc sVcc=(v&KPccdVcc_3V3)?EPccdSocket_3V3:EPccdSocket_5V0; // ??? What about xVx / yVy
1.654 + ((DPcCardVcc*)iVcc)->SetVoltage(sVcc);
1.655 +
1.656 + // Power up card (current limited).
1.657 + __KTRACE_OPT(KPBUS1,Kern::Printf("InitiatePowerUpSequence(S:%d)-Apply Vcc",iSocketNumber));
1.658 + if (iVcc->SetState(EPsuOnCurLimit) != KErrNone)
1.659 + {
1.660 + __KTRACE_OPT(KPBUS1,Kern::Printf("InitiatePowerUpSequence(S:%d)-Vcc problem",iSocketNumber));
1.661 + iVcc->SetState(EPsuOff);
1.662 + iVcc->SetCurrLimited();
1.663 + PowerUpSequenceComplete(KErrGeneral);
1.664 + return;
1.665 + }
1.666 + iCardPowerUpState=EInit;
1.667 + iCardPowerUpTickCount=0;
1.668 + iCardPowerUpResetLen=KResetOnDefaultLen;
1.669 + iCardPowerUpPauseLen=KResetOffDefaultLen;
1.670 + iCardPowerUpTimer.Periodic(KPccdPowerUpReqInterval,cardPowerUpTick,this);
1.671 + }
1.672 +
1.673 +void DPcCardSocket::TerminatePowerUpSequence(TInt aResult)
1.674 + {
1.675 + __KTRACE_OPT(KPBUS1,Kern::Printf("DPcCardSocket(%d)::TerminatePowerUpSequence result %d",iSocketNumber,aResult));
1.676 + ResetPowerUpState();
1.677 + if (aResult==KErrNone)
1.678 + Restore();
1.679 + PowerUpSequenceComplete(aResult);
1.680 + }
1.681 +
1.682 +void DPcCardSocket::CardPowerUpTick()
1.683 + {
1.684 + __KTRACE_OPT(KPBUS1,Kern::Printf("CardPowerUpTick S:%d Elapsed %d State %d",iSocketNumber,iCardPowerUpTickCount,iCardPowerUpState));
1.685 + if (++iCardPowerUpTickCount>KPwrUpTimeOut)
1.686 + {
1.687 + iVcc->SetState(EPsuOff); // should leave this to timeout
1.688 + TerminatePowerUpSequence(KErrTimedOut);
1.689 + return;
1.690 + }
1.691 + switch (iCardPowerUpState)
1.692 + {
1.693 + case EInit:
1.694 + HwReset(ETrue); // Apply reset - Turns on interface
1.695 + iCardPowerUpState=EApplyingReset;
1.696 + break;
1.697 + case EApplyingReset:
1.698 + if (iCardPowerUpTickCount>iCardPowerUpResetLen)
1.699 + {
1.700 + HwReset(EFalse); // remove reset
1.701 + iCardPowerUpState=ECheckVcc;
1.702 + }
1.703 + break;
1.704 + case ECheckVcc:
1.705 + {
1.706 + iCardPowerUpState=EWaitForVccReading;
1.707 + TInt cv=iVcc->CheckVoltage(KPsuChkOnPwrUp);
1.708 + if (cv==KErrNotSupported)
1.709 + iCardPowerUpState=EWaitForReady;
1.710 + else if (cv!=KErrNone)
1.711 + TerminatePowerUpSequence(cv);
1.712 + break;
1.713 + }
1.714 + case EWaitForVccReading:
1.715 + break;
1.716 + case EWaitForReady:
1.717 + if (Ready())
1.718 + {
1.719 + iCardPowerUpState=EPauseAfterReady; // Card is ready
1.720 + // Its effectively powered up now so reset the elapsed time and use it
1.721 + // to measure pause after reset (ie this is limited to KPwrUpTimeOut too).
1.722 + iCardPowerUpTickCount=0;
1.723 + }
1.724 + break;
1.725 + case EPauseAfterReady:
1.726 + if (iCardPowerUpTickCount>=iCardPowerUpPauseLen)
1.727 + {
1.728 + // power-up sequence is complete
1.729 + TerminatePowerUpSequence(KErrNone);
1.730 + }
1.731 + break;
1.732 + }
1.733 + }
1.734 +
1.735 +/********************************************
1.736 + * PC card memory chunk
1.737 + ********************************************/
1.738 +DPccdChunkBase::DPccdChunkBase()
1.739 +//
1.740 +// Constructor
1.741 +//
1.742 + {
1.743 +// iSocket=NULL;
1.744 +// iCacheable=EFalse;
1.745 + }
1.746 +
1.747 +TInt DPccdChunkBase::Create(DPcCardSocket* aSocket, TPccdChnk aChunk, TUint aFlag)
1.748 +//
1.749 +// Create a chunk of Pc Card h/w.
1.750 +//
1.751 + {
1.752 + iSocket=aSocket;
1.753 + iChnk=aChunk;
1.754 + iCacheable=(aFlag&KPccdChunkCacheable);
1.755 + return DoCreate(aChunk,aFlag);
1.756 + }
1.757 +
1.758 +DPccdChunkBase::~DPccdChunkBase()
1.759 +//
1.760 +// Destructor
1.761 +//
1.762 + {
1.763 + __KTRACE_OPT(KPBUS1,Kern::Printf(">DPccdChunkBase destruct %08x",this));
1.764 + }
1.765 +
1.766 +void DPccdChunkBase::Close()
1.767 +//
1.768 +// Destructor
1.769 +//
1.770 + {
1.771 + __KTRACE_OPT(KPBUS1,Kern::Printf(">DPccdChunkBase::Close() %08x",this));
1.772 +
1.773 + // Disconnect all the Pc Card windows and then delete chunk
1.774 + SDblQueLink* pW=iWindowQ.iA.iNext;
1.775 + while (pW!=&iWindowQ.iA)
1.776 + {
1.777 + RPccdWindow& w=*(RPccdWindow*)pW;
1.778 + pW=pW->iNext;
1.779 + w.Close(); // closing last window deletes chunk
1.780 + }
1.781 + __KTRACE_OPT(KPBUS1,Kern::Printf("<DPccdChunkBase::Close() %08x",this));
1.782 + }
1.783 +
1.784 +TBool DPccdChunkBase::IsRemovable()
1.785 +//
1.786 +// Check if this chunk has any permanent windows.
1.787 +//
1.788 + {
1.789 + return (iPermanentWindows==0);
1.790 + }
1.791 +
1.792 +TBool DPccdChunkBase::IsLocked()
1.793 +//
1.794 +// Check if this chunk has any windows which are allocated to clients of the PC Card
1.795 +// Controller (as opposed to the Controller itself).
1.796 +//
1.797 + {
1.798 + return (iWindows>iSystemWindows);
1.799 + }
1.800 +
1.801 +TInt DPccdChunkBase::AllocateWinCheck(TPccdChnk aWin,TUint aFlag)
1.802 +//
1.803 +// Check if it is possible to create the specified window from this chunk.
1.804 +//
1.805 + {
1.806 + // Check if they are of compatible type
1.807 + if (!IsTypeCompatible(aWin.iMemType))
1.808 + return(KErrNotFound);
1.809 +
1.810 + // For a success, the requested window must lie entirely within this chunk.
1.811 + TUint32 chnkEnd=(iChnk.iMemBaseAddr+iChnk.iMemLen-1);
1.812 + TUint32 winEnd=(aWin.iMemBaseAddr+aWin.iMemLen-1);
1.813 + TBool startIsInChnk=(aWin.iMemBaseAddr>=iChnk.iMemBaseAddr && aWin.iMemBaseAddr<=chnkEnd);
1.814 + TBool endIsInChnk=(winEnd>=iChnk.iMemBaseAddr && winEnd<=chnkEnd);
1.815 + if (startIsInChnk&&endIsInChnk)
1.816 + {
1.817 + // Possible success - first check the cache options are compatible
1.818 + if (!(aFlag|KPccdChunkCacheable)&&iCacheable)
1.819 + return(KErrAccessDenied);
1.820 +
1.821 + // Now check that the requested window isn't already allocated
1.822 + SDblQueLink* pW=iWindowQ.iA.iNext;
1.823 + while (pW!=&iWindowQ.iA)
1.824 + {
1.825 + RPccdWindow& w=*(RPccdWindow*)pW;
1.826 + pW=pW->iNext;
1.827 + if (w.Overlap(aWin.iMemBaseAddr-iChnk.iMemBaseAddr,aWin.iMemLen) )
1.828 + return(KErrAccessDenied);
1.829 + }
1.830 + return(KErrNone);
1.831 + }
1.832 + if (startIsInChnk||endIsInChnk)
1.833 + return(KErrAccessDenied); // Requested window is partly in this chunk.
1.834 + return(KErrNotFound);
1.835 + }
1.836 +
1.837 +void DPccdChunkBase::AddWindow(RPccdWindow *aWindow)
1.838 +//
1.839 +// Add a window to this chunk.
1.840 +//
1.841 + {
1.842 + iWindowQ.Add(aWindow);
1.843 +// Kern::EnterCS(); Not needed since a single thread is used
1.844 + iWindows++;
1.845 + if (aWindow->IsPermanent())
1.846 + iPermanentWindows++;
1.847 + if (aWindow->IsShareable())
1.848 + iShareableWindows++;
1.849 + if (aWindow->IsSystemOwned())
1.850 + iSystemWindows++;
1.851 + else
1.852 + iSocket->iClientWindows++;
1.853 +// Kern::LeaveCS();
1.854 + aWindow->iChunk=this;
1.855 + }
1.856 +
1.857 +void DPccdChunkBase::RemoveWindow(RPccdWindow *aWindow)
1.858 +//
1.859 +// Remove a window from this chunk (even if it's permanent).
1.860 +//
1.861 + {
1.862 +
1.863 + if (aWindow->iNext && aWindow->iChunk==this)
1.864 + {
1.865 + aWindow->Deque();
1.866 + aWindow->iNext=NULL;
1.867 +// Kern::EnterCS(); Not needed since a single thread is used
1.868 + iWindows--;
1.869 + if (aWindow->IsPermanent())
1.870 + iPermanentWindows--;
1.871 + if (aWindow->IsShareable())
1.872 + iShareableWindows--;
1.873 + if (aWindow->IsSystemOwned())
1.874 + iSystemWindows--;
1.875 + else
1.876 + iSocket->iClientWindows--;
1.877 +// Kern::LeaveCS();
1.878 + if (iWindows==0)
1.879 + {
1.880 + iSocket->RemoveChunk(this);
1.881 + delete this;
1.882 + }
1.883 + }
1.884 + }
1.885 +
1.886 +/********************************************
1.887 + * PC card memory window
1.888 + ********************************************/
1.889 +EXPORT_C RPccdWindow::RPccdWindow()
1.890 +//
1.891 +// Constructor
1.892 +//
1.893 + : iAccessSpeed(EAcSpeedInValid),iMemType(EPccdAttribMem),iOffset(0),iLen(0),iType(0)
1.894 + {
1.895 + iNext=NULL;
1.896 + iChunk=NULL;
1.897 + }
1.898 +
1.899 +EXPORT_C TInt RPccdWindow::Create(DPcCardSocket* aSocket, TPccdChnk aChnk, TPccdAccessSpeed aSpeed, TUint aFlag)
1.900 +//
1.901 +// Create a block of memory (IO, Common or Attribute memory).
1.902 +//
1.903 + {
1.904 +
1.905 + DPccdChunkBase *chunk=NULL;
1.906 + TBool chunkExists=EFalse;
1.907 + TInt r;
1.908 +
1.909 + // See if requested window is actually part of a chunk already created
1.910 + TInt i;
1.911 + for (i=0;i<aSocket->iMemChunks.Count();i++)
1.912 + {
1.913 + if ((r=aSocket->iMemChunks[i]->AllocateWinCheck(aChnk,aFlag))==KErrNone)
1.914 + {
1.915 + chunk=aSocket->iMemChunks[i];
1.916 + chunkExists=ETrue;
1.917 + break;
1.918 + }
1.919 + if (r==KErrAccessDenied)
1.920 + return r;
1.921 + }
1.922 +
1.923 + // If necesary, create a chunk
1.924 + if (!chunkExists)
1.925 + {
1.926 + // Create the memory chunk
1.927 + chunk=aSocket->NewPccdChunk(aChnk.iMemType);
1.928 + if (!chunk)
1.929 + return KErrNoMemory;
1.930 + TInt r=chunk->Create(aSocket, aChnk, aFlag);
1.931 + if (r==KErrNone)
1.932 + r=aSocket->iMemChunks.Append(chunk);
1.933 + if (r!=KErrNone)
1.934 + {
1.935 + delete chunk;
1.936 + return r;
1.937 + }
1.938 + }
1.939 + __KTRACE_OPT(KPBUS2,Kern::Printf("Skt:CreateMemWindowL-got chunk(existing-%d)",chunkExists));
1.940 +
1.941 + // Create the memory window
1.942 + iOffset=aChnk.iMemBaseAddr-chunk->BaseAddr();
1.943 + iLen=aChnk.iMemLen;
1.944 + iAccessSpeed=aSpeed;
1.945 + iMemType=aChnk.iMemType;
1.946 + iWaitSig=(aFlag&KPccdRequestWait);
1.947 + iType=aFlag&(KPccdChunkShared|KPccdChunkPermanent|KPccdChunkSystemOwned); // Save flag settings
1.948 + chunk->AddWindow(this);
1.949 + __KTRACE_OPT(KPBUS2,Kern::Printf("Skt:CreateMemWindowL-created window"));
1.950 + return KErrNone;
1.951 + }
1.952 +
1.953 +EXPORT_C void RPccdWindow::Close()
1.954 + {
1.955 + if (iNext && iChunk)
1.956 + iChunk->RemoveWindow(this);
1.957 + }
1.958 +
1.959 +EXPORT_C TInt RPccdWindow::SetupChunkHw(TUint aFlag)
1.960 +//
1.961 +// Config h/w in preparation for accessing window. Flag is for platform dependant info.
1.962 +//
1.963 + {
1.964 +
1.965 + if (!iChunk)
1.966 + return(KErrNotReady);
1.967 + iChunk->SetupChunkHw(iAccessSpeed,iMemType,iWaitSig,aFlag);
1.968 +// iVcc->ResetInactivityTimer();
1.969 + return(KErrNone);
1.970 + }
1.971 +
1.972 +EXPORT_C TLinAddr RPccdWindow::LinearAddress()
1.973 +//
1.974 +// Return linear address of window
1.975 +//
1.976 + {
1.977 + return iChunk->LinearAddress()+iOffset;
1.978 + }
1.979 +
1.980 +TBool RPccdWindow::Overlap(TUint32 anOffset,TUint aLen)
1.981 +//
1.982 +//
1.983 +//
1.984 + {
1.985 + // If this window is sharable then it doesn't matter if they overlap or not.
1.986 + if (IsShareable())
1.987 + return(EFalse);
1.988 +
1.989 + TUint32 winEnd=(anOffset+aLen-1);
1.990 + TUint32 thisEnd=(iOffset+iLen-1);
1.991 + if ((anOffset>=iOffset && anOffset<=thisEnd) ||
1.992 + (winEnd>=iOffset && winEnd<=thisEnd) )
1.993 + return(ETrue);
1.994 +
1.995 + return(EFalse);
1.996 + }
1.997 +