diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-66FD040B-133E-57CF-80DD-9369F62709C6.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-66FD040B-133E-57CF-80DD-9369F62709C6.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,336 @@ + + + + + +Implement +the PSL for the targetThis document describes how to implement the Platform Specific +Layer for the Power Resource Manager. +
Purpose

The PSL must be implemented in order for +the PRM and the hardware to be able to communicate.

Introduction

The +PSL side of the Resource Controller should be derived from the class DPowerResourceController.

+
Implementing the PSL

The following tasks are +covered in this tutorial:

    +
  • Create an entry point,

  • +
  • Override the pure virtual functions,

  • +
  • Create static resources that support dependencies,

  • +
  • Initialise the pools,

  • +
  • Registering with the Power Controller.

  • +

Create an entry +Point

The PIL layer of the PRM offers the following macro. This +needs to be invoked from the PSL. The macro calls the DoInitController() and DoInitResources() functions +implemented by the PSL.

/** +Extension entry point +*/ +DECLARE_RESOURCE_MANAGER_EXTENSION() + { + __KTRACE_OPT(KBOOT, Kern::Printf("CreateController called")); + return new DH4PowerResourceController; + }

If the PRM is a PDD the entry point +is as follows:

static DH4PowerResourceController TheController; +DECLARE_STANDARD_PDD() + { + TInt r = DPowerResourceController::InitController(); + if® == KErrNone) + r = TheController->InitResources(); + if® == KErrNone) + return new DResConPddFactory; + return NULL; + }

Override +the pure virtual functions

Override the virtual functions of the DPowerResourceController base +class:

    +
  • DoInitController(),

  • +
  • DoRegisterStaticResources().

  • +

Here is an example H4 HRP implementation:

class DH4PowerResourceController : DPowerResourceController + { +public: + DH4PowerResourceController(); + TInt DoInitController(); + TInt DoRegisterStaticResources(DStaticPowerResource**& aStaticResourceArray, TUint16& aStaticResourceCount); +private: + static DStaticPowerResource* iResources[];

DoInitController()

Override DPowerResourceController::DoInitController() so that it creates +a DFC queue and then invokes the base class function DPowerResourceController::SetDfcQ(). DoInitController() should +also initialise the pools by invoking DPowerResourceController::InitPools() passing +the platform defined sizes for the pools of clients, client levels and request +objects. DoInitController() is called by the PSL +during its initialisation. Below is the reference implementation code.

#define KERNEL_CLIENTS 0x2 // Expected number of kernel clients (MMC and Sound_SC) +#define USER_CLIENTS 0x0 // No user side clients expected. +#define CLIENT_LEVELS 0x8 // Expected resource state change of 8 resources +#define REQUESTS 0x0 // No asynchronous operation (state change or read) expected. + +TInt DH4PowerResourceController::DoInitController() + { + // Create a DFC queue and then invoke SetDfcQ() +__KTRACE_OPT(KRESMANAGER, Kern::Printf(">DH4PowerResourceController::DoInitController\n")); + + // NKern::ThreadEnterCS(); // Not needed, as this is executed during kernel boot which is done within a critical section. + TInt r = Kern::DfcQCreate(iDfcQ,28,&KResThreadName); + + // NKern::ThreadLeaveCS(); + if (KErrNone!=r) return r; + SetDfcQ(iDfcQ); + r = InitPools(KERNEL_CLIENTS,USER_CLIENTS,CLIENT_LEVELS,REQUESTS); +__KTRACE_OPT(KRESMANAGER, Kern::Printf("<DH4PowerResourceController::DoInitController\n")); + return r; + }

DoRegisterStaticResources()

DoRegisterStaticResources() is called by the PIL during its initialisation. Override the pure virtual +function DPowerResourceController::DoRegisterStaticResources() so +that it:

    +
  • creates all the static +resources in the kernel heap,

  • +
  • creates an array of +pointers to the static resources (indexed by their id),

  • +
  • sets the passed pointer +(aStaticResourceArray) to point to the created array of pointers,

