kerneltest/e32test/resourceman/acctst/d_prmacctst.cpp
author Slion
Tue, 08 Dec 2009 08:11:42 +0100
branchanywhere
changeset 19 f6d3d9676ee4
parent 0 a41df078684a
child 97 41f0cfe18c80
permissions -rw-r--r--
Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.

// Copyright (c) 2007-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:
//

#include <kernel/kernel.h>
#include <drivers/resourceman.h>
#include "d_prmacctst.h"
#ifdef RESOURCE_MANAGER_SIMULATED_PSL
#include "../resourceman_psl/rescontrol_psl.h"
#endif // RESOURCE_MANAGER_SIMULATED_PSL

#define TEST_KERRNONE(x) { TInt  _r = (x); if (_r != KErrNone) \
	Kern::Printf("Test failed: %s line %d error %d", __FILE__, __LINE__, _r); }
#define TEST(x) { if (!(x)) Kern::Printf("Test failed: %s line %d", __FILE__, __LINE__); }

_LIT(KTestDfcQueBaseName, "PrmIfDfc");
const TInt KTestDfcQuePrority = KMaxDfcPriority - 1;

//---------------------------------------------------------------------------

class DPrmIfDevice : public DLogicalDevice
	{
public:
	DPrmIfDevice();
	virtual TInt Install();
	virtual void GetCaps(TDes8& aDes) const;
	virtual TInt Create(DLogicalChannelBase*& aChannel);
	};

//---------------------------------------------------------------------------

class DPrmIfChannel : public DLogicalChannel
	{
public:
	DPrmIfChannel();
	~DPrmIfChannel();
protected:
	virtual void HandleMsg(TMessageBase* aMsg);
	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
private:
	TInt DoControl(TInt aReqNo, TAny *a1, TAny *a2);
	TInt DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny *a1, TAny *a2);
	void Shutdown();

public:
	static TUint KernelExtensionClientId;
private:
	DThread*		iUserThread;
	TUint			iClientId;
	HBuf*			iClientName;
	};

TUint DPrmIfChannel::KernelExtensionClientId = 0;

void TestCallbackFunction(TUint /* aClientId */,
						  TUint /* aResourceId */,
						  TInt  /* aLevel */,
						  TInt  /* aLevelOwnerId */,
						  TInt  /* aResult */,
						  TAny* aSem);

//---------------------------------------------------------------------------

DPrmIfDevice::DPrmIfDevice()
	{
	}

TInt DPrmIfDevice::Install()
	{
	return SetName(&KPrmIfLddName);
	}

void DPrmIfDevice::GetCaps(TDes8& /* aDes */) const
	{
	// Not used but required as DLogicalDevice::GetCaps is pure virtual
	}

TInt DPrmIfDevice::Create(DLogicalChannelBase*& aChannel)
	{
	aChannel = new DPrmIfChannel;
	return aChannel ? KErrNone : KErrNoMemory;
	}

//---------------------------------------------------------------------------

DPrmIfChannel::DPrmIfChannel()
	{
	iUserThread = &Kern::CurrentThread();
	((DObject*) iUserThread)->Open();
	}

DPrmIfChannel::~DPrmIfChannel()
	{
	if(iDfcQ)
	  ((TDynamicDfcQue*)iDfcQ)->Destroy();
	// Close our reference on the client thread
	Kern::SafeClose((DObject*&)iUserThread,NULL);
	}

void DPrmIfChannel::HandleMsg(TMessageBase *aMsg)
	{
	TThreadMessage& m = *(TThreadMessage*) aMsg;
	TInt id = m.iValue;

	if (id == (TInt) ECloseMsg)
		{
		m.Complete(KErrNone, EFalse);
		return;
		}
	else if (id == KMaxTInt)
		{
		// DoCancel
		m.Complete(KErrNone, ETrue);
		return;
		}
	else if (id < 0)
		{
		// DoRequest
		TRequestStatus* pS = (TRequestStatus*) m.Ptr0();
		TInt r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
		if (r != KErrNone)
			{
			Kern::RequestComplete(iUserThread, pS, r);
			}
		m.Complete(KErrNone, ETrue);
		}
	else
		{
		// DoControl
		TInt r = DoControl(id, m.Ptr0(), m.Ptr1());
		if(r != KErrCompletion)
			{
			m.Complete(r, ETrue);
			}
		}
	}

TInt DPrmIfChannel::DoCreate(TInt /* aUnit */, const TDesC8* /* aInfo */, const TVersion& /* aVer */)
	{
	TDynamicDfcQue* dfcQ;
	TInt r = Kern::DynamicDfcQCreate(dfcQ, KTestDfcQuePrority, KTestDfcQueBaseName);
	TEST_KERRNONE(r);
	iDfcQ = dfcQ;
	if (r != KErrNone)
		{
		return r;
		}
	SetDfcQ(iDfcQ);
	iMsgQ.Receive();
	return KErrNone;
	}

