kerneltest/sdiotest/source/d_sdioif.cpp
branchRCL_3
changeset 268 345b1ca54e88
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/sdiotest/source/d_sdioif.cpp	Wed Sep 15 13:42:27 2010 +0300
@@ -0,0 +1,825 @@
+// Copyright (c) 2003-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:
+// LDD for testing SDIO functions
+// 
+//
+
+#include <kernel/kernel.h>
+#include "regifc.h"
+#include "cisreader.h"
+#include "d_sdioif.h"
+
+/**
+Define the name of the LDD.
+
+@internal
+@test
+*/
+_LIT(KLddName,"D_SDIOIF");
+
+/**
+Define the version of the LDD.
+
+@internal
+@test
+*/
+const TInt KMajorVersionNumber=1;
+const TInt KMinorVersionNumber=0;
+const TInt KBuildVersionNumber=1;
+
+/**
+Define the default socket number.
+
+@internal
+@test
+*/
+#ifdef __WINS__
+	const TInt KSocketNumber = 0;
+#else
+	const TInt KSocketNumber = 0;
+//	const TInt KSocketNumber = 1;	// 1 for Integrator!!
+#endif
+
+/**
+Define the default stack number.
+
+@internal
+@test
+*/
+const TInt KStackNumber  = 0;
+
+/**
+Define the default card number.
+
+@internal
+@test
+*/
+const TInt KCardNumber   = 0;
+
+/**
+Define an invalid function number outside the normal 0-7 range.
+
+@internal
+@test
+*/
+const TUint8 KInvalidFuncNum = 8;
+
+/**
+Define the global Dfc Que.
+
+@internal
+@test
+*/
+TDynamicDfcQue* gDfcQ;
+
+class DTestFactory : public DLogicalDevice
+/**
+Class to act as a factory for the test LDD
+
+@internal
+@test
+*/
+	{
+public:
+	DTestFactory();
+	~DTestFactory();
+	virtual TInt Install(); 					//overriding pure virtual
+	virtual void GetCaps(TDes8& aDes) const;	//overriding pure virtual
+	virtual TInt Create(DLogicalChannelBase*& aChannel); 	//overriding pure virtual
+	};
+
+
+class DTest : public DLogicalChannel
+/**
+Class containing the logical device driver to drive the SDIO classes.
+
+@internal
+@test
+*/
+	{
+public:
+	DTest();
+	virtual ~DTest();
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual void HandleMsg(class TMessageBase *);
+	virtual TInt SendMsg(TMessageBase* aMsg);
+private:
+	TInt SendRequest(TMessageBase* aMsg);
+	TInt DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2);
+	TInt SendControl(TMessageBase* aMsg);
+	TInt DoControl(TInt aFunction, TAny* a1, TAny* a2);
+	TInt CheckForChangeOfCis(TInt aFunc);
+	TInt DoCancel(TUint aMask);
+	static void EventCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2);
+
+private:
+	// The SDIO objects
+	DMMCSocket* iSocketP;
+	DMMCStack*  iStackP;
+	TSDIOCard*  iCardP;
+    TInt iFunc;
+	TCisReader iCisRd;
+
+	DThread* iClient;
+	TPBusCallBack iBusEventCallback;
+
+	// Client requests used for creating local copies of user requests, WDP safe
+	TClientRequest* 								iPowerUpRequest;
+	TClientRequest* 								iResetCisRequest;
+	TClientDataRequest<TSDIOCardConfig>*			iCardCommonReadRequest;
+	TClientDataRequest<TSDIOFunctionCaps>*			iFunctionCapsRequest;
+	TClientDataRequest<TUint>*						iReadDirectRequest; // Use TUint rather than TUint8 for alignment purposes
+	};
+
+DECLARE_STANDARD_LDD()
+/**
+The standard entry point for logical device drivers.
+
+@internal
+@test
+*/
+	{
+	return new DTestFactory;
+	}
+
+DTestFactory::DTestFactory()
+/**
+Constructor.
+
+@internal
+@test
+*/
+	{
+    iParseMask=KDeviceAllowUnit;
+	iUnitsMask=0xffffffff;
+	iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+	}
+
+TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
+/**
+Create a new DTest on this logical device.
+
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+	{
+	aChannel=new DTest;
+	return aChannel?KErrNone:KErrNoMemory;
+	}
+
+const TInt KDSdioIfThreadPriority = 27;
+ _LIT(KDSdioIfThread,"DSdioIfThread");
+
+TInt DTestFactory::Install()
+/**
+Install the LDD - overriding pure virtual.
+
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+	{
+	// Allocate a kernel thread to run the DFC 
+	TInt r = Kern::DynamicDfcQCreate(gDfcQ, KDSdioIfThreadPriority, KDSdioIfThread);
+
+	if (r != KErrNone)
+		return r; 	
+
+	return SetName(&KLddName);
+	}
+
+void DTestFactory::GetCaps(TDes8& aDes) const
+/**
+Return the capabilities of the LDD.
+
+@return A packaged TCapsTestV01.
+
+@internal
+@test
+*/
+	{
+	TCapsTestV01 b;
+	b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+    Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
+	}
+
+DTestFactory::~DTestFactory()
+/**
+Destructor
+
+@internal
+@test
+*/
+	{
+	if (gDfcQ)
+		gDfcQ->Destroy();
+	}
+
+TInt DTest::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& aVer)
+/**
+Create a logical channel.
+
+@param aUnit The socket number.
+@param aInfo Not used.
+@param aVer The version requested.
+
+@return KErrNone if the channel was created. KErrNotSupported if the version is not supported
+        otherwise one of the system wide error codes.
+
+@internal
+@test
+*/
+	{
+
+	if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
+		return KErrNotSupported;
+
+	// Create the asynchronous callback client request
+	TInt ret = Kern::CreateClientRequest(iPowerUpRequest);
+	if (ret != KErrNone)
+		return ret;
+
+	ret = Kern::CreateClientRequest(iResetCisRequest);
+	if (ret != KErrNone)
+		return ret;
+	
+	ret = Kern::CreateClientDataRequest(iReadDirectRequest);
+	if (ret != KErrNone)
+		return ret;
+
+	ret = Kern::CreateClientDataRequest(iCardCommonReadRequest);
+	if (ret != KErrNone)
+		return ret;
+
+	ret = Kern::CreateClientDataRequest(iFunctionCapsRequest);
+	if (ret != KErrNone)
+		return ret;
+	
+	//
+	// Obtain the appropriate card from the socket/stack
+	//
+	iSocketP = static_cast<DMMCSocket*>(DPBusSocket::SocketFromId(KSocketNumber));
+	if(iSocketP == NULL)
+		return KErrNoMemory;
+
+	iStackP = static_cast<DSDIOStack*>(iSocketP->Stack(KStackNumber));
+	if(iStackP == NULL)
+		return KErrNoMemory;
+
+	iCardP = static_cast<TSDIOCard*>(iStackP->CardP(KCardNumber));
+	if(iCardP == NULL)
+		return KErrNoMemory;
+
+	iFunc=KInvalidFuncNum; // Indicates Cis reader isn't selected
+
+	SetDfcQ(gDfcQ);
+	iMsgQ.Receive();
+
+	iBusEventCallback.SetSocket(aUnit);
+	iBusEventCallback.Add();
+
+	return KErrNone;
+	}
+
+DTest::DTest()
+/**
+Constructor.
+
+@internal
+@test
+*/
+	: iBusEventCallback(DTest::EventCallBack, this)
+	{
+	iClient=&Kern::CurrentThread();
+	((DObject*)iClient)->Open();	// can't fail since thread is running
+	}
+
+
+DTest::~DTest()
+/**
+Destructor.
+
+@internal
+@test
+*/
+	{
+	iBusEventCallback.Remove();
+	
+	// Destroy the client requests 
+	Kern::DestroyClientRequest(iPowerUpRequest);
+	Kern::DestroyClientRequest(iResetCisRequest);
+	Kern::DestroyClientRequest(iReadDirectRequest);	
+	Kern::DestroyClientRequest(iCardCommonReadRequest);
+	Kern::DestroyClientRequest(iFunctionCapsRequest);
+	
+	Kern::SafeClose((DObject*&)iClient,NULL);
+	}
+
+/**
+Pre-process the received message to prepare the client's request.
+
+@param aMsg A pointer to a message (request) from the user side.
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+TInt DTest::SendMsg(TMessageBase* aMsg)
+	{
+	TThreadMessage& m = *(TThreadMessage*)aMsg;
+    TInt id = m.iValue;
+
+	// we only support one client
+	if (id != (TInt)ECloseMsg && m.Client() != iClient)
+		return KErrAccessDenied;
+	
+	TInt r = KErrNone;
+	if (id != (TInt)ECloseMsg && id != KMaxTInt)
+		{
+		if (id<0)
+			{
+			// It's a request
+			TRequestStatus* pS = (TRequestStatus*)m.Ptr0();
+			
+			// Pre-process the request
+			r = SendRequest(aMsg);
+			if (r != KErrNone)
+				Kern::RequestComplete(pS,r);
+			}
+		else
+			{
+			// Pre-process the control 
+			r = SendControl(aMsg);
+			}
+		}
+	else
+		r = DLogicalChannel::SendMsg(aMsg);
+	
+	return r;
+	}
+
+/**
+Handle a request message from the user side RSdioCardCntrlIf.
+
+@param aMsg A pointer to a message (request) from the user side.
+
+@internal
+@test
+*/
+void DTest::HandleMsg(TMessageBase* aMsg)
+    {
+    TThreadMessage& m=*(TThreadMessage*)aMsg;
+    TInt id=m.iValue;
+    
+	if (id==(TInt)ECloseMsg)
+		{
+	    // Check for a close message
+		m.Complete(KErrNone, EFalse);
+		return;
+		}
+    else if (id==KMaxTInt)
+		{
+		// DoCancel
+		DoCancel(m.Int0());
+		m.Complete(KErrNone, ETrue);
+		return;
+		}
+
+    if (id<0)
+		{
+		// DoRequest
+		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+		TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
+		if (r!=KErrNone)
+	    	Kern::RequestComplete(iClient, pS, r);
+		m.Complete(KErrNone,ETrue);
+		}
+    else
+		{
+		// DoControl
+		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+		m.Complete(r,ETrue);
+		}
+	}
+
+/**
+Handle a pre-process for a request message from the user side RSdioCardCntrlIf.
+This will set-up the client requests.
+
+@param aMsg A pointer to a message (request) from the user side.
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+TInt DTest::SendRequest(TMessageBase* aMsg)
+	{
+	TThreadMessage& m = *(TThreadMessage*)aMsg;
+    TInt function = ~m.iValue;
+	TRequestStatus* pS = (TRequestStatus*)m.Ptr0();
+	TAny* a2 = m.Ptr2();
+		
+	TInt r = KErrNotSupported;
+	switch (function)
+		{
+		// A request to power up the SDIO card & stack
+		case RSdioCardCntrlIf::EReqPwrUp:
+			r = iPowerUpRequest->SetStatus(pS);
+	       	if (r != KErrNone)
+        		return r;
+ 			break;
+		// A request to read generic data from the SDIO card 
+        case RSdioCardCntrlIf::ERequestReadDirect:
+           	{
+            r = iReadDirectRequest->SetStatus(pS);
+            if (r != KErrNone)
+            	return r;
+            iReadDirectRequest->SetDestPtr(a2);            
+            }
+    		break;			
+    	// A request to reset the CIS pointer 
+        case RSdioCardCntrlIf::ERequestResetCis:
+			r = iResetCisRequest->SetStatus(pS);
+			if (r != KErrNone)
+				return r;
+			break;
+			
+       	// A request to read the Card Common Config  
+        case RSdioCardCntrlIf::ERequestGetCommonConfig:
+        	{
+        	r = iCardCommonReadRequest->SetStatus(pS);
+        	if (r != KErrNone)
+        		return r;
+        	iCardCommonReadRequest->SetDestPtr(a2);
+        	}
+			break;
+			
+        // A request to read the function data (FBR)  
+        case RSdioCardCntrlIf::ERequestGetFunctionConfig:
+        	{
+        	r = iFunctionCapsRequest->SetStatus(pS);
+        	if (r != KErrNone)
+        		return r;
+        	iFunctionCapsRequest->SetDestPtr(a2);
+        	}
+			break;
+		}
+
+	if (r == KErrNone)
+		r = DLogicalChannel::SendMsg(aMsg);
+	return r;
+	}
+
+/**
+Process any asynchronous requests from the user side.
+
+@param aFunction The asynchronous function to invoke. 
+@param aStatus On completion, the success code for the function.
+@param a1 Context sensitive data.
+@param a2 Context sensitive data.
+
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+TInt DTest::DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+	{
+	TInt r=KErrNone;
+    TInt func = (TInt)a1;
+	switch (aFunction)
+		{
+		// A request to power up the SDIO card & stack
+        case RSdioCardCntrlIf::EReqPwrUp:
+			{
+			if(!iSocketP->CardIsPresent())
+				{
+				// An SDIO card is not present
+				Kern::QueueRequestComplete(iClient, iPowerUpRequest, KErrNotReady);
+				}
+			else if(iSocketP->State() == EPBusOn)
+				{
+				// The card is already powered up
+				Kern::QueueRequestComplete(iClient, iPowerUpRequest, KErrNone);
+				}
+			else
+				{
+				// Power up the card
+				iSocketP->PowerUp();
+				}
+			break;
+			}
+
+		// A request to read generic data from the SDIO card 
+        case RSdioCardCntrlIf::ERequestReadDirect:
+            {
+            TInt addr = (TInt)a1;
+
+    		TUint8 val = 0;
+			r = iCardP->CommonRegisterInterface()->Read8(addr, &val);
+			if(r == KErrNone)
+				{
+		   		iReadDirectRequest->Data() = (TUint)val;
+				}
+				
+			Kern::QueueRequestComplete(iClient, iReadDirectRequest, r);
+			break;
+            }
+
+    	// A request to reset the CIS pointer 
+        case RSdioCardCntrlIf::ERequestResetCis:
+            {
+	        if ((r=CheckForChangeOfCis(func))==KErrNone)
+	            {
+			    iCisRd.Restart();
+	            }
+	            
+			Kern::QueueRequestComplete(iClient, iResetCisRequest, r);
+			break;
+            }
+
+       	// A request to read the card common config  
+        case RSdioCardCntrlIf::ERequestGetCommonConfig:
+            {
+	        if ((r=CheckForChangeOfCis(func))==KErrNone)
+                {
+				memset(&iCardCommonReadRequest->Data(), 0, sizeof(TSDIOCardConfig));
+				
+		        r = iCisRd.FindReadCommonConfig(iCardCommonReadRequest->Data());
+				Kern::QueueRequestComplete(iClient, iCardCommonReadRequest, r);
+                }
+			break;
+            }
+
+        // A request to read the function data (FBR)  
+        case RSdioCardCntrlIf::ERequestGetFunctionConfig:
+            {		        
+	        if ((r=CheckForChangeOfCis(func))==KErrNone)
+                {
+				memset(&iFunctionCapsRequest->Data(), 0, sizeof(TSDIOFunctionCaps));
+				
+		        r=iCisRd.FindReadFunctionConfig(iFunctionCapsRequest->Data());	
+				Kern::QueueRequestComplete(iClient, iFunctionCapsRequest, r);
+                }            
+			break;
+            }
+
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	return r;
+	}
+
+/**
+Surround the DoControl command, creating a kernel copy of the user side data, then copying back afterwards
+
+@param aMsg The message 
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+TInt DTest::SendControl(TMessageBase* aMsg)
+	{
+	TThreadMessage& m = *(TThreadMessage*)aMsg;
+    TInt id = m.iValue;
+
+    TSdioCardInfo kernelCardInfo;
+    TAny* userCardInfoPtr = m.Ptr0();
+    
+	// thread-local copy of configuration data	
+	switch (id)
+		{
+		case RSdioCardCntrlIf::ESvCardInfo:
+			// copy config from client to local buffer in context of client thread
+			umemget32(&kernelCardInfo, userCardInfoPtr, sizeof(TSdioCardInfo));
+			// update message to point to kernel-side buffer
+			m.iArg[0] = &kernelCardInfo;
+			break;
+		}
+
+	TInt r = DLogicalChannel::SendMsg(aMsg);
+	if (r != KErrNone)
+		return r;
+
+	switch (id)
+		{
+		case RSdioCardCntrlIf::ESvCardInfo:
+			// copy config from local bufferto client in context of client thread
+			umemput32(userCardInfoPtr, &kernelCardInfo, sizeof(TSdioCardInfo));
+			break;
+		}
+
+	return r;
+	}
+
+/**
+Process any synchronous requests from the user side.
+
+@param aFunction The synchronous function to invoke. 
+@param a1 Context sensitive data.
+@param a2 Context sensitive data.
+
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+TInt DTest::DoControl(TInt aFunction, TAny* a1, TAny* /*a2*/)
+	{
+	TInt r=KErrNone;
+	switch (aFunction)
+		{
+		// Read the card information data
+		case RSdioCardCntrlIf::ESvCardInfo:
+            {
+			if(iCardP)
+				{
+				iCardP->CheckCIS();
+				TSdioCardInfo* cardInfoPtr = (TSdioCardInfo*)a1;
+				TSdioCardInfo& info = *cardInfoPtr;
+
+				//
+				// Extract the card information
+				//
+				info.isComboCard=iCardP->IsComboCard();				
+	            info.iIsReady=iCardP->IsPresent();
+	            info.iIsLocked=iCardP->IsLocked();
+	            info.iCardSpeed=iCardP->MaxTranSpeedInKilohertz();
+				TCID* cid=(TCID*)&(iCardP->CID());
+				TInt i;
+				for (i=0;i<16;i++)
+					info.iCID[i]=cid->At(i);
+				const TCSD& csd = iCardP->CSD();
+				for (i=0;i<16;i++)
+					info.iCSD[i]=csd.At(i);
+	            info.iRCA=TUint16(iCardP->RCA());
+	            info.iMediaType=TMmcMediaType(iCardP->MediaType());
+
+				//
+				// Extract the function information
+				//
+				info.iFuncCount = iCardP->FunctionCount();
+
+				TSDIOFunctionCaps functionCaps;
+				TSDIOFunction* functionP = NULL;
+
+				for(TUint8 func=0; func<=info.iFuncCount; func++)
+					{
+					functionP = iCardP->IoFunction((TUint8) (func));
+					if(functionP)
+						{
+						functionCaps = functionP->Capabilities();
+						info.iFunction[func].iType = (TSdioFunctionType)(functionCaps.iType);
+						}
+					}
+				}
+			else
+			    {
+                r = KErrGeneral;
+			    }
+
+			break;
+            }
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	return r;
+	}
+
+
+/**
+Check if diferent function selected, select new CIS if necessary.
+
+@param aFunc The SDIO function. 
+
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+TInt DTest::CheckForChangeOfCis(TInt aFunc)
+	{
+
+	if (iFunc!=aFunc||iFunc==KInvalidFuncNum)
+		{
+		TInt err;
+		if ((err=iCisRd.SelectCis(KSocketNumber,0,0,(TUint8) aFunc))==KErrNone)
+			iFunc=aFunc;
+		return(err);
+		}
+	return(KErrNone);
+	}
+
+/**
+Cancel an asynchronous request
+
+@param aMask Mask of requests to cancel
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+TInt DTest::DoCancel(TUint /*aMask*/)
+	{	
+	if (iPowerUpRequest->IsReady())
+		{
+		Kern::QueueRequestComplete(iClient, iPowerUpRequest, KErrCancel);
+		}
+	
+	if (iResetCisRequest->IsReady())
+		{
+		Kern::QueueRequestComplete(iClient, iPowerUpRequest, KErrCancel);
+		}
+
+	if (iCardCommonReadRequest->IsReady())
+		{
+		Kern::QueueRequestComplete(iClient, iPowerUpRequest, KErrCancel);
+		}
+
+	if (iFunctionCapsRequest->IsReady())
+		{
+		Kern::QueueRequestComplete(iClient, iPowerUpRequest, KErrCancel);
+		}
+
+	if (iReadDirectRequest->IsReady())
+		{
+		Kern::QueueRequestComplete(iClient, iPowerUpRequest, KErrCancel);
+		}
+	
+	return KErrNone;
+	}
+
+/**
+Asynchronous call backs from the SDIO stack
+
+@param aPtr Data passed in when the callback was registered.
+@param aReason The reason for the callback, one of TPBusCallBack::EPBusStateChange
+               or TPBusCallBack::EPBusCustomNotification.                  
+@param a1 Context sensitive data.
+@param a2 Context sensitive data.
+
+@return One of the system wide error codes.
+
+@internal
+@test
+*/
+void DTest::EventCallBack(TAny* aPtr, TInt aReason, TAny* a1, TAny* a2)
+	{
+	DTest &mci = *(DTest*)aPtr;
+
+	if (mci.iPowerUpRequest->IsReady())
+		{
+		// There is an TRequestStatus pending
+		TInt retCode = KErrCompletion;
+
+		switch(aReason)
+			{
+			// There has been a state change
+			case TPBusCallBack::EPBusStateChange:
+				{
+				TPBusState newState = (TPBusState)(TInt)a1;
+				TInt errorCode = (TInt)a2;
+
+				switch(newState)
+					{
+					case EPBusCardAbsent:	retCode = KErrNotFound;		break;			
+					case EPBusOff:			retCode = errorCode;		break;
+					case EPBusPsuFault:		retCode = KErrBadPower;		break;
+					case EPBusOn:			retCode = KErrNone;			break;
+					case EPBusPowerUpPending:
+					case EPBusPoweringUp:
+					default:	
+						break;
+					}
+
+				break;
+				}
+			}
+
+		if(retCode != KErrCompletion)
+			{
+   			Kern::QueueRequestComplete(mci.iClient, mci.iPowerUpRequest, retCode);
+			}
+		}
+	}
+
+
+