os/kernelhwsrv/kernel/eka/drivers/pbus/pccard/spccard.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\drivers\pbus\pccard\spccard.cpp
    15 // 
    16 //
    17 
    18 #include <pccard.h>
    19 #include "cis.h"
    20 
    21 LOCAL_D const TPccdAccessSpeed CisDevSpeedTable[8] =
    22 	{EAcSpeedInValid,EAcSpeed250nS,EAcSpeed200nS,EAcSpeed150nS,
    23 	EAcSpeed100nS,EAcSpeedInValid,EAcSpeedInValid,EAcSpeedInValid};
    24 LOCAL_D const TUint32 CisDevSizeInBytesTable[8] =
    25 	{0x00000200,0x00000800,0x00002000,0x00008000,0x00020000,0x00080000,0x00200000,0};
    26 LOCAL_D const TInt CisMantisaTable[0x10] =
    27 	{10,12,13,15,20,25,30,35,40,45,50,55,60,70,80,90};
    28 LOCAL_D const TInt CisSpeedExponentTable[8] =
    29 	{0,1,10,100,1000,10000,100000,1000000};
    30 
    31 GLDEF_C void PcCardPanic(TPcCardPanic aPanic)
    32 	{
    33 	Kern::Fault("PCCARD",aPanic);
    34 	}
    35 
    36 LOCAL_C TPccdAccessSpeed DevSpeedFromExtended(TInt aSpeedInNanoSecs)
    37 	{
    38 
    39 	if (aSpeedInNanoSecs<=100) return(EAcSpeed100nS);
    40 	if (aSpeedInNanoSecs<=150) return(EAcSpeed150nS);
    41 	if (aSpeedInNanoSecs<=200) return(EAcSpeed200nS);
    42 	if (aSpeedInNanoSecs<=250) return(EAcSpeed250nS);
    43 	if (aSpeedInNanoSecs<=300) return(EAcSpeed300nS);
    44 	if (aSpeedInNanoSecs<=450) return(EAcSpeed450nS);
    45 	if (aSpeedInNanoSecs<=600) return(EAcSpeed600nS);
    46 	if (aSpeedInNanoSecs<=750) return(EAcSpeed750nS);
    47 	return(EAcSpeedExtended);
    48 	}
    49 
    50 LOCAL_C TMemDeviceType DevType(TInt aTypeCode)
    51 	{
    52 	if ( aTypeCode>=KTpDiDTypeNull && aTypeCode<=KTpDiDTypeDram )
    53 		return( (TMemDeviceType)aTypeCode );
    54 	else if (aTypeCode>=KTpDiDTypeFuncSpec)
    55 		return(EDeviceFunSpec);
    56 	else
    57 		return(EDeviceInvalid);
    58 	}
    59 
    60 LOCAL_C TInt ExtendedSpeedToNanoSeconds(TUint8 aVal)
    61 //
    62 // Converts extended device speed field to speed in nS.
    63 //
    64 	{
    65 
    66 	TInt mant=(aVal&KCisTplMantM)>>KCisTplMantFO;
    67 	TInt s=(mant==0)?0:CisMantisaTable[mant-1];
    68 	s*=CisSpeedExponentTable[aVal&KCisTplExponM];
    69 	return(s);
    70 	}
    71 	 
    72 LOCAL_C TInt PwrTplToMicroAmps(TUint aVal,TUint anExt)
    73 //
    74 // Converts a power tuple into an integer value - units uA.
    75 //
    76 	{
    77 	TInt p=CisMantisaTable[(aVal&KCisTplMantM)>>KCisTplMantFO];
    78 	p*=10;
    79 	if (anExt<=99)
    80 		p+=anExt;	// Add on the extension
    81 	switch ( aVal&KCisTplExponM )
    82 		{
    83 		case 7: return(p*=10000);   case 6: return(p*=1000); 
    84 		case 5: return(p*=100);	 	case 4: return(p*=10); 
    85 		case 3: return(p);  		case 2: return(p/=10);
    86 		case 1: return(p/=100);
    87 		default: return(0); // Anything else is too small to worry about 
    88 		}
    89 	}
    90 
    91 LOCAL_C TInt PwrTplToMilliVolts(TUint aVal,TUint anExt)
    92 //
    93 // Converts a power tuple into a integer value - units mV.
    94 //
    95 	{
    96 	return(PwrTplToMicroAmps(aVal,anExt)/10);
    97 	}
    98 
    99 LOCAL_C TInt ParseConfigTuple(TDes8 &configTpl,TPcCardConfig &anInfo,TInt &aLastEntry)
   100 //
   101 // Parse a KCisTplConfig tuple.
   102 // (Always alters iConfigBaseAddr and iRegPresent).  
   103 //
   104 	{
   105 
   106 	anInfo.iConfigBaseAddr=0;
   107 	anInfo.iRegPresent=0;
   108 
   109 	// Get the sizes of the ConfReg base addr & ConfReg present fields
   110 	TInt rasz=((configTpl[2]&KTpCcRaszM)>>KTpCcRaszFO)+1;
   111 	TInt rmsz=((configTpl[2]&KTpCcRmszM)>>KTpCcRmszFO)+1;
   112 	if ( (configTpl.Size()-4) < (rasz+rmsz) )
   113 		return(KErrNotSupported); // Size of fields longer than tuple length.
   114 	aLastEntry=configTpl[3];
   115 
   116 	// Read Config. Reg. base address.
   117 	TInt i;
   118 	for (i=0;i<rasz;i++)
   119 		anInfo.iConfigBaseAddr += (configTpl[4+i]<<(8*i));
   120 
   121 	// Read Config. Reg. present mask
   122 	if (rmsz>4) rmsz=4;	  // We only have 32bit field
   123 	for (i=0;i<rmsz;i++)
   124 		anInfo.iRegPresent += (configTpl[4+rasz+i]<<(8*i));
   125 	return(KErrNone); // Ignore custom interface subtuples
   126 	}
   127 
   128 LOCAL_C TInt ParsePowerEntry(const TUint8 *aTplPtr,TInt *aVMax,TInt *aVMin,TInt *aPeakI,TInt *aPdwnI)
   129 //
   130 // Parse a Power descriptor in a KCisTplCfTableEntry tuple. Returns the 
   131 // number of bytes we have parsed. 
   132 //
   133 	{
   134 	const TUint8 *initPtr = aTplPtr;
   135 	TUint8 present = *aTplPtr++;
   136 	TBuf8<16> pwr;
   137 	pwr.FillZ(16);	  // Important
   138 
   139 	TInt i;
   140 	for (i=0;i<16;i+=2,present>>=1)
   141 		{
   142 		if (present&0x01)
   143 			{
   144 			pwr[i]=(TUint8)((*aTplPtr)&(~KCisTplExt));
   145 			if (*aTplPtr++ & KCisTplExt)
   146 				{
   147 				pwr[i+1]=(TUint8)((*aTplPtr)&(~KCisTplExt));	// Extension tuple
   148 				while( *aTplPtr++ & KCisTplExt );				// Jump past any more extensions
   149 				}
   150 			}
   151 		}
   152 
   153 	if (aVMin && aVMax)
   154 		{
   155 		if (pwr[0])						 // NomV (assume +/-5%)
   156 			{
   157 			(*aVMin)=(*aVMax)=PwrTplToMilliVolts(pwr[0],pwr[1]);
   158 			(*aVMin) = ((*aVMin)*95)/100;
   159 			(*aVMax) = ((*aVMax)*105)/100;
   160 			}
   161 		if (pwr[2])							// MinV
   162 			*aVMin=PwrTplToMilliVolts(pwr[2],pwr[3]);
   163   		if (pwr[4])							// MaxV
   164 			*aVMax=PwrTplToMilliVolts(pwr[4],pwr[5]);
   165 		}
   166 	// We'll settle for average/static if no peak.
   167 	if (aPeakI && (pwr[10]||pwr[8]||pwr[6]) )
   168 		{
   169 		if (pwr[6])
   170 			*aPeakI = PwrTplToMicroAmps(pwr[6],pwr[7]);
   171 		if (pwr[8])
   172 			*aPeakI = PwrTplToMicroAmps(pwr[8],pwr[9]);
   173 		if (pwr[10])
   174 			*aPeakI = PwrTplToMicroAmps(pwr[10],pwr[11]); // Last one overides others
   175 		}
   176 	if (aPdwnI && pwr[12])
   177 		*aPdwnI = PwrTplToMicroAmps(pwr[12],pwr[13]); 
   178 
   179 	return(aTplPtr-initPtr);
   180 	}
   181 
   182 LOCAL_C TInt ParseTimingEntry(const TUint8 *aTplPtr)
   183 //
   184 // Parse a timing descriptor in a KCisTplCfTableEntry tuple. Returns the 
   185 // number of bytes we have parsed. 
   186 //
   187 	{
   188 	// We ignore this information - just jump past this field
   189 	const TUint8 *initPtr=aTplPtr;
   190 
   191 	TUint8 present=*aTplPtr++;	  // First the timing present field
   192 
   193 	if ((present & KTpCeTimWaitM) != KTpCeTimWaitM)
   194 		while( *aTplPtr++ & KCisTplExt ); // Wait time (jump past any extensions)
   195 	if ((present & KTpCeTimRdyM) != KTpCeTimRdyM)
   196 		while( *aTplPtr++ & KCisTplExt ); // Ready time (jump past any extensions)
   197 	if ((present & KTpCeTimResM) != KTpCeTimResM)
   198 		while( *aTplPtr++ & KCisTplExt ); // Reserved time (jump past any extensions)
   199 	return(aTplPtr-initPtr);
   200 	}
   201 
   202 LOCAL_C TInt ParseIoEntry(const TUint8 *aTplPtr,TPccdChnk *aChnk,TInt &aNextChnkNum)
   203 //
   204 // Parse an IO space descriptor in a KCisTplCfTableEntry tuple. Returns the 
   205 // number of bytes we have parsed (or a negative error value). Also returns the 
   206 // number of config chunk entries used ('aNextChunkNum').
   207 //
   208 	{
   209 	TPccdMemType memType;
   210 	TInt bytesParsed = 1; // Must be a minimum of a single byte descriptor here.
   211 
   212 	// Always at least one I/O space descriptor
   213 	switch( (*aTplPtr & KTpCeBus16_8M) >> KTpCeBus16_8FO )
   214 		{
   215 		case 1: case 2:
   216 			memType = EPccdIo8Mem;	 // Card supports 8bit I/O only.
   217 			break;
   218 		case 3:
   219 			memType = EPccdIo16Mem;	// Card supports 8 & 16 bit I/O.
   220 			break;
   221 		default:
   222 			return(KErrCorrupt);	
   223 		}
   224 	TUint ioLines = (*aTplPtr & KTpCeIoLinesM) >> KTpCeIoLinesFO;
   225 
   226 	TInt ranges=1; // We always specify one chunk even if no range descriptors follow
   227 	TInt addrInBytes=0; 
   228 	TInt lenInBytes=0;
   229 	// Are there any IO Range description bytes to follow
   230 	if (*aTplPtr++ & KTpCeRangePresM)
   231 		{
   232 		ranges = ((*aTplPtr & KTpCeIoRangesM) >> KTpCeIoRangesFO)+1;
   233 		addrInBytes = (*aTplPtr & KTpCeIoAddrSzM) >> KTpCeIoAddrSzFO;
   234 		lenInBytes = (*aTplPtr & KTpCeIoAddrLenM) >> KTpCeIoAddrLenFO;
   235 		aTplPtr++;
   236 
   237 		// There could be multiple range descriptors
   238 		if ((ranges+aNextChnkNum)<=KMaxChunksPerConfig)
   239 			bytesParsed += (ranges * (addrInBytes + lenInBytes))+1;
   240 		else
   241 			return(KErrNotSupported);	// Too many descriptors for us
   242 		}
   243 
   244 	aChnk+=aNextChnkNum;
   245 	for (;ranges>0;ranges--,aChnk++,aNextChnkNum++)
   246 		{
   247 		TInt j;
   248 		aChnk->iMemType=memType;	 // I/O memory type
   249 
   250 		// Lets get the IO start address
   251 		aChnk->iMemBaseAddr=0;
   252 		if (addrInBytes)
   253 			{
   254 			for (j=0;j<addrInBytes;j++)
   255 				aChnk->iMemBaseAddr += (*aTplPtr++) << (8*j);
   256 			}
   257 
   258 		// Finally, lets get the IO length
   259 		if (lenInBytes)
   260 			{
   261 			for (j=0,aChnk->iMemLen=0;j<lenInBytes;j++)
   262 		   		aChnk->iMemLen += (*aTplPtr++) << (8*j);
   263 			(aChnk->iMemLen)++;
   264 			}
   265 		else
   266 			{
   267 			if (ioLines)
   268 				aChnk->iMemLen = 0x01<<ioLines;
   269 			else
   270 				return(KErrCorrupt); // No ioLines and no length, it's invalid.   
   271 			}
   272 		}
   273 	return(bytesParsed);
   274 	}
   275 
   276 LOCAL_C TInt ParseMemEntry(const TUint8 *aTplPtr,TInt aFeatureVal,TPccdChnk *aChnk,TInt &aNextChnkNum)
   277 //
   278 // Parse a memory space descriptor in a KCisTplCfTableEntry tuple. Returns
   279 // the number of bytes we have parsed (or a negative error value). Also returns the 
   280 // number of config chunk entries used ('aNextChunkNum').
   281 //
   282 	{
   283 
   284 	const TUint8 *initPtr=aTplPtr;
   285 	TInt windows=0; 		
   286 	TInt lenInBytes=0;  	
   287 	TInt addrInBytes=0;		
   288 	TBool hostAddr=EFalse;
   289 	switch (aFeatureVal)
   290 		{
   291 		case 3:   // Memory space descriptor
   292 			windows=(*aTplPtr & KTpCeMemWindowsM)+1;
   293 			lenInBytes=(*aTplPtr & KTpCeMemLenSzM) >> KTpCeMemLenSzFO;
   294 			addrInBytes=(*aTplPtr & KTpCeMemAddrSzM) >> KTpCeMemAddrSzFO;
   295 			hostAddr=(*aTplPtr & KTpCeMemHostAddrM);
   296 			aTplPtr++;
   297 			break;
   298 		case 2:			// Length(2byte) and base address(2byte) specified.
   299 			addrInBytes=2; 
   300 		case 1:			// Single 2-byte length specified.
   301 			lenInBytes=2;
   302 			windows=1;
   303 			break;
   304 		}
   305 
   306 	if ((windows+aNextChnkNum)>KMaxChunksPerConfig)
   307 		return(KErrNotSupported);	// Too many descriptors for us
   308 
   309 	aChnk+=aNextChnkNum;
   310 	TInt i;
   311 	for (;windows>0;windows--,aChnk++,aNextChnkNum++)
   312 		{
   313 		aChnk->iMemType=EPccdCommon16Mem;
   314 		aChnk->iMemLen=0;
   315 		if (lenInBytes)
   316 			{
   317 			for (i=0;i<lenInBytes;i++)
   318 				aChnk->iMemLen += (*aTplPtr++) << ((8*i)+8);  	// in 256 byte pages
   319 			}
   320 		aChnk->iMemBaseAddr=0;
   321 		if (addrInBytes)
   322 			{
   323 			for (i=0;i<addrInBytes;i++)
   324 				aChnk->iMemBaseAddr += (*aTplPtr++) << ((8*i)+8);// in 256 byte pages
   325 			}
   326 		if (hostAddr)
   327 			{
   328 			for (i=0;i<addrInBytes;i++)
   329 				aTplPtr++; // Dont record this, just advance the tuple pointer
   330 			}
   331 		}
   332 	return(aTplPtr-initPtr);
   333 	}
   334 
   335 LOCAL_C TInt ParseMiscEntry(const TUint8 *aTplPtr, TBool &aPwrDown)
   336 //
   337 // Parse a miscellaneous features field in a KCisTplCfTableEntry tuple.
   338 // Returns the number of bytes we have parsed. 
   339 //
   340 	{
   341 	aPwrDown=(*aTplPtr&KTpCePwrDownM);
   342 
   343 	TInt i;
   344 	for (i=1;*aTplPtr & KCisTplExt;i++,aTplPtr++);
   345 	return(i);
   346 	}
   347 
   348 LOCAL_C TInt ParseConfigEntTuple(TDes8 &cTpl,TPcCardConfig &anInfo)
   349 //
   350 // Parse a KCisTplCfTableEntry tuple. anInfo contains default values on 
   351 // entry so this routine only adds data it finds in the tuple.
   352 //
   353 	{
   354 
   355 	// Parse the Index byte.
   356 	const TUint8 *tplPtr=cTpl.Ptr()+2; // First tuple after link
   357 	anInfo.iConfigOption=(*tplPtr & KTpCeOptionM);
   358 	anInfo.iIsDefault=(*tplPtr & KTpCeIsDefaultM);
   359 
   360 	// Check if there is an interface description field to follow
   361 	if (*tplPtr++ & KTpCeIntfPresM)
   362 		{
   363  		anInfo.iIsIoAndMem=(*tplPtr&KTpCeIntfTypeM);
   364 		anInfo.iActiveSignals=*tplPtr&(KTpCeBvdM|KTpCeWpM|KTpCeReadyM|KTpCeWaitM);
   365 		tplPtr++;
   366 		}
   367 
   368 	// Next byte should be the feature selection byte.
   369 	TUint8 features=*tplPtr++;
   370 
   371 	// Next might be 0-3 power description structures. 1st one is always VCC info.
   372 	TInt entry=(features & KTpCePwrPresM)>>KTpCePwrPresFO;
   373 	if (entry)
   374 		{
   375 		tplPtr += ParsePowerEntry(tplPtr,&anInfo.iVccMaxInMilliVolts,&anInfo.iVccMinInMilliVolts,
   376 							      &anInfo.iOperCurrentInMicroAmps,&anInfo.iPwrDwnCurrentInMicroAmps);
   377 		entry--;
   378 		}
   379 	
   380 	// We only support a single Vpp supply. However we need to parse both (Vpp1+Vpp2)
   381 	// in order to advance the tuple pointer.
   382 	while ( entry-- )
   383 		tplPtr += ParsePowerEntry(tplPtr,&anInfo.iVppMaxInMilliVolts,&anInfo.iVppMinInMilliVolts,NULL,NULL);
   384 
   385 	// Next might be timing info.
   386 	if (features & KTpCeTimPresM)
   387 		tplPtr += ParseTimingEntry(tplPtr);
   388 
   389 	// Next might be IO space description.
   390 	TInt ret;
   391 	TInt nextFreeChunk=0;
   392 	if (features & KTpCeIoPresM)
   393 		{
   394 		if((ret=ParseIoEntry(tplPtr,&(anInfo.iChnk[0]),nextFreeChunk))<0)
   395 			return(ret);
   396 		anInfo.iValidChunks=nextFreeChunk;
   397 		tplPtr += ret;
   398 		}
   399 
   400 	// Next might be IRQ description.
   401 	if (features & KTpCeIrqPresM)
   402 		{
   403 		anInfo.iInterruptInfo=*tplPtr&(KPccdIntShare|KPccdIntPulse|KPccdIntLevel);
   404 		tplPtr+=(*tplPtr&KTpCeIrqMaskM)?3:1; // Ignore mask bytes if present
   405 		}
   406 
   407 	// Next might be memory space description.
   408 	entry=((features & KTpCeMemPresM) >> KTpCeMemPresFO);
   409 	if (entry)
   410 		{
   411 		if ((ret=ParseMemEntry(tplPtr,entry,&(anInfo.iChnk[0]),nextFreeChunk))<0)
   412 			return(ret);
   413 		anInfo.iValidChunks=nextFreeChunk;
   414 		tplPtr+=ret;
   415 		}
   416 
   417 	// And finally there might be a miscellaneous features field
   418 	if (features & KTpCeMiscPresM)
   419 		tplPtr+=ParseMiscEntry(tplPtr,anInfo.iPwrDown);
   420 
   421 	// Check that we haven't been reading beyond the tuple.
   422 	if ((tplPtr-cTpl.Ptr()) > (cTpl[1]+2))
   423 		return(KErrCorrupt);
   424 
   425 	return(KErrNone);
   426 	}
   427 
   428 LOCAL_C TInt ParseDeviceInfo(const TUint8 *aTplPtr,TPcCardRegion &anInfo)
   429 //
   430 // Parse a device info field in a KCisTplDeviceX tuple.
   431 // Returns the number of bytes we have parsed (or a negative error value). 
   432 //
   433 	{
   434 
   435 	const TUint8 *initPtr=aTplPtr;
   436 	TInt val;
   437 	// Device ID - device type field
   438 	val=((*aTplPtr & KTpDiDTypeM) >> KTpDiDTypeFO);
   439 	if (val==KTpDiDTypeExtend)
   440 		return(KErrNotSupported);	   // Don't support extended device type
   441 	anInfo.iDeviceType=DevType(val);
   442 
   443 	// Device ID - write protect field
   444 	if (!(*aTplPtr&KTpDiWpsM))
   445 		anInfo.iActiveSignals|=KSigWpActive;
   446 
   447 	// Device ID - device speed field
   448 	val=(*aTplPtr & KTpDiDSpeedM);
   449 	if (val==KTpDiDSpeedExt)
   450 		{
   451 		aTplPtr++;
   452 		anInfo.iExtendedAccSpeedInNanoSecs=ExtendedSpeedToNanoSeconds(*aTplPtr);
   453 		anInfo.iAccessSpeed=DevSpeedFromExtended(anInfo.iExtendedAccSpeedInNanoSecs);
   454 		while(*aTplPtr++ & KCisTplExt); // Jump past any (further) extended speed fields
   455 		}
   456 	else
   457 		{
   458 		anInfo.iExtendedAccSpeedInNanoSecs=0;
   459 		anInfo.iAccessSpeed=CisDevSpeedTable[val];
   460 		aTplPtr++;
   461 		}
   462 
   463 	// Now the Device size
   464 	TInt size,numUnits;
   465 	size=((*aTplPtr & KTpDiDSizeM) >> KTpDiDSizeFO);
   466 	numUnits=((*aTplPtr++ & KTpDiDUnitsM) >> KTpDiDUnitsFO)+1;
   467 	if (size>KTpDiDSize2M)
   468 		return(KErrCorrupt);	 
   469 	anInfo.iChnk.iMemLen=numUnits*CisDevSizeInBytesTable[size];
   470 	return(aTplPtr-initPtr);
   471 	}
   472 /*
   473 LOCAL_C TInt SocketIsInRange(TSocket aSocket)
   474 //
   475 // Check socket is valid for this machine
   476 //
   477 	{
   478 
   479 //	return(aSocket>=0&&aSocket<ThePcCardController->TotalSupportedBuses());
   480 	return (aSocket>=0 && aSocket<KMaxPBusSockets && TheSockets[aSocket]!=NULL);
   481 	}
   482 */
   483 EXPORT_C TCisReader::TCisReader()
   484 //
   485 // Constructor.
   486 //
   487 	: iFunc(0),iCisOffset(0),iLinkOffset(0),iMemType(EPccdAttribMem),
   488 	  iLinkFlags(0),iRestarted(EFalse),iRegionCount(0),
   489 	  iConfigCount(0)
   490 	{
   491 	iSocket=NULL;
   492 	}
   493 
   494 EXPORT_C TInt TCisReader::SelectCis(TSocket aSocket,TInt aCardFunc)
   495 //
   496 //  Assign the CIS reader to a socket and function.
   497 //
   498 	{
   499 	// We need to have read the CIS format
   500 	__KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:SelectCis(S:%d F:%d)",aSocket,aCardFunc));
   501 	DPcCardSocket* pS=(DPcCardSocket*)TheSockets[aSocket];
   502 	if (pS->CardIsReadyAndVerified()!=KErrNone)
   503 		return KErrNotReady;
   504 	iSocket=pS;
   505 	return(DoSelectCis(aCardFunc));
   506 	}
   507 
   508 TInt TCisReader::DoSelectCis(TInt aCardFunc)
   509 //
   510 //  Actually assign the CIS reader to a socket and function.
   511 //
   512 	{
   513 
   514 	// Check that the function is valid
   515 	TInt r;
   516 	if (!iSocket->IsValidCardFunc(aCardFunc))
   517 		{
   518 		iSocket=NULL;
   519 		r=KErrNotFound;
   520 		}
   521 	else
   522 		{
   523 		iFunc=aCardFunc;
   524 		DoRestart();
   525 		iConfigCount=0;
   526 		r=KErrNone;
   527 		}
   528 	__KTRACE_OPT(KPBUS1,Kern::Printf("<CisReader:DoSelectCis(F:%d)-%d",aCardFunc,r));
   529 	return(r);
   530 	}
   531 
   532 EXPORT_C TInt TCisReader::Restart()
   533 //
   534 // Restart the CIS reader back to the start of the CIS, and re-initialise
   535 // config entry parsing.
   536 //
   537 	{
   538 	if (iSocket==NULL)
   539 		return(KErrGeneral);
   540 	DoRestart();
   541 	iConfigCount=0;
   542 	return(KErrNone);
   543 	}
   544 
   545 void TCisReader::DoRestart()
   546 //
   547 //  Restart the CIS reader back to the start of the CIS
   548 //
   549 	{
   550 
   551 	TPcCardFunction *func=iSocket->CardFunc(iFunc);
   552 	iCisOffset=func->InitCisOffset();	
   553 	iLinkOffset=0;	
   554 	iMemType=func->InitCisMemType();
   555 	iLinkFlags=0;
   556 	iRestarted=ETrue;
   557 	iRegionCount=0;
   558 	__KTRACE_OPT(KPBUS1,Kern::Printf("<CisReader:DoRestart"));
   559 	}
   560 
   561 EXPORT_C TInt TCisReader::FindReadTuple(TUint8 aDesiredTpl,TDes8 &aDes,TUint aFlag)
   562 //
   563 // Find a specified tuple from the CIS and read it.
   564 //
   565 	{                                 
   566 	__ASSERT_ALWAYS(iSocket!=NULL,PcCardPanic(EPcCardCisReaderUnInit)); 
   567 
   568 	// We're going to read the card itself so it must be ready.
   569 	if ( iSocket->CardIsReadyAndVerified()!=KErrNone )
   570 		return(KErrNotReady);
   571 
   572 	return(DoFindReadTuple(aDesiredTpl,aDes,aFlag));
   573 	}
   574 
   575 TInt TCisReader::DoFindReadTuple(TUint8 aDesiredTpl,TDes8 &aDes,TUint aFlag)
   576 //
   577 // Actually find a specified tuple from the CIS and read it.
   578 //
   579 	{
   580 
   581 	__KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:DoFindReadTuple(T:%xH)",aDesiredTpl));
   582 
   583 	TBuf8<KSmallTplBufSize> tpl;
   584 	TBuf8<KSmallTplBufSize> linkAddr;
   585 	TInt i,j,err;
   586 
   587 	// Read the previous tuple
   588 	if ((err=iSocket->ReadCis(iMemType,iCisOffset,tpl,2))!=KErrNone)
   589 		return(err);
   590 
   591 	for (j=0;j<KMaxTuplesPerCis;j++)
   592 		{
   593 		// Adjust CIS offset beyond last tuple read (unless we've just restarted)
   594 		if (iRestarted)
   595 			iRestarted=EFalse;
   596 		else
   597 			{
   598 			if (tpl[0]!=KCisTplEnd && tpl[1]!=0xff)
   599 				iCisOffset+=(tpl[0]==KCisTplNull)?1:(tpl[1]+2); // A null tuple has no link field
   600 			else
   601 				{
   602 				// End of chain tuple
   603 				if ((err=FollowLink(aFlag&KPccdReportErrors))!=KErrNone)
   604 					return(err);
   605 				}
   606 			}
   607 
   608 		// Read the next tuple
   609 		if ((err=iSocket->ReadCis(iMemType,iCisOffset,tpl,2))!=KErrNone)
   610 			return(err);
   611 
   612 		// Check for a link tuple (need to store next chain addr. for later)
   613 		switch(tpl[0])
   614 			{
   615 			case KCisTplLongLinkA:
   616 				iLinkFlags |= KPccdLinkA;
   617 				if ((err= iSocket->ReadCis(iMemType,iCisOffset+2,linkAddr,4)) != KErrNone)
   618 					return(err);
   619 				for (iLinkOffset=0,i=0 ; i<4 ; i++)
   620 					iLinkOffset += linkAddr[i] << (8*i);
   621 				break;
   622 			case KCisTplLongLinkC:
   623 				iLinkFlags |= KPccdLinkC;
   624 				if ((err= iSocket->ReadCis(iMemType,iCisOffset+2,linkAddr,4)) != KErrNone)
   625 					return(err);
   626 				for (iLinkOffset=0,i=0 ; i<4 ; i++)
   627 					iLinkOffset += linkAddr[i] << (8*i);
   628 				break;
   629 			case KCisTplLongLinkMfc:
   630 				iLinkFlags |= KPccdLinkMFC;
   631 				break;
   632 			case KCisTplNoLink:
   633 				iLinkFlags |= KPccdNoLink;
   634 			default:
   635 				break;
   636 			}
   637 
   638 		// Check if we have found the specified tuple
   639 		if (aDesiredTpl==KPccdNonSpecificTpl || aDesiredTpl==tpl[0])
   640 			{
   641 			// The following are ignored unless KPccdReturnLinkTpl is set. 
   642 			if ((tpl[0]==KCisTplNull)||
   643 				(tpl[0]==KCisTplEnd)||
   644 				(tpl[0]==KCisTplLongLinkA)||
   645 				(tpl[0]==KCisTplLongLinkC)||
   646 				(tpl[0]==KCisTplLongLinkMfc)||
   647 				(tpl[0]==KCisTplNoLink)||
   648 				(tpl[0]==KCisTplLinkTarget))
   649 				{
   650 				if (aFlag&KPccdReturnLinkTpl)
   651 					break;
   652 				}
   653 			else
   654 				break;
   655 			}
   656 		}
   657 
   658 	// We got a result (or we've wandered off into the weeds)
   659 	if (j>=KMaxTuplesPerCis)
   660 		return( (aFlag&KPccdReportErrors)?KErrCorrupt:KErrNotFound );
   661 	else
   662 		return((aFlag&KPccdFindOnly)?KErrNone:DoReadTuple(aDes));
   663 	}
   664 
   665 EXPORT_C TInt TCisReader::ReadTuple(TDes8 &aDes)
   666 //
   667 // Read the tuple at the current CIS offset.
   668 //
   669 	{
   670 	__ASSERT_ALWAYS(iSocket!=NULL,PcCardPanic(EPcCardCisReaderUnInit)); 
   671 
   672 	// We're going to read the card itself so it must be ready.
   673 	if ( iSocket->CardIsReadyAndVerified()!=KErrNone )
   674 		return(KErrNotReady);
   675 
   676 	return(DoReadTuple(aDes));
   677 	}
   678 
   679 TInt TCisReader::DoReadTuple(TDes8 &aDes)
   680 //
   681 // Actually read the tuple at the current CIS offset.
   682 //
   683 	{
   684 
   685 	__KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:DoReadTuple"));
   686 	TInt err;
   687 
   688 	// Read the tuple type and link
   689 	TBuf8<KSmallTplBufSize> tpl;
   690 	if ((err= iSocket->ReadCis(iMemType,iCisOffset,tpl,2)) != KErrNone)
   691 		return(err);
   692 
   693 	TInt tplLen ;
   694 	if ((tpl[0] == KCisTplNull) || (tpl[0] == KCisTplEnd))
   695 		tplLen = 1 ;			// These tuples dont have a link.
   696 	else
   697 		tplLen = (tpl[1]+2) ;
   698 	if ( tplLen>aDes.MaxLength() )   // We dont want a panic if aDes too small
   699 		return(KErrArgument);
   700 
   701 	// Lets copy the tuple
   702 	if ((err= iSocket->ReadCis(iMemType,iCisOffset,aDes,tplLen)) != KErrNone)
   703 		return(err);
   704 	else
   705 		return(KErrNone);
   706 	}
   707 
   708 TInt TCisReader::FollowLink(TUint aFullErrorReport)
   709 //
   710 // Called at the end of a tuple chain, this moves CIS pointer to the next
   711 // CIS chain if a long link has been detected.
   712 //
   713 	{
   714 
   715 	TInt err;
   716 	switch (iLinkFlags)
   717 		{
   718 		case 0: // Haven't found anything so assume longlink to 0 in common.
   719 			iLinkOffset=0;
   720 		case KPccdLinkC:
   721 			iCisOffset=iLinkOffset;
   722 			iMemType=EPccdCommon8Mem;
   723 			iLinkOffset=0;
   724 			if ((err=VerifyLinkTarget())!=KErrNone)
   725 				{
   726 				DoRestart(); // Leave pointers somewhere safe.
   727 				if (iLinkFlags==0||!aFullErrorReport)
   728 					err=KErrNotFound; // Above assumption wrong
   729 				}
   730 			break;
   731 		case KPccdLinkA:
   732 			iCisOffset=iLinkOffset;
   733 			iMemType=EPccdAttribMem;
   734 			iLinkOffset=0;
   735 			if ((err=VerifyLinkTarget())!=KErrNone)
   736 				{
   737 				iCisOffset>>=1; // Check if the link offset is wrong
   738 				if (VerifyLinkTarget()!=KErrNone)
   739 					{
   740 					DoRestart(); // Leave pointers somewhere safe.
   741 					if (!aFullErrorReport)
   742 						err=KErrNotFound;
   743 					}
   744 				else
   745 					err=KErrNone;
   746 				}
   747 			break;
   748 		case KPccdNoLink:
   749 		case KPccdLinkMFC: // Can't follow a multi-function link
   750 			DoRestart(); // Leave pointers somewhere safe.
   751 			err=KErrNotFound;
   752 			break;
   753 		default:	// Shouldn't have more than 1 link per chain
   754 			DoRestart(); // Leave pointers somewhere safe.
   755 			err=(aFullErrorReport)?KErrCorrupt:KErrNotFound;   
   756 		}
   757 	iLinkFlags=0;
   758 	return(err);
   759 	}
   760 
   761 TInt TCisReader::VerifyLinkTarget()
   762 //
   763 //	Verify a new tuple chain starts with a valid link target tuple
   764 //
   765 	{
   766 	TBuf8<KSmallTplBufSize> tpl;
   767 	TInt err;
   768 	if ((err=iSocket->ReadCis(iMemType,iCisOffset,tpl,5))!=KErrNone)
   769 		return(err);
   770 	if ( (tpl[0]!=KCisTplLinkTarget) || (tpl[1]<3) || (tpl.Find(_L8("CIS"))!=2) )
   771 		return(KErrCorrupt);
   772 	return(KErrNone);
   773 	}
   774 
   775 EXPORT_C TInt TCisReader::FindReadRegion(TPccdSocketVcc aSocketVcc,TPcCardRegion &anInfo,TUint8 aDesiredTpl)
   776 //
   777 // Read region info from the CIS on the specified Socket/Function. Can
   778 // be called multiple times to read all regions (eventually
   779 // returns KErrNotFound). 
   780 // If the function returns an error value then ignore anInfo.
   781 //
   782 	{
   783 
   784 	if (!aDesiredTpl)
   785 		aDesiredTpl=(aSocketVcc==EPccdSocket_5V0)?KCisTplDevice:KCisTplDeviceOC;
   786 	__KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:FindReadRegion(TPL:%xH)",aDesiredTpl));
   787 
   788 	TInt ret;
   789 	TBuf8<KLargeTplBufSize> devTpl;
   790 	if (!iRegionCount)				 // Count of regions processed in tuple
   791 		ret=FindReadTuple(aDesiredTpl,devTpl);
   792 	else
   793 		ret=ReadTuple(devTpl);
   794 	if (ret!=KErrNone)
   795 		return(ret);
   796 	const TUint8 *tplPtr=devTpl.Ptr();
   797 	const TUint8 *tplE=tplPtr+devTpl.Length(); 
   798 	tplPtr+=2; // First tuple after link
   799 
   800 	if (aDesiredTpl==KCisTplDeviceOC||aDesiredTpl==KCisTplDeviceOA)
   801 		{
   802 		// Process the Other Conditions info.
   803 		anInfo.iChnk.iMemType=(aDesiredTpl==KCisTplDeviceOA)?EPccdAttribMem:EPccdCommon16Mem;
   804 		anInfo.iActiveSignals=(*tplPtr & KTpDoMWaitM)?KSigWaitRequired:0;
   805 		switch( (*tplPtr & KTpDoVccUsedM) >> KTpDoVccUsedFO )
   806 			{
   807 			case 3: anInfo.iVcc=EPccdSocket_yVy; break;
   808 			case 2: anInfo.iVcc=EPccdSocket_xVx; break;
   809 			case 1: anInfo.iVcc=EPccdSocket_3V3; break;
   810 			default: anInfo.iVcc=EPccdSocket_5V0; break;
   811 			}
   812 		while (*tplPtr++ & KCisTplExt);	 // Ignore any extensions
   813 		}
   814 	else
   815 		{ // KCisTplDevice
   816 		anInfo.iChnk.iMemType=(aDesiredTpl==KCisTplDeviceA)?EPccdAttribMem:EPccdCommon16Mem;
   817 		anInfo.iVcc=EPccdSocket_5V0;
   818 		anInfo.iActiveSignals=0;
   819 		}
   820 
   821 	// Now start on the Device Info fields
   822 	anInfo.iAccessSpeed=EAcSpeedInValid;
   823 	anInfo.iChnk.iMemBaseAddr = anInfo.iChnk.iMemLen = 0;
   824 	for (TInt regions=1;*tplPtr!=0xFF&&tplPtr<tplE;tplPtr+=ret,regions++)
   825 		{
   826 		// Add length of previous region to give new base address.
   827 		anInfo.iChnk.iMemBaseAddr+=anInfo.iChnk.iMemLen;
   828 
   829 		if ((ret=ParseDeviceInfo(tplPtr,anInfo)) < 0)
   830 			return(ret);
   831 
   832 		// Check if we have new region to report (dont report null regions)
   833 		if (anInfo.iDeviceType!=EDeviceNull && regions>iRegionCount)
   834 			{
   835 			iRegionCount=regions; // Save for next time
   836 			return(KErrNone);
   837 			}
   838 		}
   839 	return(KErrNotFound); 
   840 	}
   841 
   842 EXPORT_C TInt TCisReader::FindReadConfig(TPcCardConfig &anInfo)
   843 //
   844 // Read configuration info from the CIS on the specified Socket/Function. Can
   845 // be called multiple times to read all configuration options (eventually
   846 // returns KErrNotFound). Uses previous configuration option value to mark
   847 // where we are in a configuration table.
   848 // If the function returns an error value then ignore anInfo.
   849 //
   850 	{
   851 
   852 	__KTRACE_OPT(KPBUS1,Kern::Printf(">CisReader:FindReadConfig(%d)",iConfigCount));
   853 	__ASSERT_ALWAYS(iSocket!=NULL,PcCardPanic(EPcCardCisReaderUnInit)); 
   854 
   855 	DoRestart();	  // Start from beginning of CIS each time (dont reset iConfigCount though).
   856 
   857 	// Create an initial default configuration
   858 	TPcCardConfig defaultConfInfo;
   859 	defaultConfInfo.iVccMaxInMilliVolts=5250;	// 5V+5%		
   860 	defaultConfInfo.iVccMinInMilliVolts=4750;	// 5V-5%					
   861 	defaultConfInfo.iAccessSpeed=DEF_IO_ACSPEED;
   862 	defaultConfInfo.iActiveSignals=0;
   863 					  
   864 	TBuf8<KLargeTplBufSize> configTpl;
   865 	TInt lastEntryIndex;
   866 	TBool foundLast=EFalse;
   867 	TInt err;
   868 	TInt i=0;
   869 	if (
   870 		 (err=FindReadTuple(KCisTplConfig,configTpl))==KErrNone &&
   871 		 (err=ParseConfigTuple(configTpl,defaultConfInfo,lastEntryIndex))==KErrNone
   872 	   )
   873 		{
   874 		// Start of new configuration table
   875 		for (; (err=FindReadTuple(KCisTplCfTableEntry,configTpl))==KErrNone && i<KMaxCfEntriesPerCis ; i++)
   876 			{
   877 			anInfo=defaultConfInfo; 		// Entries assume values from last default entry
   878 			err=ParseConfigEntTuple(configTpl,anInfo);
   879 			if (anInfo.iConfigOption==lastEntryIndex)
   880 				foundLast=ETrue;
   881 			else
   882 				{
   883 				if (foundLast)
   884 					{
   885 					err=KErrNotFound; // We've passed the last entry
   886 					break;
   887 					}
   888 				}
   889 			if (iConfigCount==i)
   890 				break;
   891 			if (err==KErrNone && anInfo.iIsDefault)
   892 				defaultConfInfo=anInfo;
   893 			}
   894 		}
   895 	if (i>=KMaxCfEntriesPerCis)
   896 		err=KErrCorrupt;
   897 	if (err==KErrNone)
   898 		iConfigCount++;
   899 	__KTRACE_OPT(KPBUS1,Kern::Printf("<CisReader:FindReadConfig-%d",err));
   900 	return(err);
   901 	}
   902 
   903 TPcCardFunction::TPcCardFunction(TUint32 anOffset,TPccdMemType aMemType)
   904 //
   905 // Constructor
   906 //
   907 	: iFuncType(EUnknownCard),iInitCisOffset(anOffset),iInitCisMemType(aMemType),
   908 	  iConfigBaseAddr(0),iConfigRegMask(0),iConfigIndex(KInvalidConfOpt),iConfigFlags(0)
   909 	{
   910 	iClientID=NULL;
   911 	}
   912 
   913 void TPcCardFunction::SetConfigOption(TInt anIndex,DBase *aClientID,TUint aConfigFlags)
   914 //
   915 // Save configuration index and client ID
   916 //
   917 	{
   918 
   919 	iConfigIndex=anIndex;
   920 	iClientID=aClientID;
   921 	iConfigFlags=aConfigFlags;
   922 	}
   923 
   924 TInt TPcCardFunction::ConfigRegAddress(TInt aRegOffset,TInt &anAddr)
   925 //
   926 // Provide the specified configuration register address.
   927 //
   928 	{
   929 
   930 	// Must be configured or we wont have the ConfigReg base address
   931 	if (!IsConfigured())
   932 		return(KErrGeneral);
   933 	anAddr=(iConfigBaseAddr + (aRegOffset<<1));
   934 
   935 	// Return an error if the register isn't present
   936 	if ( !(iConfigRegMask & (0x01<<aRegOffset)) )
   937 		return(KErrNotSupported);
   938 	else
   939 		return(KErrNone);
   940 	}
   941 
   942 EXPORT_C TPccdChnk::TPccdChnk()
   943 //
   944 // Constructor
   945 //
   946 	: iMemType(EPccdAttribMem),iMemBaseAddr(0),iMemLen(0)
   947 	{}
   948 
   949 EXPORT_C TPccdChnk::TPccdChnk(TPccdMemType aType,TUint32 aBaseAddr,TUint32 aLen)
   950 //
   951 // Constructor
   952 //
   953 	: iMemType(aType),iMemBaseAddr(aBaseAddr),iMemLen(aLen)
   954 	{}
   955 
   956 EXPORT_C TPcCardConfig::TPcCardConfig()
   957 //
   958 // Constructor (iConfigOption to KInvalidConfOpt guarentees that we start with
   959 // 1st configuration entry).
   960 //
   961 	: iAccessSpeed(EAcSpeedInValid),iActiveSignals(0),iVccMaxInMilliVolts(0),
   962 	  iVccMinInMilliVolts(0),iValidChunks(0),iIsIoAndMem(FALSE),iIsDefault(FALSE),
   963 	  iPwrDown(FALSE),iVppMaxInMilliVolts(0),iVppMinInMilliVolts(0),iOperCurrentInMicroAmps(0),
   964 	  iPwrDwnCurrentInMicroAmps(0),iInterruptInfo(0),iConfigOption(KInvalidConfOpt),iConfigBaseAddr(0),
   965 	  iRegPresent(0)
   966 	{}
   967 
   968 EXPORT_C TBool TPcCardConfig::IsMachineCompatible(TSocket aSocket,TInt aFlag)
   969 //
   970 // Return ETrue if this configuration is compatible with this machine
   971 //
   972 	{
   973 
   974 	DPcCardSocket* pS=(DPcCardSocket*)TheSockets[aSocket];
   975 	DPcCardVcc* pV=(DPcCardVcc*)pS->iVcc;
   976 	TInt nomSocketVcc=DPcCardVcc::SocketVccToMilliVolts(pV->VoltageSetting());
   977     if (!(aFlag&KPccdCompatNoVccCheck))
   978         {
   979 	    // Check Vcc level compatibility
   980 	    if (iVccMaxInMilliVolts<nomSocketVcc||iVccMinInMilliVolts>nomSocketVcc)
   981 		    {
   982 		    __KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Vcc"));
   983 		    return(EFalse);
   984 		    }
   985         }
   986 
   987 	TPcCardSocketInfo si;
   988 	pS->SocketInfo(si);
   989     if (!(aFlag&KPccdCompatNoVppCheck))
   990 		{
   991 		// Check Vpp level compatibility
   992 		if (iVppMaxInMilliVolts<si.iNomVppInMilliVolts||iVppMinInMilliVolts>si.iNomVppInMilliVolts) 
   993 			{
   994 			__KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Vpp"));
   995 			return(EFalse);
   996 			} 
   997 		}
   998 
   999     if (!(aFlag&KPccdCompatNoPwrCheck))
  1000 		{
  1001 		// Check the configurations power requirements can be supported
  1002 		if (iOperCurrentInMicroAmps>pV->MaxCurrentInMicroAmps())
  1003 			{
  1004 			__KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Pwr"));
  1005 			return(EFalse);
  1006 			}
  1007 		}
  1008 
  1009 	// If wait requested then check its supported
  1010 	if ((iActiveSignals&KSigWaitRequired)&&!(si.iSupportedSignals&KSigWaitSupported))
  1011 		{
  1012 		__KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Wait-sig"));
  1013 		return(EFalse);
  1014 		}
  1015 	// Dealt with WAIT - mask out any other signls which aren't supported - not reason to reject though
  1016 	iActiveSignals&=si.iSupportedSignals;
  1017 	return(ETrue);
  1018 	}
  1019 
  1020 EXPORT_C TPcCardRegion::TPcCardRegion()
  1021 //
  1022 // Constructor (iDeviceType to EDeviceInvalid guarentees that we start with
  1023 // 1st device information entry).
  1024 //
  1025 	: iAccessSpeed(EAcSpeedInValid),iActiveSignals(0),iVcc(EPccdSocket_Invalid),
  1026 	  iDeviceType(EDeviceInvalid),iExtendedAccSpeedInNanoSecs(0)
  1027 	{}
  1028 
  1029 EXPORT_C TBool TPcCardRegion::IsMachineCompatible(TSocket aSocket)
  1030 //
  1031 // Return ETrue if this configuration is compatible with this machine
  1032 //
  1033 	{
  1034 
  1035 	DPcCardSocket* pS=(DPcCardSocket*)TheSockets[aSocket];
  1036 	TPccdSocketVcc vcc=pS->VccSetting();
  1037 	// Check Vcc level compatibility
  1038 	if (iVcc!=vcc)
  1039 		{
  1040 		__KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Vcc"));
  1041 		return(EFalse);
  1042 		}
  1043 
  1044 	// If wait requested then check its supported
  1045 	TPcCardSocketInfo si;
  1046 	pS->SocketInfo(si);
  1047 	TBool waitReq=(iActiveSignals&KSigWaitRequired);
  1048 	if (waitReq&&!(si.iSupportedSignals&KSigWaitSupported))
  1049 		{
  1050 		__KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad Wait-sig"));
  1051 		return(EFalse);
  1052 		}
  1053 	// Dealt with WAIT - mask out any other signls which aren't supported - not reason to reject though
  1054 	iActiveSignals&=si.iSupportedSignals;
  1055 
  1056 	// Check requested access speed (ie not too slow for us)
  1057 	TPccdAccessSpeed as=__IS_ATTRIB_MEM(iChnk.iMemType)?si.iMaxAttribAccSpeed:si.iMaxCommonIoAccSpeed;
  1058 	if (iAccessSpeed>as && !waitReq)
  1059 		{
  1060 		__KTRACE_OPT(KPBUS1,Kern::Printf("MachineCompatible-Bad speed"));
  1061 		return(EFalse);
  1062 		}
  1063 	return(ETrue);
  1064 	}
  1065 
  1066 EXPORT_C TPccdType::TPccdType()
  1067 //
  1068 // Constructor
  1069 //
  1070 	: iFuncCount(0)
  1071 	{
  1072 	for (TInt i=0;i<(TInt)KMaxFuncPerCard;i++)
  1073 		iFuncType[i]=EUnknownCard;
  1074 	}
  1075 
  1076