TInt DPrmIfChannel::DoControl(TInt aReqNo, TAny *a1, TAny *a2)
	{
	TInt r = KErrNotSupported;
	switch (aReqNo)
		{
		case RPrmIf::EControlOpenClient:
			{
			if (iClientId)
				{
				return KErrAlreadyExists;
				}
			TBuf8<80> clientName;
			r = PowerResourceManager::GetClientName((TUint) a1, (TUint) a1, clientName);
			TEST_KERRNONE(r);
			if (r == KErrNone)
				iClientId = (TUint) a1;
			break;
			}

		case RPrmIf::EControlGetKernelExtClientId:
			{
			r = Kern::ThreadRawWrite(iUserThread, a1, &KernelExtensionClientId, sizeof(TUint));
			TEST_KERRNONE(r);
			break;
			}

		case RPrmIf::EControlRegisterClient:
			{
			if (iClientId)
				{
				return KErrAlreadyExists;
				}
			iClientName = HBuf::New(KNameMaxLength);
			r = Kern::ThreadDesRead(iUserThread, a1, *iClientName, 0);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			r = PowerResourceManager::RegisterClient(iClientId, *iClientName);
			TEST_KERRNONE(r);
			break;
			}

		case RPrmIf::EControlDeRegisterClient:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			r = PowerResourceManager::DeRegisterClient(iClientId);
			if (r == KErrNone)
				{
				if (iClientId == KernelExtensionClientId)
					{
					// Set it to 0 so it cannot be re-opened
					KernelExtensionClientId = 0;
					}
				delete iClientName;
				iClientId = 0;
				}
			break;
			}

		case RPrmIf::EControlGetInfoOnResourcesInUseByClient:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			TUint nores;
			r = PowerResourceManager::GetNumResourcesInUseByClient(iClientId, (TUint) a1, nores);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			if (nores > 0)
				{
				HBuf* resinfo;
				resinfo = HBuf::New(nores * sizeof(TResInfo));
				TEST(resinfo != NULL);
				if (resinfo == NULL)
					{
					return KErrNoMemory;
					}
				r = PowerResourceManager::GetInfoOnResourcesInUseByClient(iClientId, (TUint) a1, nores, (TAny*) resinfo);
				TEST_KERRNONE(r);
				if (r)
					{
					delete resinfo;
					return r;
					}
				r = Kern::ThreadDesWrite(iUserThread, a2, *resinfo, 0);
				TEST_KERRNONE(r);
				delete resinfo;
				}
			break;
			}

		case RPrmIf::EControlChangeResourceState:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			r = PowerResourceManager::ChangeResourceState(iClientId, (TUint) a1, (TInt) a2);
			break;
			}

		case RPrmIf::EControlGetResourceState:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			TInt state;
			TInt levelowner;
			r = PowerResourceManager::GetResourceState(iClientId, (TUint) a1, EFalse, state, levelowner);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			r = Kern::ThreadRawWrite(iUserThread, a2, (TAny*) &state, sizeof(TInt));
			TEST_KERRNONE(r);
			break;
			}

		case RPrmIf::EControlGetResourceStateCached:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			TInt state;
			TInt levelowner;
			r = PowerResourceManager::GetResourceState(iClientId, (TUint) a1, ETrue, state, levelowner);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			r = Kern::ThreadRawWrite(iUserThread, a2, (TAny*) &state, sizeof(TInt));
			TEST_KERRNONE(r);
			break;
			}

		case RPrmIf::EControlGetLevelOwner:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			TInt state;
			TInt levelowner;
			r = PowerResourceManager::GetResourceState(iClientId, (TUint) a1, EFalse, state, levelowner);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			r = Kern::ThreadRawWrite(iUserThread, a2, (TAny*) &levelowner, sizeof(TInt));
			TEST_KERRNONE(r);
			break;
			}

		case RPrmIf::EControlGetTotalNumberOfResources:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			TUint nores;
			r = PowerResourceManager::GetNumResourcesInUseByClient(iClientId, 0, nores);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			r = Kern::ThreadRawWrite(iUserThread, a1, (TAny*) &nores, sizeof(TUint));
			TEST_KERRNONE(r);
			break;
			}

#ifdef PRM_ENABLE_EXTENDED_VERSION
		case RPrmIf::EControlGetResourceDependencies:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			// Get the resource information from the PRM
			TUint numres;
			r = PowerResourceManager::GetNumDependentsForResource(iClientId, (TUint) a1, numres);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}

			// Create a descriptor with the list of dependencies
			HBuf* depdes;
			depdes = HBuf::New(sizeof(SResourceDependencyInfo) * numres);
			TEST(depdes != NULL);
			if (depdes == NULL)
				{
				return KErrNoMemory;
				}

			TUint numres2 = numres;
			r = PowerResourceManager::GetDependentsIdForResource(iClientId, (TUint) a1, (TAny*) depdes, numres2);
			TEST_KERRNONE(r);
			TEST(numres == numres2);
			
			// Copy the descriptor contents to the user-side descriptor
			r = Kern::ThreadDesWrite(iUserThread, a2, *depdes, 0);
			TEST_KERRNONE(r);
			delete depdes;
			break;
			}
