diff -r 000000000000 -r a41df078684a kernel/eka/drivers/resmanus/d_resmanus.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/resmanus/d_resmanus.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,2485 @@ +// Copyright (c) 1995-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\drivers\resmanus\d_resmanus.cpp +// +// + +// LDD for Resource Manager user side API +#include "resmanus.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RESOURCE_MANAGER_SIMULATED_PSL +#include "rescontrol_psl.h" +#endif + +#ifdef PRM_US_INSTRUMENTATION_MACRO +#include +#endif + +#ifdef PRM_ENABLE_EXTENDED_VERSION2 +_LIT(KResManUsThreadName,"ResManUsExtendedCoreLddThread"); +#elif defined (PRM_ENABLE_EXTENDED_VERSION) +_LIT(KResManUsThreadName,"ResManUsExtendedLddThread"); +#else +_LIT(KResManUsThreadName,"ResManUsLddThread"); +#endif + +#define RESMANUS_FAULT() Kern::Fault("RESMANUS",__LINE__) + +const TInt KResManUsThreadPriority = 24; +const TInt KResManUsRegistrationPriority = 5; // Arbitrary! Can be 0-7, 7 is highest +const TInt KResManCallBackPriority = 5; // Arbitrary! Can be 0-7, 7 is highest + +//Macro to return appropriate request type. +#define GET_USER_REQUEST(request, buffer, type) \ + { \ + if(type == EGetState) \ + request = ((TTrackGetStateBuf*)buffer)->iRequest; \ + else if(type == ESetState) \ + request = ((TTrackSetStateBuf*)buffer)->iRequest; \ + else \ + request = ((TTrackNotifyBuf*)buffer)->iRequest; \ + } + +/*************************************************************************************** + class TTrackGetStateBuf + ***************************************************************************************/ +TTrackGetStateBuf::TTrackGetStateBuf(TPowerResourceCbFn aFn, TAny* aPtr, + TDfcQue* aQue, TInt aPriority) + : iCtrlBlock(aFn, aPtr, aQue, aPriority) + { + iRequest = NULL; + } + +/*************************************************************************************** + class TTrackSetStateBuf + ***************************************************************************************/ +TTrackSetStateBuf::TTrackSetStateBuf(TPowerResourceCbFn aFn, TAny* aPtr, + TDfcQue* aQue, TInt aPriority) + : iCtrlBlock(aFn, aPtr, aQue, aPriority) + { + iRequest = NULL; + } + +/*************************************************************************************** + class TTrackNotifyBuf + ***************************************************************************************/ +TTrackNotifyBuf::TTrackNotifyBuf(TPowerResourceCbFn aFn, TAny* aPtr, + TDfcQue* aQue, TInt aPriority) + : iNotifyBlock(aFn, aPtr, aQue, aPriority) + { + iRequest = NULL; + } + +TTrackNotifyBuf::~TTrackNotifyBuf() + { + if(iRequest) + Kern::DestroyClientRequest(iRequest); + } + +TTrackSetStateBuf::~TTrackSetStateBuf() + { + if(iRequest) + Kern::DestroyClientRequest(iRequest); + } + +TTrackGetStateBuf::~TTrackGetStateBuf() + { + if(iRequest) + Kern::DestroyClientRequest(iRequest); + } + +/*************************************************************************************** + class DDeviceResManUs + ***************************************************************************************/ +DDeviceResManUs::DDeviceResManUs() +// Constructor + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceResManUs::DDeviceResManUs()")); + iParseMask=KDeviceAllowAll&~KDeviceAllowUnit; // Allow info and pdd, but not units + iUnitsMask=0; + iVersion=TVersion(KResManUsMajorVersionNumber, + KResManUsMinorVersionNumber, + KResManUsBuildVersionNumber); + } + +DDeviceResManUs::~DDeviceResManUs() +// Destructor + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceResManUs::~DDeviceResManUs()")); +#ifdef RESOURCE_MANAGER_SIMULATED_PSL + iSharedDfcQue->Destroy(); +#else + delete iSharedDfcQue; +#endif + } + +TInt DDeviceResManUs::Install() +// Install the device driver. + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceResManUs::Install()")); + // Create the message queue and initialise the DFC queue pointer +#ifndef RESOURCE_MANAGER_SIMULATED_PSL + TInt r=Kern::DfcQInit(iSharedDfcQue,KResManUsThreadPriority,&KResManUsThreadName); +#else + TInt r = Kern::DynamicDfcQCreate(iSharedDfcQue,KResManUsThreadPriority,KResManUsThreadName); +#endif + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DfcQCreate r = %d", r)); + if(r!=KErrNone) + return r; + +#ifdef CPU_AFFINITY_ANY + NKern::ThreadSetCpuAffinity((NThread*)(iSharedDfcQue->iThread), KCpuAffinityAny); +#endif + r = SetName(&KLddRootName); + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> SetName, r = %d", r)); + return r; + } + + +void DDeviceResManUs::GetCaps(TDes8& aDes) const +// Return the ResManUs capabilities. + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceResManUs::GetCaps(TDes8& aDes) const")); + TPckgBuf b; + b().version=TVersion(KResManUsMajorVersionNumber, + KResManUsMinorVersionNumber, + KResManUsBuildVersionNumber); + Kern::InfoCopy(aDes,b); + } + + +TInt DDeviceResManUs::Create(DLogicalChannelBase*& aChannel) +// Create a channel on the device. + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceResManUs::Create(DLogicalChannelBase*& aChannel)")); + if(iOpenChannels>=KMaxNumChannels) + return KErrOverflow; + aChannel=new DChannelResManUs; + return aChannel?KErrNone:KErrNoMemory; + } + + +/*************************************************************************************** + class DChannelResManUs + ***************************************************************************************/ +DChannelResManUs::DChannelResManUs() +// Constructor + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::DChannelResManUs()")); + iClient=&Kern::CurrentThread(); + // Increase the DThread's ref count so that it does not close without us + iClient->Open(); + } + + +DChannelResManUs::~DChannelResManUs() +// Destructor + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::~DChannelResManUs()")); + + // Cancel any outstanding requests + // + // For each tracker (Get, Set and notify) + // + if(iGetStateTracker != NULL) + { + CancelTrackerRequests(iGetStateTracker,EFalse,0,NULL); // EFalse,0, to ignore resource IDs + RemoveTrackingControl(iGetStateTracker); + } + if(iSetStateTracker != NULL) + { + CancelTrackerRequests(iSetStateTracker,EFalse,0,NULL); // EFalse,0, to ignore resource IDs + RemoveTrackingControl(iSetStateTracker); + } + if(iListenableTracker != NULL) + { + CancelTrackerRequests(iListenableTracker,EFalse,0,NULL); // EFalse,0, to ignore resource IDs + RemoveTrackingControl(iListenableTracker); + } + + delete iUserNameUsed; + delete iResourceDependencyIds; + delete iClientNamesResCtrl; + delete iResourceInfoResCtrl; + + // decrement the DThread's reference count + Kern::SafeClose((DObject*&)iClient, NULL); + } + + +static void AsyncCallBackFn(TUint aClient, TUint aResourceId, TInt aLevel, TInt aLevelOwnerId, TInt aResult, TAny* aTrackingBuffer) + { +// Callback function for asynchronous requests + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> AsyncCallBackFn aClient=0x%x aResourceId=0x%x, aLevel=0x%x, aResult=0x%x, aTrackingBuffer=0x%x\n",aClient, aResourceId, aLevel, aResult, aTrackingBuffer)); + TTrackingBuffer* buffer = ((TTrackingBuffer*)aTrackingBuffer); + TTrackingControl* tracker = buffer->GetTrackingControl(); + __ASSERT_ALWAYS((tracker!=NULL),RESMANUS_FAULT()); + DChannelResManUs* channel = tracker->iOwningChannel; + +#ifdef PRM_US_INSTRUMENTATION_MACRO + if(tracker->iType==EGetState) + { + PRM_US_GET_RESOURCE_STATE_END_TRACE; + } + else if(tracker->iType==ESetState) + { + PRM_US_SET_RESOURCE_STATE_END_TRACE; + } +#endif + if(tracker->iType == EGetState) + { + TTrackGetStateBuf* stateBuf = (TTrackGetStateBuf*)aTrackingBuffer; + if(aResult==KErrNone) + { + // Write the state value to the user-supplied variable + stateBuf->iRequest->Data1() = aLevel; + stateBuf->iRequest->Data2() = aLevelOwnerId; + } + Kern::QueueRequestComplete(channel->iClient, ((TTrackGetStateBuf*)buffer)->iRequest, aResult); + } + else if(tracker->iType == ESetState) + { + Kern::QueueRequestComplete(channel->iClient, ((TTrackSetStateBuf*)buffer)->iRequest, aResult); + } + // Once notified of a change in a resource state, must cancel the notification + // request in the Resource Controller to give the client the appearance of a + // 'one'shot' type of operation. + else if(tracker->iType==ENotify) + { +#ifdef PRM_ENABLE_EXTENDED_VERSION + if(((TInt)aClient==KDynamicResourceDeRegistering)&&(aResourceId&KIdMaskDynamic)) + { + // Resource has de-registered from Resource Controller, so can't expect any more notifications + // of this type. Cancellation of notifications (i.e. invoke Resource Controller) and transfer of + // buffers to free queue (for both conditional and unconditional notifications) is already done. + // To distinguish removal of a dynamic resource, hijack aResult (the value used when completing + // the user-side TRequestStatus object) and set it to KErrDisconnected. + aResult = KErrDisconnected; + } + +#endif + TInt r = (channel->iPddPtr)->CancelNotification(channel->ClientHandle(),aResourceId, + ((TTrackNotifyBuf*)buffer)->iNotifyBlock); + __ASSERT_ALWAYS((r == KErrCancel),RESMANUS_FAULT()); + Kern::QueueRequestComplete(channel->iClient, ((TTrackNotifyBuf*)buffer)->iRequest, aResult); + } + + // Return the tracking buffer to the free queue + channel->FreeTrackingBuffer(buffer); + } + +TInt DChannelResManUs::GetValidName(const TDesC8* aInfo) + { +// Extract a usable name from that supplied by the client + __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DChannelResManUs::GetValidName")); + TInt err=KErrNone; + if(aInfo) + { + DThread* thread = &Kern::CurrentThread(); + TInt nameLen = Kern::ThreadGetDesLength(thread, aInfo); + if(nameLen<0) + return nameLen; // return error code + iNameProvidedLength = nameLen; + if(nameLen > MAX_CLIENT_NAME_LENGTH) + err=KErrBadName; + else + { + nameLen = (nameLen<=MAX_NAME_LENGTH_IN_RESMAN) ? nameLen : MAX_NAME_LENGTH_IN_RESMAN; + if((iUserNameUsed = HBuf8::New(nameLen))==NULL) + return KErrNoMemory; + err = Kern::ThreadDesRead(thread,aInfo,*iUserNameUsed,0); + if(err!=KErrNone) + return err; + } + } + else + err=KErrBadName; + return err; + } + +TInt DChannelResManUs::RequestUserHandle(DThread* aThread, TOwnerType aType) +// Called when a user thread requests a handle to this channel + { + // Make sure that only our client can get a handle + __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DChannelResManUs::RequestUserHandle")); + if (aType!=EOwnerThread || aThread!=iClient) + return KErrAccessDenied; + return KErrNone; + } + +void DChannelResManUs::RegistrationDfcFunc(TAny* aChannel) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DChannelResManUs::RegistrationDfcFunc")); + // DFC function invoked for registration with Resource Controller + DChannelResManUs* channel = (DChannelResManUs*)aChannel; + // RegisterProxyClient(TUint& aProxyId, const TDesC& aName); + TUint uintVal=0; + TInt r = KErrNone; + __ASSERT_ALWAYS((r==KErrNone),RESMANUS_FAULT()); + + r=(channel->iPddPtr)->RegisterProxyClient(uintVal,*((TDesC8*)(channel->iUserNameUsed))); + if(r!=KErrNone) + { + // Registration failed + // Ensure that the client-side flag is cleared in uintVal + // so the failure can be detected in DoCreate + uintVal &= ~USER_SIDE_CLIENT_BIT_MASK; // Copied from rescontrol_export + } + channel->SetClientHandle((TInt)uintVal); + NKern::FSSignal(channel->iFastSem); + } + + +TInt DChannelResManUs::RegisterWithResCtrlr() + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DChannelResManUs::RegisterWithResCtrlr")); + TInt r = KErrNone; + // Initialise the channel's fast semaphore + iFastSem = new NFastSemaphore(); + if(iFastSem == NULL) + r = KErrNoMemory; + else + { + iFastSem->iOwningThread = (NThreadBase*)NKern::CurrentThread(); + + // Attempt to perform registration with the Resource Controller on behalf of the client. + SetDfcQ(((DDeviceResManUs*)(iDevice))->iSharedDfcQue); + TDfc tempDfc(RegistrationDfcFunc, this, iDfcQ, KResManUsRegistrationPriority); + + // Block this thread until the DFC has executed + tempDfc.Enque(); + NKern::FSWait(iFastSem); + // Have finished with iFastSem + delete iFastSem; + + // Registration complete - check success + if(!(USER_SIDE_CLIENT_BIT_MASK & ClientHandle())) + { + // Registration failed + r = KErrCouldNotConnect; + } + // Start receiving messages ... + iMsgQ.Receive(); + } + return r; + } + +TInt DChannelResManUs::DoCreate(TInt /*aUnit*/, + const TDesC8* aInfo, + const TVersion &aVer) +// Create the channel from the passed info. + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)")); + + TInt r = KErrNone; + iPddPtr = ((DUserSideProxyInterface*)iPdd)->iController; + // Check client has appropriate capabilities + if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by DDevicePowerRsrc::Create"))) + return KErrPermissionDenied; + + // Check software version + if (!Kern::QueryVersionSupported(TVersion(KResManUsMajorVersionNumber, + KResManUsMinorVersionNumber, + KResManUsBuildVersionNumber), + aVer)) + return KErrNotSupported; + + // Implementation note: if this method fails, the destructor will be invoked + // as part of which all successfully-allocated memory will be freed. Therefore, + // no memory will be explicitly freed in the event of failure in the code which follows. + + // Allocate the arrays used for acquiring client, resource and dependency information + if((iClientNamesResCtrl = HBuf8::New(KNumClientNamesResCtrl * sizeof(TPowerClientInfoV01)))==NULL) + return KErrNoMemory; + if((iResourceInfoResCtrl = HBuf8::New(KNumResourceInfoResCtrl * sizeof(TPowerResourceInfoV01)))==NULL) + return KErrNoMemory; + if((iResourceDependencyIds = HBuf8::New(KNumResourceDependencies * sizeof(SResourceDependencyInfo)))==NULL) + return KErrNoMemory; + // Obtain the channel name to use + if((r=GetValidName(aInfo))!=KErrNone) + return r; +#ifdef PRM_ENABLE_EXTENDED_VERSION + iResDepsValid = 0; +#endif + +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_OPEN_CHANNEL_START_TRACE; +#endif + + // Set up the request tracking support + iGetStateTracker = new TTrackingControl(); + iSetStateTracker = new TTrackingControl();; + iListenableTracker = new TTrackingControl(); + if((iGetStateTracker==NULL) || (iSetStateTracker==NULL) || (iListenableTracker==NULL)) + return KErrNoMemory; + + // Register with the Resource Controller + r = RegisterWithResCtrlr(); + +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_OPEN_CHANNEL_END_TRACE; +#endif + + return r; + } + +//Override sendMsg to allow data copy in the context of client thread for WDP. +TInt DChannelResManUs::SendMsg(TMessageBase* aMsg) + { + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt id = m.iValue; + TInt r = KErrNone; + if (id != (TInt)ECloseMsg && id != KMaxTInt) + { + if (id<0) + { + TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); + r = SendRequest(aMsg); + if (r != KErrNone) + Kern::RequestComplete(pS,r); + } + else + r = SendControl(aMsg); + } + else + r = DLogicalChannel::SendMsg(aMsg); + return r; + } + +TInt DChannelResManUs::SendRequest(TMessageBase* aMsg) + { + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt id = ~m.iValue; + TRequestStatus* pS = (TRequestStatus*)m.Ptr0(); + TInt r = KErrNone; + TTrackingBuffer *trackBuf = NULL; + TUint parms[4]; + TPowerResourceCb *callBack; + DPowerResourceNotification *prn; + + switch(id) + { + case RBusDevResManUs::EChangeResourceState: + { + __ASSERT_ALWAYS(m.Ptr2() != NULL, RESMANUS_FAULT()); +#ifdef _DUMP_TRACKERS + if((r=DumpTracker(iSetStateTracker))!=KErrNone) + break; +#endif + r = GetAndInitTrackingBuffer(iSetStateTracker, trackBuf, (TUint)m.Ptr1(), pS); + if( r != KErrNone) + return r; + callBack = &(((TTrackSetStateBuf*)trackBuf)->iCtrlBlock); + new (callBack) TPowerResourceCb(&AsyncCallBackFn, (TAny*)trackBuf, iDfcQ, KResManCallBackPriority); + parms[0] = (TUint)m.Ptr2(); + parms[1] = (TUint)callBack; + m.iArg[2] = &(parms[0]); + break; + } + case RBusDevResManUs::EGetResourceState: + { + __ASSERT_ALWAYS(m.Ptr2() != NULL, RESMANUS_FAULT()); + umemget32(&(parms[0]), m.Ptr2(), 3*sizeof(TInt)); +#ifdef _DUMP_TRACKERS + if((r=DumpTracker(iGetStateTracker))!=KErrNone) + break; +#endif + r = GetStateBuffer(iGetStateTracker, trackBuf, (TUint)m.Ptr1(), (TInt*)parms[1], (TInt*)parms[2], callBack, pS); + if(r != KErrNone) + return r; + parms[3] = (TUint)callBack; + m.iArg[2] = &(parms[0]); + break; + } + case RBusDevResManUs::ERequestChangeNotification: + { + __ASSERT_ALWAYS(m.Ptr1() != NULL, RESMANUS_FAULT()); + r = GetAndInitTrackingBuffer(iListenableTracker, trackBuf, (TUint)m.Ptr1(), pS); + if(r != KErrNone) + return r; + prn = &(((TTrackNotifyBuf*)trackBuf)->iNotifyBlock); + new (prn) DPowerResourceNotification(&AsyncCallBackFn, (TAny*)trackBuf, iDfcQ, KResManCallBackPriority); + m.iArg[2] = (TAny*)prn; + break; + } + case RBusDevResManUs::ERequestQualifiedChangeNotification: + { + __ASSERT_ALWAYS(m.Ptr1() != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(m.Ptr2() != NULL, RESMANUS_FAULT()); + umemget32(&(parms[0]), m.Ptr2(), 2*sizeof(TUint)); + m.iArg[2] = &parms[0]; + r = GetAndInitTrackingBuffer(iListenableTracker, trackBuf, (TUint)parms[0], pS); + if(r != KErrNone) + return r; + prn = &(((TTrackNotifyBuf*)trackBuf)->iNotifyBlock); + new (prn) DPowerResourceNotification(&AsyncCallBackFn, (TAny*)trackBuf, iDfcQ, KResManCallBackPriority); + parms[2] = (TUint)prn; + break; + } + default: + { + return KErrNotSupported; + } + } + + if(r == KErrNone) + r = DLogicalChannel::SendMsg(aMsg); + if(r != KErrNone) + FreeTrackingBuffer(trackBuf); + return r; + } + + +TInt DChannelResManUs::SendControl(TMessageBase* aMsg) + { + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt id = m.iValue; + TInt param1 = 0; + TUint parms[4]; + TAny* a1 = m.Ptr0(); + TAny* a2 = m.Ptr1(); + TAny* ptr1 = NULL; + switch(id) + { + case RBusDevResManUs::EInitialise: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + TUint8 stateRes[3]; + umemget(&(stateRes[0]), a1, 3*sizeof(TUint8)); + m.iArg[0] = &(stateRes[0]); + break; + } + case RBusDevResManUs::EGetNoOfResources: + case RBusDevResManUs::EGetResourceControllerVersion: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + m.iArg[0] = ¶m1; + break; + } + case RBusDevResManUs::EGetNoOfClients: + case RBusDevResManUs::EGetNumClientsUsingResource: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + umemget32(&(parms[0]), a2, 3*sizeof(TUint)); + m.iArg[1] = &(parms[0]); + m.iArg[0] = ¶m1; + break; + } + case RBusDevResManUs::EGetNumResourcesInUseByClient: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + TBuf8 clientName; + Kern::KUDesGet(clientName, *(TDesC8*)m.Ptr0()); + m.iArg[0] = (TAny*)&clientName; + umemget32(&(parms[0]), m.Ptr1(), 2*sizeof(TUint)); + param1 = parms[1]; + m.iArg[1] = ¶m1; + break; + } + case RBusDevResManUs::EGetResourceIdByName: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + TBuf8 resourceName; + Kern::KUDesGet(resourceName, *(TDesC8*)m.Ptr0()); + m.iArg[0] = (TAny*)&resourceName; + m.iArg[1] = ¶m1; + break; + } +#ifdef RESOURCE_MANAGER_SIMULATED_PSL + case RBusDevResManUs::EGetNumCandidateAsyncResources: + case RBusDevResManUs::EGetNumCandidateSharedResources: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + m.iArg[0] = ¶m1; + break; + } + case RBusDevResManUs::EGetCandidateAsyncResourceId: + case RBusDevResManUs::EGetCandidateSharedResourceId: + { + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + m.iArg[1] = ¶m1; + break; + } +#endif + case RBusDevResManUs::EGetNumDependentsForResource: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + umemget32(&(parms[0]), m.Ptr1(), 2*sizeof(TUint)); + m.iArg[1] = &(parms[0]); + m.iArg[0] = ¶m1; + break; + } + case RBusDevResManUs::EGetDependentsIdForResource: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + umemget32(&(parms[0]), m.Ptr1(), 3*sizeof(TUint)); + TInt len, maxLen; + ptr1 = (TAny*)parms[1]; + Kern::KUDesInfo(*(const TDesC8*)parms[1], len, maxLen); + umemget32(¶m1, m.Ptr0(), sizeof(TUint)); + if((maxLen - len) < (TInt)(param1 * sizeof(SResourceDependencyInfo))) + { + return KErrArgument; + } + m.iArg[0] = ¶m1; + m.iArg[1] = &(parms[0]); + break; + } + case RBusDevResManUs::EGetResourceInfo: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + TResourceInfoBuf buf; + m.iArg[1] = &buf; + break; + } + case RBusDevResManUs::EGetAllResourcesInfo: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + umemget32(&(parms[0]), m.Ptr1(), 2*sizeof(TUint)); + ptr1 = (TAny*)parms[0]; + umemget32(¶m1, (TAny*)parms[0], sizeof(TUint)); + parms[0] =(TUint)¶m1; + RSimplePointerArray infoPtrs; + umemget(&infoPtrs, m.Ptr0(), sizeof(RSimplePointerArray)); + if((infoPtrs.Count() < 0) || (infoPtrs.Count() < param1)) + return KErrArgument; + m.iArg[1] = &(parms[0]); + break; + } + case RBusDevResManUs::EGetInfoOnClientsUsingResource: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + umemget32(&parms[0], m.Ptr1(), 4*sizeof(TUint)); + ptr1 = (TAny*)parms[0]; + umemget32(¶m1, (TAny*)parms[0], sizeof(TUint)); + parms[0] = (TUint)¶m1; + RSimplePointerArrayinfoPtrs; + umemget(&infoPtrs, m.Ptr0(), sizeof(RSimplePointerArray)); + if((infoPtrs.Count() < 0) || (infoPtrs.Count() < param1)) + return KErrArgument; + m.iArg[1] = &(parms[0]); + break; + } + case RBusDevResManUs::EGetNamesAllClients: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + umemget32(&parms[0], m.Ptr1(), 4*sizeof(TUint)); + ptr1 = (TAny*)parms[0]; + umemget32(¶m1, (TAny*)parms[0], sizeof(TUint)); + parms[0] = (TUint)¶m1; + RSimplePointerArray infoPtrs; + umemget(&infoPtrs, m.Ptr0(), sizeof(RSimplePointerArray)); + if((infoPtrs.Count() < 0) || (infoPtrs.Count() < param1)) + return KErrArgument; + m.iArg[1] = &(parms[0]); + break; + } + case RBusDevResManUs::EGetInfoOnResourcesInUseByClient: + { + __ASSERT_ALWAYS(a1 != NULL, RESMANUS_FAULT()); + __ASSERT_ALWAYS(a2 != NULL, RESMANUS_FAULT()); + TBuf8 clientName; + Kern::KUDesGet(clientName, *(TDesC8*)m.Ptr0()); + m.iArg[0] = (TAny*)&clientName; + umemget32(&parms[0], m.Ptr1(), 3*sizeof(TUint)); + ptr1 = (TAny*)parms[0]; + umemget32(¶m1, (TAny*)parms[0], sizeof(TUint)); + parms[0] = (TUint)¶m1; + RSimplePointerArray infoPtrs; + umemget(&infoPtrs, (TAny*)parms[1], sizeof(RSimplePointerArray)); + if((infoPtrs.Count() < 0) || (infoPtrs.Count() < param1)) + return KErrArgument; + m.iArg[1] = &(parms[0]); + break; + } + } + + TInt r = DLogicalChannel::SendMsg(aMsg); + if(r != KErrNone) + return r; + + switch(id) + { + case RBusDevResManUs::EGetNoOfResources: + case RBusDevResManUs::EGetNoOfClients: + case RBusDevResManUs::EGetNumClientsUsingResource: + case RBusDevResManUs::EGetResourceControllerVersion: + case RBusDevResManUs::EGetNumDependentsForResource: + { + umemput32(a1, (TAny*)¶m1, sizeof(TUint)); + break; + } + case RBusDevResManUs::EGetNumResourcesInUseByClient: + { + umemput32((TAny*)parms[0], (TAny*)¶m1, sizeof(TUint)); + break; + } + case RBusDevResManUs::EGetResourceIdByName: + { + umemput32(a2, (TAny*)¶m1, sizeof(TUint)); + break; + } +#ifdef RESOURCE_MANAGER_SIMULATED_PSL + case RBusDevResManUs::EGetNumCandidateAsyncResources: + case RBusDevResManUs::EGetNumCandidateSharedResources: + { + umemput32(a1, (TAny*)¶m1, sizeof(TUint)); + break; + } + case RBusDevResManUs::EGetCandidateAsyncResourceId: + case RBusDevResManUs::EGetCandidateSharedResourceId: + { + umemput32(a2, (TAny*)¶m1, sizeof(TUint)); + break; + } +#endif + case RBusDevResManUs::EGetDependentsIdForResource: + { + r = Kern::ThreadDesWrite(iClient,(TAny*)ptr1, (const TDesC8&)*(SResourceDependencyInfo*)parms[1], 0); + if(r == KErrOverflow) //This is done to retain the error as per API spec + r = KErrArgument; + break; + } + case RBusDevResManUs::EGetResourceInfo: + { + Kern::KUDesPut(*(TDes8*)a2, (const TDesC8&)*(TResourceInfoBuf*)m.Ptr1()); + break; + } + case RBusDevResManUs::EGetAllResourcesInfo: + { + TUint numToCopy; + RSimplePointerArray infoPtrs; + umemget(&infoPtrs, a1, sizeof(RSimplePointerArray)); + numToCopy = (infoPtrs.Count() < param1) ? infoPtrs.Count() : param1; + umemput32(ptr1, (TAny*)¶m1, sizeof(TUint)); + TResourceInfoBuf** entriesAddr = infoPtrs.Entries(); + TInt* entryPtr = (TInt*)entriesAddr; + TPowerResourceInfoV01 *currRes = (TPowerResourceInfoV01*)iResourceInfoResCtrl->Ptr(); + TResourceInfoBuf* clientAddr; + TResourceInfoBuf tempInfo; + for(TUint index = 0; index < numToCopy; index++) + { + umemget32(&clientAddr, entryPtr, sizeof(TResourceInfoBuf*)); + entryPtr++; + r = ExtractResourceInfo(currRes, tempInfo); + if(r != KErrNone) + return r; + umemput((TAny*)clientAddr, (TAny*)&(tempInfo), tempInfo.Length()); + currRes++; + } + break; + } + case RBusDevResManUs::EGetInfoOnClientsUsingResource: + { + TUint numToCopy; + RSimplePointerArray infoPtrs; + umemget(&infoPtrs, a1, sizeof(RSimplePointerArray)); + numToCopy = infoPtrs.Count(); + TClientInfoBuf** entriesAddr = infoPtrs.Entries(); + TInt* entryPtr = (TInt*)entriesAddr; + TPowerClientInfoV01* rcDataPtr = (TPowerClientInfoV01*)iClientNamesResCtrl->Ptr(); + TClientInfoBuf* clientAddr; + TUint userSideClients = 0; + TClientInfoBuf tempInfo; + for(TInt index = 0; index < param1; index++) + { + if((!parms[1]) && !(rcDataPtr->iClientId & USER_SIDE_CLIENT_BIT_MASK)) + { + rcDataPtr++; + continue; + } + if(numToCopy == 0) + { + userSideClients++; + continue; + } + umemget32(&clientAddr, entryPtr, sizeof(TClientName*)); + entryPtr++; + tempInfo().iId = rcDataPtr->iClientId; + tempInfo().iName = *rcDataPtr->iClientName; + Kern::InfoCopy(*clientAddr, tempInfo); + rcDataPtr++; + numToCopy--; + userSideClients++; + } + if(parms[1]) + umemput32(ptr1, (TAny*)¶m1, sizeof(TUint)); + else + umemput32(ptr1, (TAny*)&userSideClients, sizeof(TUint)); + break; + } + case RBusDevResManUs::EGetNamesAllClients: + { + TUint numToCopy; + RSimplePointerArray infoPtrs; + umemget(&infoPtrs, a1, sizeof(RSimplePointerArray)); + numToCopy = infoPtrs.Count(); + TClientName** entriesAddr = infoPtrs.Entries(); + TInt* entryPtr = (TInt*)entriesAddr; + TPowerClientInfoV01* rcDataPtr = (TPowerClientInfoV01*)iClientNamesResCtrl->Ptr(); + TClientName* clientAddr; + TUint userSideClients = 0; + for(TInt index = 0; index < param1; index++) + { + if((!parms[1]) && !(rcDataPtr->iClientId & USER_SIDE_CLIENT_BIT_MASK)) + { + rcDataPtr++; + continue; + } + if(numToCopy == 0) + { + userSideClients++; + continue; + } + umemget32(&clientAddr, entryPtr, sizeof(TClientName*)); + entryPtr++; + Kern::KUDesPut(*((TDes8*)clientAddr), *(const TDesC8*)rcDataPtr->iClientName); + rcDataPtr++; + numToCopy--; + userSideClients++; + } + if(parms[1]) + umemput32(ptr1, (TAny*)¶m1, sizeof(TUint)); + else + umemput32(ptr1, (TAny*)&userSideClients, sizeof(TUint)); + break; + } + case RBusDevResManUs::EGetInfoOnResourcesInUseByClient: + { + TUint numToCopy; + RSimplePointerArray infoPtrs; + umemget(&infoPtrs, (TAny*)parms[1], sizeof(RSimplePointerArray)); + numToCopy = (infoPtrs.Count() < param1) ? infoPtrs.Count() : param1; + umemput32(ptr1, (TAny*)¶m1, sizeof(TUint)); + TResourceInfoBuf** entriesAddr = infoPtrs.Entries(); + TInt* entryPtr = (TInt*)entriesAddr; + TPowerResourceInfoV01* currRes = (TPowerResourceInfoV01*)iResourceInfoResCtrl->Ptr(); + TResourceInfoBuf* clientAddr; + TResourceInfoBuf tempInfo; + for(TUint index = 0; index < numToCopy; index++) + { + umemget32(&clientAddr, entryPtr, sizeof(TResourceInfoBuf*)); + entryPtr++; + r = ExtractResourceInfo(currRes, tempInfo); + if(r != KErrNone) + return r; + umemput((TAny*)clientAddr, (TAny*)&(tempInfo), tempInfo.Length()); + currRes++; + } + break; + } + } + return r; + } + +void DChannelResManUs::HandleMsg(TMessageBase* aMsg) + { + TThreadMessage& m=*(TThreadMessage*)aMsg; + TInt id=m.iValue; + + __KTRACE_OPT(KRESMANAGER, Kern::Printf(" >ldd: DChannelResManUs::HandleMsg(TMessageBase* aMsg) id=%d\n", id)); + + if (id==(TInt)ECloseMsg) + { + // Deregister here to ensure the correct thread ID is read + if(ClientHandle() != 0) + { + // Must de-register from Resource Controller before closing down + // Not checking return value - still need to delete allocated buffers +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_DEREGISTER_CLIENT_START_TRACE; +#endif + ((DPowerResourceController*)iPddPtr)->DeregisterProxyClient(ClientHandle()); + +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_DEREGISTER_CLIENT_END_TRACE; +#endif + SetClientHandle(0); + } + iMsgQ.iMessage->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()); + m.Complete(r,ETrue); + } + else + { + // DoControl + __KTRACE_OPT(KRESMANAGER, Kern::Printf(" >ldd: do control id=%d...\n", id)); + TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); + m.Complete(r,ETrue); + } + } + +TInt DChannelResManUs::CancelTrackerRequests(TTrackingControl* aTracker, TBool aSingleRsrc, TUint aResourceId, TRequestStatus* aStatus) + { + // Cancel all outstanding requests from this client for a specified operation on + // a specified resource + + // Loop all entries in the iBusyQue of requests to locate a match for the + // operation type and resource ID + // + // For each match, remove the buffer from the busy queue and return to the free queue + // If the request is already being processed, and so the callback function will be called + // later, then the callback will exit gracefully. + // + __KTRACE_OPT(KRESMANAGER, Kern::Printf(" > DChannelResManUs::CancelTrackerRequests")); + TInt returnVal = KErrNone; + TBool statusMatched=EFalse; + TTrackingBuffer* firstLink = NULL; + TTrackingBuffer* lastLink = NULL; + TInt type = aTracker->iType; + +#ifdef PRM_US_INSTRUMENTATION_MACRO + if(type==EGetState) + { + PRM_US_CANCEL_GET_RESOURCE_STATE_START_TRACE; + } + else if(type==ESetState) + { + PRM_US_CANCEL_SET_RESOURCE_STATE_START_TRACE; + } +#endif + + if(aTracker->iBusyQue != NULL) + { + firstLink = (TTrackingBuffer*)(aTracker->iBusyQue->iA.iNext); + lastLink = (TTrackingBuffer*)(&(aTracker->iBusyQue->iA)); + } + while(( firstLink!=lastLink )&&(!statusMatched)) + { + TTrackingBuffer* buffer = firstLink; + TUint resourceId = buffer->GetResourceId(); + if(aSingleRsrc) + if(resourceId != aResourceId) // Required resource? + { + firstLink=(TTrackingBuffer*)(firstLink->iNext); + continue; + } + if(aStatus!=NULL) + { + TClientRequest *request; + GET_USER_REQUEST(request, buffer, type) + if(request->StatusPtr() == aStatus) + { + statusMatched = ETrue; + } + else + { + firstLink=(TTrackingBuffer*)(firstLink->iNext); + continue; + } + } + TInt r = KErrNone; + if(type==EGetState) + { + TTrackGetStateBuf* stateBuf = (TTrackGetStateBuf*)firstLink; + r=((DPowerResourceController*)iPddPtr)->CancelAsyncRequestCallBack(ClientHandle(), + resourceId, (stateBuf->iCtrlBlock)); + } + else if(type==ESetState) + { + TTrackSetStateBuf* stateBuf = (TTrackSetStateBuf*)firstLink; + r = ((DPowerResourceController*)iPddPtr)->CancelAsyncRequestCallBack(ClientHandle(), + resourceId, (stateBuf->iCtrlBlock)); + } + else if(type==ENotify) + { + TTrackNotifyBuf* notifyBuf = (TTrackNotifyBuf*)firstLink; + r=((DPowerResourceController*)iPddPtr)->CancelNotification(ClientHandle(), resourceId, + notifyBuf->iNotifyBlock); + } + + // Process the accumulated return value + if((r==KErrCompletion)&&((returnVal==KErrNone)||(returnVal==KErrCancel))) + { + returnVal=KErrCompletion; + } + else if((r==KErrInUse)&& + ((returnVal==KErrNone)||(returnVal==KErrCompletion)||(returnVal==KErrCancel))) + { + returnVal=KErrInUse; + } + else if(r!=KErrCancel) + { + returnVal=r; + } + + // Return the tracking buffer to the free queue + TTrackingBuffer* tempLink = (TTrackingBuffer*)(firstLink->iNext); + FreeTrackingBuffer(firstLink); + firstLink = tempLink; + +#ifdef PRM_US_INSTRUMENTATION_MACRO + if(type==EGetState) + { + PRM_US_CANCEL_GET_RESOURCE_STATE_END_TRACE; + } + else if(type==ESetState) + { + PRM_US_CANCEL_SET_RESOURCE_STATE_END_TRACE; + } +#endif + // Complete the TRequestStatus object + if((r!=KErrCompletion)&&(r!=KErrInUse)) + { + TClientRequest* request; + GET_USER_REQUEST(request, buffer, type) + Kern::QueueRequestComplete(iClient, request, r); + } + + } // while + return returnVal; + } + + +TTrackingControl* DChannelResManUs::MapRequestToTracker(TInt aRequestType) +// Utility function to map identifiers for cancel commands to request types. + { + TTrackingControl *tracker=NULL; + switch(aRequestType) + { + case RBusDevResManUs::ECancelChangeResourceStateRequests: + case RBusDevResManUs::ECancelChangeResourceState: + { + tracker=iSetStateTracker; + break; + } + case RBusDevResManUs::ECancelGetResourceStateRequests: + case RBusDevResManUs::ECancelGetResourceState: + { + tracker=iGetStateTracker; + break; + } + case RBusDevResManUs::ECancelChangeNotificationRequests: + case RBusDevResManUs::ECancelRequestChangeNotification: + { + tracker=iListenableTracker; + break; + } + default: + { + __ASSERT_ALWAYS(0,RESMANUS_FAULT()); + } + } + return tracker; + } + + +TInt DChannelResManUs::CancelRequestsOfType(TInt aRequestType, TRequestStatus* aStatus) +// Cancel a particular request. This may be qualified by the type of operation + { + __ASSERT_ALWAYS(((aRequestType==RBusDevResManUs::ECancelChangeResourceState)|| + (aRequestType==RBusDevResManUs::ECancelGetResourceState)|| + (aRequestType==RBusDevResManUs::ECancelRequestChangeNotification)|| + (KMaxTInt)), + RESMANUS_FAULT()); + // For the KMaxTInt case, the type of the request is not known and so all trackers + // must be considered before the request is found. + // For all other cases, only the relevant tracker is searched. + TInt r=KErrNone; + if(aRequestType!=KMaxTInt) + { + TTrackingControl*tracker=MapRequestToTracker(aRequestType); + r=CancelTrackerRequests(tracker, EFalse, 0, aStatus); + } + else + { + TTrackingControl* tracker[3] = {iGetStateTracker, iSetStateTracker, iListenableTracker}; + TUint8 index=0; + while((index<3) && (r==KErrNone)) + { + r=CancelTrackerRequests(tracker[index], EFalse, 0, aStatus); + ++index; + } + } + if(r==KErrCancel) + r=KErrNone; // All cancellations were successful + + return r; + } + + +void DChannelResManUs::DoCancel(TInt aMask) +// Cancel an outstanding request. + { + TRequestStatus* status = (TRequestStatus*)aMask; + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoCancel, TRequestStatus addr = 0x%x",(TInt)status)); + + CancelRequestsOfType(KMaxTInt, status); // Ignore return value + return; + } + +TInt DChannelResManUs::DoRequest(TInt aReqNo, TRequestStatus* /*aStatus*/, TAny* a1, TAny* a2) +// Asynchronous requests. + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)")); + + TInt r=KErrNone; + switch (aReqNo) + { + case RBusDevResManUs::EChangeResourceState: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoRequest case EChangeResourceState")); + // a1 specifies the identifier of the required resource + // a2 specifies the required state for the resource + // + TUint *param = (TUint*)a2; + TUint resourceId = (TUint)a1; + TInt newState = (TInt)param[0]; + +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_SET_RESOURCE_STATE_START_TRACE; +#endif + // Invoke the API + r=((DPowerResourceController*)iPddPtr)->ChangeResourceState(ClientHandle(), + resourceId, newState, (TPowerResourceCb*)param[1]); + break; + } + + case RBusDevResManUs::EGetResourceState: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoRequest case EGetResourceState")); + // a1 specifies the resource ID + // a2 specifies the container stating if a cached value is required, the address of the variable + // to be update with the state value and the address of the level owner ID + // + TUint resourceId = (TUint)a1; + TUint *parms = (TUint*)a2; + TBool cached = (TBool)(parms[0]); + +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_GET_RESOURCE_STATE_START_TRACE; +#endif + // Always invoke the asynchronous version of the API + r=((DPowerResourceController*)iPddPtr)->GetResourceState(ClientHandle(), + resourceId, cached, *((TPowerResourceCb*)parms[3])); + break; + } + + + case RBusDevResManUs::ERequestChangeNotification: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoRequest case ERequestChangeNotification")); + // a1 specifies the resource ID + r=((DPowerResourceController*)iPddPtr)->RequestNotification(ClientHandle(), + (TUint)a1, *((DPowerResourceNotification*)a2)); + break; + } + + case RBusDevResManUs::ERequestQualifiedChangeNotification: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoRequest case ERequestQualifiedChangeNotification")); + // a1 specifies the threshold value that the state is to change by + // a2 specifies the address of the container holding the resourceID and the required direction + TInt threshold = (TInt)a1; + TUint *parms = (TUint*)a2; + TUint resourceId = parms[0]; + TBool direction = (TBool)(parms[1]); + r=((DPowerResourceController*)iPddPtr)->RequestNotification(ClientHandle(), + resourceId, *((DPowerResourceNotification*)parms[2]), threshold, direction); + break; + } + + default: + return KErrNotSupported; + } + return r; + } + +TInt DChannelResManUs::DoControl(TInt aFunction, TAny* a1, TAny* a2) +// Synchronous requests. + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::DoControl(TInt aFunction, TAny* a1, TAny* a2)") ); + + TInt r=KErrNone; + switch (aFunction) + { + case RBusDevResManUs::EInitialise: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EInitialise")); + // a1 specifies the array describing the number of 'gettable' and 'settable' state resources + // and the number of 'listenable' resources + // + TUint8 *stateRes = (TUint8*)a1; +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_REGISTER_CLIENT_START_TRACE; +#endif + // The call to the Resource Controller's AllocReserve method requires two parameters: + // the number of client level objects and the number of request message objects + // Each 'settable' state resource requires a client level object and a request message object + // Each 'gettable' state resource requires a request message object, only. + // Call Resource Control to make allocations + r=((DPowerResourceController*)iPddPtr)->AllocReserve(ClientHandle(), + stateRes[1], // Number of settable + (TUint8)(stateRes[1] + stateRes[0])); // Number of (settable + gettable) +#ifdef PRM_US_INSTRUMENTATION_MACRO + PRM_US_REGISTER_CLIENT_END_TRACE; +#endif + if(r==KErrNone) + { + // Require 1 TPowerResourceCb object per gettable resource state + // Require 1 TPowerResourceCb object per settable resource state + // Require 1 DPowerResourceNotification object per listenable resource + // + if(stateRes[0]>0) + r=InitTrackingControl(iGetStateTracker,EGetState,stateRes[0]); + if((r==KErrNone) && (stateRes[1]>0)) + r=InitTrackingControl(iSetStateTracker,ESetState,stateRes[1]); + if((r==KErrNone) && (stateRes[2]>0)) + r=InitTrackingControl(iListenableTracker,ENotify,stateRes[2]); +#ifdef _DUMP_TRACKERS + if((r=DumpTracker(iGetStateTracker))!=KErrNone) + break; + if((r=DumpTracker(iSetStateTracker))!=KErrNone) + break; +#endif + } + break; + } + + case RBusDevResManUs::EGetNoOfResources: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetNoOfResources")); + TUint numResources; + r=((DPowerResourceController*)iPddPtr)->GetNumResourcesInUseByClient(ClientHandle(),0,numResources); + iResInfoValid = 0; // New numResources invalidates the iResInfoXXXX information + iResInfoStoredClientId = 0; + iResInfoStoredNum = 0; + if(r!=KErrNone) + return r; + // a2 specifies whether the resource information should be loaded + if((r==KErrNone)&&(a2!=NULL)) + { + TUint prevNumRes = 0; + while((numResources != prevNumRes)&&(r==KErrNone)) + { + // if the number of resources is greater than can be accommodated by the array, + // re-size it + if((r=EnsureSizeIsSufficient(iResourceInfoResCtrl, (TInt)(numResources*sizeof(TPowerResourceInfoV01))))!=KErrNone) + break; + prevNumRes = numResources; + // Get the resource info from the Resource Controller + // Specify 'aTargetClientId' as zero to access all resources + iResourceInfoResCtrl->SetLength(0); + r=((DPowerResourceController*)iPddPtr)->GetInfoOnResourcesInUseByClient( + ClientHandle(),0,numResources,iResourceInfoResCtrl); + } + if(r==KErrNone) + { + iResInfoValid = 1; + iResInfoStoredClientId = KAllResInfoStored; + iResInfoStoredNum = numResources; + } + } + if(r==KErrNone) + *(TUint*)a1 = numResources; + break; + } + + case RBusDevResManUs::EGetAllResourcesInfo: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetAllResourcesInfo")); + // Parameters are passed in TUint* parms[2] + // The address of the number of resources is at element 0 + // The flag to indicate if the resource info stored is to be refreshed is at element 1 + TUint* parms = (TUint*)a2; + TUint numResources = *(TUint*)parms[0]; + TBool refresh=(TBool)(parms[1]); + + // The results are to be written to an RSimplePointerArray, the address is in a1 + // Check that the array has enough elements + if(refresh) + { + // For the refresh option, invoke Resource Controller API once, only (do not recurse) + // If the number of requested resources is greater than can be accommodated by the array, + // re-size it + if((r=EnsureSizeIsSufficient(iResourceInfoResCtrl, (TInt)(numResources*sizeof(TPowerResourceInfoV01))))!=KErrNone) + break; + // Get the resource info from the Resource Controller + // Specify 'aTargetClientId' as zero to access all resources + iResourceInfoResCtrl->SetLength(0); + r=((DPowerResourceController*)iPddPtr)->GetInfoOnResourcesInUseByClient( + ClientHandle(),0,numResources,iResourceInfoResCtrl); + if(numResources != iResInfoStoredNum) + { + iResInfoValid = 0; // Assume cohesion is now lost + iResInfoStoredClientId = 0; + iResInfoStoredNum = 0; + } + } + else + { + // If the information stored is not valid or is not for all resources return KErrNotReady + if((iResInfoValid != 1)||(iResInfoStoredClientId != KAllResInfoStored)) + { + r=KErrNotReady; + break; + } + // The number of resources for which information is available in this case is iResInfoStoredNum + numResources = iResInfoStoredNum; + } +#ifdef RESOURCE_MANAGER_SIMULATED_PSL + TPowerResourceInfoV01* currRes = (TPowerResourceInfoV01*)iResourceInfoResCtrl->Ptr(); + for(TUint index = 0; index < numResources; index++) + { + CheckForCandidateAsyncResource(currRes); + CheckForCandidateSharedResource(currRes); + currRes++; + } +#endif + *(TUint*)(parms[0]) = numResources; + + break; + } + + case RBusDevResManUs::EGetNoOfClients: + case RBusDevResManUs::EGetNumClientsUsingResource: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetNoOfClients")); + // Parameters are passed in TUint parms[3] + // The flag to indicate if kernel-side clients are to be included is at element 0 + // The ID of the resource of interest (0 is expected for EGetNoOfClients) + // The flag to indicate if the client info is to be read now is at element 1 + TUint *parms = (TUint*)a2; + TUint includeKern = parms[0]; + TUint resourceId = parms[1]; + TUint infoRead = parms[2]; + TUint requiredId = resourceId; + if(aFunction == RBusDevResManUs::EGetNoOfClients) + { + __ASSERT_ALWAYS(resourceId==0,RESMANUS_FAULT()); + requiredId = KAllClientInfoStored; + } + TUint numClients = 0; + if(includeKern==1) + { + // Client must exhibit PlatSec capability ReadDeviceData + if(!iClient->HasCapability(ECapabilityReadDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Resource Manager user-side API function EGetNoOfClients"))) + { + r = KErrPermissionDenied; + break; + } + if(r==KErrNone) + r=((DPowerResourceController*)iPddPtr)->GetNumClientsUsingResource(ClientHandle(),resourceId,numClients); + } + else + numClients = (TUint)(iDevice->iOpenChannels); + + // New numClients invalidates the iClientInfoXXXX information + iClientInfoValid = 0; + iClientInfoStoredResId = 0; + iClientInfoStoredNum= 0; + + if((r==KErrNone)&&(infoRead==1)) + { + // Capability check already performed, so no need to repeat ... + TUint prevNumClients = 0; + while((numClients != prevNumClients)&&(r == KErrNone)) + { + // Ensure buffer is large enough to store the information + if((r=EnsureSizeIsSufficient(iClientNamesResCtrl, (TInt)(numClients*sizeof(TPowerClientInfoV01))))!=KErrNone) + break; + prevNumClients = numClients; + // Invoke the API + r=((DPowerResourceController*)iPddPtr)->GetInfoOnClientsUsingResource(ClientHandle(), + resourceId,numClients,iClientNamesResCtrl); + }; + + if(r==KErrNone) + { + iClientInfoValid = 1; + iClientInfoStoredResId = requiredId; + iClientInfoStoredNum = numClients; + if(includeKern!=1) + { + TUint numAllClients = numClients; + numClients = 0; + TPowerClientInfoV01* rcDataPtr = (TPowerClientInfoV01*)(iClientNamesResCtrl->Ptr()); + for(TUint i=0; iiClientId & USER_SIDE_CLIENT_BIT_MASK) + ++numClients; + ++rcDataPtr; + } + } + } + } + if(r==KErrNone) + *(TUint*)a1 = numClients; + break; + } + + case RBusDevResManUs::EGetNamesAllClients: + case RBusDevResManUs::EGetInfoOnClientsUsingResource: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetNamesAllClients-EGetInfoOnClientsUsingResource")); + // Parameters are passed in TUint* parms[4] + // The address of the number of clients is at element 0 + // The flag to indicate if kernel-side info is requested is at element 1 + // The resource ID is at element 2 + // The flag to indicate if the client information stored is to be refreshed is at element 3 + TUint* parms = (TUint*)a2; + TUint numClients = *(TUint*)parms[0]; + TBool includeKern=(TBool)(parms[1]); + TUint resourceId=(TUint)(parms[2]); + TBool refresh=(TBool)(parms[3]); + + TUint numClientsAvailable = 0; + iClientNamesResCtrl->SetLength(0); + + if(includeKern) + { + // Client must exhibit PlatSec capability ReadDeviceData + if(!iClient->HasCapability(ECapabilityReadDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Resource Manager user-side API function EGetNamesAllClients-EGetInfoOnClientsUsingResource"))) + { + r = KErrPermissionDenied; + break; // Early exit in event of error + } + TUint requiredId = (resourceId==0)?(TUint)KAllClientInfoStored:resourceId; + if(refresh) + { + // For the refresh option, invoke Resource Controller API once, only (do not recurse) + // If the number of clients is greater than can be accommodated by the array, + // re-size it + if((r=EnsureSizeIsSufficient(iClientNamesResCtrl, (TInt)(numClients*sizeof(TPowerClientInfoV01))))!=KErrNone) + break; + // Invoke the API + numClientsAvailable = numClients; // Arbitrary initialisation (to silence compiler warning) + r=((DPowerResourceController*)iPddPtr)->GetInfoOnClientsUsingResource(ClientHandle(), + resourceId,numClientsAvailable,iClientNamesResCtrl); + if((r!=KErrNone)||(numClientsAvailable != iClientInfoStoredNum)||(iClientInfoStoredResId != requiredId)) + { + iClientInfoValid = 0; // Assume cohesion is now lost + iClientInfoStoredResId = 0; + iClientInfoStoredNum = 0; + } + } + else + { + // If the information stored is not valid, is not for the required resources return KErrNotReady + if((iClientInfoValid != 1)||(iClientInfoStoredResId != requiredId)) + r=KErrNotReady; + // The number of clients for which information is available in this case is iClientInfoStoredNum + numClientsAvailable = iClientInfoStoredNum; + } + } + else + { + // Resource Controller will return information for the number of clients requested, + // taken in order from its internal storage - but this will be regardless of whether + // they are kernel-side or user-side; the USER_SIDE_CLIENT_BIT_MASK bit must be + // interrogated to determine this. + // + // Therefore, need to read all the clients - but to do this, must find out how many + // clients there are first. + TUint numAllClients; + r=((DPowerResourceController*)iPddPtr)->GetNumClientsUsingResource(ClientHandle(),resourceId,numAllClients); + if(r!=KErrNone) + break; // Early exit in event of error + if(numAllClients > 0) + { + if(refresh) + { + // For the refresh option, invoke Resource Controller API once, only (do not recurse) + // If the number of clients is greater than can be accommodated by the array, + // re-size it + if((r=EnsureSizeIsSufficient(iClientNamesResCtrl, (TInt)(numAllClients*sizeof(TPowerClientInfoV01))))!=KErrNone) + break; + // Invoke the API + r=((DPowerResourceController*)iPddPtr)->GetInfoOnClientsUsingResource(ClientHandle(), + resourceId,numAllClients,iClientNamesResCtrl); + TUint requiredId = (resourceId==0)?(TUint)KAllClientInfoStored:resourceId; + if((r!=KErrNone)||(numClientsAvailable != iClientInfoStoredNum)||(iClientInfoStoredResId != requiredId)) + { + iClientInfoValid = 0; // Assume cohesion is now lost + iClientInfoStoredResId = 0; + iClientInfoStoredNum = 0; + break; + } + else + { + iClientInfoValid = 1; + iClientInfoStoredResId = requiredId; + iClientInfoStoredNum = numAllClients; + } + } + else + { + // If the information stored is not valid, is not for the required resources return KErrNotReady + TUint requiredId = (resourceId==0)?(TUint)KAllClientInfoStored:resourceId; + if((iClientInfoValid != 1)||(iClientInfoStoredResId != requiredId)) + { + r=KErrNotReady; + break; + } + // The number of clients for which information is available in this case is iClientInfoStoredNum + numAllClients = iClientInfoStoredNum; + } + numClientsAvailable = numAllClients; + } // if(numAllClients > 0) + } + // Write the total number of user side cients available + *(TUint*)parms[0] = numClientsAvailable; + break; + } + case RBusDevResManUs::EGetNumResourcesInUseByClient: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetNumResourcesInUseByClient")); + // a1 specifies the container holding the client name + // + + // If client doesn't exist, return KErrNotFound + // If client has appropriate capabilities, or if the client for which the information is sought + // is user-side, invoke the Resource Controller API directly + // Otherwise, return KErrPermissionDenied + TUint clientId=0; + r=((DPowerResourceController*)iPddPtr)->GetClientId(ClientHandle(), + *(TDesC8*)a1,clientId); + if(r!=KErrNone) + return KErrNotFound; + // Perform capability check + if(!iClient->HasCapability(ECapabilityReadDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Resource Manager user-side API function EGetNoOfClients"))) + { + if(!(clientId & USER_SIDE_CLIENT_BIT_MASK)) + return KErrPermissionDenied; + } + TUint numResources=0; + if(r==KErrNone) + r=((DPowerResourceController*)iPddPtr)->GetNumResourcesInUseByClient(ClientHandle(), + clientId,numResources); + // New numResources invalidates the iResXXXX information + iResInfoValid = 0; + iResInfoStoredClientId = 0; + iResInfoStoredNum= 0; + + // parms[1] specifies whether the resource information should be loaded + if((r==KErrNone)&&(*(TUint*)a2 != NULL)) + { + TUint prevNumRes = 0; + while((numResources != prevNumRes)&&(r==KErrNone)) + { + // if the number of resources is greater than can be accommodated by the array, + // re-size it + if((r=EnsureSizeIsSufficient(iResourceInfoResCtrl, (TInt)(numResources*sizeof(TPowerResourceInfoV01))))!=KErrNone) + break; + prevNumRes = numResources; + // Get the resource info from the Resource Controller + // Specify 'aTargetClientId' as zero to access all resources + iResourceInfoResCtrl->SetLength(0); + r=((DPowerResourceController*)iPddPtr)->GetInfoOnResourcesInUseByClient( + ClientHandle(),clientId,numResources,iResourceInfoResCtrl); + } + if(r==KErrNone) + { + iResInfoValid = 1; + iResInfoStoredClientId = clientId; + iResInfoStoredNum = numResources; + } + } + if(r==KErrNone) + *(TUint*)a2 = numResources; + break; + } + + case RBusDevResManUs::EGetInfoOnResourcesInUseByClient: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetInfoOnResourcesInUseByClient")); + // a1 specifies the container holding the client name + // a2 specifies an array TUint* parms[3] which contains: + // - the address of the variable to write the number of reasources to + // - a pointer to the container to hold the resources' information + // - the flag to indicate whether the resource info should be (re-)read here + + TUint clientId=0; + TUint *parms = (TUint*)a2; + TUint numResources = *(TUint*)parms[0]; + // The results are to be written to an RSimplePointerArray, the address is in parms[1] + // Check that the array has enough elements + // If client doesn't exist, return KErrNotFound + // If client has appropriate capabilities, or if the client for which the information is sought + // is user-side, invoke the Resource Controller API directly + // Otherwise, return KErrPermissionDenied + r=((DPowerResourceController*)iPddPtr)->GetClientId(ClientHandle(), + *(TDesC8*)a1,clientId); + if(r!=KErrNone) + return KErrNotFound; + // Perform capability check + if(!iClient->HasCapability(ECapabilityReadDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Resource Manager user-side API function EGetNoOfClients"))) + { + if(!(clientId & USER_SIDE_CLIENT_BIT_MASK)) + return KErrPermissionDenied; + } + + TUint updatedNumResources = numResources; + r=((DPowerResourceController*)iPddPtr)->GetNumResourcesInUseByClient(ClientHandle(),clientId,updatedNumResources); + if(r!=KErrNone) + break; + + if(updatedNumResources>0) + { + if((TUint)(parms[2] != 0)) + { + // For the refresh option, invoke Resource Controller API once, only (do not recurse) + // If the number of requested resources is greater than can be accommodated by the array, + // re-size it + if((r=EnsureSizeIsSufficient(iResourceInfoResCtrl, (TInt)(numResources*sizeof(TPowerResourceInfoV01))))!=KErrNone) + break; + // Get the resource info from the Resource Controller + // Specify 'aTargetClientId' as zero to access all resources + iResourceInfoResCtrl->SetLength(0); + r=((DPowerResourceController*)iPddPtr)->GetInfoOnResourcesInUseByClient( + ClientHandle(),clientId,numResources,iResourceInfoResCtrl); + if((numResources != iResInfoStoredNum)||(iResInfoStoredClientId != clientId)) + { + iResInfoValid = 0; // Assume cohesion is now lost + iResInfoStoredClientId = 0; + iResInfoStoredNum = 0; + } + } + else + { + // If the information stored is not valid or is not for the required clientId return KErrNotReady + if((iResInfoValid != 1)||(iResInfoStoredClientId != clientId)) + r=KErrNotReady; + // The number of resources for which information is available in this case is iResInfoStoredNum + numResources = iResInfoStoredNum; + } + } + if(r==KErrNone) + *(TUint*)parms[0] = updatedNumResources; + + break; + } + + case RBusDevResManUs::EGetResourceIdByName: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetResourceIdByName")); + // a1 specifies the container holding the resource name + // a2 specifies the variable to be update with the ID + TUint resourceId; + r=((DPowerResourceController*)iPddPtr)->GetResourceId(ClientHandle(), *(TDesC8*)a1, resourceId); + if(r==KErrNone) + *(TUint *)a2 = resourceId; + break; + } + + case RBusDevResManUs::EGetResourceInfo: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetResourceInfo")); + // a1 specifies the container holding the resource ID + // a2 specifies the address of the container to be written to + + TUint resourceId= (TUint)a1; + TPowerResourceInfoBuf01 resCtrlInfo; + resCtrlInfo.SetLength(0); + TResourceInfoBuf tempInfo; + r=((DPowerResourceController*)iPddPtr)->GetResourceInfo(ClientHandle(),resourceId,&resCtrlInfo); + if(r==KErrNone) + { + // Copy the client buffer to tempInfo so that its size can be determined + // by ExtractResourceInfo + r=ExtractResourceInfo(&(resCtrlInfo()), tempInfo); + } + if(r==KErrNone) + { + // Write the resources' info to the client thread + *(TResourceInfoBuf*)a2 = tempInfo; + } + break; + } + + + case RBusDevResManUs::ECancelChangeResourceStateRequests: + case RBusDevResManUs::ECancelGetResourceStateRequests: + case RBusDevResManUs::ECancelChangeNotificationRequests: + { + TUint resourceId = (TUint)a1; + TTrackingControl*tracker=MapRequestToTracker(aFunction); + r=CancelTrackerRequests(tracker, ETrue, resourceId, NULL); + if(r==KErrCancel) + r=KErrNone; // All cancellations were successful + break; + } + + case RBusDevResManUs::ECancelChangeResourceState: + case RBusDevResManUs::ECancelGetResourceState: + case RBusDevResManUs::ECancelRequestChangeNotification: + { + TRequestStatus* status = (TRequestStatus*)a1; + r=CancelRequestsOfType(aFunction, status); + break; + } + + +#ifdef RESOURCE_MANAGER_SIMULATED_PSL + case RBusDevResManUs::EGetNumCandidateAsyncResources: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetNumCandidateAsyncResources")); + TUint numResources; + GetNumCandidateAsyncResources(numResources); + // Write the result to the client thread + *(TUint*)a1 = numResources; + break; + } + case RBusDevResManUs::EGetCandidateAsyncResourceId: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetCandidateAsyncResourceId")); + // Get the index to use + TUint index = (TUint)a1; + TUint resourceId = 0; + r=GetCandidateAsyncResourceId(index, resourceId); + if(r==KErrNone) // Write the result to the client thread + *(TUint*)a2 = resourceId; + break; + } + + case RBusDevResManUs::EGetNumCandidateSharedResources: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetNumCandidateSharedResources")); + TUint numResources; + GetNumCandidateSharedResources(numResources); + // Write the result to the client thread + *(TUint*)a1 = numResources; + break; + } + case RBusDevResManUs::EGetCandidateSharedResourceId: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetCandidateSharedResourceId")); + // Get the index to use + TUint index = (TUint)a1; + TUint resourceId = 0; + r=GetCandidateSharedResourceId(index, resourceId); + if(r==KErrNone) // Write the result to the client thread + *(TUint*)a2 = resourceId; + break; + } +#endif + + case RBusDevResManUs::EGetResourceControllerVersion: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetResourceControllerVersion")); + // a1 specifies the address of the TVersion variable to be written to + // a2 is not used + TUint version; + if((r=((DPowerResourceController*)iPddPtr)->GetInterface(ClientHandle(), + KResManControlIoGetVersion, + (TAny*)&version, + NULL, + NULL))!=KErrNone) + return r; + // Write the required information + *(TUint*)a1 = version; + break; + } + + case RBusDevResManUs::EGetNumDependentsForResource: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetNumDependentsForResource")); + // a1 specifies a pointer to the variable to be written to + // a2 specifies an array TUint parms[2] which contains: + // - the resource ID + // - flag to indicate if dependency information is to be loaded as part of this call + TUint *parms = (TUint*)a2; + TUint numDependents = 0; + r=((DPowerResourceController*)iPddPtr)->GetInterface(ClientHandle(), + KResManControlIoGetNumDependents, + (TAny*)(parms[0]), // Resource ID + &numDependents, + NULL); + iResDepsValid=EFalse; // The number of dependents may differ from the dependency information stored + if(r!=KErrNone) + return r; + + // Load the dependency information, if required. + if(parms[1]) + { + // The dependency information may be updated subsequent to the request for the number of dependents. In order + // to provide a coherent number and array of dependents, the requests for dependency information will be + // re-issued if the (new) number of dependents differs from that previously read. + TUint prevNumDeps = 0; + TUint newNumDeps = numDependents; + while((newNumDeps != prevNumDeps)&&(r == KErrNone)) + { + if((r=EnsureSizeIsSufficient(iResourceDependencyIds, (TInt)(newNumDeps*sizeof(SResourceDependencyInfo))))!=KErrNone) + return r; + prevNumDeps = newNumDeps; + if((r=((DPowerResourceController*)iPddPtr)->GetInterface(ClientHandle(), + KResManControlIoGetDependentsId, + (TAny*)(parms[0]), // Resource ID + (TAny*)(iResourceDependencyIds), + (TAny*)&newNumDeps))!=KErrNone) + return r; + }; + // Dependency information now in synch with number reported + numDependents = newNumDeps; + iNumResDepsStored = newNumDeps; + iResDepsValid = ETrue; + } + // Write the number of dependents to the client thread + *(TUint*)a1 = numDependents; + break; + } + + + case RBusDevResManUs::EGetDependentsIdForResource: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl case EGetDependentsIdForResource")); + // a1 specifies a pointer to the variable to hold the number of dependencies + // a2 specifies an array TUint parms[4] which contains: + // - the resource ID + // - the address of the array to write the required IDs to + // - flag to indicate if dependency information is to be (re-)loaded as part of this call + TUint *parms = (TUint*)a2; + TUint numDependents = 0; + + // (Re-)Load the dependency information, if required. + if(parms[2]) + { + if((r=((DPowerResourceController*)iPddPtr)->GetInterface(ClientHandle(), + KResManControlIoGetNumDependents, + (TAny*)(parms[0]), + (TAny*)&numDependents, + NULL))!=KErrNone) + return r; + + iResDepsValid=EFalse; // The number of dependents may differ from the dependency information stored + // In order to provide a coherent number and array of dependents, the requests for dependency information + // will be re-issued if the (new) number of dependents differs from that previously read. + TUint prevNumDeps = 0; + TUint newNumDeps = numDependents; + while(newNumDeps != prevNumDeps) + { + if((r=EnsureSizeIsSufficient(iResourceDependencyIds, (TInt)(newNumDeps*sizeof(SResourceDependencyInfo))))!=KErrNone) + return r; + prevNumDeps = newNumDeps; + if((r=((DPowerResourceController*)iPddPtr)->GetInterface(ClientHandle(), + KResManControlIoGetDependentsId, + (TAny*)(parms[0]), // Resource ID + (TAny*)(iResourceDependencyIds), + (TAny*)&newNumDeps))!=KErrNone) + return r; + }; + + // Dependency information now in synch with number reported + numDependents = newNumDeps; + iNumResDepsStored = newNumDeps; + iResDepsValid = ETrue; + } + + // If iResDepsValid equals zero, the results are invalid - so return KErrNotReady. + if(iResDepsValid==0) + return KErrNotReady; + + // Write the number of dependencies available to the client + *(TUint*)a1 = iNumResDepsStored; + // Write the dependencies to the client array if it is of sufficient size + // Copy the required dependency information to the user-supplied container. + parms[1] = (TUint)iResourceDependencyIds; + break; + } + + default: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::DoControl default 0x%x", aFunction)); + r=KErrNotSupported; + } + } + return(r); + } + + +TInt DChannelResManUs::EnsureSizeIsSufficient(HBuf*& aBuffer, TInt aMinSize) + { +// Utility function to ensure a buffer is of at least the minimum required size +// If the buffer is to small, an attempt is made to increase its size. +// If the re-sizing fails, KErrNoMemory is returned; otherwise KErrNone. + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::EnsureSizeIsSufficient")); + + if(aBuffer->MaxLength() < aMinSize) + { + aBuffer = aBuffer->ReAlloc(aMinSize); + if(aBuffer->MaxLength() < aMinSize) + return KErrNoMemory; // ReAlloc failed - aBuffer is unchanged + } + aBuffer->SetLength(0); + return KErrNone; + } + +void DChannelResManUs::FreeTrackingBuffer(TTrackingBuffer*& aBuffer) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DChannelResManUs::FreeTrackingBuffer")); + // Function invoked for to free tracking buffers from the busy to free queue of a tracking control + __ASSERT_ALWAYS((aBuffer!=NULL),RESMANUS_FAULT()); + NKern::FMWait(&iBufferFastMutex); + TTrackingControl* tracker = aBuffer->GetTrackingControl(); + SDblQue* bufQue = aBuffer->GetQue(); + + __ASSERT_ALWAYS(((tracker!=NULL)&&(bufQue!=NULL)),RESMANUS_FAULT()); + + // Check that the buffer is still in the busy queue of the tracker - exit if not + if(bufQue == tracker->iBusyQue) + { + aBuffer->Deque(); + tracker->iFreeQue->Add(aBuffer); + aBuffer->SetQue(tracker->iFreeQue); + } + NKern::FMSignal(&iBufferFastMutex); + } + + +TInt DChannelResManUs::GetAndInitTrackingBuffer(TTrackingControl*& aTracker, TTrackingBuffer*& aBuffer, TUint aResourceId, TRequestStatus* aStatus) + { +// Utility function - perform the necessary processing to get a buffer to support +// asynchronous requests to change the state of a resource + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::GetAndInitTrackingBuffer")); + TInt r=KErrNone; + NKern::FMWait(&iBufferFastMutex); + if(aTracker->iFreeQue->IsEmpty()) + r = KErrUnderflow; + else + { + // Need intermediate cast from SDblQueLink* to TAny* before TTrackingBuffer* + TAny* ptr = (TAny*)(aTracker->iFreeQue->GetFirst()); + aBuffer = (TTrackingBuffer*)ptr; + aTracker->iBusyQue->Add((SDblQueLink*)ptr); + aBuffer->SetQue(aTracker->iBusyQue); + aBuffer->SetResourceId(aResourceId); + TClientRequest* request; + TTrackingControl* tracker = aBuffer->GetTrackingControl(); + GET_USER_REQUEST(request, aBuffer, tracker->iType); + request->Reset(); + request->SetStatus(aStatus); + } + NKern::FMSignal(&iBufferFastMutex); + return r; + } + +TInt DChannelResManUs::GetStateBuffer(TTrackingControl*& aTracker, TTrackingBuffer*& aBuffer, TUint aResourceId, TInt* aState, TInt* aLevelOwnerPtr, TPowerResourceCb*& aCb, TRequestStatus* aStatus) + { +// Utility function - perform the necessary processing to get a buffer and control block +// to support asynchronous requests to change the state of a resource + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::GetStateBuffer")); + + TInt r=GetAndInitTrackingBuffer(aTracker, aBuffer, aResourceId, aStatus); + if(r==KErrNone) + { + TTrackGetStateBuf* stateBuf = (TTrackGetStateBuf*)aBuffer; + stateBuf->iRequest->SetDestPtr1(aState); + stateBuf->iRequest->SetDestPtr2(aLevelOwnerPtr); + // Use placement new to update the content of the TPowerResourceCb + aCb = &(stateBuf->iCtrlBlock); + new (aCb) TPowerResourceCb(&AsyncCallBackFn,(TAny*)aBuffer,iDfcQ,KResManCallBackPriority); + } + return r; + } + + +#ifdef _DUMP_TRACKERS +TInt DChannelResManUs::DumpTracker(TTrackingControl* aTracker) + { + Kern::Printf("\nDChannelResManUs::DumpTracker"); + Kern::Printf("Tracker at 0x%x\n",aTracker); + if(NULL==aTracker) + return KErrGeneral; + Kern::Printf("iType=%d",aTracker->iType); + switch(aTracker->iType) + { + case 0: + Kern::Printf("= GetState tracker\n"); + break; + case 1: + Kern::Printf("= SetState tracker\n"); + break; + case 2: + Kern::Printf("= Notify tracker\n"); + break; + } + Kern::Printf("iOwningChannel at 0x%x\n",aTracker->iOwningChannel); + Kern::Printf("iFreeQue at 0x%x\n",aTracker->iFreeQue); + SDblQueLink* buf; + if(aTracker->iFreeQue!=NULL) + { + buf=aTracker->iFreeQue->First(); + while(buf!=aTracker->iFreeQue->Last()) + { + Kern::Printf("iFreeQue buffer at 0x%x\n",buf); + TAny* intermediatePtr = (TAny*)buf; + if((aTracker->iType == EGetState)||(aTracker->iType == ESetState)) + { + TTrackStateBuf* tempBuf =(TTrackStateBuf*)intermediatePtr; + Kern::Printf("buffer control block at 0x%x\n",tempBuf->iCtrlBlock); + } + buf= buf->iNext; + }; + } + Kern::Printf("iBusyQue at 0x%x\n",aTracker->iBusyQue); + if(aTracker->iBusyQue!=NULL) + { + buf=aTracker->iBusyQue->First(); + while(buf!=aTracker->iBusyQue->Last()) + { + Kern::Printf("iBusyQue buffer at 0x%x\n",buf); + TAny* intermediatePtr = (TAny*)buf; + if((aTracker->iType == EGetState)||(aTracker->iType == ESetState)) + { + TTrackStateBuf* tempBuf =(TTrackStateBuf*)intermediatePtr; + Kern::Printf("buffer control block at 0x%x\n",tempBuf->iCtrlBlock); + } + buf= buf->iNext; + }; + } + + return KErrNone; + } +#endif + +TInt DChannelResManUs::InitTrackingControl(TTrackingControl*& aTracker, TUint8 aType, TUint8 aNumBuffers) + { +// Set the tracker type, create the tracking queues and required tracking buffers. +// Assign all the tracking buffers to the free queue. +// + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::InitTrackingControl()")); + + TInt r = KErrNone; + aTracker->iType = (TAsyncOpType)aType; + aTracker->iOwningChannel = this; + aTracker->iFreeQue = new SDblQue(); + __ASSERT_DEBUG(aTracker->iFreeQue != NULL, RESMANUS_FAULT()); + if(aTracker->iFreeQue == NULL) + r = KErrNoMemory; + if(r==KErrNone) + { + aTracker->iBusyQue = new SDblQue(); + __ASSERT_DEBUG(aTracker->iBusyQue != NULL, RESMANUS_FAULT()); + if(aTracker->iBusyQue == NULL) + { + delete aTracker->iFreeQue; + r = KErrNoMemory; + } + } + if(r==KErrNone) + { + for(TUint8 i=0; (iiType) + { + case EGetState: + { + buf = (TAny*)(new TTrackGetStateBuf(&AsyncCallBackFn,ptr,iDfcQ,KResManCallBackPriority)); + r = Kern::CreateClientDataRequest2(((TTrackGetStateBuf*)buf)->iRequest); + break; + } + case ESetState: + { + buf = (TAny*)(new TTrackSetStateBuf(&AsyncCallBackFn, ptr, iDfcQ, KResManCallBackPriority)); + r = Kern::CreateClientRequest(((TTrackSetStateBuf*)buf)->iRequest); + break; + } + case ENotify: + { + buf = (TAny*)(new TTrackNotifyBuf(&AsyncCallBackFn,ptr,iDfcQ,KResManCallBackPriority)); + r = Kern::CreateClientRequest(((TTrackNotifyBuf*)buf)->iRequest); + break; + } + default: + __ASSERT_ALWAYS(0,RESMANUS_FAULT()); + } + __ASSERT_DEBUG(buf!=NULL, RESMANUS_FAULT()); + if((buf == NULL) || (r == KErrNoMemory)) + { + r = KErrNoMemory; + break; + } + else + { + ((TTrackingBuffer*)buf)->SetTrackingControl(aTracker); + (aTracker->iFreeQue)->Add((SDblQueLink*)buf); + ((TTrackingBuffer*)buf)->SetQue(aTracker->iFreeQue); + } + } + // If buffer allocation failed, need to remove all previously-allocated buffers and the queues + if(r!=KErrNone) + { + SDblQueLink* ptr = (aTracker->iFreeQue)->First(); + do + { + SDblQueLink* next = NULL; + if(ptr !=NULL) + next = ptr->iNext; + delete ptr; + ptr = next; + } while ((ptr!=NULL)&&(ptr!=(aTracker->iFreeQue)->Last())); + delete aTracker->iFreeQue; + delete aTracker->iBusyQue; + } + } + return r; + } + + +void DChannelResManUs::RemoveTrackingControl(TTrackingControl*& aTracker) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DChannelResManUs::RemoveTrackingControl()")); + + // Free the resource-tracking links and their respective queues + TAny* buf; + if(aTracker->iFreeQue!=NULL) + { + while(!aTracker->iFreeQue->IsEmpty()) + { + buf = (TAny*)(aTracker->iFreeQue->GetFirst()); // Dequeues the element + delete buf; + } + delete aTracker->iFreeQue; + } + + if(aTracker->iBusyQue!=NULL) + { + while(!aTracker->iBusyQue->IsEmpty()) + { + buf = (TAny*)(aTracker->iBusyQue->GetFirst()); // Dequeues the element + delete buf; + } + delete aTracker->iBusyQue; + } + delete aTracker; + } + + +#ifdef RESOURCE_MANAGER_SIMULATED_PSL +void DChannelResManUs::CheckForCandidateAsyncResource(TPowerResourceInfoV01* aResource) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::CheckForCandidateAsyncResource")); + // Proceed only if we already have less that the maximum number of candidate resources + if(iNoCandidateAsyncRes >= MAX_NUM_CANDIDATE_RESOURCES) + return; + // For the purposes of asynchronous testing, we need a long latency resource + if(((TInt)(aResource->iLatencyGet)==(TInt)(EResLongLatency)) && + ((TInt)(aResource->iLatencySet)==(TInt)(EResLongLatency))) + { + // An additional requirement is that the level of the resource can be + // updated a sufficient amount of times to support the required testing. + if(((aResource->iMaxLevel - aResource->iMinLevel) > LEVEL_GAP_REQUIRED_FOR_ASYNC_TESTING) && + ((TInt)(aResource->iSense) == (TInt)(EResPositive)) ) + { + TInt r=((DPowerResourceController*)iPddPtr)->GetResourceId(ClientHandle(), *(aResource->iResourceName), iCandidateAsyncResIds[iNoCandidateAsyncRes]); + if(r!=KErrNone) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Failed to identify long latency resource\n")); + } + else + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Potential async resource ID = %d\n",iCandidateAsyncResIds[iNoCandidateAsyncRes])); + iHaveLongLatencyResource = ETrue; + ++iNoCandidateAsyncRes; + } + } + } + } + + +void DChannelResManUs::GetNumCandidateAsyncResources(TUint& aNumResources) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::GetNumCandidateAsyncResources")); + + aNumResources = iNoCandidateAsyncRes; + } + +TInt DChannelResManUs::GetCandidateAsyncResourceId(TUint aIndex, TUint& aResourceId) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::GetCandidateAsyncResourceId")); + TInt r = KErrNone; + if(aIndex>=iNoCandidateAsyncRes) + r = KErrNotFound; + else + aResourceId = iCandidateAsyncResIds[aIndex]; + return r; + } + +void DChannelResManUs::CheckForCandidateSharedResource(TPowerResourceInfoV01* aResource) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::CheckForCandidateSharedResource")); + + // Proceed only if we already have less that the maximum number of candidate resources + if(iNoCandidateSharedRes >= MAX_NUM_CANDIDATE_RESOURCES) + return; + + // For the purposes of testing shared usgae of resources, we need a shareable resource + if((TInt)(aResource->iUsage)==(TInt)(EResShared)) + { + // An additional requirement is that the level of the resource can be + // updated a sufficient amount of times to support the required testing. + if(((aResource->iMaxLevel - aResource->iMinLevel) > LEVEL_GAP_REQUIRED_FOR_SHARED_TESTING) && + ((TInt)(aResource->iSense) == (TInt)(EResPositive)) ) + { + TInt r=((DPowerResourceController*)iPddPtr)->GetResourceId(ClientHandle(), *(aResource->iResourceName), iCandidateSharedResIds[iNoCandidateSharedRes]); + if(r!=KErrNone) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Failed to identify shared resource\n")); + } + else + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Potential shared resource ID = %d\n",iCandidateSharedResIds[iNoCandidateAsyncRes])); + iHaveLongLatencyResource = ETrue; + ++iNoCandidateSharedRes; + } + } + } + } + +void DChannelResManUs::GetNumCandidateSharedResources(TUint& aNumResources) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::GetNumCandidateSharedResources")); + + aNumResources = iNoCandidateSharedRes; + } + +TInt DChannelResManUs::GetCandidateSharedResourceId(TUint aIndex, TUint& aResourceId) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::GetCandidateSharedResourceId")); + TInt r = KErrNone; + if(aIndex>=iNoCandidateSharedRes) + r = KErrNotFound; + else + aResourceId = iCandidateSharedResIds[aIndex]; + return r; + } + +#endif + +TInt DChannelResManUs::ExtractResourceInfo(const TPowerResourceInfoV01* aPwrResInfo, TResourceInfoBuf& aInfo) + { +// Extract data from a TPowerResourceInfoV01 object to a TResourceInfo instance + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::ExtractResourceInfo")); + + TInt r=KErrNone; + TInt copyLength=(((aInfo().iName).MaxLength())<((aPwrResInfo->iResourceName)->Length()))? + (aInfo().iName).MaxLength(): + (aPwrResInfo->iResourceName)->Length(); + (aInfo().iName).Copy((aPwrResInfo->iResourceName)->Ptr(),copyLength); + aInfo().iId = aPwrResInfo->iResourceId; + aInfo().iClass = (TResourceClass)aPwrResInfo->iClass; + aInfo().iType = (TResourceType)aPwrResInfo->iType; + aInfo().iUsage = (TResourceUsage)aPwrResInfo->iUsage; + aInfo().iSense = (TResourceSense)aPwrResInfo->iSense; + aInfo().iMinLevel = aPwrResInfo->iMinLevel; + aInfo().iMaxLevel = aPwrResInfo->iMaxLevel; + +#ifdef _DUMP_TRACKERS + r=DumpResource(aPwrResInfo); +#endif + return r; + } + +#ifdef _DUMP_TRACKERS +TInt DChannelResManUs::DumpResource(const TPowerResourceInfoV01* aResource) + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelResManUs::DumpResource")); + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Resource name = %S \n",aResource->iResourceName)); + __KTRACE_OPT(KRESMANAGER, Kern::Printf("Resource ID = 0x%d \n",aResource->iResourceId)); + switch(aResource->iClass) + { + case DStaticPowerResource::EPhysical: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("class = EPhysical\n")); + break; + } + case DStaticPowerResource::ELogical: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("class = ELogical\n")); + break; + } + default: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("class = % is UNKNOWN!\n")); + return KErrGeneral; + } + } + switch(aResource->iType) + { + case DStaticPowerResource::EBinary: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("type = EBinary\n")); + break; + } + case DStaticPowerResource::EMultilevel: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("type = EMultilevel\n")); + break; + } + case DStaticPowerResource::EMultiProperty: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("type = EMultiProperty\n")); + break; + } + default: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("type = % is UNKNOWN!\n")); + return KErrGeneral; + } + } + switch(aResource->iUsage) + { + case DStaticPowerResource::ESingleUse: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("usage = ESingleUse\n")); + break; + } + case DStaticPowerResource::EShared: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("usage = EShared\n")); + break; + } + default: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("usage = % is UNKNOWN!\n")); + return KErrGeneral; + } + } + switch(aResource->iSense) + { + case DStaticPowerResource::EPositive: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("sense = EPositive\n")); + break; + } + case DStaticPowerResource::ENegative: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("sense = ENegative\n")); + break; + } + case DStaticPowerResource::ECustom: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("sense = ECustom\n")); + break; + } + default: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("sense = % is UNKNOWN!\n")); + return KErrGeneral; + } + } + switch(aResource->iLatencyGet) + { + case DStaticPowerResource::EInstantaneous: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("latency get = EInstantaneous\n")); + break; + } + case DStaticPowerResource::ENegative: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("latency get = ELongLatency\n")); + break; + } + default: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("latency get = % is UNKNOWN!\n")); + return KErrGeneral; + } + } + switch(aResource->iLatencySet) + { + case DStaticPowerResource::EInstantaneous: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("latency set = EInstantaneous\n")); + break; + } + case DStaticPowerResource::ENegative: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("latency set = ELongLatency\n")); + break; + } + default: + { + __KTRACE_OPT(KRESMANAGER, Kern::Printf("latency set = % is UNKNOWN!\n")); + return KErrGeneral; + } + } + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DefaultLevel = %d\n",aResource->iDefaultLevel)); + __KTRACE_OPT(KRESMANAGER, Kern::Printf("MinLevel = %d\n",aResource->iMinLevel)); + __KTRACE_OPT(KRESMANAGER, Kern::Printf("MaxLevel = %d\n",aResource->iMaxLevel)); + + return KErrNone; + } +#endif + +#ifndef RESOURCE_MANAGER_SIMULATED_PSL +DECLARE_EXTENSION_LDD() + { + return new DDeviceResManUs; + } + + +DECLARE_STANDARD_EXTENSION() + { + DDeviceResManUs* device = new DDeviceResManUs; + __KTRACE_OPT(KBOOT, Kern::Printf("DECLARE_STANDARD_EXTENSION, device = 0x%x\n",device)); + + if(device == NULL) + return KErrNoMemory; + else + { + device->iSharedDfcQue = new TDfcQue(); + if(device->iSharedDfcQue==NULL) + return KErrNoMemory; + + return (Kern::InstallLogicalDevice(device)); + } + } +#else +DECLARE_STANDARD_LDD() + { + TInt r = DSimulatedPowerResourceController::CompleteResourceControllerInitialisation(); + if(r != KErrNone) + { + // Unconditionally print message + __KTRACE_OPT(KRESMANAGER, Kern::Printf("DECLARE_STANDARD_LDD: initialise Resource Controller failed with %d\n",r)); + return NULL; + } + DDeviceResManUs* device = new DDeviceResManUs; + return device; + } +#endif