  • +
  • updates the count of +the static resources (in aStaticResourceCount).

  • +

The reference implementation is below:

TInt DH4PowerResourceController::DoRegisterStaticResources(DStaticPowerResource**& aStaticResourceArray, TUint16& aStaticResourceCount) + { + aStaticResourceCount = 0; + __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DH4PowerResourceController::DoRegisterStaticResources\n")); + aStaticResourceArray = (DStaticPowerResource**) new (DStaticPowerResource*[EH4ResourceCount]); + if(!aStaticResourceArray) + return KErrNoMemory; + + DH4MmcFclkResource *pMmcFclk = new (DH4MmcFclkResource); + if (!pMmcFclk) + return KErrNoMemory; + aStaticResourceArray[EMmcFclkRes] = pMmcFclk; + + DH4MmcIclkResource *pMmcIclk = new (DH4MmcIclkResource); + if (!pMmcIclk) + CLEAN_AND_RETURN(KErrNoMemory, EMmcIclkRes) + aStaticResourceArray[EMmcIclkRes] = pMmcIclk; + + DH4MmcClkResource *pMmcBusClk = new (DH4MmcClkResource); + if (!pMmcBusClk) + CLEAN_AND_RETURN(KErrNoMemory, EMmcClkRes) + aStaticResourceArray[EMmcClkRes] = pMmcBusClk; + + DH4MmcCtrllerPwrResource *pMmcCtrlrPwr = new (DH4MmcCtrllerPwrResource); + if (!pMmcCtrlrPwr) + CLEAN_AND_RETURN(KErrNoMemory, EMmcCtrlrPwrRes) + aStaticResourceArray[EMmcCtrlrPwrRes] = pMmcCtrlrPwr; + + DH4MmcPowerResource *pMmcPwr = new (DH4MmcPowerResource); + if (!pMmcPwr) + CLEAN_AND_RETURN(KErrNoMemory, EMmcPwrRes) + aStaticResourceArray[EMmcPwrRes] = pMmcPwr; + + DH4SndFclkResource *pSndFclk = new (DH4SndFclkResource); + if (!pSndFclk) + CLEAN_AND_RETURN(KErrNoMemory, ESndFclkRes) + aStaticResourceArray[ESndFclkRes] = pSndFclk; + + DH4SndIclkResource *pSndIclk = new (DH4SndIclkResource); + if (!pSndIclk) + CLEAN_AND_RETURN(KErrNoMemory ,ESndIclkRes) + aStaticResourceArray[ESndIclkRes] = pSndIclk; + + DH4SndMClkResource *pSndMclk = new (DH4SndMClkResource); + if (!pSndMclk) + CLEAN_AND_RETURN(KErrNoMemory, ESndMClkRes) + aStaticResourceArray[ESndMClkRes] = pSndMclk; + + aStaticResourceCount = EH4ResourceCount; + + __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DH4PowerResourceController::DoRegisterStaticResources, Total resources:%d\n", EH4ResourceCount)); + + return KErrNone; + }

Create +static resources that support dependencies

If there are static +resources that support dependencies then the PSL must implement the function DPowerResourceController::DoRegisterStaticResourcesDependency(). Note: Static resources that support dependencies are only available +in the extended version of the library. See setup +and configuration.