#endif // PRM_ENABLE_EXTENDED_VERSION
		}
	return r;
	}

TInt DPrmIfChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny *a1, TAny *a2)
	{
	TInt r = KErrNotSupported;
	switch (aReqNo)
		{
		case RPrmIf::ERequestChangeResourceStateAndGetState:
			{
			if (!iClientId)
				{
				return KErrNotReady;
				}
			TTestResourceStateBuf args;
			r = Kern::ThreadDesRead(iUserThread, a1, args, 0);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			NFastSemaphore sem;
			NKern::FSSetOwner(&sem, (NThreadBase*) NKern::CurrentThread());
			TPowerResourceCb cbfn(&TestCallbackFunction, (TAny*) &sem, /*iDfcQ*/ Kern::DfcQue0(), KMaxDfcPriority - 2);
			// Change the state of the resource (asynchronous call)
			r = PowerResourceManager::ChangeResourceState(iClientId, args().iResourceId, args().iNewState, &cbfn);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			// Retrieve the intermediate state of the resource
			TInt state;
			TInt levelowner;
			r = PowerResourceManager::GetResourceState(iClientId, args().iResourceId, EFalse, state, levelowner);
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			r = Kern::ThreadRawWrite(iUserThread, a2, (TAny*) &state, sizeof(TInt));
			TEST_KERRNONE(r);
			if (r)
				{
				return r;
				}
			// Wait for the callback function
			NKern::FSWait(&sem);
			Kern::RequestComplete(iUserThread, aStatus, r);
			break;
			}
		}
	return r;
	}

//---------------------------------------------------------------------------

//
// Callback function for Latency Tests
//
void TestCallbackFunction(TUint /* aClientId */,
						  TUint /* aResourceId */,
						  TInt  /* aLevel */,
						  TInt  /* aLevelOwnerId */,
						  TInt  /* aResult */,
						  TAny* aSem)
	{
	if (!aSem)
		{
		return;
		}
	NKern::FSSignal((NFastSemaphore*) aSem);
	}

//
// This function is called during kernel initialisation. It registers a client
// on the PRM in order to take ownership of the Single-User resources before
// anyone else does.
//
static void InitExtension(TAny*)
	{
	TInt r;	

	// Get the overall number of resources
	TUint nores;
	r = PowerResourceManager::GetNumResourcesInUseByClient(DPrmIfChannel::KernelExtensionClientId, 0, nores);
	TEST_KERRNONE(r);
	if (r)
		{
		return;
		}

	// Get hold of all of the resources by setting their state to the default level
	TInt i;
	for (i = 0; i < (TInt) nores; i++)
		{
		TPowerResourceInfoBuf01 res;
		res.Zero();
		r = PowerResourceManager::GetResourceInfo(DPrmIfChannel::KernelExtensionClientId, i + 1, (TAny*) &res);
		TEST_KERRNONE(r);
		if (r)
			{
			return;
			}
		r = PowerResourceManager::ChangeResourceState(DPrmIfChannel::KernelExtensionClientId, i + 1, res().iDefaultLevel);
		TEST_KERRNONE(r);
		if (r)
			{
			return;
			}
		}
	TUint resinuse;
	r = PowerResourceManager::GetNumResourcesInUseByClient(DPrmIfChannel::KernelExtensionClientId, DPrmIfChannel::KernelExtensionClientId, resinuse);
	TEST_KERRNONE(r);
	TEST(resinuse == nores);
	}

static TDfc InitExtensionDfc(&InitExtension, NULL, Kern::SvMsgQue(), KMaxDfcPriority - 2); // Priority lower than the Resource Controller (KMaxDfcPriority - 1)

#ifndef RESOURCE_MANAGER_SIMULATED_PSL
_LIT8(KTestKExtClientName, "KEXTC");
DECLARE_STANDARD_EXTENSION()
	{
	// Register the initial PRM client (kernel will crash if this fails)
	TUint clientid;
	TInt r = PowerResourceManager::RegisterClient(clientid, KTestKExtClientName);
	TEST_KERRNONE(r);
	if (r)
		{
		return r;
		}
	DPrmIfChannel::KernelExtensionClientId = clientid;
	// Queue the DFC call to take control of all the resources
	InitExtensionDfc.Enque();
	return KErrNone;
	}

DECLARE_EXTENSION_LDD()
	{
	return new DPrmIfDevice;
	}
#else
DECLARE_STANDARD_LDD()
	{
	TInt r = DSimulatedPowerResourceController::CompleteResourceControllerInitialisation();
	if (r != KErrNone)
		{
		return NULL;
		}
	return new DPrmIfDevice;
	}
#endif