diff -r 000000000000 -r a41df078684a kernel/eka/include/drivers/resourcecontrol.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/include/drivers/resourcecontrol.h Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,920 @@ +// 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: +// e32\include\drivers\resourcecontrol.h +// +// WARNING: This file contains some APIs which are internal and are subject +// to change without notice. Such APIs should therefore not be used +// outside the Kernel and Hardware Services package. +// + +#ifndef __RESOURCECONTROL_H__ +#define __RESOURCECONTROL_H__ +#include +#include +#include +#include +#define PRM_CONTROLLER +#ifndef PRM_ENABLE_EXTENDED_VERSION +#include +#else +#include +#endif +#include + +/** #defines for client bit masks */ +#define ID_INDEX_BIT_MASK 0x3FFF /* bit 0 -13 */ +#define USER_SIDE_CLIENT_BIT_MASK 0x4000 //Bit 14 +#define CLIENT_THREAD_RELATIVE_BIT_MASK 0x80000000 //Bit 31 +#define INSTANCE_COUNT_BIT_MASK 0x1FFF //13 Bits +#define INSTANCE_COUNT_POS 18 +#define CLIENT_POWER_CONTROLLER_BIT_MASK 0x8000 //Bit 15 +/** Bit to indicate valid post boot level in resource */ +#define SET_VALID_POST_BOOT_LEVEL 0x8000 //Bit 15 + +#define RESOURCE_NOT_IN_OPERATION 0x1 +#define PRM_DYNAMIC_RESOURCE_INITIAL_SIZE 2 + +#define PRM_STATIC_RESOURCE 0x0 +#define PRM_STATIC_DEPENDENCY_RESOURCE 0x1 +#define PRM_DYNAMIC_RESOURCE 0x2 +#define PRM_DYNAMIC_DEPENDENCY_RESOURCE 0x3 +#define RESOURCE_BIT_IN_ID_CHECK 16 + + +static const TInt KMaxResourceNameLength=0x20; //Maximum allowable resource length is 32 characters. +static const TInt KMaxClientNameLength=0x20; //Maximum allowable client length is 32 characters. + + +_LIT8(KPowerController, "PowerController"); +_LIT8(KDfcThread1Name, "DfcThread1"); +_LIT8(KDfcThread0Name, "DfcThread0"); +_LIT8(KNullThreadName, "Null"); +_LIT8(KNoClient, "NoClient"); +_LIT8(KParentResource, "ParentResource"); +/** Macro to check the context of client calling RM API. + Panics if it is called from ISR, IDFC, NULL thread or DFC thread1 */ +#ifdef DEBUG_VERSION +#define CHECK_CONTEXT(t) \ + __ASSERT_ALWAYS(NKern::CurrentContext() == NKern::EThread, Panic(ECalledFromIsr)); \ + const TDesC8* pDfc1 = &KDfcThread1Name; \ + if(!pDfc1->Compare(*(TDesC8*)t.iName)) \ + Panic(ECalledFromDfcThread1); \ + const TDesC8* pNull = &KNullThreadName; \ + if(!pNull->Compare(*(TDesC8*)t.iName)) \ + Panic(ECalledFromNullThread); +#else +#define CHECK_CONTEXT(t) +#endif + +/** Macro to unlock and return */ +#define UNLOCK_RETURN(retval) \ + { \ + UnLock(); \ + return(retval); \ + } + +/** Macro to push the item into the specified list. Item are pushed to the head of the list. */ +#define LIST_PUSH(list,item,link) \ + { \ + (item)->link = (list); \ + (list) = (item); \ + } + +/** Macro to pop the item from the specified list. Item are poped from the head of the list. */ +#define LIST_POP(list,item,link) \ + { \ + (item) = (list); \ + if ((item)) \ + { \ + (list) = (item)->link; \ + (item)->link = NULL; \ + } \ + } + +/** Macro to remove the item from the list. */ +#define LIST_REMOVE(list,item,link,className) \ + if (list) \ + { \ + className* current = (list); \ + if (current==(item)) \ + { \ + (list) = (item)->link; \ + (item)->link = NULL; \ + } \ + else \ + { \ + className* next = current->link; \ + while (next) \ + { \ + if ((item)==next) \ + { \ + current->link=next->link; \ + next->link = NULL; \ + break; \ + } \ + current = next; \ + next = next->link; \ + } \ + } \ + } + + +/* Macro to add dynamic resource to appropriate containers. Used only in extended version */ +#define ADD_TO_RESOURCE_CONTAINER(list, res, resId, resIdCount) \ + { \ + TUint16 growBy = (list).GrowBy(); \ + if(!growBy) \ + (list).Initialise((TUint16)PRM_DYNAMIC_RESOURCE_INITIAL_SIZE); \ + if((list).Add(res, resId) == KErrNoMemory) \ + { \ + TInt r = (list).ReSize(growBy); \ + if(r != KErrNone) \ + return r; \ + (list).Add(res, resId); \ + } \ + res->iResourceId |= resId; \ + resId = res->iResourceId; \ + resIdCount++; \ + } + +/* Macro to get the resource from appropriate list. Used only in extended version */ +#define GET_RESOURCE_FROM_LIST(resId, res) \ + { \ + switch((resId >> RESOURCE_BIT_IN_ID_CHECK) & 0x3) \ + { \ + case PRM_STATIC_RESOURCE: \ + if(resId > iStaticResourceArrayEntries) \ + UNLOCK_RETURN(KErrNotFound); \ + res = iStaticResourceArray[resId - 1]; \ + if(!res) \ + UNLOCK_RETURN(KErrNotFound); \ + break; \ + case PRM_STATIC_DEPENDENCY_RESOURCE: \ + if((TUint16)(resId & ID_INDEX_BIT_MASK) > iStaticResDependencyCount) \ + UNLOCK_RETURN(KErrNotFound); \ + res = iStaticResDependencyArray[(TUint16)(resId & ID_INDEX_BIT_MASK) - 1]; \ + break; \ + case PRM_DYNAMIC_RESOURCE: \ + res = iDynamicResourceList[(TUint16)(resId & ID_INDEX_BIT_MASK)]; \ + if(!res) \ + UNLOCK_RETURN(KErrNotFound); \ + break; \ + case PRM_DYNAMIC_DEPENDENCY_RESOURCE: \ + res = iDynamicResDependencyList[(TUint16)(resId & ID_INDEX_BIT_MASK)]; \ + if(!res) \ + UNLOCK_RETURN(KErrNotFound); \ + break; \ + default: \ + UNLOCK_RETURN(KErrArgument); \ + } \ + } + +/**Macro to get the client from appropriate client list based on bit 14 of client ID. + If the client is registered as thread relative, then check is made to make sure + it is called from the same thread. */ +#define VALIDATE_CLIENT(t) \ + if(aClientId & USER_SIDE_CLIENT_BIT_MASK) \ + pC = iUserSideClientList[(TUint16)(aClientId & ID_INDEX_BIT_MASK)]; \ + else \ + pC = iClientList[(TUint16)(aClientId & ID_INDEX_BIT_MASK)]; \ + if(!pC) \ + { \ + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client ID not Found")); \ + UNLOCK_RETURN(KErrAccessDenied); \ + } \ + if(pC->iClientId != aClientId) \ + { \ + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client ID does not match")); \ + UNLOCK_RETURN(KErrAccessDenied); \ + } \ + if(pC->iClientId & CLIENT_THREAD_RELATIVE_BIT_MASK) \ + { \ + if(pC->iThreadId != t.iId) \ + { \ + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client not called from thread context(Thread Relative)")); \ + UNLOCK_RETURN(KErrAccessDenied); \ + } \ + } + +/** Macro to get the target client from appropriate client list based on bit 14 of client ID. */ +#define GET_TARGET_CLIENT() \ + if(aTargetClientId & USER_SIDE_CLIENT_BIT_MASK) \ + pC = iUserSideClientList[(TUint16)(aTargetClientId & ID_INDEX_BIT_MASK)]; \ + else \ + pC = iClientList[(TUint16)(aTargetClientId & ID_INDEX_BIT_MASK)]; \ + if(!pC) \ + { \ + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Target Client ID not found")); \ + UNLOCK_RETURN(KErrNotFound); \ + } \ + if(pC->iClientId != aTargetClientId) \ + { \ + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client ID does not match")); \ + UNLOCK_RETURN(KErrNotFound); \ + } + +/* Macro definition for entry point of Power Resource Controller */ +#define DECLARE_RESOURCE_MANAGER_EXTENSION(TheController) \ + static void ResourceInit(TAny* aController) \ + { \ + TInt aReason = NKern::EThread; \ + PRM_BOOTING_TRACE \ + ((DPowerResourceController*)aController)->InitResources(); \ + return; \ + } \ + void CreateController(); \ + GLDEF_C TInt KernelModuleEntry(TInt aReason) \ + { \ + if(aReason==KModuleEntryReasonVariantInit0) \ + { \ + __KTRACE_OPT(KBOOT, Kern::Printf("Create Resource Controller")); \ + CreateController(); \ + return KErrNone; \ + } \ + if (aReason==KModuleEntryReasonExtensionInit0) \ + return KExtensionMaximumPriority; \ + if (aReason!=KModuleEntryReasonExtensionInit1) \ + return KErrArgument; \ + PRM_BOOTING_TRACE \ + __KTRACE_OPT(KBOOT, Kern::Printf("Initialise Resource Controller")); \ + TInt r = KErrNone; \ + r = DPowerResourceController::InitController(); \ + if(r != KErrNone) \ + return r; \ + __KTRACE_OPT(KBOOT, Kern::Printf("Create PDD and queue ResourceInit DFC")); \ + DResConPddFactory* device = new DResConPddFactory; \ + if(!device) \ + return KErrNoMemory; \ + r = Kern::InstallPhysicalDevice(device); \ + if(r != KErrNone) \ + return r; \ + TDfc* resourceInitDfc = new TDfc(&ResourceInit,(TAny*)&TheController,Kern::SvMsgQue(),KMaxDfcPriority-1); \ + if(!resourceInitDfc) \ + return KErrNoMemory; \ + resourceInitDfc->Enque(); \ + return KErrNone; \ + } \ + GLDEF_C void CreateController() + +/* Macro defintion for handling dependency resource state change. This is used only in extended version */ +#define HANDLE_CHANGE_PROPAGATION(TheController, resourceTypePointer, traceEnabled, originatorId, originatorName) \ + switch(aProp) \ + { \ + case EChangeStart: \ + { \ + if(!pDR->iDependencyList) /*No dependents so change state of the resource*/ \ + { \ + aRequest.ReturnCode() = pDR->DoRequest(aRequest); \ + if(aRequest.ReturnCode() == KErrNone) \ + { \ + iCachedLevel = aRequest.Level(); \ + iLevelOwnerId = aRequest.ClientId(); \ + if(iIdleListEntry) \ + { \ + iIdleListEntry->iCurrentLevel = aRequest.Level(); \ + iIdleListEntry->iLevelOwnerId = aRequest.ClientId(); \ + } \ + TheController->CompleteNotifications(aRequest.ClientId(), pDR, \ + aRequest.Level(), aRequest.ReturnCode(), aRequest.ClientId()); \ + } \ + break; \ + } \ + depRequest.ResourceId() = aRequest.ResourceId(); \ + depRequest.ClientId() = aRequest.ResourceId(); \ + depRequest.Level() = aRequest.Level(); \ + depRequest.Resource() = pDR; \ + result = pDR->HandleChangePropagation(depRequest, ECheckChangeAllowed, originatorId, originatorName); \ + if(result != KErrNone) \ + return result; \ + /*Adjust resource client level*/ \ + if(clientLevelCount) \ + { \ + result = TheController->ReserveClientLevelPoolCount(clientLevelCount); \ + if(result != KErrNone) \ + return result; \ + } \ + /*Resource change of dependents */ \ + pDR->HandleChangePropagation(aRequest, ERequestStateChange, originatorId, originatorName); \ + /*Notification to dependents */ \ + pDR->HandleChangePropagation(aRequest, EIssueNotifications, originatorId, originatorName); \ + break; \ + } \ + case ECheckChangeAllowed: \ + { \ + TChangePropagationStatus status; \ + for(SNode* depNode = pDR->iDependencyList; depNode != NULL; depNode = depNode->iNext) \ + { \ + pDepRes = (resourceTypePointer)depNode->iResource; \ + if((aRequest.ClientId() & KIdMaskResourceWithDependencies) && \ + (pDepRes->iResourceId == (TUint)aRequest.ClientId())) \ + continue; \ + /*Resource need not change if it is already in that state, so continue with \ + another dependent state.*/ \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + status = ((DDynamicPowerResourceD*)pDepRes)->TranslateDependentState(aRequest.ResourceId(), \ + aRequest.Level(), resState); \ + else \ + status = ((DStaticPowerResourceD*)pDepRes)->TranslateDependentState(aRequest.ResourceId(), \ + aRequest.Level(), resState); \ + if((status == ENoChange) || (pDepRes->iCachedLevel == resState)) \ + { \ + depNode->iRequiresChange = EFalse; \ + continue; \ + } \ + if(status == EChangeNotAccepted) \ + return KErrPermissionDenied; \ + depRequest.ResourceId() = pDepRes->iResourceId; \ + depRequest.ClientId() = aRequest.ResourceId(); /*ID of the dependent resource */ \ + depRequest.Level() = resState; \ + depRequest.Resource() = pDepRes; \ + /*Check resource client list and resource list to see whether change is allowed.*/ \ + if(pDepRes->Sense() == DStaticPowerResource::ECustom) \ + { \ + /*Call custom function to check whether change is allowed.*/ \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + depRequest.RequiresChange() = ((DDynamicPowerResourceD*)pDepRes)->iDepCustomFunction(depRequest.ClientId(), \ + originatorName, depRequest.ResourceId(), EClientChangeLevel, depRequest.Level(), (TAny*)&pDepRes->iClientList, \ + (TAny*)&((DDynamicPowerResourceD*)pDepRes)->iResourceClientList, NULL); \ + else \ + depRequest.RequiresChange() = ((DStaticPowerResourceD*)pDepRes)->iDepCustomFunction(depRequest.ClientId(), \ + originatorName, depRequest.ResourceId(), EClientChangeLevel, depRequest.Level(), (TAny*)&pDepRes->iClientList, \ + (TAny*)&((DStaticPowerResourceD*)pDepRes)->iResourceClientList, NULL); \ + if(!depRequest.RequiresChange()) \ + return KErrPermissionDenied; \ + } \ + SPowerResourceClientLevel*pN=NULL; \ + for(SDblQueLink* pNL=pDepRes->iClientList.First();pNL!=&pDepRes->iClientList.iA; pNL=pNL->iNext) \ + { \ + pN = (SPowerResourceClientLevel*)pNL; \ + if(pDepRes->Sense() == DStaticPowerResource::EPositive) \ + { \ + if(pN->iLevel > depRequest.Level()) \ + return KErrPermissionDenied; \ + } \ + else if(pDepRes->Sense() == DStaticPowerResource::ENegative) \ + { \ + if(pN->iLevel < depRequest.Level()) \ + return KErrPermissionDenied; \ + } \ + } \ + \ + /*check through the resource client level */ \ + SPowerResourceClientLevel*pCL = NULL; \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + pCL = ((DDynamicPowerResourceD*)pDepRes)->iResourceClientList; \ + else \ + pCL = ((DStaticPowerResourceD*)pDepRes)->iResourceClientList; \ + for(; pCL != NULL; pCL = pCL->iNextInList) \ + { \ + if(pCL->iClientId == pDR->iResourceId) \ + break; \ + } \ + if(!pCL) \ + clientLevelCount++; \ + /*check dependent resource client list & resource list to see whether change is allowed */ \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + result = ((DDynamicPowerResourceD*)pDepRes)->HandleChangePropagation(depRequest, \ + ECheckChangeAllowed, originatorId, originatorName); \ + else \ + result = ((DStaticPowerResourceD*)pDepRes)->HandleChangePropagation(depRequest, \ + ECheckChangeAllowed, originatorId, originatorName); \ + if(result != KErrNone) \ + return result; \ + depNode->iPropagatedLevel = resState; \ + depNode->iRequiresChange = ETrue; \ + } \ + break; \ + } \ + case ERequestStateChange: \ + { \ + SPowerResourceClientLevel* pCL = NULL; \ + for(SNode* depNode = pDR->iDependencyList; depNode != NULL; depNode = depNode->iNext) \ + { \ + pDepRes = (resourceTypePointer)depNode->iResource; \ + if((!depNode->iRequiresChange) || (pDepRes->iResourceId == (TUint)aRequest.ClientId())) \ + continue; \ + depRequest.ResourceId() = pDepRes->iResourceId; \ + depRequest.ClientId() = aRequest.ResourceId(); \ + depRequest.Level() = depNode->iPropagatedLevel; \ + depRequest.Resource() = pDepRes; \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + ((DDynamicPowerResourceD*)pDepRes)->HandleChangePropagation(depRequest, ERequestStateChange, \ + originatorId, originatorName); \ + else \ + ((DStaticPowerResourceD*)pDepRes)->HandleChangePropagation(depRequest, ERequestStateChange, \ + originatorId, originatorName); \ + /*Update level if resource client level is already present for this resource.*/ \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + pCL = ((DDynamicPowerResourceD*)pDepRes)->iResourceClientList; \ + else \ + pCL = ((DStaticPowerResourceD*)pDepRes)->iResourceClientList; \ + for(; pCL != NULL; pCL = pCL->iNextInList) \ + { \ + if(pCL->iClientId == pDR->iResourceId) \ + { \ + pCL->iLevel = depNode->iPropagatedLevel; \ + break; \ + } \ + } \ + if(!pCL) /*Create a new resource client level*/ \ + { \ + TheController->RemoveClientLevelFromPool(pCL); \ + pCL->iClientId = pDR->iResourceId; \ + pCL->iResourceId = pDepRes->iResourceId; \ + pCL->iLevel = depNode->iPropagatedLevel; \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + { \ + LIST_PUSH(((DDynamicPowerResourceD*)pDepRes)->iResourceClientList, pCL, iNextInList); \ + } \ + else \ + { \ + LIST_PUSH(((DStaticPowerResourceD*)pDepRes)->iResourceClientList, pCL, iNextInList); \ + } \ + clientLevelCount--; \ + } \ + } \ + if(traceEnabled && (aRequest.ClientId() & KIdMaskResourceWithDependencies)) \ + { \ + SPowerResourceClient res; \ + SPowerResourceClient* pC = &res; \ + pC->iClientId = aRequest.ClientId(); \ + pC->iName = &KParentResource; \ + DStaticPowerResource*pR = (DStaticPowerResource*)pDR; \ + TUint aResourceId = pDR->iResourceId; \ + TInt aNewState = aRequest.Level(); \ + PRM_CLIENT_CHANGE_STATE_START_TRACE \ + } \ + DoRequest(aRequest); \ + if(traceEnabled && (aRequest.ClientId() & KIdMaskResourceWithDependencies)) \ + { \ + SPowerResourceClient res; \ + SPowerResourceClient* pC = &res; \ + pC->iClientId = aRequest.ClientId(); \ + pC->iName = &KParentResource; \ + DStaticPowerResource*pR = (DStaticPowerResource*)pDR; \ + TUint aResourceId = pDR->iResourceId; \ + TInt aNewState = aRequest.Level(); \ + TInt r = KErrNone; \ + PRM_CLIENT_CHANGE_STATE_END_TRACE \ + } \ + pDR->iCachedLevel = aRequest.Level(); \ + pDR->iLevelOwnerId = aRequest.ClientId(); \ + if(pDR->iIdleListEntry) \ + { \ + pDR->iIdleListEntry->iCurrentLevel = aRequest.Level(); \ + pDR->iIdleListEntry->iLevelOwnerId = aRequest.ClientId(); \ + } \ + break; \ + } \ + case EIssueNotifications: \ + { \ + for(SNode* depNode = pDR->iDependencyList; depNode != NULL; depNode = depNode->iNext) \ + { \ + pDepRes = (resourceTypePointer)depNode->iResource; \ + if((!depNode->iRequiresChange) || (pDepRes->iResourceId == (TUint)aRequest.ClientId())) \ + continue; \ + depRequest.ResourceId() = pDepRes->iResourceId; \ + depRequest.ClientId() = pDepRes->iLevelOwnerId; \ + depRequest.Level() = pDepRes->iCachedLevel; \ + depRequest.Resource() = pDepRes; \ + if(pDepRes->iResourceId & KIdMaskDynamic) \ + ((DDynamicPowerResourceD*)pDepRes)->HandleChangePropagation(depRequest, EIssueNotifications, \ + originatorId, originatorName); \ + else \ + ((DStaticPowerResourceD*)pDepRes)->HandleChangePropagation(depRequest, EIssueNotifications, \ + originatorId, originatorName); \ + } \ + TheController->CompleteNotifications(aRequest.ClientId(), pDR, aRequest.Level(), KErrNone, \ + aRequest.ClientId()); \ + break; \ + } \ + default: \ + return KErrNotSupported; \ + } \ + return result; + +struct SPowerResourceClient; +struct TPowerRequest; +struct SPowerRequest; +struct SPowerResourceClientLevel; +struct SIdleResourceInfo; +class DPowerResourceController; + +/** +@internalComponent +@prototype 9.5 +Interface class for Resource Manager +Functions from PowerResourceManager calls corresponding functions of this +class which in turn calls Powercontroller functions. +*/ +class TInterface + { +public: + static TInt RegisterClient(TUint& aClientId, const TDesC8& aName, TOwnerType aType=EOwnerProcess); + static TInt DeRegisterClient(TUint aClientId); + static TInt GetClientName(TUint aClientId, TUint aTargetClientId, TDes8& aName); + static TInt GetClientId(TUint aClientId, TDesC8& aClientName, TUint& aTargetClientId); + static TInt GetResourceId(TUint aClientId, TDesC8& aResourceName, TUint& aResourceId); + static TInt GetResourceInfo(TUint aClientId, TUint aResourceId, TAny* aInfo); + static TInt GetNumResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, TUint& aNumResources); + static TInt GetInfoOnResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, TUint& aNumResources, TAny* aInfo); + static TInt GetNumClientsUsingResource(TUint aClientId, TUint aResourceId, TUint& aNumClients); + static TInt GetInfoOnClientsUsingResource(TUint aClientId, TUint aResourceId, TUint& aNumClients, TAny* aInfo); + static TInt AllocReserve(TUint aClientId, TUint8 aNumCl, TUint8 aNumRm); + static TInt ChangeResourceState(TUint aClientId, TUint aResourceId, TInt aNewState, TPowerResourceCb* aCb=NULL); + static TInt GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TInt& aState, TInt& aLevelOwnerId); + static TInt GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TPowerResourceCb& aCb); + static TInt CancelAsyncRequestCallBack(TUint aClientId, TUint aResourceId, TPowerResourceCb& aCb); + static TInt RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN); + static TInt RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN, TInt aThreshold, TBool aDirection); + static TInt CancelNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN); + static TInt DeRegisterClientLevelFromResource(TUint aClientId, TUint aResourceId); + static DPowerResourceController* GetPowerResourceController(void); + static TInt ControlIO(TUint aClientId, TUint aFunction, TAny* aParam1, TAny* aParam2, TAny* aParam3); + }; + +/** +@internalComponent +@prototype 9.5 +Container class to create containers of pointers to clients. +*/ +template +class DResourceCon : public DBase + { +public: + inline TInt Initialise(TUint16 aInitialSize); + inline void Delete(); + inline T* operator[](TUint16 aIndex); + inline TInt Remove(T* aObj, TUint16 aIndex); + inline TInt Add(T* aObj, TUint &aId); + inline TInt Find(T*& anEntry, TDesC& aName); + inline TInt ReSize(TUint16 aGrowBy); + inline TUint16 Count() {return iCount;} + inline TUint16 Allocd() {return iAllocated;} + inline TUint16 GrowBy() {return iGrowBy;} +private: + TUint16 iGrowBy; //Size to grow the size of the array. + TUint16 iAllocated; //Size of the array + TUint16 iCount; //Valid entries in the array + TUint16 iInstanceCount; //FreeCounter incremented whenever an entry is added. + TUint16 iFreeLoc; //Cached free location in the array + TUint16 iSpare; + T** iArray; + }; + +/** +@internalComponent +@prototype 9.5 +Factory class for physical device +*/ +NONSHARABLE_CLASS(DResConPddFactory) : public DPhysicalDevice + { +public: + /** + Structure for holding PDD capabilities information + */ + class TCaps + { + public: + TVersion iVersion; + }; +public: + DResConPddFactory(); + virtual TInt Install(); + virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); + virtual TInt Validate(TInt aUint, const TDesC8* anInfo, const TVersion& aVer); + virtual void GetCaps(TDes8& aDes) const; + inline static TVersion VersionRequired(); + }; + +/** +@internalComponent +@prototype 9.5 +Interface class for user side resource controller proxy. For each user side channel opened an object of +this class is created in heap and pointer to resource controller is stored in iController member variable. +User side resource controller proxy calls the resource controller API's by deferencing the pointer. +This class is required as when the channel is closed the device driver framework tries to delete +the object stored in ipdd, because of which it is not possible to pass the controller pointer directly. +*/ +class DUserSideProxyInterface: public DBase + { + public: + DPowerResourceController *iController; + }; + + +/** +@publishedPartner +@prototype 9.5 +resource manager implementation base class +*/ +NONSHARABLE_CLASS (DPowerResourceController) : public DBase + { +public: + TInt RegisterClient(TUint& aClientId, const TDesC8& aName, TOwnerType aType=EOwnerProcess); + TInt DeRegisterClient(TUint aClientId); + virtual TInt GetClientName(TUint aClientId, TUint aTargetClientId, TDes8& aName); + virtual TInt GetClientId(TUint aClientId, TDesC8& aClientName, TUint& aTargetClientId); + virtual TInt GetResourceId(TUint aClientId, TDesC8& aResourceName, TUint& aResourceId); + virtual TInt GetResourceInfo(TUint aClientId, TUint aResourceId, TAny* aInfo); + virtual TInt GetNumResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, TUint& aNumResources); + virtual TInt GetInfoOnResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, TUint& aNumResources, TAny* aInfo); + virtual TInt GetNumClientsUsingResource(TUint aClientId, TUint aResourceId, TUint& aNumClients); + virtual TInt GetInfoOnClientsUsingResource(TUint aClientId, TUint aResourceId, TUint& aNumClients, TAny* aInfo); + virtual TInt AllocReserve(TUint aClientId, TUint8 aNumCl, TUint8 aNumRm); + virtual TInt ChangeResourceState(TUint aClientId, TUint aResourceId, TInt aNewState, TPowerResourceCb* aCb=NULL); + virtual TInt GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TInt& aState, TInt& aLevelOwnerId); + virtual TInt GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TPowerResourceCb& aCb); + virtual TInt CancelAsyncRequestCallBack(TUint aClientId, TUint aResourceId, TPowerResourceCb& aCb); + virtual TInt RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN); + virtual TInt RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN, TInt aThreshold, TBool aDirection); + virtual TInt CancelNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN); + virtual TInt DeRegisterClientLevelFromResource(TUint aClientId, TUint aResourceId); +public: + enum TResConPanic + { + ECalledFromDfcThread0 = 0, + ECalledFromIsr = 1, + ECalledFromNullThread = 2, + ECalledFromDfcThread1 = 3, + EClientHasPendingAsyncRequest = 4, + EClientHasNotificationObject = 5, + EControllerAlreadyExists = 6, + ECustomFunctionNotSet = 7, + EClientIdNotInClientLevelList = 8, + ENoMemToCreatePowerControllerClient = 9, + EResourceNameExceedsLimit = 10, + EObjectNotFoundInList = 11 + }; +#ifdef PRM_ENABLE_EXTENDED_VERSION + enum TExtendedResConPanic + { + EClosedLoopDependencies = EObjectNotFoundInList + 2, //13 + ERegisteringNonDependentStaticResource = 14, + EClientHasDynamicResourceRegistered = 15, + EDynamicResourceStillRegistered = 16, + ERegisteringDependentStaticResourceWithHoles = 17 + }; +#endif + enum TResConStartSequence + { + EResConCreated, + EResConInitialised, + EResConStartupCompleted + }; + //early initialization + IMPORT_C static TInt InitController(); + TInt InitResources(); + //request a post-boot level for the resource + IMPORT_C static TInt PostBootLevel(TUint aResId, TInt aLevel); + //request registration of static resource + IMPORT_C static TInt RegisterStaticResource(TUint aClientId, DStaticPowerResource* pR); + //request registration of group/array of static resources + IMPORT_C static TInt RegisterArrayOfStaticResources(TUint aClientId, DStaticPowerResource**& aStaticResourceArray, TUint aResCount); + //registration for proxy client + virtual TInt RegisterProxyClient(TUint& aProxyId, const TDesC8& aName); + virtual TInt DeregisterProxyClient(TUint aClientId); + //register list of resources whose state matter to Idle + virtual TInt RegisterResourcesForIdle(TInt aPowerControllerId, TUint aNumResources, TPtr* aBuf); + static void Panic(TUint8 aPanic); + virtual TInt GetInterface(TUint aClientId, TUint aInterfaceId, TAny* aParam1, TAny* aParam2, TAny* aParam3); + virtual ~DPowerResourceController(); + /**@internalComponent*/ + void CompleteNotifications(TInt aClientId, DStaticPowerResource* aResource, TInt aState, TInt aReturnCode, TInt aLevelOwnerId, TBool aLock = ETrue); +#ifdef PRM_ENABLE_EXTENDED_VERSION + /**@internalComponent*/ + TInt ReserveClientLevelPoolCount(TUint16 aCount); + /**@internalComponent*/ + void RemoveClientLevelFromPool(SPowerResourceClientLevel *&aLevelPtr); +#endif +protected: + //generic layer function to be called by the PSL + DPowerResourceController(); + void SetDfcQ(TDfcQue* aDfcQ); + #ifdef PRM_ENABLE_EXTENDED_VERSION + void SetDfcQDependency(TDfcQue* aDfcQ); + #endif + TInt InitPools(TUint16 aKClients, TUint16 aUClients, TUint16 aNClientLevels, TUint16 aNRequests); + /* Lock the resource controller mutex */ + inline void Lock() { NKern::ThreadEnterCS(); + Kern::MutexWait(*iResourceMutex); } + inline void UnLock() { Kern::MutexSignal(*iResourceMutex); + NKern::ThreadLeaveCS();} +#ifdef PRM_ENABLE_EXTENDED_VERSION + //Default implementation, PSL re-implements these if features supported + virtual TInt DoRegisterStaticResourcesDependency(DStaticPowerResourceD**& aStaticResourceDArray, TUint16& aStaticResourceDCount); +#endif +private: + // pure virtual implemented by PSL - to be called by PIL + virtual TInt DoInitController()=0; + virtual TInt DoRegisterStaticResources(DStaticPowerResource**& aStaticResourceArray, TUint16& aStaticResourceCount)=0; + /**@internalComponent*/ + TInt CheckLevelAndAddClient(SPowerResourceClient* pC, TPowerRequest* Request); + static void MsgQFunc(TAny* aPtr); + #ifdef PRM_ENABLE_EXTENDED_VERSION + static void MsgQDependencyFunc(TAny* aPtr); + #endif + + /**@internalComponent*/ + void ResourceStateChangeOfClientLevels(SPowerResourceClient* pC); + /**@internalComponent*/ + void HandleMsg(TPowerRequest& aRequest); + #ifdef PRM_ENABLE_EXTENDED_VERSION + /**@internalComponent*/ + void HandleDependencyMsg(TPowerRequest& aRequest); + #endif + /**@internalComponent*/ + void CompleteRequest(TPowerRequest& aRequest); + /**@internalComponent*/ + void MoveRequestToFreePool(TPowerRequest *aReq); + /**@internalComponent*/ + TInt HandleReservationOfObjects(TPowerRequest& aRequest); + /**@internalComponent*/ + TInt HandleClientRegistration(TPowerRequest& aRequest); +#ifdef PRM_ENABLE_EXTENDED_VERSION + TInt RegisterDynamicResource(SPowerResourceClient* aClientPtr, DDynamicPowerResource* aPDRes, TUint* aDynamicResourceId); + TInt DeregisterDynamicResource(SPowerResourceClient* aClientPtr, TUint aDynamicResourceId, TInt* aPDefLevel); + TInt RegisterResourceDependency(SPowerResourceClient* aClientPtr, SResourceDependencyInfo* aInfo1, SResourceDependencyInfo* aInfo2); + /**@internalComponent*/ + void CheckForDependencyLoop(DStaticPowerResourceD* pR, TUint aParentResId, TUint aTargetResId); + TInt DeregisterResourceDependency(SPowerResourceClient* aClientPtr, TUint aResId1, TUint aResId2); + /**@internalComponent*/ + TInt HandleDependencyResourceStateChange(SPowerResourceClient* pC, TPowerRequest& aRequest); + TInt GetNumDependentsForResource(TUint aResourceId, TUint* aNumResources); + TInt GetDependentsIdForResource(TUint aResourceId, TAny* aInfo, TUint* aNumDepResources); + TInt HandleResourceRegistration(TPowerRequest& aReq); +#endif +public: + DMutex* iResourceMutex; +protected: + TDfcQue* iDfcQ; + TMessageQue *iMsgQ; +#ifdef PRM_ENABLE_EXTENDED_VERSION + TDfcQue* iDfcQDependency; + TMessageQue* iMsgQDependency; + TBool iDfcQDependencyLock; +#endif +private: + DStaticPowerResource** iStaticResourceArray; + DResourceCon iClientList; + DResourceCon iUserSideClientList; + SPowerResourceClient* iClientPool; + SPowerRequest* iRequestPool; + SPowerResourceClientLevel* iClientLevelPool; + TUint iPowerControllerId; //Stores the ID allocated to PowerController + SIdleResourceInfo* iListForIdle; + TUint iInitialised; + TUint16 iClientCount; + TUint16 iUserSideClientCount; + TUint16 iClientLevelPoolCount; + TUint16 iClientLevelPoolGrowBy; + TUint16 iRequestPoolCount; + TUint16 iRequestPoolGrowBy; + TUint16 iStaticResourceArrayEntries; //Number of entries in the array including holes if any. + TUint16 iStaticResourceCount; //Actual number of static resources registered (valid entries). + TUint iReserved2; //Reserved for future use +#ifdef PRM_ENABLE_EXTENDED_VERSION + DResourceCon iDynamicResourceList; + DResourceCon iDynamicResDependencyList; + DStaticPowerResourceD** iStaticResDependencyArray; + SPowerResourceClientLevel* iResourceLevelPool; + TUint16 iResourceLevelPoolCount; + TUint16 iStaticResDependencyCount; + TUint16 iDynamicResourceCount; + TUint8 iDynamicResDependencyCount; + TUint8 iSpare2; + TUint iReserved3; //Reserved for future use. +#endif + }; + +/** +@publishedPartner +@prototype 9.5 +power level of client in a shared resource +*/ +struct SPowerResourceClientLevel : public SDblQueLink + { + TUint iClientId; + TUint iResourceId; + TInt iLevel; + SPowerResourceClientLevel* iNextInList; + }; + +/** +@internalComponent +@prototype 9.5 +respresent client in resource manager +*/ +struct SPowerResourceClient + { + TUint iClientId; + const TDesC8* iName; + SPowerResourceClient* iNextInList; + SPowerResourceClientLevel* iLevelList; + DPowerResourceNotification* iNotificationList; + TUint8 iReservedCl; + TUint8 iReservedRm; + TUint8 iPendingReqCount; + TUint8 iUnderFlowRmCount; + TUint8 iUnderFlowClCount; + TUint8 iDynamicResCount; //Counter for dynamic resource registered by the client. Used only in extended version + TUint8 iSpare1; + TUint8 iSpare2; + union + { + TUint iThreadId; + TAny* iSpare3; + }; + }; + +/** +@publishedPartner +@prototype 9.5 +represents a request inside the resource manager +*/ +struct TPowerRequest : public TThreadMessage + { + /** requests can either be to get the resource value or to change the resource value*/ + enum TReqType {EGet, EChange, ESetDefaultLevel, ERegisterKernelClient, ERegisterUsersideClient, EAllocReserve, + ERegisterDynamicResource }; + /** @return thread's own message and turn into a power request. Used for sync/instant calls*/ + inline static TPowerRequest& Get() + {return (TPowerRequest&)Kern::Message();} + /** @return type of request get or set */ + inline TReqType& ReqType() // one of TReqType + {return *(TReqType*)&iValue;} + /** @return resource id which is being requested*/ + inline TUint& ResourceId() + {return *(TUint*)&iArg[0];} + /** @return id of client making request (only valid on change requests)*/ + inline TInt& ClientId() + {return *(TInt*)&iArg[1];} + /** + On resource state change operations the PIL sets this field with the required level before + invoking the DoRequest(..) function; on return from DoRequest(..) function the PSL sets this field + with the real state of the resource to be cached by the PIL.On resource state read operations PSL + sets it with the level read. + */ + inline TInt& Level() + {return *(TInt*)&iArg[2];} + /** @return pointer the resource being requested */ + inline DStaticPowerResource*& Resource() + {return *(DStaticPowerResource**)&iArg[3];} + /** @return pointer to resource callback structure, used for async requests */ + inline TPowerResourceCb*& ResourceCb() + {return *(TPowerResourceCb**)&iArg[4];} + /** @return return code of resource's DoRequest function when request has been processed */ + inline TInt& ReturnCode() + {return *(TInt*)&iArg[5];} + /** @return return ETrue if a change is required on a shared resource */ + inline TBool& RequiresChange() + {return *(TInt*)&iArg[6];} + /** @return number of client level objects requested by a client to reserve */ + inline TInt& ClientLevelCount() + {return *(TInt*)&iArg[7];} + /** @return number of request objects requested by a client to reserve */ + inline TInt& RequestCount() + {return *(TInt*)&iArg[8];} + }; + +/** +@internalComponent +@prototype 9.5 +*/ +struct SPowerRequest + { + TPowerRequest iRequest; + SPowerRequest* iNext; + }; + +/** +@publishedPartner +@prototype 9.5 +Structure representing resource information used for Idle power management +*/ +struct SIdleResourceInfo + { + TUint iResourceId; + TInt iLevelOwnerId; //Owner of the resource. + TInt iCurrentLevel; //Cached resource state + TInt iReserved1; //Reserved for future use. + TInt iReserved2; //Reserved for future use. + TInt iReserved3; //Reserved for future use. + }; + +#include + +#endif //__RESOURCECONTROL_H__ + +