The function DoRegisterStaticResourcesDependency():

    +
  • creates all static resources +that support dependencies in kernel heap,

  • +
  • creates an array of +pointers to them,

  • +
  • establishes the dependencies +between them (using the resource's DStaticPowerResourceD::AddNode() function), +See creating +dependencies between static resources for a description of AddNode() and +the SNode structure.

  • +
  • sets the passed pointer +(aStaticResourceDArray) to point to the array of pointers +to static resource with dependency,

  • +
  • updates the count of +the static resource that supports dependency in aStaticResourceDCount.

  • +

This function is called by the PIL during PRM initialisation. Below +is an example:

/** +This function creates all static resources that support dependencies and establishes the dependencies between them. This is called by the PIL. +This is the dependency tree input: + ResourceA <---------> ResourceD <-------> ResourceE <--------> ResourceC + | | + | | + | | + ResourceF ResourceG +*/ +TInt DSimulatedPowerResourceController::DoRegisterStaticResourcesDependency(DStaticPowerResourceD**& aStaticResourceDArray, TUint16& aStaticResourceDCount) + { + aStaticResourceDArray = (DStaticPowerResourceD**) new (DStaticPowerResourceD*[MAX_DEPENDENT_RESOURCE_COUNT]); + if(!aStaticResourceDArray) + return KErrNoMemory; + + DStaticPowerResourceD* pR = NULL; + + pR = new DMLSLGLSPDependResource(); + if(!pR) + CLEAN_AND_RETURN(iStaticResDependencyCount, aStaticResourceDArray, KErrNoMemory) + aStaticResourceDArray[iStaticResDependencyCount++] = pR; + + pR = new DMLSIGLSNDependResource(); + if(!pR) + CLEAN_AND_RETURN(iStaticResDependencyCount, aStaticResourceDArray, KErrNoMemory) + aStaticResourceDArray[iStaticResDependencyCount++] = pR; + + pR = new DBSIGLSPDependResource(); + if(!pR) + CLEAN_AND_RETURN(iStaticResDependencyCount, aStaticResourceDArray, KErrNoMemory) + aStaticResourceDArray[iStaticResDependencyCount++] = pR; + + pR = new DMLSHIGLSPDependResource(); + if(!pR) + CLEAN_AND_RETURN(iStaticResDependencyCount, aStaticResourceDArray, KErrNoMemory) + aStaticResourceDArray[iStaticResDependencyCount++] = pR; + + pR = new DBSHLGLSNDependResource(); + if(!pR) + CLEAN_AND_RETURN(iStaticResDependencyCount, aStaticResourceDArray, KErrNoMemory) + aStaticResourceDArray[iStaticResDependencyCount++] = pR; + + pR = new DMLSHLGLSNDependResource(); + if(!pR) + CLEAN_AND_RETURN(iStaticResDependencyCount, aStaticResourceDArray, KErrNoMemory) + aStaticResourceDArray[iStaticResDependencyCount++] = pR; + + // Establish resource dependencies + if(CreateResourceDependency(aStaticResourceDArray)) + CLEAN_AND_RETURN(iStaticResDependencyCount, aStaticResourceDArray, KErrNoMemory) + + iDependencyResources = aStaticResourceDArray; + + aStaticResourceDCount = iStaticResDependencyCount; + return KErrNone; + } + +// This function establishes above dependency between static dependent resource +TInt DSimulatedPowerResourceController::CreateResourceDependency(DStaticPowerResourceD** pResArray) + { + iNodeArray = new SNode[10]; + SNode* pN1; + SNode* pN2; + iNodeCount = 0; + + if(!iNodeArray) + return KErrNoMemory; + // Create Dependency between Resource A and Resource D + pN1 = &iNodeArray[iNodeCount++]; + pN2 = &iNodeArray[iNodeCount++]; + CREATE_DEPENDENCY_BETWEEN_NODES(pN1, pN2, pResArray[0], pResArray[1], 1, 1) + + // Create Dependency between Resource D and Resource F + pN1 = &iNodeArray[iNodeCount++]; + pN2 = &iNodeArray[iNodeCount++]; + CREATE_DEPENDENCY_BETWEEN_NODES(pN1, pN2, pResArray[0], pResArray[2], 1, 3) + + // Create Dependency between Resource D and Resource E + pN1 = &iNodeArray[iNodeCount++]; + pN2 = &iNodeArray[iNodeCount++]; + CREATE_DEPENDENCY_BETWEEN_NODES(pN1, pN2, pResArray[0], pResArray[3], 3, 2) + + // Create Dependency between Resource E and Resource C + pN1 = &iNodeArray[iNodeCount++]; + pN2 = &iNodeArray[iNodeCount++]; + CREATE_DEPENDENCY_BETWEEN_NODES(pN1, pN2, pResArray[3], pResArray[4], 1, 1) + + // Create Dependency between Resource E and Resource G + pN1 = &iNodeArray[iNodeCount++]; + pN2 = &iNodeArray[iNodeCount++]; + CREATE_DEPENDENCY_BETWEEN_NODES(pN1, pN2, pResArray[3], pResArray[5], 1, 2) + + return KErrNone; + } + +#define CREATE_DEPENDENCY_BETWEEN_NODES(pN1, pN2, pRes1, pRes2, priRes1, priRes2) \ + pN1->iPriority = priRes1; \ + pN1->iResource = pRes1; \ + pN1->iPropagatedLevel = 0; \ + pN1->iVisited = EFalse; \ + pN2->iPriority = priRes2; \ + pN2->iResource = pRes2; \ + pN2->iPropagatedLevel = 0; \ + pN2->iVisited = EFalse; \ + pN1->iResource->AddNode(pN2); \ + pN2->iResource->AddNode(pN1);

Creating +dependencies between static resources

DStaticPowerResourceD::AddNode() is +used to establish a dependency between static resources. Dependencies between +static resources cannot be removed.

AddNode() takes +a pointer to an SNode object that contains the dependent +resource information. This passed node pointed is added to the resource dependency +list within the class DStaticPowerResourceD. Note: +the kernel panics if the specified dependency priority is already in use.

Information +within SNode includes:

    +
  • iResource is +a pointer to dependent resource,

  • +
  • iPriority is +the priority of the dependency resource. This is used by the PRM when propagating +the resource change,

  • +
  • iSpare is +reserved for future use,

  • +
  • iNext is +a pointer to next node in the list.

  • +

The members iPropagatedLevel, iRequiresChange and iVisited are +used internally by the PRM.

To link to dynamic resources that support +dependency use the PRM function RegisterResourceDependency() as +described in creating +resource dependencies.

Initialise +the pools

Pools are implemented as singly linked lists during +the initialisation of the PRM. The PSL initialises the pools by invoking DPowerResourceController::InitPools() and +passing the platform defined sizes for the pools of kernel side clients, user +side clients, client levels and requests. See the example DoInitController() implementation.

The PRM has three +types of pools:

    +
  • client pools to store +client information,

  • +
  • request pools to send requests for operation on long latency resource +to the Resource Controller thread,

  • +
  • client level pools to capture the resource level request by each client +for a resource.

  • +

If the client pool is set to zero, then the PRM will not allow a +client of that type to register. For example, if the kernel side clients pool +is set to zero, then the PIL will not allow any kernel side clients to register. +The size of the client pools to specify depends on how many kernel side device +drivers (clients) and user side clients will access PRM and size of request +pool depends on the number of long latency resource available in the system. +Size of client level pool depends on number of clients that will request a +resource state change. If the client pools are exhausted the PIL will try +to increase the size of the pool. The size of the pool never decreases.

Registering with the Power +Controller

The Resource Controller must call DPowerController::RegisterResourceController() to +register itself with the Power Controller. RegisterResourceController() sets +the iResourceControllerData.iResourceController data member +within DPowerController to the passed Resource Controller +pointer and sets iResouceControllerData.iClientId to the +client ID used by the Power Controller when calling the Resource Controller's +APIs.

The platform specific implementation of the Power Controller +overrides the RegisterResourceController() function. See DPowerController::RegisterResourceController().

Idle power management

The resource controller's APIs +cannot be called from a NULL thread. However, the PSL may need to know the +state of the resources from a NULL thread to take the system to appropriate +power states. To allow access to this information the PRM provides the virtual +function DPowerResourceController::RegisterResourcesForIdle().

+
+Porting the +Power Resource Manager +Implement +the controllable power resources +Port client +drivers to use the PRM +Debugging +the PRM +Testing the +PRM PSL +
\ No newline at end of file