|
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\drivers\resourceman\resourcecontrol.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <drivers/resourcecontrol.h> |
|
19 #include <drivers/resourcecontrol_trace.h> |
|
20 #ifdef DEBUG_VERSION |
|
21 #define GET_CRITICAL_SECTION_COUNT \ |
|
22 DThread& thread = Kern::CurrentThread(); \ |
|
23 TInt CsCount = thread.iNThread.iCsCount; |
|
24 |
|
25 #define LOCK_AND_CRITICAL_SECTION_COUNT_CHECK \ |
|
26 if(thread.iNThread.iCsCount != CsCount) \ |
|
27 Kern::Fault("PowerResourceController CScount", __LINE__); \ |
|
28 if(PowerResourceController->iResourceMutex->iHoldCount != 0) \ |
|
29 Kern::Fault("PowerResourceController HoldCount", __LINE__); |
|
30 #else |
|
31 #define GET_CRITICAL_SECTION_COUNT |
|
32 #define LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
33 #endif |
|
34 |
|
35 /** Allow interface class to call this. */ |
|
36 DPowerResourceController* PowerResourceController = NULL; |
|
37 |
|
38 /** Resource Controller factory class implementation */ |
|
39 #ifdef RESOURCE_MANAGER_SIMULATED_PSL |
|
40 #ifndef PRM_ENABLE_EXTENDED_VERSION |
|
41 _LIT(KPddName,"resourcecontroller.pdd"); |
|
42 #else |
|
43 _LIT(KPddName, "resourcecontrollerextended.pdd"); |
|
44 #endif |
|
45 #else |
|
46 #ifndef PRM_ENABLE_EXTENDED_VERSION |
|
47 _LIT(KPddName, "resman.pdd"); |
|
48 #else |
|
49 _LIT(KPddName, "resmanextended.pdd"); |
|
50 #endif |
|
51 #endif |
|
52 |
|
53 /** Factory class constructor */ |
|
54 DResConPddFactory::DResConPddFactory() |
|
55 { |
|
56 //Set Version number |
|
57 iVersion = DResConPddFactory::VersionRequired(); |
|
58 } |
|
59 |
|
60 TInt DResConPddFactory::Install() |
|
61 { |
|
62 // Set a Name for Resource Controller Factory class object. |
|
63 return(SetName(&KPddName)); |
|
64 } |
|
65 |
|
66 /** Called by the kernel's device driver framework to create a Physical Channel. */ |
|
67 TInt DResConPddFactory::Create(DBase*& aChannel, TInt /*aUint*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/) |
|
68 { |
|
69 //Create new interface for each channel. |
|
70 DUserSideProxyInterface *pI = new (DUserSideProxyInterface); |
|
71 if(!pI) |
|
72 return KErrNoMemory; |
|
73 pI->iController = PowerResourceController; //Store the resource controller. |
|
74 aChannel = (DBase*)pI; |
|
75 return KErrNone; |
|
76 } |
|
77 |
|
78 /** Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.*/ |
|
79 TInt DResConPddFactory::Validate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer) |
|
80 { |
|
81 if (!Kern::QueryVersionSupported(DResConPddFactory::VersionRequired(),aVer)) |
|
82 return(KErrNotSupported); |
|
83 return KErrNone; |
|
84 } |
|
85 |
|
86 /** Return the driver capabilities */ |
|
87 void DResConPddFactory::GetCaps(TDes8& aDes) const |
|
88 { |
|
89 // Create a capabilities object |
|
90 TCaps caps; |
|
91 caps.iVersion = iVersion; |
|
92 // Zero the buffer |
|
93 TInt maxLen = aDes.MaxLength(); |
|
94 aDes.FillZ(maxLen); |
|
95 // Copy cpabilities |
|
96 TInt size=sizeof(caps); |
|
97 if(size>maxLen) |
|
98 size=maxLen; |
|
99 aDes.Copy((TUint8*)&caps,size); |
|
100 } |
|
101 |
|
102 /** Entry point for a standard physical device driver (PDD) that is also an extension */ |
|
103 #ifndef RESOURCE_MANAGER_SIMULATED_PSL |
|
104 DECLARE_EXTENSION_PDD() |
|
105 { |
|
106 return new DResConPddFactory; |
|
107 } |
|
108 #endif |
|
109 |
|
110 /** Interface class implementation */ |
|
111 TInt TInterface::RegisterClient(TUint& aClientId, const TDesC8& aName, TOwnerType aType) |
|
112 { |
|
113 GET_CRITICAL_SECTION_COUNT |
|
114 TInt r; |
|
115 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::RegisterClient")); |
|
116 r = PowerResourceController->RegisterClient(aClientId, aName, aType); |
|
117 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
118 return r; |
|
119 } |
|
120 |
|
121 TInt TInterface::DeRegisterClient(TUint aClientId) |
|
122 { |
|
123 GET_CRITICAL_SECTION_COUNT |
|
124 TInt r; |
|
125 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::DeRegisterClient")); |
|
126 r = PowerResourceController->DeRegisterClient(aClientId); |
|
127 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
128 return r; |
|
129 } |
|
130 |
|
131 TInt TInterface::GetClientName(TUint aClientId, TUint aTargetClientId, TDes8& aName) |
|
132 { |
|
133 GET_CRITICAL_SECTION_COUNT |
|
134 TInt r; |
|
135 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetClientName")); |
|
136 r = PowerResourceController->GetClientName(aClientId, aTargetClientId, aName); |
|
137 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
138 return r; |
|
139 } |
|
140 |
|
141 TInt TInterface::GetClientId(TUint aClientId, TDesC8& aClientName, TUint& aTargetClientId) |
|
142 { |
|
143 GET_CRITICAL_SECTION_COUNT |
|
144 TInt r; |
|
145 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetClientId")); |
|
146 r = PowerResourceController->GetClientId(aClientId, aClientName, aTargetClientId); |
|
147 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
148 return r; |
|
149 } |
|
150 |
|
151 TInt TInterface::GetResourceId(TUint aClientId, TDesC8& aResourceName, TUint& aResourceId) |
|
152 { |
|
153 GET_CRITICAL_SECTION_COUNT |
|
154 TInt r; |
|
155 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetResourceId")); |
|
156 r = PowerResourceController->GetResourceId(aClientId, aResourceName, aResourceId); |
|
157 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
158 return r; |
|
159 } |
|
160 |
|
161 TInt TInterface::GetResourceInfo(TUint aClientId, TUint aResourceId, TAny* aInfo) |
|
162 { |
|
163 GET_CRITICAL_SECTION_COUNT |
|
164 TInt r; |
|
165 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetResourceInfo")); |
|
166 r = PowerResourceController->GetResourceInfo(aClientId, aResourceId, aInfo); |
|
167 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
168 return r; |
|
169 } |
|
170 |
|
171 TInt TInterface::GetNumResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, TUint& aNumResource) |
|
172 { |
|
173 GET_CRITICAL_SECTION_COUNT |
|
174 TInt r; |
|
175 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetNumResourcesInUseByClient")); |
|
176 r = PowerResourceController->GetNumResourcesInUseByClient(aClientId, aTargetClientId, aNumResource); |
|
177 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
178 return r; |
|
179 } |
|
180 |
|
181 TInt TInterface::GetInfoOnResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, TUint& aNumResources, TAny* aInfo) |
|
182 { |
|
183 GET_CRITICAL_SECTION_COUNT |
|
184 TInt r; |
|
185 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetInfoOnResourcesInUseByClient")); |
|
186 r = PowerResourceController->GetInfoOnResourcesInUseByClient(aClientId, aTargetClientId, aNumResources, aInfo); |
|
187 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
188 return r; |
|
189 } |
|
190 |
|
191 TInt TInterface::GetNumClientsUsingResource(TUint aClientId, TUint aResourceId, TUint& aNumClients) |
|
192 { |
|
193 GET_CRITICAL_SECTION_COUNT |
|
194 TInt r; |
|
195 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetNumClientsUsingResource")); |
|
196 r = PowerResourceController->GetNumClientsUsingResource(aClientId, aResourceId, aNumClients); |
|
197 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
198 return r; |
|
199 } |
|
200 |
|
201 TInt TInterface::GetInfoOnClientsUsingResource(TUint aClientId, TUint aResourceId, TUint& aNumClients, TAny* aInfo) |
|
202 { |
|
203 GET_CRITICAL_SECTION_COUNT |
|
204 TInt r; |
|
205 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetInfoOnClientsUsingResource")); |
|
206 r = PowerResourceController->GetInfoOnClientsUsingResource(aClientId, aResourceId, aNumClients, aInfo); |
|
207 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
208 return r; |
|
209 } |
|
210 |
|
211 TInt TInterface::ChangeResourceState(TUint aClientId, TUint aResourceId, TInt aNewState, TPowerResourceCb* aCb) |
|
212 { |
|
213 GET_CRITICAL_SECTION_COUNT |
|
214 TInt r; |
|
215 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::ChangeResourceState")); |
|
216 r = PowerResourceController->ChangeResourceState(aClientId, aResourceId, aNewState, aCb); |
|
217 if(!aCb) //Not checking incase of asynchronous function as mutex might be held in RC thread, when this is checked. |
|
218 { |
|
219 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
220 } |
|
221 return r; |
|
222 } |
|
223 |
|
224 TInt TInterface::GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TInt& aState, TInt& aLevelOwnerId) |
|
225 { |
|
226 GET_CRITICAL_SECTION_COUNT |
|
227 TInt r; |
|
228 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetResourceState")); |
|
229 r = PowerResourceController->GetResourceState(aClientId, aResourceId, aCached, aState, aLevelOwnerId); |
|
230 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
231 return r; |
|
232 } |
|
233 |
|
234 TInt TInterface::GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TPowerResourceCb& aCb) |
|
235 { |
|
236 GET_CRITICAL_SECTION_COUNT |
|
237 TInt r; |
|
238 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetResourceState")); |
|
239 r = PowerResourceController->GetResourceState(aClientId, aResourceId, aCached, aCb); |
|
240 if(!&aCb) //Not checking incase of asynchronous function as mutex might be held in RC thread, when this is checked. |
|
241 { |
|
242 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
243 } |
|
244 return r; |
|
245 } |
|
246 |
|
247 TInt TInterface::CancelAsyncRequestCallBack(TUint aClientId, TUint aResourceId, TPowerResourceCb& aCb) |
|
248 { |
|
249 GET_CRITICAL_SECTION_COUNT |
|
250 TInt r; |
|
251 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::CancelAsyncRequestCallback")); |
|
252 r = PowerResourceController->CancelAsyncRequestCallBack(aClientId, aResourceId, aCb); |
|
253 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
254 return r; |
|
255 } |
|
256 |
|
257 TInt TInterface::RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN) |
|
258 { |
|
259 GET_CRITICAL_SECTION_COUNT |
|
260 TInt r; |
|
261 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::RequestNotification")); |
|
262 r = PowerResourceController->RequestNotification(aClientId, aResourceId, aN); |
|
263 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
264 return r; |
|
265 } |
|
266 |
|
267 TInt TInterface::RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN, TInt aThreshold, |
|
268 TBool aDirection) |
|
269 { |
|
270 GET_CRITICAL_SECTION_COUNT |
|
271 TInt r; |
|
272 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::RequestNotification")); |
|
273 r = PowerResourceController->RequestNotification(aClientId, aResourceId, aN, aThreshold, aDirection); |
|
274 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
275 return r; |
|
276 } |
|
277 |
|
278 TInt TInterface::CancelNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN) |
|
279 { |
|
280 GET_CRITICAL_SECTION_COUNT |
|
281 TInt r; |
|
282 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::CancelNotification")); |
|
283 r = PowerResourceController->CancelNotification(aClientId, aResourceId, aN); |
|
284 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
285 return r; |
|
286 } |
|
287 |
|
288 TInt TInterface::DeRegisterClientLevelFromResource(TUint aClientId, TUint aResourceId) |
|
289 { |
|
290 GET_CRITICAL_SECTION_COUNT |
|
291 TInt r; |
|
292 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::DeRegisterClientLevelFromResource")); |
|
293 r = PowerResourceController->DeRegisterClientLevelFromResource(aClientId, aResourceId); |
|
294 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
295 return r; |
|
296 } |
|
297 |
|
298 TInt TInterface::AllocReserve(TUint aClientId, TUint8 aNumCl, TUint8 aNumRm) |
|
299 { |
|
300 GET_CRITICAL_SECTION_COUNT |
|
301 TInt r; |
|
302 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::AllocReserve")); |
|
303 r = PowerResourceController->AllocReserve(aClientId, aNumCl, aNumRm); |
|
304 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
305 return r; |
|
306 } |
|
307 |
|
308 /** This function is used by export functions of Resource contoller defined in seperate file */ |
|
309 DPowerResourceController* TInterface::GetPowerResourceController(void) |
|
310 { |
|
311 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::GetPowerResourceController")); |
|
312 return PowerResourceController; |
|
313 } |
|
314 |
|
315 TInt TInterface::ControlIO(TUint aClientId, TUint aFunction, TAny* aParam1, TAny* aParam2, TAny* aParam3) |
|
316 { |
|
317 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">TInterface::ControlIO")); |
|
318 return PowerResourceController->GetInterface(aClientId, aFunction, aParam1, aParam2, aParam3); |
|
319 } |
|
320 |
|
321 /** Resouce controller panic */ |
|
322 void DPowerResourceController::Panic(TUint8 aPanic) |
|
323 { |
|
324 Kern::Fault("Power Resource Controller", aPanic); |
|
325 } |
|
326 |
|
327 /** Constructor for power controller. Creates message queue and generates ID for power controller to use. */ |
|
328 DPowerResourceController::DPowerResourceController() |
|
329 { |
|
330 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::DPowerResouceController()")); |
|
331 //Constructor is expected to invoke multiple times (during creation, variant init 0 and extension init 1) |
|
332 if(PowerResourceController) |
|
333 return; |
|
334 PowerResourceController = this; |
|
335 iClientList.Initialise(0); |
|
336 iUserSideClientList.Initialise(0); |
|
337 iInitialised = EResConCreated; |
|
338 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
339 iDynamicResourceList.Initialise(0); |
|
340 iDynamicResDependencyList.Initialise(0); |
|
341 #endif |
|
342 } |
|
343 |
|
344 /** Destructor for power controller. Frees the memory allocated in kernel heap. */ |
|
345 DPowerResourceController::~DPowerResourceController() |
|
346 { |
|
347 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::~DPowerResourceController()")); |
|
348 //Push Power controller ID back to Pool |
|
349 SPowerResourceClient* pC = NULL; |
|
350 pC = iClientList[(TUint16)(iPowerControllerId & ID_INDEX_BIT_MASK)]; |
|
351 if(pC) |
|
352 { |
|
353 iClientCount--; //Decrement client count |
|
354 LIST_PUSH(iClientPool, pC, iNextInList); |
|
355 } |
|
356 iClientList.Delete(); |
|
357 iUserSideClientList.Delete(); |
|
358 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
359 iDynamicResourceList.Delete(); |
|
360 iDynamicResDependencyList.Delete(); |
|
361 #endif |
|
362 pC = iClientPool; |
|
363 while(iClientPool) //Find the starting position of array to delete |
|
364 { |
|
365 if(iClientPool < pC) |
|
366 pC = iClientPool; |
|
367 iClientPool = iClientPool->iNextInList; |
|
368 } |
|
369 //delete pC; |
|
370 delete []pC; |
|
371 SPowerResourceClientLevel *pCL = iClientLevelPool; |
|
372 while(iClientLevelPool) //Find the starting position of array to delete |
|
373 { |
|
374 if(iClientLevelPool < pCL) |
|
375 pCL = iClientLevelPool; |
|
376 iClientLevelPool = iClientLevelPool->iNextInList; |
|
377 } |
|
378 //delete pCL; |
|
379 delete []pCL; |
|
380 SPowerRequest *pReq = iRequestPool; |
|
381 while(iRequestPool) //Find the starting position of array to delete |
|
382 { |
|
383 if(iRequestPool < pReq) |
|
384 pReq = iRequestPool; |
|
385 iRequestPool = iRequestPool->iNext; |
|
386 } |
|
387 //delete pR |
|
388 delete []pReq; |
|
389 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
390 pCL = iResourceLevelPool; |
|
391 while(iResourceLevelPool) |
|
392 { |
|
393 if(iResourceLevelPool < pCL) |
|
394 pCL = iResourceLevelPool; |
|
395 iResourceLevelPool = iResourceLevelPool->iNextInList; |
|
396 } |
|
397 //delete resource pool |
|
398 delete []pCL; |
|
399 //delete Message Queue dependency |
|
400 delete iMsgQDependency; |
|
401 #endif |
|
402 //delete Message Queue |
|
403 delete iMsgQ; |
|
404 } |
|
405 |
|
406 /** Send notificatins to clients registered for it for the specified resource. */ |
|
407 void DPowerResourceController::CompleteNotifications(TInt aClientId, DStaticPowerResource* aResource, TInt aState, |
|
408 TInt aReturnCode, TInt aLevelOwnerId, TBool aLock) |
|
409 { |
|
410 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::CompleteNotifications")); |
|
411 if(aLock) |
|
412 Lock(); |
|
413 DPowerResourceNotification*pN=NULL; |
|
414 for(SDblQueLink* pNL=aResource->iNotificationList.First();pNL!=&aResource->iNotificationList.iA; pNL=pNL->iNext) |
|
415 { |
|
416 pN = _LOFF(pNL, DPowerResourceNotification, iNotificationLink); |
|
417 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
418 //If dyanmic resource is deregistering, send notification to all clients requested for it |
|
419 if((pN->iCallback.iResourceId & KIdMaskDynamic) && (aClientId == KDynamicResourceDeRegistering)) |
|
420 { |
|
421 pN->iCallback.iResult = aReturnCode; |
|
422 pN->iCallback.iLevel = aState; |
|
423 pN->iCallback.iClientId = aClientId; |
|
424 pN->iCallback.iLevelOwnerId = aLevelOwnerId; |
|
425 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Notification ClientId = 0x%x, ResourceId = %d, state = %d, \ |
|
426 Result = %d", pN->iCallback.iClientId, pN->iCallback.iResourceId, aState, aReturnCode)); |
|
427 PRM_POSTNOTIFICATION_SENT_TRACE |
|
428 pN->iCallback.Enque(); |
|
429 continue; |
|
430 } |
|
431 #endif |
|
432 if((pN->iType==DPowerResourceNotification::EUnconditional) || |
|
433 (pN->iDirection && ((pN->iPreviousLevel < pN->iThreshold) && (aState >= pN->iThreshold))) || |
|
434 (!pN->iDirection && ((pN->iPreviousLevel > pN->iThreshold) && (aState <= pN->iThreshold)))) |
|
435 { |
|
436 pN->iCallback.iResult=aReturnCode; |
|
437 pN->iCallback.iLevel=aState; |
|
438 pN->iCallback.iClientId = aClientId; |
|
439 pN->iCallback.iLevelOwnerId = aLevelOwnerId; |
|
440 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Notifications ClientId = 0x%x, ResourceId = %d, State = %d, \ |
|
441 Result = %d", pN->iCallback.iClientId, pN->iCallback.iResourceId, aState, aReturnCode)); |
|
442 PRM_POSTNOTIFICATION_SENT_TRACE |
|
443 pN->iCallback.Enque(); |
|
444 } |
|
445 pN->iPreviousLevel = aState; //Update the state |
|
446 } |
|
447 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::CompleteNotifications")); |
|
448 if(aLock) |
|
449 UnLock(); |
|
450 return; |
|
451 } |
|
452 |
|
453 /** Complete the asynchronous request. */ |
|
454 void DPowerResourceController::CompleteRequest(TPowerRequest& aRequest) |
|
455 { |
|
456 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::CompleteRequest")); |
|
457 // Complete notification for state change operation |
|
458 DStaticPowerResource* pR=aRequest.Resource(); |
|
459 //If request in EChange or ESetDefaultValue and no error and if shared resources and if change is done then |
|
460 //issue notification. |
|
461 if(((aRequest.ReqType() == TPowerRequest::EChange) || (aRequest.ReqType() == TPowerRequest::ESetDefaultLevel)) |
|
462 && (aRequest.ReturnCode() == KErrNone) && ((!pR->Usage()) || (pR->Usage() && aRequest.RequiresChange()))) |
|
463 { |
|
464 CompleteNotifications(aRequest.ClientId(), aRequest.Resource(), aRequest.Level(), |
|
465 aRequest.ReturnCode(), aRequest.ClientId()); |
|
466 } |
|
467 //Do not update the level if the resource is shared and change is not required or any error. |
|
468 if(aRequest.ReturnCode()==KErrNone && ((aRequest.ReqType() ==TPowerRequest::EGet) || |
|
469 (((aRequest.ReqType()==TPowerRequest::EChange) || (aRequest.ReqType()==TPowerRequest::ESetDefaultLevel)) |
|
470 && ((!pR->Usage()) || (pR->Usage() && aRequest.RequiresChange()))))) |
|
471 { |
|
472 Lock(); |
|
473 // Cache the latest value |
|
474 pR->iCachedLevel=aRequest.Level(); |
|
475 //Need to update client ID only during state change. |
|
476 if(aRequest.ReqType() != TPowerRequest::EGet) |
|
477 pR->iLevelOwnerId=aRequest.ClientId(); |
|
478 // Cache Idle list entry for this reosurce if requested. |
|
479 if(pR->iIdleListEntry) |
|
480 { |
|
481 SIdleResourceInfo* pI=pR->iIdleListEntry; |
|
482 if(aRequest.ReqType() != TPowerRequest::EGet) |
|
483 pI->iLevelOwnerId= aRequest.ClientId(); |
|
484 pI->iCurrentLevel=aRequest.Level(); |
|
485 } |
|
486 UnLock(); |
|
487 } |
|
488 |
|
489 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::CompleteRequest")); |
|
490 } |
|
491 |
|
492 /** Handle/process the asynchronous request sent to resource controller. |
|
493 The request can be one of the following |
|
494 1) State change of long latency reosurce |
|
495 2) Get the state of long latency resource |
|
496 3) Set the default value of long latency resource */ |
|
497 void DPowerResourceController::HandleMsg(TPowerRequest& aRequest) |
|
498 { |
|
499 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::HandleMsg")); |
|
500 DStaticPowerResource* pR=aRequest.Resource(); |
|
501 //Get client using client ID |
|
502 TUint aClientId = aRequest.ClientId(); |
|
503 SPowerResourceClient* pC = NULL; |
|
504 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
505 if((TInt)aClientId != KDynamicResourceDeRegistering) |
|
506 { |
|
507 if(aClientId & USER_SIDE_CLIENT_BIT_MASK) |
|
508 pC = iUserSideClientList[TUint16(aClientId & ID_INDEX_BIT_MASK)]; |
|
509 else |
|
510 pC = iClientList[TUint16(aClientId & ID_INDEX_BIT_MASK)]; |
|
511 } |
|
512 #else |
|
513 if(aClientId & USER_SIDE_CLIENT_BIT_MASK) |
|
514 pC = iUserSideClientList[TUint16(aClientId & ID_INDEX_BIT_MASK)]; |
|
515 else |
|
516 pC = iClientList[TUint16(aClientId & ID_INDEX_BIT_MASK)]; |
|
517 #endif |
|
518 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Request Type = %d, ClientId = 0x%x, ResourceId = %d", \ |
|
519 aRequest.ReqType(), aRequest.ClientId(), aRequest.ResourceId())); |
|
520 if(aRequest.ReqType()==TPowerRequest::EChange) |
|
521 { |
|
522 if(pR->Usage()) //Handling shared resource |
|
523 { |
|
524 Lock(); //To avoid race condition between deregister resource level. |
|
525 aRequest.ReturnCode() = CheckLevelAndAddClient(pC, &aRequest); |
|
526 UnLock(); |
|
527 if((aRequest.ReturnCode()!= KErrNone) || (!aRequest.RequiresChange())) |
|
528 { |
|
529 aRequest.Level() = pR->iCachedLevel; //If no change then send the current level back. |
|
530 CompleteRequest(aRequest); |
|
531 return; |
|
532 } |
|
533 } |
|
534 else if(pR->iLevelOwnerId ==-1) //No existing client. |
|
535 { |
|
536 // Add client Level |
|
537 if(pC->iReservedCl==0 && !iClientLevelPoolCount) |
|
538 { |
|
539 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Reserved Client Level exhausted and its free pool empty")); |
|
540 aRequest.ReturnCode() = KErrUnderflow; |
|
541 CompleteRequest(aRequest); |
|
542 return; |
|
543 } |
|
544 SPowerResourceClientLevel* pSCL=NULL; |
|
545 LIST_POP(iClientLevelPool, pSCL, iNextInList); |
|
546 pSCL->iClientId=aClientId; |
|
547 pSCL->iResourceId=aRequest.ResourceId(); |
|
548 pSCL->iLevel=aRequest.Level(); |
|
549 LIST_PUSH(pC->iLevelList, pSCL, iNextInList); //Add to client |
|
550 pR->iClientList.Add(pSCL); //Add in resource |
|
551 if(pC->iReservedCl==0) |
|
552 { |
|
553 iClientLevelPoolCount--; |
|
554 pC->iUnderFlowClCount++; |
|
555 } |
|
556 else |
|
557 pC->iReservedCl--; |
|
558 } |
|
559 else |
|
560 { |
|
561 //Update the level in the client list. |
|
562 SPowerResourceClientLevel* pSCL = (SPowerResourceClientLevel*)pR->iClientList.First(); |
|
563 pSCL->iLevel = aRequest.Level(); |
|
564 } |
|
565 } |
|
566 else if(aRequest.ReqType()==TPowerRequest::ESetDefaultLevel) |
|
567 { |
|
568 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
569 if((aRequest.ResourceId() & KIdMaskDynamic) && ((TInt)aClientId == KDynamicResourceDeRegistering)) |
|
570 { |
|
571 //Try to change the resource to requested level and if that fails try to change it to default level |
|
572 if(pR->iDefaultLevel != aRequest.Level()) |
|
573 { |
|
574 aRequest.ReqType() = TPowerRequest::EChange; |
|
575 aRequest.ReturnCode() = pR->DoRequest(aRequest); |
|
576 if(aRequest.ReturnCode() != KErrNone) |
|
577 { |
|
578 aRequest.ReqType() = TPowerRequest::ESetDefaultLevel; |
|
579 aRequest.Level() = pR->iDefaultLevel; |
|
580 pR->DoRequest(aRequest); |
|
581 } |
|
582 } |
|
583 else |
|
584 pR->DoRequest(aRequest); |
|
585 aRequest.ReturnCode() = KErrNone; |
|
586 aRequest.RequiresChange() = ETrue; |
|
587 CompleteRequest(aRequest); |
|
588 return; |
|
589 } |
|
590 #endif |
|
591 if(pR->Usage()) |
|
592 { |
|
593 aRequest.ReturnCode() = CheckLevelAndAddClient(pC, &aRequest); |
|
594 if((aRequest.ReturnCode()!= KErrNone) || (!aRequest.RequiresChange())) |
|
595 { |
|
596 aRequest.Level() = pR->iCachedLevel; //If no change then send the current level back. |
|
597 CompleteRequest(aRequest); |
|
598 return; |
|
599 } |
|
600 } |
|
601 else |
|
602 { |
|
603 aRequest.ClientId() = -1; |
|
604 aRequest.Level() = pR->iDefaultLevel; |
|
605 } |
|
606 } |
|
607 aRequest.ReturnCode() = pR->DoRequest(aRequest); |
|
608 CompleteRequest(aRequest); |
|
609 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::HandleMsg")); |
|
610 } |
|
611 |
|
612 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
613 /** Handle/process the dependency resource. |
|
614 The request can be one of the following |
|
615 1) State change of a dependency resource |
|
616 2) Get the state of a dependency resource |
|
617 3) Set the default value of a dependency resource */ |
|
618 void DPowerResourceController::HandleDependencyMsg(TPowerRequest& aRequest) |
|
619 { |
|
620 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::HandleDependencyMsg")); |
|
621 DStaticPowerResource* pR=aRequest.Resource(); |
|
622 //Get client using client ID |
|
623 TUint aClientId = aRequest.ClientId(); |
|
624 SPowerResourceClient* pC = NULL; |
|
625 |
|
626 if((TInt)aClientId != KDynamicResourceDeRegistering) |
|
627 { |
|
628 if(aClientId & USER_SIDE_CLIENT_BIT_MASK) |
|
629 pC = iUserSideClientList[TUint16(aClientId & ID_INDEX_BIT_MASK)]; |
|
630 else |
|
631 pC = iClientList[TUint16(aClientId & ID_INDEX_BIT_MASK)]; |
|
632 } |
|
633 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Request Type = %d, ClientId = 0x%x, ResourceId = %d", \ |
|
634 aRequest.ReqType(), aRequest.ClientId(), aRequest.ResourceId())); |
|
635 if((aRequest.ResourceId() & KIdMaskResourceWithDependencies) && (aRequest.ReqType() != TPowerRequest::EGet)) |
|
636 { |
|
637 Lock(); |
|
638 iDfcQDependencyLock = ETrue; |
|
639 UnLock(); |
|
640 PowerResourceController->HandleDependencyResourceStateChange(pC, aRequest); |
|
641 Lock(); |
|
642 iDfcQDependencyLock = EFalse; |
|
643 UnLock(); |
|
644 return; |
|
645 } |
|
646 //Get the resource current level. |
|
647 aRequest.ReturnCode() = pR->DoRequest(aRequest); |
|
648 CompleteRequest(aRequest); |
|
649 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::HandleDependencyMsg")); |
|
650 } |
|
651 #endif |
|
652 |
|
653 /** Function called whenever there is a message in resource controller message queue. */ |
|
654 void DPowerResourceController::MsgQFunc(TAny* aPtr) |
|
655 { |
|
656 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::MsgQFunc")); |
|
657 DPowerResourceController* pRC=(DPowerResourceController*)aPtr; |
|
658 TPowerRequest* aReq=(TPowerRequest*)pRC->iMsgQ->iMessage; |
|
659 if(aReq->ReqType() == TPowerRequest::EAllocReserve) |
|
660 { |
|
661 aReq->ReturnCode() = pRC->HandleReservationOfObjects(*aReq); |
|
662 aReq->Complete(aReq->ReturnCode(),ETrue); |
|
663 return; |
|
664 } |
|
665 if((aReq->ReqType() == TPowerRequest::ERegisterKernelClient) || (aReq->ReqType() == TPowerRequest::ERegisterUsersideClient)) |
|
666 { |
|
667 aReq->ReturnCode() = pRC->HandleClientRegistration(*aReq); |
|
668 aReq->Complete(aReq->ReturnCode(), ETrue); |
|
669 return; |
|
670 } |
|
671 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
672 if(aReq->ReqType() == TPowerRequest::ERegisterDynamicResource) |
|
673 { |
|
674 aReq->ReturnCode() = pRC->HandleResourceRegistration(*aReq); |
|
675 aReq->Complete(aReq->ReturnCode(), ETrue); |
|
676 return; |
|
677 } |
|
678 #endif |
|
679 pRC->HandleMsg(*aReq); |
|
680 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
681 if((aReq->ResourceId() & KIdMaskDynamic) && (aReq->ResourceCb())) |
|
682 { |
|
683 pRC->Lock(); |
|
684 ((DDynamicPowerResource*)aReq->Resource())->UnLock(); |
|
685 pRC->UnLock(); |
|
686 } |
|
687 #endif |
|
688 //Below code is for Btrace |
|
689 #ifdef PRM_INSTRUMENTATION_MACRO |
|
690 SPowerResourceClient* pC = NULL; |
|
691 SPowerResourceClient tRes; |
|
692 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
693 if((aReq->ClientId() == -1) || (aReq->ClientId() == KDynamicResourceDeRegistering)) |
|
694 #else |
|
695 if(aReq->ClientId() == -1) |
|
696 #endif |
|
697 { |
|
698 pC = &tRes; |
|
699 pC->iClientId = (TUint)-1; |
|
700 pC->iName = &KNoClient; |
|
701 } |
|
702 else if(aReq->ClientId() & USER_SIDE_CLIENT_BIT_MASK) |
|
703 pC = pRC->iUserSideClientList[TUint16(aReq->ClientId() & ID_INDEX_BIT_MASK)]; |
|
704 else |
|
705 pC = pRC->iClientList[TUint16(aReq->ClientId() & ID_INDEX_BIT_MASK)]; |
|
706 |
|
707 DStaticPowerResource *pR = aReq->Resource(); |
|
708 TUint aResourceId = aReq->ResourceId(); |
|
709 TInt r = aReq->ReturnCode(); |
|
710 if(aReq->ReqType()==TPowerRequest::EGet) |
|
711 { |
|
712 TInt aState = aReq->Level(); |
|
713 PRM_RESOURCE_GET_STATE_END_TRACE |
|
714 } |
|
715 else |
|
716 { |
|
717 TInt aNewState = aReq->Level(); |
|
718 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
719 } |
|
720 #endif |
|
721 //Check whether callback is cancelled and if not queue the DFC. |
|
722 TPowerResourceCb* pCb = aReq->ResourceCb(); |
|
723 if(pCb) |
|
724 { |
|
725 pCb->iResult=aReq->ReturnCode(); |
|
726 pCb->iLevel=aReq->Level(); |
|
727 pCb->iResourceId=aReq->ResourceId(); |
|
728 pCb->iClientId=aReq->ClientId(); |
|
729 pCb->iLevelOwnerId = pR->iLevelOwnerId; |
|
730 pCb->Enque(); |
|
731 } |
|
732 aReq->Complete(aReq->ReturnCode(),ETrue); |
|
733 if(aReq->ResourceCb()) |
|
734 pRC->MoveRequestToFreePool(aReq); |
|
735 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::MsgQFunc")); |
|
736 return; |
|
737 } |
|
738 |
|
739 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
740 /** Function called whenever there is a message in resource controller Dependency message queue. */ |
|
741 void DPowerResourceController::MsgQDependencyFunc(TAny* aPtr) |
|
742 { |
|
743 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::MsgQDependencyFunc")); |
|
744 DPowerResourceController* pRC=(DPowerResourceController*)aPtr; |
|
745 TPowerRequest* aReq=(TPowerRequest*)pRC->iMsgQDependency->iMessage; |
|
746 pRC->HandleDependencyMsg(*aReq); |
|
747 if((aReq->ResourceId() & KIdMaskDynamic) && (aReq->ResourceCb())) |
|
748 { |
|
749 pRC->Lock(); |
|
750 ((DDynamicPowerResource*)aReq->Resource())->UnLock(); |
|
751 pRC->UnLock(); |
|
752 } |
|
753 //Below code is for Btrace |
|
754 #ifdef PRM_INSTRUMENTATION_MACRO |
|
755 SPowerResourceClient* pC = NULL; |
|
756 SPowerResourceClient tRes; |
|
757 if((aReq->ClientId() != -1) && (aReq->ClientId() != KDynamicResourceDeRegistering) && |
|
758 (aReq->ClientId() & KIdMaskResourceWithDependencies)) |
|
759 { |
|
760 pC = &tRes; |
|
761 pC->iClientId = aReq->ClientId(); |
|
762 DDynamicPowerResourceD* pDRes; |
|
763 if(aReq->ClientId() & KIdMaskDynamic) |
|
764 pDRes = pRC->iDynamicResDependencyList[(TUint16)(aReq->ClientId() & ID_INDEX_BIT_MASK)]; |
|
765 else |
|
766 pDRes = (DDynamicPowerResourceD*)pRC->iStaticResDependencyArray[(aReq->ClientId() & ID_INDEX_BIT_MASK) - 1]; |
|
767 pC->iName = pDRes->iName; |
|
768 } |
|
769 else if((aReq->ClientId() == -1) || (aReq->ClientId() == KDynamicResourceDeRegistering)) |
|
770 { |
|
771 pC = &tRes; |
|
772 pC->iClientId = (TUint)-1; |
|
773 pC->iName = &KNoClient; |
|
774 } |
|
775 else if(aReq->ClientId() & USER_SIDE_CLIENT_BIT_MASK) |
|
776 pC = pRC->iUserSideClientList[TUint16(aReq->ClientId() & ID_INDEX_BIT_MASK)]; |
|
777 else |
|
778 pC = pRC->iClientList[TUint16(aReq->ClientId() & ID_INDEX_BIT_MASK)]; |
|
779 |
|
780 DStaticPowerResource *pR = aReq->Resource(); |
|
781 TUint aResourceId = aReq->ResourceId(); |
|
782 TInt r = aReq->ReturnCode(); |
|
783 if(aReq->ReqType()==TPowerRequest::EGet) |
|
784 { |
|
785 TInt aState = aReq->Level(); |
|
786 PRM_RESOURCE_GET_STATE_END_TRACE |
|
787 } |
|
788 else |
|
789 { |
|
790 TInt aNewState = aReq->Level(); |
|
791 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
792 } |
|
793 #endif |
|
794 //Check whether callback is cancelled and if not queue the DFC. |
|
795 TPowerResourceCb* pCb = aReq->ResourceCb(); |
|
796 if(pCb) |
|
797 { |
|
798 pCb->iResult=aReq->ReturnCode(); |
|
799 pCb->iLevel=aReq->Level(); |
|
800 pCb->iResourceId=aReq->ResourceId(); |
|
801 pCb->iClientId=aReq->ClientId(); |
|
802 pCb->iLevelOwnerId = pR->iLevelOwnerId; |
|
803 pCb->Enque(); |
|
804 } |
|
805 aReq->Complete(aReq->ReturnCode(),ETrue); |
|
806 if(aReq->ResourceCb()) |
|
807 pRC->MoveRequestToFreePool(aReq); |
|
808 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::MsgQDependencyFunc")); |
|
809 return; |
|
810 } |
|
811 #endif |
|
812 /** Function to move the request object to free pool and update client request count accordingly. */ |
|
813 void DPowerResourceController::MoveRequestToFreePool(TPowerRequest *aReq) |
|
814 { |
|
815 //Return request to free pool |
|
816 SPowerRequest* pS=_LOFF(aReq, SPowerRequest, iRequest); |
|
817 Lock(); |
|
818 LIST_PUSH(iRequestPool, pS, iNext); |
|
819 SPowerResourceClient* pC = NULL; |
|
820 if(aReq->ClientId() & USER_SIDE_CLIENT_BIT_MASK) |
|
821 pC = iUserSideClientList[TUint16(aReq->ClientId() & ID_INDEX_BIT_MASK)]; |
|
822 else |
|
823 pC = iClientList[TUint16(aReq->ClientId() & ID_INDEX_BIT_MASK)]; |
|
824 pC->iPendingReqCount--; |
|
825 if(pC->iUnderFlowRmCount > 0) |
|
826 { |
|
827 iRequestPoolCount++; |
|
828 pC->iUnderFlowRmCount--; |
|
829 } |
|
830 else |
|
831 pC->iReservedRm++; |
|
832 UnLock(); |
|
833 return; |
|
834 } |
|
835 |
|
836 /** This function is called by PSL to set the DFC queue created */ |
|
837 void DPowerResourceController::SetDfcQ(TDfcQue* aDfcQ) |
|
838 { |
|
839 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::SetDfcQ")); |
|
840 iDfcQ=aDfcQ; |
|
841 iMsgQ->SetDfcQ(iDfcQ); |
|
842 } |
|
843 |
|
844 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
845 /** This function is called by PSL to set the DFC Dependency queue created */ |
|
846 void DPowerResourceController::SetDfcQDependency(TDfcQue* aDfcQDependency) |
|
847 { |
|
848 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::SetDfcQDependency")); |
|
849 iDfcQDependency=aDfcQDependency; |
|
850 iMsgQDependency->SetDfcQ(iDfcQDependency); |
|
851 } |
|
852 #endif |
|
853 /**This is called as a result of DFC queued in supervisor thread to complete the initialisation |
|
854 of resource controller.It registers the resource controller with the power controller. It also |
|
855 calls PSL (DoInitResources()) to initialise all static resources to their post-reboot state. |
|
856 Finally mark resource controller as fully initialised (ready to accept state change and get request) |
|
857 and start the message queue if exists. */ |
|
858 TInt DPowerResourceController::InitResources() |
|
859 { |
|
860 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::InitResources()")); |
|
861 TUint16 count; |
|
862 //Create a Kernel client object for Power Controller |
|
863 Lock(); |
|
864 SPowerResourceClient * pC = NULL; |
|
865 // By now client pool should be created |
|
866 LIST_POP(iClientPool, pC, iNextInList); |
|
867 if(!pC) |
|
868 { |
|
869 UnLock(); |
|
870 TUint16 growBy = iClientList.GrowBy(); |
|
871 // coverity[alloc_fn] |
|
872 SPowerResourceClient *pCL = new SPowerResourceClient[growBy]; |
|
873 if(!pCL) |
|
874 { |
|
875 __KTRACE_OPT(KRESMANAGER, Kern::Printf("No memory to grow client pool")); |
|
876 Panic(ENoMemToCreatePowerControllerClient); |
|
877 } |
|
878 if(iClientList.ReSize(growBy)) |
|
879 Panic(ENoMemToCreatePowerControllerClient); |
|
880 Lock(); |
|
881 for(count = 0; count < growBy-1; count++) |
|
882 LIST_PUSH(iClientPool, &pCL[count], iNextInList); |
|
883 pC = &pCL[count]; |
|
884 #ifdef PRM_INSTRUMENTATION_MACRO |
|
885 TUint size = growBy *sizeof(SPowerResourceClient); |
|
886 PRM_MEMORY_USAGE_TRACE |
|
887 #endif |
|
888 } |
|
889 pC->iName = (const TDesC8*)&KPowerController; |
|
890 iClientList.Add(pC, iPowerControllerId); |
|
891 pC->iClientId = iPowerControllerId | CLIENT_POWER_CONTROLLER_BIT_MASK; |
|
892 iPowerControllerId = pC->iClientId; |
|
893 iClientCount++; |
|
894 if(TPowerController::PowerController()) |
|
895 TPowerController::PowerController()->RegisterResourceController(this, iPowerControllerId); |
|
896 iInitialised =EResConStartupCompleted; |
|
897 UnLock(); |
|
898 //Check the resource for postboot level and send notifications to clients registered for it. |
|
899 DStaticPowerResource *pR = NULL; |
|
900 TInt r; |
|
901 TPowerRequest req = TPowerRequest::Get(); |
|
902 //For Static resource with no dependencies |
|
903 for(count = 0; count< iStaticResourceArrayEntries; count++) |
|
904 { |
|
905 pR = iStaticResourceArray[count]; |
|
906 if(pR && (pR->iFlags & SET_VALID_POST_BOOT_LEVEL)) |
|
907 { |
|
908 //Form the request message |
|
909 req.ReqType() = TPowerRequest::EChange; |
|
910 req.ResourceId() = count+1; |
|
911 req.ClientId() = -1; |
|
912 req.Level() = pR->iPostBootLevel; |
|
913 req.Resource() = pR; |
|
914 req.ResourceCb() = NULL; |
|
915 req.RequiresChange() = ETrue; |
|
916 r = pR->DoRequest(req); |
|
917 if(r == KErrNone) |
|
918 { |
|
919 CompleteNotifications(-1, pR, req.Level(), r, -1, ETrue); |
|
920 pR->iCachedLevel = req.Level(); //Update the cached level. |
|
921 } |
|
922 } |
|
923 } |
|
924 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
925 //For Static resource with dependencies |
|
926 for(count = 0; count < iStaticResDependencyCount; count++) |
|
927 { |
|
928 pR = iStaticResDependencyArray[count]; |
|
929 if(pR->iFlags & SET_VALID_POST_BOOT_LEVEL) |
|
930 { |
|
931 req.ReqType() = TPowerRequest::EChange; |
|
932 req.ResourceId() = ((DStaticPowerResourceD*)pR)->iResourceId; |
|
933 req.ClientId() = -1; |
|
934 req.Level() = pR->iPostBootLevel; |
|
935 req.Resource() = pR; |
|
936 req.ResourceCb() = NULL; |
|
937 req.RequiresChange() = ETrue; |
|
938 //Form the request message |
|
939 ((DStaticPowerResourceD*)pR)->HandleChangePropagation(req, EChangeStart, req.ClientId(), KNoClient); |
|
940 } |
|
941 } |
|
942 #endif |
|
943 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::InitResources()")); |
|
944 return KErrNone; |
|
945 } |
|
946 |
|
947 /** @internalComponent |
|
948 This function is called for shared resources to determine level for the shared resource. |
|
949 This takes care of updating the resource level for each client. |
|
950 */ |
|
951 TInt DPowerResourceController::CheckLevelAndAddClient(SPowerResourceClient* pC, TPowerRequest* aReq) |
|
952 { |
|
953 //Client level addition in state change needs to be taken care. |
|
954 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient, ClientId = 0x%x, \ |
|
955 ResourceId = %d, ReqType = %d", pC->iClientId, aReq->ResourceId(), aReq->ReqType())); |
|
956 |
|
957 SPowerResourceClientLevel* pSCL=NULL; //Place to hold the current client |
|
958 SPowerResourceClientLevel* pMCL=NULL; //Place to hold the prevailing client. |
|
959 DStaticPowerResource* aResource = aReq->Resource(); |
|
960 aReq->RequiresChange() = EFalse; |
|
961 TInt maxLevel=KMinTInt; |
|
962 TInt CurrentLevel; |
|
963 TInt count = 0; |
|
964 //Get the nextmaximum, current client information.If the change is requested by client holding the prevailing |
|
965 //level of the resource then maxlevel will be next highest level with respect to sense. Otherwise will contain |
|
966 //the maximum level. |
|
967 SPowerResourceClientLevel* pL = NULL; |
|
968 for(SDblQueLink* pCL=aResource->iClientList.First();pCL!=&aResource->iClientList.iA;pCL=pCL->iNext,count++) |
|
969 { |
|
970 pL=(SPowerResourceClientLevel*)pCL; |
|
971 if(pL->iClientId == pC->iClientId) |
|
972 { |
|
973 pSCL=pL; |
|
974 if(aResource->Sense() == DStaticPowerResource::ECustom) |
|
975 break; |
|
976 continue; |
|
977 } |
|
978 |
|
979 if((count == 0) || ((pSCL != NULL) && (maxLevel == KMinTInt))) |
|
980 { |
|
981 maxLevel = pL->iLevel; |
|
982 pMCL = pL; |
|
983 continue; |
|
984 } |
|
985 if(((aResource->Sense() == DStaticPowerResource::ENegative) && (pL->iLevel < maxLevel)) || |
|
986 ((aResource->Sense() == DStaticPowerResource::EPositive) && (pL->iLevel > maxLevel))) |
|
987 { |
|
988 maxLevel=pL->iLevel; |
|
989 pMCL = pL; |
|
990 } |
|
991 } |
|
992 //Get the current level. |
|
993 if(((TInt)pC->iClientId == aResource->iLevelOwnerId)) |
|
994 // coverity[var_deref_op] |
|
995 CurrentLevel = pSCL->iLevel; |
|
996 else |
|
997 CurrentLevel = maxLevel; |
|
998 |
|
999 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1000 if(aResource->iLevelOwnerId & KIdMaskResourceWithDependencies) |
|
1001 { |
|
1002 CurrentLevel = aResource->iCachedLevel; |
|
1003 } |
|
1004 #endif |
|
1005 TBool newClient = EFalse; |
|
1006 if(!pSCL) |
|
1007 { |
|
1008 // If the client is new, get free client level from pool and populate with client information |
|
1009 // and add it to the client list and in resource list. |
|
1010 if((pC->iReservedCl ==0) && !iClientLevelPoolCount) |
|
1011 { |
|
1012 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client level quota exhausted and its free pool empty, \ |
|
1013 iReservedCl = %d, iClientLevelPoolCount = %d", pC->iReservedCl, iClientLevelPoolCount)); |
|
1014 return KErrUnderflow; |
|
1015 } |
|
1016 LIST_POP(iClientLevelPool, pSCL, iNextInList); |
|
1017 pSCL->iClientId=pC->iClientId; |
|
1018 pSCL->iResourceId=aReq->ResourceId(); |
|
1019 pSCL->iLevel = aReq->Level(); |
|
1020 //Add to the resource list |
|
1021 aResource->iClientList.Add(pSCL); |
|
1022 //Add to the client List |
|
1023 LIST_PUSH(pC->iLevelList, pSCL, iNextInList); |
|
1024 if(pC->iReservedCl == 0) |
|
1025 { |
|
1026 iClientLevelPoolCount--; |
|
1027 pC->iUnderFlowClCount++; |
|
1028 } |
|
1029 else |
|
1030 pC->iReservedCl--; |
|
1031 //If no client is holding the resource already and is not custom sense resource, then change is allowed |
|
1032 if((aResource->iLevelOwnerId == -1) && (aResource->Sense() != DStaticPowerResource::ECustom)) |
|
1033 { |
|
1034 aReq->RequiresChange() = ETrue; |
|
1035 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient")); |
|
1036 return KErrNone; |
|
1037 } |
|
1038 if(aResource->Sense() == DStaticPowerResource::ECustom) |
|
1039 newClient = ETrue; |
|
1040 } |
|
1041 else |
|
1042 // Capture the new level requested by the client. |
|
1043 pSCL->iLevel=aReq->Level(); |
|
1044 |
|
1045 if(aResource->Sense() == DStaticPowerResource::ECustom) |
|
1046 { |
|
1047 |
|
1048 if(!aResource->iCustomFunction) |
|
1049 Panic(ECustomFunctionNotSet); |
|
1050 // coverity[var_deref_op] |
|
1051 if(aReq->ReqType() == TPowerRequest::EChange) |
|
1052 { |
|
1053 aReq->RequiresChange() = aResource->iCustomFunction(aReq->ClientId(), *(pC->iName), aReq->ResourceId(), |
|
1054 newClient ? EClientRequestLevel : EClientChangeLevel, |
|
1055 aReq->Level(), (TAny*)&aResource->iClientList, NULL); |
|
1056 } |
|
1057 else |
|
1058 { |
|
1059 aReq->RequiresChange() = aResource->iCustomFunction(aReq->ClientId(), *(pC->iName), aReq->ResourceId(), |
|
1060 EClientRelinquishLevel, |
|
1061 aReq->Level(), (TAny*)&aResource->iClientList, NULL); |
|
1062 } |
|
1063 if((aReq->ClientId() != -1) && (aReq->ClientId() != (TInt)pC->iClientId) ) |
|
1064 { |
|
1065 //Check whether the updated client Id (by custom function) is in the client level list. |
|
1066 for(SDblQueLink* pCL=aResource->iClientList.First();pCL!=&aResource->iClientList.iA;pCL=pCL->iNext) |
|
1067 { |
|
1068 pL = (SPowerResourceClientLevel*)pCL; |
|
1069 if((TInt)pL->iClientId == aReq->ClientId()) |
|
1070 break; |
|
1071 } |
|
1072 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1073 if(aReq->ClientId() & (1 << RESOURCE_BIT_IN_ID_CHECK)) |
|
1074 { |
|
1075 if(aResource->iResourceId & KIdMaskDynamic) |
|
1076 pL = ((DDynamicPowerResourceD*)aResource)->iResourceClientList; |
|
1077 else |
|
1078 pL = ((DStaticPowerResourceD*)aResource)->iResourceClientList; |
|
1079 while(pL != NULL) |
|
1080 { |
|
1081 if((TInt)pL->iClientId == aReq->ClientId()) |
|
1082 break; |
|
1083 } |
|
1084 } |
|
1085 #endif |
|
1086 // coverity[var_deref_op] |
|
1087 if((TInt)pL->iClientId != aReq->ClientId()) |
|
1088 Panic(EClientIdNotInClientLevelList); |
|
1089 } |
|
1090 if(!aReq->RequiresChange() && (aReq->ClientId() != (TInt)pC->iClientId)) |
|
1091 { |
|
1092 aResource->iLevelOwnerId=aReq->ClientId(); |
|
1093 //Update resource details for Idle |
|
1094 if(aResource->iIdleListEntry) |
|
1095 aResource->iIdleListEntry->iLevelOwnerId=aReq->ClientId(); |
|
1096 } |
|
1097 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient")); |
|
1098 return KErrNone; |
|
1099 } |
|
1100 //Handle client deregistration |
|
1101 if(aReq->ReqType() == TPowerRequest::ESetDefaultLevel) |
|
1102 { |
|
1103 aReq->RequiresChange() = ETrue; |
|
1104 // If the client is the only ask PSL to set to default level. |
|
1105 if(count == 1) |
|
1106 { |
|
1107 aReq->ReqType() = TPowerRequest::ESetDefaultLevel; |
|
1108 aReq->Level() = aResource->iDefaultLevel; |
|
1109 aReq->ClientId() = -1; |
|
1110 } |
|
1111 else |
|
1112 { |
|
1113 //Change the state to next maximum level with respect to sense. |
|
1114 aReq->ReqType() = TPowerRequest::EChange; |
|
1115 // coverity[var_deref_op] |
|
1116 aReq->ClientId() = pMCL->iClientId; |
|
1117 aReq->Level() = pMCL->iLevel; |
|
1118 if(pSCL->iLevel == pMCL->iLevel) |
|
1119 { |
|
1120 //Change the client alone and level remains the same. |
|
1121 aResource->iLevelOwnerId = pMCL->iClientId; |
|
1122 if(aResource->iIdleListEntry) |
|
1123 aResource->iIdleListEntry->iLevelOwnerId = pMCL->iClientId; |
|
1124 aReq->RequiresChange() = EFalse; |
|
1125 } |
|
1126 } |
|
1127 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient")); |
|
1128 return KErrNone; |
|
1129 } |
|
1130 |
|
1131 //If the level is in increasing order with respect to sense the change is allowed. |
|
1132 if(((aResource->Sense() == DStaticPowerResource::ENegative) && aReq->Level()<CurrentLevel) || |
|
1133 ((aResource->Sense() == DStaticPowerResource::EPositive) && aReq->Level()>CurrentLevel)) |
|
1134 { |
|
1135 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Resource is in increasing order with respect to sense and level is %d",\ |
|
1136 aReq->Level())); |
|
1137 aReq->RequiresChange()=ETrue; |
|
1138 return KErrNone; |
|
1139 } |
|
1140 if((TInt)pC->iClientId == aResource->iLevelOwnerId) |
|
1141 { |
|
1142 if(aReq->Level() == CurrentLevel) |
|
1143 { |
|
1144 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient")); |
|
1145 return KErrNone; |
|
1146 } |
|
1147 if(count == 1) |
|
1148 { |
|
1149 aReq->RequiresChange() = ETrue; |
|
1150 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient")); |
|
1151 return KErrNone; |
|
1152 } |
|
1153 // If the client requesting is the client holding current level, then chnage it to the nextmaximum level. |
|
1154 // Next maximum level is the max of requesting level or next maximum level. |
|
1155 if(((aResource->Sense()==DStaticPowerResource::ENegative) && maxLevel < aReq->Level()) || |
|
1156 ((aResource->Sense()==DStaticPowerResource::EPositive) && maxLevel > aReq->Level())) |
|
1157 { |
|
1158 aReq->Level() = maxLevel; |
|
1159 aReq->ClientId() = pMCL->iClientId; |
|
1160 if(maxLevel == CurrentLevel) |
|
1161 { |
|
1162 aResource->iLevelOwnerId=pMCL->iClientId; |
|
1163 //Update resource details for Idle |
|
1164 if(aResource->iIdleListEntry) |
|
1165 aResource->iIdleListEntry->iLevelOwnerId=pMCL->iClientId; |
|
1166 aReq->RequiresChange() = EFalse; |
|
1167 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient")); |
|
1168 return KErrNone; |
|
1169 } |
|
1170 } |
|
1171 aReq->RequiresChange() = ETrue; |
|
1172 } |
|
1173 __KTRACE_OPT(KRESMANAGER, Kern::Printf("DPowerResourceController::CheckLevelAndAddClient")); |
|
1174 return KErrNone; |
|
1175 } |
|
1176 |
|
1177 /** |
|
1178 Initialise pools of request structures, client strutures and client power level structures. |
|
1179 By preallocating sufficiently large structures we remove any allocations whilst the resource manager mutex is held. |
|
1180 The function basically ensures that sufficient memory is preallocated to the resource manager to ensure that none is |
|
1181 required at run time. |
|
1182 @param aKClients number of kernel side clients expected in the resource manager |
|
1183 @param aUClients number of user side clients expected in the resource manager |
|
1184 @param aNClientLevels number of client levels the RM should preallocate. This is roughly the number of clients |
|
1185 that are expected to use shared resources multiplied by the number of shared resources. |
|
1186 @param aNRequest number of simultaneous asynchronous requests the resource manager is likely to handle |
|
1187 @return KErrNone if preallocations succeed |
|
1188 @return KErrNoMemory if one the prealocations fails |
|
1189 */ |
|
1190 TInt DPowerResourceController::InitPools(TUint16 aKClients, TUint16 aUClients, TUint16 aNClientLevels, TUint16 aNRequests) |
|
1191 { |
|
1192 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::InitPools")); |
|
1193 __KTRACE_OPT(KRESMANAGER, Kern::Printf("aKClients = %d, aUClients = %d, aNClientLevels = %d, aNRequests = %d", \ |
|
1194 aKClients, aUClients, aNClientLevels, aNRequests)); |
|
1195 __ASSERT_ALWAYS((iInitialised == EResConCreated) && !(iClientPool || iRequestPool || iClientLevelPool), Kern::Fault("Already initialized" |
|
1196 __FILE__, __LINE__)); |
|
1197 |
|
1198 // Create client pool |
|
1199 SPowerResourceClient* pC = NULL; |
|
1200 SPowerResourceClientLevel* pCL = NULL; |
|
1201 SPowerRequest* pR = NULL; |
|
1202 aKClients++; //Add one default for PowerController |
|
1203 if(aKClients + aUClients) |
|
1204 { |
|
1205 // coverity[alloc_fn] |
|
1206 pC = new SPowerResourceClient[aKClients+aUClients]; |
|
1207 if(!pC) |
|
1208 { |
|
1209 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client Pool Allocation Failed")); |
|
1210 return KErrNoMemory; |
|
1211 } |
|
1212 } |
|
1213 // Create Client level pool |
|
1214 if(aNClientLevels) |
|
1215 { |
|
1216 // coverity[alloc_fn] |
|
1217 pCL = new SPowerResourceClientLevel[aNClientLevels]; |
|
1218 if(!pCL) |
|
1219 { |
|
1220 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client Level Pool Allocation Failed")); |
|
1221 delete []pC; |
|
1222 return KErrNoMemory; |
|
1223 } |
|
1224 } |
|
1225 // Create Request pool |
|
1226 if(aNRequests) |
|
1227 { |
|
1228 // coverity[alloc_fn] |
|
1229 pR = new SPowerRequest[aNRequests]; |
|
1230 if(!pR) |
|
1231 { |
|
1232 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Request Pool Allocation Failed")); |
|
1233 delete []pC; |
|
1234 delete []pCL; |
|
1235 return KErrNoMemory; |
|
1236 } |
|
1237 } |
|
1238 //Create the client Array for kernel and user side clients. |
|
1239 if(iClientList.Initialise(aKClients)) |
|
1240 { |
|
1241 delete []pC; |
|
1242 delete []pCL; |
|
1243 delete []pR; |
|
1244 return KErrNoMemory; |
|
1245 } |
|
1246 if(iUserSideClientList.Initialise(aUClients)) |
|
1247 { |
|
1248 delete []pC; |
|
1249 delete []pCL; |
|
1250 delete []pR; |
|
1251 iClientList.Delete(); |
|
1252 return KErrNoMemory; |
|
1253 } |
|
1254 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1255 SPowerResourceClientLevel* pRL = NULL; |
|
1256 if(iStaticResDependencyCount) |
|
1257 { |
|
1258 pRL = new SPowerResourceClientLevel[iStaticResDependencyCount]; |
|
1259 if(!pRL) |
|
1260 { |
|
1261 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Resource level Pool Allocation Failed")); |
|
1262 delete []pC; |
|
1263 delete []pCL; |
|
1264 delete []pR; |
|
1265 iClientList.Delete(); |
|
1266 iUserSideClientList.Delete(); |
|
1267 return KErrNoMemory; |
|
1268 } |
|
1269 } |
|
1270 Lock(); |
|
1271 TUint16 c; |
|
1272 for(c = 0; c < iStaticResDependencyCount; c++) |
|
1273 { |
|
1274 LIST_PUSH(iResourceLevelPool, &pRL[c], iNextInList); |
|
1275 } |
|
1276 iResourceLevelPoolCount = iStaticResDependencyCount; |
|
1277 #else |
|
1278 Lock(); |
|
1279 TUint16 c; |
|
1280 #endif |
|
1281 // Create Client pool list |
|
1282 for(c = 0; c< (aKClients + aUClients); c++) |
|
1283 { |
|
1284 LIST_PUSH(iClientPool, &pC[c], iNextInList); |
|
1285 } |
|
1286 // Create client level pool list |
|
1287 for(c = 0; c < aNClientLevels; c++) |
|
1288 { |
|
1289 LIST_PUSH(iClientLevelPool, &pCL[c], iNextInList); |
|
1290 } |
|
1291 // Create request pool list |
|
1292 for(c = 0; c < aNRequests; c++) |
|
1293 { |
|
1294 LIST_PUSH(iRequestPool, &pR[c], iNext); |
|
1295 } |
|
1296 // When the pool is exhausted they are increased by half of initial size. */ |
|
1297 iClientLevelPoolGrowBy=(TUint16)(aNClientLevels/2); |
|
1298 iRequestPoolGrowBy=(TUint16)(aNRequests/2); |
|
1299 // Initialise the free pool size |
|
1300 iClientLevelPoolCount=aNClientLevels; |
|
1301 iRequestPoolCount=aNRequests; |
|
1302 #ifdef PRM_INSTRUMENTATION_MACRO |
|
1303 TUint size = (((aKClients + aUClients)*sizeof(SPowerResourceClient)) + |
|
1304 (aNClientLevels * sizeof(SPowerResourceClientLevel)) + (aNRequests * sizeof(SPowerRequest))); |
|
1305 PRM_MEMORY_USAGE_TRACE |
|
1306 #endif |
|
1307 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::InitPools")); |
|
1308 UNLOCK_RETURN(KErrNone); |
|
1309 } |
|
1310 |
|
1311 /** |
|
1312 @publishedPartner |
|
1313 @prototype 9.5 |
|
1314 |
|
1315 Register a client with the Resource Manager. |
|
1316 |
|
1317 @param aClientId A reference to a client ID: returns a unique handle if registration was |
|
1318 successful, 0 otherwise. |
|
1319 @param aName Descriptor with name for client. The descriptor is created by the client |
|
1320 in kernel data space or its user address space. |
|
1321 NOTE: Name should ideally relate to component name and should take care |
|
1322 of name uniqueness as it is checked only if DEBUG_VERSION macro is enabled. |
|
1323 @param aType Defines ownership |
|
1324 EOwnerProcess - The client ID can be used by all thread in the process to |
|
1325 call the resource manager API's |
|
1326 EOwnerThread - The client ID can only be used by the thread that registered |
|
1327 the client to resource manager to call the PRM API's |
|
1328 By default this is set to EOwnerProcess. |
|
1329 |
|
1330 @return KErrNone if the operation was successful, |
|
1331 KErrNoMemory if a new client link was needed but could not be created and |
|
1332 added to the client list, |
|
1333 KErrTooBig if the length of the descriptor passed is greater than 32. |
|
1334 KErrAlreadyExists if the specified name already exists. This is valid only if |
|
1335 DEBUG_VERSION macro is enabled. |
|
1336 KErrNotSupported if number of expected kernel side clients is set to zero by |
|
1337 PSL. |
|
1338 |
|
1339 @pre Interrupts must be enabled. |
|
1340 @pre Kernel must be unlocked. |
|
1341 @pre No fast mutex can be held. |
|
1342 @pre Call in a thread context, but not from null thread or DFC thread1. |
|
1343 @pre Can be used in a device driver |
|
1344 */ |
|
1345 TInt DPowerResourceController::RegisterClient(TUint& aClientId, const TDesC8& aName, TOwnerType aType) |
|
1346 { |
|
1347 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RegisterClient, Name = %S, \ |
|
1348 Type = %d", &aName, aType)); |
|
1349 DThread& thread = Kern::CurrentThread(); |
|
1350 CHECK_CONTEXT(thread) |
|
1351 //If number of expected kernel side clients is set to 0 during initial configuration |
|
1352 //then dont allow to configure kernel side clients. |
|
1353 if(!iClientList.GrowBy()) |
|
1354 return KErrNotSupported; |
|
1355 if (aName.Length() > KMaxClientNameLength) return KErrTooBig; |
|
1356 SPowerResourceClient *pC = NULL; |
|
1357 Lock(); |
|
1358 #ifdef DEBUG_VERSION |
|
1359 if(!iClientList.Find(pC, (TDesC8&)aName)) |
|
1360 UNLOCK_RETURN(KErrAlreadyExists); |
|
1361 #endif |
|
1362 //Call from thread Id. |
|
1363 TPowerRequest* req = (TPowerRequest*)&TPowerRequest::Get(); |
|
1364 req->ReqType() = TPowerRequest::ERegisterKernelClient; |
|
1365 UnLock(); |
|
1366 req->SendReceive(iMsgQ); |
|
1367 if(req->ReturnCode() == KErrNone) |
|
1368 { |
|
1369 pC = iClientList[(TUint16)(req->ClientId() & ID_INDEX_BIT_MASK)]; |
|
1370 if(aType == EOwnerThread) |
|
1371 { |
|
1372 pC->iClientId |= CLIENT_THREAD_RELATIVE_BIT_MASK; //Set 31st bit; |
|
1373 //Store the current thread Id; |
|
1374 pC->iThreadId = thread.iId; |
|
1375 } |
|
1376 pC->iName = &aName; |
|
1377 aClientId = pC->iClientId; |
|
1378 } |
|
1379 PRM_CLIENT_REGISTER_TRACE |
|
1380 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RegisterClient, clientId = 0x%x", aClientId)); |
|
1381 return(req->ReturnCode()); |
|
1382 } |
|
1383 |
|
1384 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1385 TInt DPowerResourceController::HandleResourceRegistration(TPowerRequest& aReq) |
|
1386 { |
|
1387 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::HandleResourceRegistration")); |
|
1388 DDynamicPowerResource* pDRes = (DDynamicPowerResource*)aReq.Resource(); |
|
1389 //Add to appropriate container |
|
1390 if(pDRes->iResourceId & KIdMaskResourceWithDependencies) |
|
1391 ADD_TO_RESOURCE_CONTAINER(iDynamicResDependencyList, ((DDynamicPowerResourceD*)pDRes), aReq.ResourceId(), |
|
1392 iDynamicResDependencyCount) |
|
1393 else |
|
1394 ADD_TO_RESOURCE_CONTAINER(iDynamicResourceList, pDRes, aReq.ResourceId(), iDynamicResourceCount) |
|
1395 |
|
1396 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::HandleResourceRegistration")); |
|
1397 return KErrNone; |
|
1398 } |
|
1399 #endif |
|
1400 |
|
1401 /** |
|
1402 @internalComponent |
|
1403 @prototype 9.5 |
|
1404 |
|
1405 This function runs in the context of the RC thread and |
|
1406 handles registration of client (kernel and user side). |
|
1407 */ |
|
1408 TInt DPowerResourceController::HandleClientRegistration(TPowerRequest& aRequest) |
|
1409 { |
|
1410 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RegisterClient")); |
|
1411 SPowerResourceClient* pC = NULL; |
|
1412 TUint clientId; |
|
1413 if(aRequest.ReqType() == TPowerRequest::ERegisterKernelClient) |
|
1414 { |
|
1415 //Get Next client from FreePool |
|
1416 LIST_POP(iClientPool, pC, iNextInList); |
|
1417 if(!pC) |
|
1418 { |
|
1419 //Free Pool is empty, so try to grow the pool. |
|
1420 TUint16 growBy = iClientList.GrowBy(); |
|
1421 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client pool exhausted so growing client Pool by %d", growBy)); |
|
1422 // coverity[alloc_fn] |
|
1423 SPowerResourceClient *pCL = new SPowerResourceClient[growBy]; |
|
1424 if(!pCL) |
|
1425 { |
|
1426 __KTRACE_OPT(KRESMANAGER, Kern::Printf("No memory to grow client pool")); |
|
1427 return(KErrNoMemory); |
|
1428 } |
|
1429 //Resize the container for holding client list |
|
1430 if(!iClientList.ReSize(growBy)) |
|
1431 { |
|
1432 __KTRACE_OPT(KRESMANAGER, Kern::Printf("No memory for client container allocation")); |
|
1433 delete []pCL; |
|
1434 return(KErrNoMemory); |
|
1435 } |
|
1436 Lock(); |
|
1437 TUint16 count; |
|
1438 for(count = 0; count < growBy-1; count++) |
|
1439 LIST_PUSH(iClientPool, &pCL[count], iNextInList); |
|
1440 UnLock(); |
|
1441 #ifdef PRM_INSTRUMENTATION_MACRO |
|
1442 TUint size = growBy *sizeof(SPowerResourceClient); |
|
1443 PRM_MEMORY_USAGE_TRACE |
|
1444 #endif |
|
1445 pC = &pCL[count]; |
|
1446 } |
|
1447 pC->iClientId = 0; |
|
1448 Lock(); |
|
1449 iClientList.Add(pC, clientId); |
|
1450 ++iClientCount; |
|
1451 UnLock(); |
|
1452 } |
|
1453 else // Request is registration of user side client |
|
1454 { |
|
1455 //Get Next client from FreePool |
|
1456 LIST_POP(iClientPool, pC, iNextInList); |
|
1457 if(!pC) |
|
1458 { |
|
1459 //Free Pool is empty, so try to grow the pool. |
|
1460 TUint16 growBy = iUserSideClientList.GrowBy(); |
|
1461 SPowerResourceClient* pCL = new SPowerResourceClient[growBy]; |
|
1462 if(!pCL) |
|
1463 { |
|
1464 return KErrNoMemory; |
|
1465 } |
|
1466 //Resize the container for holding client list |
|
1467 if(!iUserSideClientList.ReSize(growBy)) |
|
1468 { |
|
1469 __KTRACE_OPT(KRESMANAGER, Kern::Printf("No memory for container class allocation")); |
|
1470 delete []pCL; |
|
1471 return KErrNoMemory; |
|
1472 } |
|
1473 Lock(); |
|
1474 TUint16 count; |
|
1475 for(count = 0; count < growBy - 1; count++) |
|
1476 LIST_PUSH(iClientPool, &pCL[count], iNextInList); |
|
1477 UnLock(); |
|
1478 #ifdef PRM_INSTRUMENTATION_MACRO |
|
1479 TUint size = growBy * sizeof(SPowerResourceClient); |
|
1480 PRM_MEMORY_USAGE_TRACE |
|
1481 #endif |
|
1482 pC = &pCL[count]; |
|
1483 } |
|
1484 pC->iClientId = 0; |
|
1485 //User side clients are always thread relative as they execute in the context of proxy driver. |
|
1486 pC->iClientId = CLIENT_THREAD_RELATIVE_BIT_MASK; //Set 31st bit; |
|
1487 pC->iClientId|=USER_SIDE_CLIENT_BIT_MASK; |
|
1488 Lock(); |
|
1489 iUserSideClientList.Add(pC, clientId); |
|
1490 ++iUserSideClientCount; |
|
1491 UnLock(); |
|
1492 } |
|
1493 //Create the unique handle for each client |
|
1494 //Client Handle format |
|
1495 // 31 30 18 16 15 14 13 0 |
|
1496 // ¦----¦-----------------------------------¦----¦-----¦-----¦-----------------------------------¦ |
|
1497 // ¦ T/P¦ Container's instance count(15 bits¦C/R ¦ PC ¦ K/U ¦ Index into Client array container ¦ |
|
1498 // ¦----¦-----------------------------------¦----¦-----¦-----¦-----------------------------------¦ |
|
1499 // T/P -> Thread / process relative |
|
1500 // PC -> Power Controller reserved ID. |
|
1501 // K/U -> Kernel / User side clients |
|
1502 // C/R -> Client / Resource Id. This bit will be set for dependency resource Id, zero for clientId. |
|
1503 pC->iLevelList = NULL; |
|
1504 pC->iNotificationList = NULL; |
|
1505 pC->iDynamicResCount = 0; |
|
1506 pC->iReservedCl = 0; |
|
1507 pC->iReservedRm = 0; |
|
1508 pC->iPendingReqCount = 0; |
|
1509 pC->iUnderFlowRmCount = 0; |
|
1510 pC->iUnderFlowClCount = 0; |
|
1511 pC->iClientId |= clientId; |
|
1512 aRequest.ClientId() = pC->iClientId; |
|
1513 return KErrNone; |
|
1514 } |
|
1515 |
|
1516 /** @internalComponent |
|
1517 @prototype 9.5 |
|
1518 This is called as the result of client deregistration and takes care of resource state changes |
|
1519 (to appropriate levels) of all the resources the client is holding active requirement. */ |
|
1520 void DPowerResourceController::ResourceStateChangeOfClientLevels(SPowerResourceClient* pC) |
|
1521 { |
|
1522 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::ResourceStateChangeOfClientLevels")); |
|
1523 TPowerRequest* pReq = (TPowerRequest*)&TPowerRequest::Get(); |
|
1524 DStaticPowerResource* pR = NULL; |
|
1525 TInt r = KErrNone; |
|
1526 SPowerResourceClientLevel* pCL = pC->iLevelList; |
|
1527 SPowerResourceClientLevel* pCLL = NULL; |
|
1528 while(pCL != NULL) |
|
1529 { |
|
1530 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client 0x%x has requirement on resource %d", pCL->iClientId, \ |
|
1531 pCL->iResourceId)); |
|
1532 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1533 switch((pCL->iResourceId >>RESOURCE_BIT_IN_ID_CHECK) & 0x3) |
|
1534 { |
|
1535 case PRM_STATIC_RESOURCE: |
|
1536 pR = iStaticResourceArray[pCL->iResourceId - 1]; |
|
1537 break; |
|
1538 case PRM_DYNAMIC_RESOURCE: |
|
1539 pR = (iDynamicResourceList[(TUint16)(pCL->iResourceId & ID_INDEX_BIT_MASK)]); |
|
1540 break; |
|
1541 case PRM_STATIC_DEPENDENCY_RESOURCE: |
|
1542 pR = (iStaticResDependencyArray[(TUint16)(pCL->iResourceId & ID_INDEX_BIT_MASK) - 1]); |
|
1543 break; |
|
1544 case PRM_DYNAMIC_DEPENDENCY_RESOURCE: |
|
1545 pR = (iDynamicResDependencyList[(TUint16)(pCL->iResourceId & ID_INDEX_BIT_MASK)]); |
|
1546 break; |
|
1547 } |
|
1548 #else |
|
1549 pR = iStaticResourceArray[pCL->iResourceId -1]; |
|
1550 #endif |
|
1551 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1552 if((((TInt)pCL->iClientId == pR->iLevelOwnerId) || (pR->Sense() == DStaticPowerResource::ECustom)) && (!(pCL->iResourceId & KIdMaskDynamic) || |
|
1553 ((pCL->iResourceId & KIdMaskDynamic) && (((DDynamicPowerResource*)pR)->LockCount() != 0)))) |
|
1554 #else |
|
1555 if(((TInt)pCL->iClientId == pR->iLevelOwnerId) || (pR->Sense() == DStaticPowerResource::ECustom)) |
|
1556 #endif |
|
1557 { |
|
1558 pReq->ReqType() = TPowerRequest::ESetDefaultLevel; |
|
1559 pReq->ResourceId() = pCL->iResourceId; |
|
1560 pReq->ClientId() = pCL->iClientId; |
|
1561 pReq->Resource() = pR; |
|
1562 pReq->Level() = pR->iCachedLevel; |
|
1563 pReq->ResourceCb() = NULL; |
|
1564 pReq->ReturnCode() = KErrNone; |
|
1565 r = KErrNone; |
|
1566 #ifdef PRM_INSTRUMENTATION_MACRO |
|
1567 //Setting level to current level as correct level will be known only at the end, |
|
1568 TInt aNewState = pR->iCachedLevel; |
|
1569 TUint aResourceId = pReq->ResourceId(); |
|
1570 PRM_CLIENT_CHANGE_STATE_START_TRACE |
|
1571 #endif |
|
1572 if(pR->LatencySet()) |
|
1573 { |
|
1574 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1575 if(pCL->iResourceId & KIdMaskDynamic) |
|
1576 ((DDynamicPowerResource*)pR)->Lock(); |
|
1577 #endif |
|
1578 UnLock(); |
|
1579 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1580 if(pR->iResourceId & KIdMaskResourceWithDependencies) //Dependency resource |
|
1581 r = pReq->SendReceive(iMsgQDependency); |
|
1582 else |
|
1583 #endif |
|
1584 r = pReq->SendReceive(iMsgQ); |
|
1585 Lock(); |
|
1586 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1587 if(pCL->iResourceId & KIdMaskDynamic) |
|
1588 ((DDynamicPowerResource*)pR)->UnLock(); |
|
1589 #endif |
|
1590 } |
|
1591 else |
|
1592 { |
|
1593 if(pR->Usage()) |
|
1594 { |
|
1595 //Not checking return value as there is no memory allocation at this point |
|
1596 CheckLevelAndAddClient(pC, pReq); |
|
1597 } |
|
1598 else |
|
1599 { |
|
1600 pReq->ClientId() = -1; |
|
1601 pReq->Level() = pR->iDefaultLevel; |
|
1602 } |
|
1603 if((!pR->Usage()) || (pR->Usage() && pReq->RequiresChange())) |
|
1604 { |
|
1605 // NOTE:Not checking error here as no action can be taken based on error. |
|
1606 UnLock(); |
|
1607 r = pR->DoRequest(*pReq); |
|
1608 Lock(); |
|
1609 CompleteNotifications(pReq->ClientId(), pReq->Resource(), pReq->Level(), |
|
1610 pReq->ReturnCode(), pReq->ClientId(), EFalse); |
|
1611 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
1612 pR->iLevelOwnerId = pReq->ClientId(); |
|
1613 pR->iCachedLevel = pReq->Level(); |
|
1614 if(pR->iIdleListEntry) |
|
1615 { |
|
1616 SIdleResourceInfo* pI = (SIdleResourceInfo*)pR->iIdleListEntry; |
|
1617 pI->iLevelOwnerId = pReq->ClientId(); |
|
1618 pI->iCurrentLevel = pReq->Level(); |
|
1619 } |
|
1620 } |
|
1621 } |
|
1622 } |
|
1623 /* Deque from resource */ |
|
1624 pCLL = pCL; |
|
1625 pCL = pCL->iNextInList; |
|
1626 pCLL->Deque(); |
|
1627 iClientLevelPoolCount++; |
|
1628 LIST_PUSH(iClientLevelPool,pCLL,iNextInList); // back to free pool |
|
1629 } |
|
1630 pC->iLevelList = NULL; |
|
1631 //Add reserved client level to free pool |
|
1632 iClientLevelPoolCount = (TUint16)(iClientLevelPoolCount + (TUint16)pC->iReservedCl); |
|
1633 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::ResourceStateChangeOfClientLevels")); |
|
1634 } |
|
1635 |
|
1636 /** |
|
1637 @publishedPartner |
|
1638 @prototype 9.5 |
|
1639 |
|
1640 Deregister a client with the resource manager |
|
1641 |
|
1642 @param aClientId The ID of the client which is being deregistered |
|
1643 |
|
1644 @return KErrNone if the operation was successful |
|
1645 KErrNotFound if this client ID could not be found in the current |
|
1646 list of clients |
|
1647 KErrArgument if user side client Id is specified or client ID to be used |
|
1648 by Power Controller is specified. |
|
1649 KErrAccessDenied if client was registered to be thread relative and this |
|
1650 API is not called from the same thread. |
|
1651 |
|
1652 @pre Interrupts must be enabled |
|
1653 @pre Kernel must be unlocked |
|
1654 @pre No fast mutex can be held |
|
1655 @pre Call in a thread context but not from null thread or DFC thread1 |
|
1656 @pre Can be used in a device driver |
|
1657 */ |
|
1658 TInt DPowerResourceController::DeRegisterClient(TUint aClientId) |
|
1659 { |
|
1660 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::DeRegisterClient, ClientId = 0x%x", aClientId)); |
|
1661 DThread& thread = Kern::CurrentThread(); |
|
1662 CHECK_CONTEXT(thread) |
|
1663 if((aClientId & USER_SIDE_CLIENT_BIT_MASK) || (aClientId == iPowerControllerId)) |
|
1664 return KErrArgument; |
|
1665 //Get the index from client ID |
|
1666 Lock(); |
|
1667 SPowerResourceClient* pC = iClientList[(TUint16)(aClientId & ID_INDEX_BIT_MASK)]; |
|
1668 if(!pC) |
|
1669 { |
|
1670 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client ID not Found")); |
|
1671 UNLOCK_RETURN(KErrNotFound); |
|
1672 } |
|
1673 if(pC->iClientId != aClientId) |
|
1674 { |
|
1675 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client ID does not match")); |
|
1676 UNLOCK_RETURN(KErrNotFound); |
|
1677 } |
|
1678 if(pC->iClientId & CLIENT_THREAD_RELATIVE_BIT_MASK) |
|
1679 { |
|
1680 if(pC->iThreadId != thread.iId) |
|
1681 { |
|
1682 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client not called from thread context(Thread Relative)")); |
|
1683 UNLOCK_RETURN(KErrAccessDenied); |
|
1684 } |
|
1685 } |
|
1686 //Check for any pending request |
|
1687 if(pC->iPendingReqCount) |
|
1688 { |
|
1689 UnLock(); |
|
1690 Panic(EClientHasPendingAsyncRequest); |
|
1691 } |
|
1692 //Check for notification request |
|
1693 if(pC->iNotificationList) |
|
1694 { |
|
1695 UnLock(); |
|
1696 Panic(EClientHasNotificationObject); |
|
1697 } |
|
1698 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1699 if(pC->iDynamicResCount) |
|
1700 { |
|
1701 UnLock(); |
|
1702 Panic(DPowerResourceController::EClientHasDynamicResourceRegistered); |
|
1703 } |
|
1704 #endif |
|
1705 //Check for registration of dynamic resource |
|
1706 ResourceStateChangeOfClientLevels(pC); |
|
1707 // Add reserved request to pool |
|
1708 iRequestPoolCount = (TUint16)(iRequestPoolCount + (TUint16)pC->iReservedRm); |
|
1709 PRM_CLIENT_DEREGISTER_TRACE |
|
1710 //Increment the free pool count for client level and request level. |
|
1711 iClientList.Remove(pC, (TUint16)(pC->iClientId & ID_INDEX_BIT_MASK)); |
|
1712 pC->iName = NULL; |
|
1713 iClientCount--; //Decrement client count |
|
1714 LIST_PUSH(iClientPool, pC, iNextInList); |
|
1715 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::DeRegisterClient")); |
|
1716 UNLOCK_RETURN(KErrNone); |
|
1717 } |
|
1718 |
|
1719 /** |
|
1720 @publishedPartner |
|
1721 @prototype 9.5 |
|
1722 |
|
1723 Obtain the name of a registered client of the resource manager |
|
1724 |
|
1725 @param aClientId The ID of the client which is requesting the name of |
|
1726 another client whose ID is specified in aTargetClientId. |
|
1727 @param aTargetClientId The ID of the client whose name is being requested. |
|
1728 @param aName Descriptor to be filled with the name of the client. The descriptor |
|
1729 is created by the client in kernel stack or heap. |
|
1730 |
|
1731 @return KErrNone if the operation was successful |
|
1732 KErrNotFound if this client ID (aTargetClientId) could not be |
|
1733 found in the current list of registered clients. |
|
1734 KErrAccessDenied if the client ID (aClientId) could not be found |
|
1735 in the current list of registered clients or if client was registered |
|
1736 to be thread relative and this API is not called from the same thread. |
|
1737 KErrArgument if size of aName is less than 32. |
|
1738 |
|
1739 @pre Interrupts must be enabled |
|
1740 @pre Kernel must be unlocked |
|
1741 @pre No fast mutex can be held |
|
1742 @pre Call in a thread context but not from null thread or DFC thread1 |
|
1743 @pre Can be used in a device driver |
|
1744 */ |
|
1745 TInt DPowerResourceController::GetClientName(TUint aClientId, TUint aTargetClientId, TDes8& aName) |
|
1746 { |
|
1747 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetClientName, CallingClientId = 0x%x, \ |
|
1748 TargetClientId = 0x%x", aClientId, aTargetClientId)); |
|
1749 DThread& thread = Kern::CurrentThread(); |
|
1750 CHECK_CONTEXT(thread) |
|
1751 if((aName.MaxLength() - aName.Length()) < KMaxClientNameLength) |
|
1752 return KErrArgument; |
|
1753 SPowerResourceClient* pC = NULL; |
|
1754 Lock(); |
|
1755 VALIDATE_CLIENT(thread); |
|
1756 GET_TARGET_CLIENT(); |
|
1757 aName.Append(*pC->iName); |
|
1758 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetClientName, ClientName = %S", &aName)); |
|
1759 UNLOCK_RETURN(KErrNone); |
|
1760 } |
|
1761 |
|
1762 /** |
|
1763 @publishedPartner |
|
1764 @prototype 9.5 |
|
1765 |
|
1766 Obtain the Id of registered client of the resource manager |
|
1767 |
|
1768 @param aClientId ID of the client which is requesting the ID of the another |
|
1769 client whose name is specified in aClientName |
|
1770 @param aClientName Descriptor containing the name of the client whose ID is being |
|
1771 requested. The client must create the descriptor in kernel stack |
|
1772 or heap. |
|
1773 NOTE: Resource manager does not check for uniqueness of client |
|
1774 name during registration, so if there are multiple clients registered |
|
1775 to PRM with same name it will return the ID of the first client it encounters. |
|
1776 @param aTargetClientId Updates with ID of the requested client on success |
|
1777 |
|
1778 @return KErrNone if the operation was successful |
|
1779 KErrNotFound if this client name could not be found in the current list of registered |
|
1780 client |
|
1781 KErrAccessDenied if the client ID (aClientId) could not be found in the current |
|
1782 list of registered client or if the client was registered to be |
|
1783 thread relative and this API is not called from the same thread. |
|
1784 KErrTooBig if the length of the descriptor passed is greater than 32. |
|
1785 |
|
1786 @pre Interrupts must be enabled |
|
1787 @pre Kernel must be unlocked |
|
1788 @pre No fast mutex can be held |
|
1789 @pre Call in a thread context but not from null thread or DFC thread1 |
|
1790 @pre Can be used in a device driver |
|
1791 */ |
|
1792 TInt DPowerResourceController::GetClientId(TUint aClientId, TDesC8& aClientName, TUint& aTargetClientId) |
|
1793 { |
|
1794 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetClientId CallingClientId = 0x%x, \ |
|
1795 ClientName = %S", aClientId, &aClientName)); |
|
1796 DThread& thread = Kern::CurrentThread(); |
|
1797 CHECK_CONTEXT(thread) |
|
1798 if(aClientName.Length() > KMaxClientNameLength) |
|
1799 return KErrTooBig; |
|
1800 SPowerResourceClient* pC = NULL; |
|
1801 Lock(); |
|
1802 VALIDATE_CLIENT(thread); |
|
1803 //Find the client ID with the specified name first from kernel client list & then user side. |
|
1804 if(iClientList.Find(pC, aClientName) && iUserSideClientList.Find(pC, aClientName)) |
|
1805 UNLOCK_RETURN(KErrNotFound); |
|
1806 aTargetClientId = pC->iClientId; |
|
1807 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetClientId TargetClientId = 0x%x", aTargetClientId)); |
|
1808 UNLOCK_RETURN(KErrNone); |
|
1809 } |
|
1810 |
|
1811 /** |
|
1812 @publishedPartner |
|
1813 @prototype 9.5 |
|
1814 |
|
1815 Obtain the ID of registered resource of the resource manager. |
|
1816 NOTE: ID of the first matching name found in the resource list will be returned |
|
1817 |
|
1818 @param aClientId ID of the client which is requesting the ID of the |
|
1819 resource, by specifying its name. |
|
1820 @param aResourceName Descriptor containing the name of the resource whose |
|
1821 ID is being requested. |
|
1822 @param aResourceId Updates with ID of the requested resource on success |
|
1823 |
|
1824 @return KErrNone if the operation was successful |
|
1825 KErrAccessDenied if the ID of the client could not be found in the |
|
1826 current list of registered clients or if the client was |
|
1827 registered to be thread relative and this API is not called |
|
1828 from the same thread. |
|
1829 KErrNotFound if this resource name could not be found in the current |
|
1830 list of registered resources. |
|
1831 KErrTooBig if the length of the descriptor passed is greater than maximum |
|
1832 allowable resource name length (32). |
|
1833 @pre Interrupts must be enabled |
|
1834 @pre Kernel must be unlocked |
|
1835 @pre No fast mutex can be held |
|
1836 @pre Call in a thread context but not from null thread or DFC thread1 |
|
1837 @pre Can be used in a device driver |
|
1838 */ |
|
1839 TInt DPowerResourceController::GetResourceId(TUint aClientId, TDesC8& aResourceName, TUint& aResourceId) |
|
1840 { |
|
1841 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetResourceId")); |
|
1842 __KTRACE_OPT(KRESMANAGER, Kern::Printf("CallingClientId = 0x%x, ResourceName = %S", aClientId, &aResourceName)); |
|
1843 DThread& thread = Kern::CurrentThread(); |
|
1844 CHECK_CONTEXT(thread) |
|
1845 SPowerResourceClient* pC; |
|
1846 if(aResourceName.Length() > KMaxResourceNameLength) |
|
1847 return KErrTooBig; |
|
1848 Lock(); |
|
1849 VALIDATE_CLIENT(thread); |
|
1850 TUint count = 0; |
|
1851 //Search in static resource with no dependencies array for specified resource name. |
|
1852 for(count = 0; count < iStaticResourceArrayEntries; count++) |
|
1853 { |
|
1854 if((iStaticResourceArray[count]) && (!(aResourceName.Compare(*(const TDesC8*)iStaticResourceArray[count]->iName)))) |
|
1855 { |
|
1856 aResourceId = ++count; |
|
1857 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetResourceId, ResourceId = 0x%x", \ |
|
1858 aResourceId)); |
|
1859 UNLOCK_RETURN(KErrNone); |
|
1860 } |
|
1861 } |
|
1862 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
1863 //Search in dynamic resource with no dependencies array for specified resource name. |
|
1864 DDynamicPowerResource* pDR = NULL; |
|
1865 if(PowerResourceController->iDynamicResourceCount && |
|
1866 !PowerResourceController->iDynamicResourceList.Find(pDR, aResourceName)) |
|
1867 { |
|
1868 aResourceId = pDR->iResourceId; |
|
1869 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetResourceId, ResourceId = 0x%x", aResourceId)); |
|
1870 UNLOCK_RETURN(KErrNone); |
|
1871 } |
|
1872 //Search in static resource with dependencies (if exists) for specified resource name |
|
1873 for(count = 0; count < iStaticResDependencyCount; count++) |
|
1874 { |
|
1875 if(!(aResourceName.Compare(*(const TDesC8*)iStaticResDependencyArray[count]->iName))) |
|
1876 { |
|
1877 aResourceId = iStaticResDependencyArray[count]->iResourceId; |
|
1878 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetResourceId, ResourceId = 0x%x", \ |
|
1879 aResourceId)); |
|
1880 UNLOCK_RETURN(KErrNone); |
|
1881 } |
|
1882 } |
|
1883 //Search in dynamic resource with dependencies (if exists) for specified resource name |
|
1884 DDynamicPowerResourceD* pDRD; |
|
1885 if(iDynamicResDependencyCount && !iDynamicResDependencyList.Find(pDRD, aResourceName)) |
|
1886 { |
|
1887 aResourceId = pDRD->iResourceId; |
|
1888 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetResourceId, ResourceId = 0x%x", aResourceId)); |
|
1889 UNLOCK_RETURN(KErrNone); |
|
1890 } |
|
1891 #endif |
|
1892 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetResourceId, ResourceID not found")); |
|
1893 UNLOCK_RETURN(KErrNotFound); |
|
1894 } |
|
1895 |
|
1896 /** |
|
1897 @publishedPartner |
|
1898 @prototype 9.5 |
|
1899 |
|
1900 Request a structure containing information on a resource. |
|
1901 |
|
1902 @param aClientId ID of the client which is requesting the resource information |
|
1903 @param aResourceId ID of the resource whose information is being requested. |
|
1904 @param aInfo A pointer to descriptor containing resource information |
|
1905 structure (TPowerResourceInfoV01) to be filled in |
|
1906 with the requested resource information. The client must |
|
1907 create the descriptor in kernel stack or heap. |
|
1908 |
|
1909 @return KErrNone if the operation was successful |
|
1910 KErrAccessDenied if the client ID could not be found in the current list |
|
1911 of registered clients or if the client was registered to be |
|
1912 thread relative and this API is not called from the same thread. |
|
1913 KErrNotFound if this resource ID could not be found in the current list |
|
1914 of controllable resource. |
|
1915 KErrArgument if aInfo is NULL or size of descriptor passed is less than size of |
|
1916 TPowerResourceInfoV01. |
|
1917 @pre Interrupts must be enabled |
|
1918 @pre Kernel must be unlocked |
|
1919 @pre No fast mutex can be held |
|
1920 @pre Call in a thread context but not from null thread or DFC thread1 |
|
1921 @pre Can be used in a device driver |
|
1922 */ |
|
1923 TInt DPowerResourceController::GetResourceInfo(TUint aClientId, TUint aResourceId, TAny* aInfo) |
|
1924 { |
|
1925 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetResourceInfo")); |
|
1926 __KTRACE_OPT(KRESMANAGER, Kern::Printf("CallingClientId = 0x%x, ResourceId = %d", aClientId, aResourceId)); |
|
1927 DThread& thread = Kern::CurrentThread(); |
|
1928 CHECK_CONTEXT(thread) |
|
1929 if(!aInfo) |
|
1930 return KErrArgument; |
|
1931 SPowerResourceClient* pC = NULL; |
|
1932 Lock(); |
|
1933 VALIDATE_CLIENT(thread); |
|
1934 TDes8* buf = (TDes8*)aInfo; |
|
1935 TInt r = KErrNone; |
|
1936 DStaticPowerResource *pR = NULL; |
|
1937 |
|
1938 //Validate buffer size |
|
1939 if((TUint)(buf->MaxLength() - buf->Length()) < sizeof(TPowerResourceInfoV01)) |
|
1940 UNLOCK_RETURN(KErrArgument); |
|
1941 |
|
1942 #ifndef PRM_ENABLE_EXTENDED_VERSION |
|
1943 if((!aResourceId) || (aResourceId > iStaticResourceArrayEntries)) |
|
1944 UNLOCK_RETURN(KErrNotFound); |
|
1945 //Get resource from static resource array. 0(1) operation. |
|
1946 pR = iStaticResourceArray[aResourceId-1]; |
|
1947 if(!pR) |
|
1948 { |
|
1949 UNLOCK_RETURN(KErrNotFound); |
|
1950 } |
|
1951 #else |
|
1952 if(!aResourceId) |
|
1953 { |
|
1954 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetResourceInfo, return value = %d", \ |
|
1955 KErrNotFound)); |
|
1956 UNLOCK_RETURN(KErrNotFound); |
|
1957 } |
|
1958 //Get resource from corresponding container |
|
1959 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
1960 #endif |
|
1961 //Update resource info |
|
1962 TPowerResourceInfoBuf01 infoBuf; |
|
1963 r = pR->GetInfo((TDes8*)infoBuf.Ptr()); |
|
1964 //Update ResourceId |
|
1965 ((TPowerResourceInfoV01*)infoBuf.Ptr())->iResourceId = aResourceId; |
|
1966 if(r == KErrNone) |
|
1967 buf->Append(infoBuf); |
|
1968 UNLOCK_RETURN(r); |
|
1969 } |
|
1970 |
|
1971 /** |
|
1972 @publishedPartner |
|
1973 @prototype 9.5 |
|
1974 |
|
1975 Request number of resources the specified client (aTargetClientId) has |
|
1976 requirement on resource level. Client ID starts from 1, so if 0 is specified in |
|
1977 aTargetClientId, returns the number of controllable resources registered with PRM. |
|
1978 |
|
1979 @param aClientId ID of the client which is requesting the number of resources |
|
1980 the specified client (aTargetClientId) holds requirement on |
|
1981 resource level change. |
|
1982 @param aTargetClientId ID of the client. The number of resources on which it |
|
1983 has requirement on resource level change is requested. |
|
1984 @param aNumResource Updated with the number of resources the specified client |
|
1985 has requirement on resource level change, if valid client |
|
1986 ID is passed. If client ID is 0, updates the total number |
|
1987 of resources registered with resource manager. |
|
1988 |
|
1989 @return KErrNone if the operation was successful. |
|
1990 KErrAccessDenied if the client ID (aClientId) could not be found in the |
|
1991 current list of registered clients or if the client was registered |
|
1992 to be thread relative and this API is not called from the same thread. |
|
1993 KErrNotFound if the client ID (aTargetClientId) could not be found in the |
|
1994 current list of registered clients and is not 0. |
|
1995 |
|
1996 @pre Interrupts must be enabled |
|
1997 @pre Kernel must be unlocked |
|
1998 @pre No fast mutex can be held |
|
1999 @pre Call in a thread context but not from null thread or DFC thread1 |
|
2000 @pre Can be used in a device driver |
|
2001 */ |
|
2002 TInt DPowerResourceController::GetNumResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, TUint& aNumResource) |
|
2003 { |
|
2004 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetNumResourcesInUseByClient")); |
|
2005 __KTRACE_OPT(KRESMANAGER, Kern::Printf("CallingClientId = 0x%x, TargetClientId = 0x%x", aClientId, aTargetClientId)); |
|
2006 DThread& thread = Kern::CurrentThread(); |
|
2007 CHECK_CONTEXT(thread) |
|
2008 SPowerResourceClient* pC = NULL; |
|
2009 Lock(); |
|
2010 VALIDATE_CLIENT(thread); |
|
2011 //Special case, return number of resources registered resource controller. |
|
2012 if(!aTargetClientId) |
|
2013 { |
|
2014 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2015 aNumResource = iStaticResourceCount + iDynamicResourceCount + iStaticResDependencyCount + |
|
2016 iDynamicResDependencyCount; |
|
2017 #else |
|
2018 aNumResource = iStaticResourceCount; |
|
2019 #endif |
|
2020 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetNumResourcesInUseByClient, \ |
|
2021 numResources = %d", aNumResource)); |
|
2022 UNLOCK_RETURN(KErrNone); |
|
2023 } |
|
2024 GET_TARGET_CLIENT(); |
|
2025 SPowerResourceClientLevel* pCL = pC->iLevelList; |
|
2026 aNumResource = 0; |
|
2027 while(pCL) |
|
2028 { |
|
2029 aNumResource++; |
|
2030 pCL = pCL->iNextInList; |
|
2031 } |
|
2032 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetNumResourcesInUseByClient, \ |
|
2033 numResources = %d", aNumResource)); |
|
2034 UNLOCK_RETURN(KErrNone); |
|
2035 } |
|
2036 |
|
2037 /** |
|
2038 @publishedPartner |
|
2039 @prototype 9.5 |
|
2040 |
|
2041 Request information on resources. |
|
2042 If client ID (aTargetClientId) is valid, aInfo is updated with the information of the resources |
|
2043 this client hold requirement on the resource level. |
|
2044 If client ID (aTargetClientId) is 0, aInfo is updated with the information of the resources |
|
2045 registered with resource controller. |
|
2046 Number of resource information updated will be equal or less than the number specified in aNumResources. |
|
2047 |
|
2048 @param aClientId ID of the client which is requesting the resource information. |
|
2049 @param aTargetClientId ID of the client. The information of all the resources on |
|
2050 which it has requirement on resource level change is requested. |
|
2051 Client ID starts from 1, so calling this API with client ID 0 will |
|
2052 fill the details of all the controllable resource registered with |
|
2053 resource manager. |
|
2054 @param aNumResources Number of resource whose information needs to be filled in aInfo i.e, |
|
2055 it specifies the size of aInfo array. |
|
2056 @param aInfo A pointer to an array of descriptor containing an information structure |
|
2057 (TPowerResourceInfoV01) to be filled in with the information |
|
2058 on the resources. It will be assumed that array allocated will be equal |
|
2059 to the number passed in aNumResources. The client must create the array |
|
2060 in Kernel stack or heap. |
|
2061 |
|
2062 @return KErrNone if the operation was successful |
|
2063 KErrAccessDenied if client ID (aClientId) could not be found in the registered |
|
2064 client list or if the client was registered to be thread relative |
|
2065 and this API is not called from the same thread. |
|
2066 KErrNotFound if client ID (aTargetClientId) could not be found in the current list |
|
2067 of registered client and is also not 0. |
|
2068 KErrArgument if aNumResources is 0 or aInfo is NULL or if size of aInfo is not sufficient |
|
2069 to hold the resource information of number of resources specified in aNumResources. |
|
2070 |
|
2071 @pre Interrupts must be enabled |
|
2072 @pre Kernel must be unlocked |
|
2073 @pre No fast mutex can be held |
|
2074 @pre Call in a thread context but not from null thread or DFC thread1 |
|
2075 @pre Can be used in a device driver |
|
2076 */ |
|
2077 TInt DPowerResourceController::GetInfoOnResourcesInUseByClient(TUint aClientId, TUint aTargetClientId, |
|
2078 TUint& aNumResources, TAny* anInfo) |
|
2079 { |
|
2080 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetInfoOnResourcesInUseByClient")); |
|
2081 __KTRACE_OPT(KRESMANAGER, Kern::Printf("CallingClientId = 0x%x, TargetClientId = 0x%x, NumResources = %d", \ |
|
2082 aClientId, aTargetClientId, aNumResources)); |
|
2083 DThread& thread = Kern::CurrentThread(); |
|
2084 CHECK_CONTEXT(thread) |
|
2085 if(!anInfo || !aNumResources) |
|
2086 return KErrArgument; |
|
2087 SPowerResourceClient* pC = NULL; |
|
2088 Lock(); |
|
2089 VALIDATE_CLIENT(thread); |
|
2090 DStaticPowerResource* pR = NULL; |
|
2091 TDes8 *pInfo = (TDes8*)anInfo; |
|
2092 if((TUint)(pInfo->MaxLength() - pInfo->Length()) < (sizeof(TPowerResourceInfoV01) * aNumResources)) |
|
2093 UNLOCK_RETURN(KErrArgument); |
|
2094 TPowerResourceInfoBuf01 buf; |
|
2095 |
|
2096 TUint16 count = 0; |
|
2097 TInt r = KErrNone; |
|
2098 //Special case, if aTargetClientId is 0 fill with all the resource |
|
2099 if(!aTargetClientId) |
|
2100 { |
|
2101 TUint numResources = aNumResources; |
|
2102 #ifndef PRM_ENABLE_EXTENDED_VERSION |
|
2103 aNumResources = iStaticResourceCount; |
|
2104 #else |
|
2105 aNumResources = iStaticResourceCount + iDynamicResourceCount + iStaticResDependencyCount + |
|
2106 iDynamicResDependencyCount; |
|
2107 #endif |
|
2108 UnLock(); |
|
2109 while(count < iStaticResourceArrayEntries) |
|
2110 { |
|
2111 if(numResources <=0) |
|
2112 return KErrNone; |
|
2113 pR = iStaticResourceArray[count++]; |
|
2114 if(!pR) |
|
2115 continue; |
|
2116 r = pR->GetInfo((TDes8*)buf.Ptr()); |
|
2117 if(r != KErrNone) |
|
2118 return r; |
|
2119 //Update Resource Id. |
|
2120 ((TPowerResourceInfoV01*)buf.Ptr())->iResourceId = count; |
|
2121 pInfo->Append(buf); |
|
2122 numResources--; |
|
2123 } |
|
2124 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2125 count = 0; |
|
2126 while(count < iStaticResDependencyCount) |
|
2127 { |
|
2128 if(count >= numResources) |
|
2129 return KErrNone; |
|
2130 pR = iStaticResDependencyArray[count++]; |
|
2131 r = pR->GetInfo((TDes8*)buf.Ptr()); |
|
2132 //Update Resource Id. |
|
2133 ((TPowerResourceInfoV01*)buf.Ptr())->iResourceId = ((DStaticPowerResourceD*)pR)->iResourceId; |
|
2134 if(r != KErrNone) |
|
2135 return r; |
|
2136 pInfo->Append(buf); |
|
2137 } |
|
2138 numResources -= iStaticResDependencyCount; |
|
2139 if((!numResources) || (!iDynamicResourceCount && !iDynamicResDependencyCount)) |
|
2140 return r; |
|
2141 Lock(); |
|
2142 TUint resCount = 0; |
|
2143 for(count = 0; count < iDynamicResourceList.Allocd(); count++) |
|
2144 { |
|
2145 pR = iDynamicResourceList[count]; |
|
2146 if(!pR) |
|
2147 continue; |
|
2148 if((resCount >= iDynamicResourceCount) || (resCount >= numResources)) |
|
2149 UNLOCK_RETURN(KErrNone); |
|
2150 r = pR->GetInfo((TDes8*)buf.Ptr()); |
|
2151 if(r != KErrNone) |
|
2152 UNLOCK_RETURN(r); |
|
2153 ((TPowerResourceInfoV01*)buf.Ptr())->iResourceId = ((DDynamicPowerResource*)pR)->iResourceId; |
|
2154 pInfo->Append(buf); |
|
2155 resCount++; |
|
2156 } |
|
2157 numResources -= resCount; |
|
2158 resCount = 0; |
|
2159 for(count = 0; count < iDynamicResDependencyList.Allocd(); count++) |
|
2160 { |
|
2161 pR = iDynamicResDependencyList[count]; |
|
2162 if(!pR) |
|
2163 continue; |
|
2164 if((resCount >= iDynamicResDependencyCount) || (resCount >= numResources)) |
|
2165 UNLOCK_RETURN(KErrNone); |
|
2166 r = pR->GetInfo((TDes8*)buf.Ptr()); |
|
2167 if(r != KErrNone) |
|
2168 UNLOCK_RETURN(r); |
|
2169 ((TPowerResourceInfoV01*)buf.Ptr())->iResourceId = ((DDynamicPowerResourceD*)pR)->iResourceId; |
|
2170 pInfo->Append(buf); |
|
2171 resCount++; |
|
2172 } |
|
2173 UnLock(); |
|
2174 #endif |
|
2175 return r; |
|
2176 } |
|
2177 GET_TARGET_CLIENT(); |
|
2178 SPowerResourceClientLevel* pCL = pC->iLevelList; |
|
2179 for (count= 0; pCL; count++, pCL = pCL->iNextInList) |
|
2180 { |
|
2181 if(count >= aNumResources) |
|
2182 continue; |
|
2183 #ifndef PRM_ENABLE_EXTENDED_VERSION |
|
2184 pR = iStaticResourceArray[pCL->iResourceId-1]; |
|
2185 #else |
|
2186 GET_RESOURCE_FROM_LIST(pCL->iResourceId, pR); |
|
2187 #endif |
|
2188 r = pR->GetInfo((TDes8*)buf.Ptr()); |
|
2189 //Update Resource Id. |
|
2190 ((TPowerResourceInfoV01*)buf.Ptr())->iResourceId = pCL->iResourceId; |
|
2191 if(r != KErrNone) |
|
2192 UNLOCK_RETURN(r); |
|
2193 pInfo->Append(buf); |
|
2194 } |
|
2195 aNumResources = count; |
|
2196 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetInfoOnResourcesInUseByClient, \ |
|
2197 AcutalNoOfResources = %d", aNumResources)); |
|
2198 UNLOCK_RETURN(KErrNone); |
|
2199 } |
|
2200 |
|
2201 /** |
|
2202 @publishedPartner |
|
2203 @prototype 9.5 |
|
2204 |
|
2205 Request number of clients which has requirements on the resource level of the specified |
|
2206 resource. Resource ID starts from 1, so 0 can be used to get the number of clients |
|
2207 registered with resource manager. |
|
2208 |
|
2209 @param aClientId ID of the client which is requesting number of clients |
|
2210 holding requirement on specified resource. |
|
2211 @param aResourceId ID of the resource. |
|
2212 @param aNumClient This is updated with number of clients having a requirement |
|
2213 on resource level if valid resource ID is specified. |
|
2214 If resource ID is 0, then it is updated with number of clients |
|
2215 registered with PRM. |
|
2216 |
|
2217 @return KErrNone if the operation was successful |
|
2218 KErrAccessDenied if the client ID could not found in the current list of |
|
2219 registered clients or if the client was registered to be thread |
|
2220 relative and this API is not called from the same thread. |
|
2221 KErrNotFound If this resource ID could not be found in the current list |
|
2222 of registered resource and is also not 0. |
|
2223 |
|
2224 @pre Interrupts must be enabled |
|
2225 @pre Kernel must be unlocked |
|
2226 @pre No fast mutex can be held |
|
2227 @pre Call in a thread context but not from null thread or DFC thread1 |
|
2228 @pre Can be used in a device driver |
|
2229 */ |
|
2230 TInt DPowerResourceController::GetNumClientsUsingResource(TUint aClientId, TUint aResourceId, TUint& aNumClients) |
|
2231 { |
|
2232 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetNumClientsUsingResource")); |
|
2233 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d", aClientId, aResourceId)); |
|
2234 DThread& thread = Kern::CurrentThread(); |
|
2235 CHECK_CONTEXT(thread) |
|
2236 SPowerResourceClient* pC = NULL; |
|
2237 Lock(); |
|
2238 VALIDATE_CLIENT(thread); |
|
2239 if(!aResourceId) |
|
2240 { |
|
2241 //Special case return the number of clients registered with resource controller. |
|
2242 aNumClients = iClientCount + iUserSideClientCount; |
|
2243 UNLOCK_RETURN(KErrNone); |
|
2244 } |
|
2245 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2246 DStaticPowerResource* pR = NULL; |
|
2247 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
2248 #else |
|
2249 if(aResourceId > iStaticResourceArrayEntries) |
|
2250 UNLOCK_RETURN(KErrNotFound); |
|
2251 DStaticPowerResource* pR = iStaticResourceArray[aResourceId-1]; |
|
2252 if(!pR) |
|
2253 UNLOCK_RETURN(KErrNotFound); |
|
2254 #endif |
|
2255 aNumClients = 0; |
|
2256 for(SDblQueLink*pCL = pR->iClientList.First(); pCL != &pR->iClientList.iA; pCL=pCL->iNext) |
|
2257 aNumClients++; |
|
2258 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetNumClientsUsingResource, \ |
|
2259 NumClients = %d", aNumClients)); |
|
2260 UNLOCK_RETURN(KErrNone); |
|
2261 } |
|
2262 |
|
2263 /** |
|
2264 @publishedPartner |
|
2265 @prototype 9.5 |
|
2266 |
|
2267 Request information on clients |
|
2268 If resource ID is valid, aInfo is updated with the information of the clients |
|
2269 which have a requirement on the resource level for the specified resource |
|
2270 If resource ID is 0, aInfo is updated with the information of the clients registered |
|
2271 with resource manager, starting from client ID 1. |
|
2272 The number of clients for which information will be provided will be equal to or less |
|
2273 than the number specified in aNumClients. |
|
2274 @param aClientId ID of the client which is requesting the information on |
|
2275 the clients which holds requirement on specified |
|
2276 resource's level change. |
|
2277 @param aResourceId Id of the resource. |
|
2278 @param aNumClients Number of clients whose information needs to be filled in aInfo |
|
2279 i.e., it specifies the size of aInfo array. |
|
2280 @param aInfo A pointer to an array of descriptor containing an information |
|
2281 structure (TPowerClientInfoV01) to be filled in with |
|
2282 the information on the client. It will be assumed that array |
|
2283 allocated will be equal to the number passed in aNumClients. |
|
2284 The Client must create the array of descriptors in kernel stack |
|
2285 or heap. |
|
2286 |
|
2287 @return KErrNone if the operation was successful. |
|
2288 KErrNotFound if resource ID could not be found in the registered resource list and is not 0. |
|
2289 KErrAccessDenied if client ID (aClientId) could not be found in the registered client |
|
2290 list or if the client was registered to be thread relative and this API is not |
|
2291 called from the same thread. |
|
2292 KErrArgument if aNumClients is 0 or aInfo is NULL or if size of aInfo is not sufficient to hold |
|
2293 client information of specified client number in aNumClients. |
|
2294 |
|
2295 @pre Interrupts must be enabled |
|
2296 @pre Kernel must be unlocked |
|
2297 @pre No fast mutex can be held |
|
2298 @pre Call in a thread context but not from null thread or DFC thread1 |
|
2299 @pre Can be used in a device driver |
|
2300 */ |
|
2301 TInt DPowerResourceController::GetInfoOnClientsUsingResource(TUint aClientId, TUint aResourceId, |
|
2302 TUint& aNumClients, TAny* anInfo) |
|
2303 { |
|
2304 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetInfoOnClientsUsingResource")); |
|
2305 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d, NumClients = %d", \ |
|
2306 aClientId, aResourceId, aNumClients)); |
|
2307 DThread& thread = Kern::CurrentThread(); |
|
2308 CHECK_CONTEXT(thread) |
|
2309 if(!anInfo || !aNumClients) |
|
2310 return KErrArgument; |
|
2311 SPowerResourceClient* pC = NULL; |
|
2312 Lock(); |
|
2313 VALIDATE_CLIENT(thread); |
|
2314 TDes8 *pInfo = (TDes8*)anInfo; |
|
2315 if((TUint)(pInfo->MaxLength() - pInfo->Length()) < (sizeof(TPowerClientInfoV01) * aNumClients)) |
|
2316 UNLOCK_RETURN(KErrArgument); |
|
2317 TPowerClientInfoV01 info; |
|
2318 if(aResourceId == 0) |
|
2319 { |
|
2320 TUint16 count = 0, resCount = 0; |
|
2321 for(count = 0; count < iClientList.Allocd(); count++) |
|
2322 { |
|
2323 if((resCount >= iClientCount) || (resCount >= aNumClients)) |
|
2324 break; |
|
2325 pC = iClientList[count]; |
|
2326 if(!pC) |
|
2327 continue; |
|
2328 resCount++; |
|
2329 info.iClientId = pC->iClientId; |
|
2330 info.iClientName = (TDesC8*)pC->iName; |
|
2331 pInfo->Append(TPckgC<TPowerClientInfoV01>(info)); |
|
2332 } |
|
2333 aNumClients -= resCount; |
|
2334 resCount = 0; |
|
2335 for(count = 0; count < iUserSideClientList.Allocd(); count++) |
|
2336 { |
|
2337 if((resCount >= iUserSideClientCount) || (resCount >= aNumClients)) |
|
2338 break; |
|
2339 pC = iUserSideClientList[count]; |
|
2340 if(!pC) |
|
2341 continue; |
|
2342 resCount++; |
|
2343 info.iClientId = pC->iClientId; |
|
2344 info.iClientName = (TDesC8*)pC->iName; |
|
2345 pInfo->Append(TPckgC<TPowerClientInfoV01>(info)); |
|
2346 } |
|
2347 aNumClients = iClientCount + iUserSideClientCount; |
|
2348 UNLOCK_RETURN(KErrNone); |
|
2349 } |
|
2350 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2351 DStaticPowerResource* pR = NULL; |
|
2352 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
2353 #else |
|
2354 if(aResourceId > iStaticResourceArrayEntries) |
|
2355 UNLOCK_RETURN(KErrNotFound); |
|
2356 DStaticPowerResource* pR = iStaticResourceArray[aResourceId-1]; |
|
2357 if(!pR) |
|
2358 UNLOCK_RETURN(KErrNotFound); |
|
2359 #endif |
|
2360 SPowerResourceClientLevel* pCL = NULL; |
|
2361 TUint c = 0; |
|
2362 for(SDblQueLink* pRC = pR->iClientList.First(); pRC != &pR->iClientList.iA; pRC = pRC->iNext, c++) |
|
2363 { |
|
2364 if(c >= aNumClients) |
|
2365 continue; |
|
2366 pCL = (SPowerResourceClientLevel*)pRC; |
|
2367 if(pCL->iClientId & USER_SIDE_CLIENT_BIT_MASK) |
|
2368 pC = iUserSideClientList[(TUint16)(pCL->iClientId & ID_INDEX_BIT_MASK)]; |
|
2369 else |
|
2370 pC = iClientList[(TUint16)(pCL->iClientId & ID_INDEX_BIT_MASK)]; |
|
2371 info.iClientId = pC->iClientId; |
|
2372 info.iClientName = (TDesC8*)pC->iName; |
|
2373 pInfo->Append(TPckgC<TPowerClientInfoV01>(info)); |
|
2374 } |
|
2375 aNumClients = c; |
|
2376 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetInfoOnClientsUsingResource, \ |
|
2377 NumClients = %d", aNumClients)); |
|
2378 UNLOCK_RETURN(KErrNone); |
|
2379 } |
|
2380 |
|
2381 /** |
|
2382 @publishedPartner |
|
2383 @prototype 9.5 |
|
2384 |
|
2385 Request changing the state of a resource |
|
2386 NOTE: If a resource callback is specified for instantaneous resource, then callback |
|
2387 will be called after resource change and will be executed in the context of the |
|
2388 client thread. |
|
2389 If a resource callback is specified for long latency reosurces, then it will be |
|
2390 executed asynchronously.When the request is accepted the API returns immediately |
|
2391 and the calling thread is unblocked: the callback (called in the client's context) |
|
2392 will be invoked when the resource change finally takes place. |
|
2393 If aCb is not specified (NULL by default) the API executes synchronously and will |
|
2394 only return when the resource change has taken place for long latency resource. |
|
2395 The client thread is blocked throughout |
|
2396 When state change for a shared resource is requested, only minimum state that |
|
2397 satisfy the requirement is guaranteed and it is not guaranteed for the absolute |
|
2398 value change. |
|
2399 |
|
2400 @param aClientId ID of the client which is requesting the resource change. |
|
2401 @param aResourceId ID of the resource whose state is to be changed. |
|
2402 @param aNewState The new state of the resource. This could be a binary value for a |
|
2403 binary resource, an integer level for a multilevel resource or some |
|
2404 platform specific token for a multi-property resource. |
|
2405 @param aCb For Long latency resource |
|
2406 A pointer to a resource callback object which encapsulates a |
|
2407 callback function to be called whenever the resource state change |
|
2408 happens (if left NULL the API will execute synchrounously). |
|
2409 For Instantaneous resource |
|
2410 A pointer to a resource callback object which encapsulates a callback |
|
2411 function to be called after resource change. This executes in the |
|
2412 context of the client thread. |
|
2413 |
|
2414 @return KErrNone If the API is to be executed synchronously it indicates the change was |
|
2415 successful, if the API is to be executed asynchronously it indicates |
|
2416 the request to change the resource state has been accepted. |
|
2417 KErrNotFound if the resource ID could not be found in the current list of |
|
2418 controllable resources. |
|
2419 KErrAccessDenied if the client ID could not be found in the list of |
|
2420 registered clients or if the client was registered to be thread |
|
2421 relative and this API is not called from the same thread or if the |
|
2422 resource is single user resource and another client is already holding |
|
2423 the resource. |
|
2424 KErrNotReady if the request is issued before the resource controller completes its |
|
2425 internal initialisation. |
|
2426 KErrUnderflow if the client has exceeded the reserved number of |
|
2427 SPowerResourceClientLevel and the free pool is empty or if it is |
|
2428 an asynchronous operation on a long latency resource and the client has |
|
2429 exceeded the reserved number of TPowerRequest and the free pool is empty. |
|
2430 KErrArgument if requested level is out of range (outside of min and max levels). |
|
2431 KErrCorrupt if internal data structure is corrupted. |
|
2432 KErrPermissionDenied if the requested state of the resource is not accepted by its dependents. |
|
2433 This error is valid only for dependent resource state change in extended version |
|
2434 of PRM. |
|
2435 |
|
2436 @pre Interrupts must be enabled |
|
2437 @pre Kernel must be unlocked |
|
2438 @pre No fast mutex can be held |
|
2439 @pre Call in a thread context but not from null thread or DFC thread1 |
|
2440 @pre Can be used in a device driver |
|
2441 @pre Do not call synchronous version from DFC thread 0 for long latency resource |
|
2442 */ |
|
2443 TInt DPowerResourceController::ChangeResourceState(TUint aClientId, TUint aResourceId, TInt aNewState, |
|
2444 TPowerResourceCb* aCb) |
|
2445 { |
|
2446 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::ChangeResourceState")); |
|
2447 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d, NewState = %d", aClientId, \ |
|
2448 aResourceId, aNewState)); |
|
2449 CHECK_CONTEXT(thread) |
|
2450 if(iInitialised <= EResConCreated) |
|
2451 return KErrNotReady; |
|
2452 DThread& thread = Kern::CurrentThread(); |
|
2453 if(!aResourceId) |
|
2454 return KErrNotFound; |
|
2455 SPowerResourceClient* pC = NULL; |
|
2456 TInt r = KErrNone; |
|
2457 Lock(); |
|
2458 VALIDATE_CLIENT(thread); |
|
2459 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2460 DStaticPowerResource *pR = NULL; |
|
2461 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
2462 #else |
|
2463 if(aResourceId > iStaticResourceArrayEntries) |
|
2464 UNLOCK_RETURN(KErrNotFound); |
|
2465 DStaticPowerResource* pR = iStaticResourceArray[aResourceId-1]; |
|
2466 if(!pR) |
|
2467 UNLOCK_RETURN(KErrNotFound); |
|
2468 #endif |
|
2469 PRM_CLIENT_CHANGE_STATE_START_TRACE |
|
2470 //If long latency resource requested synchronously from DFC thread 0 Panic |
|
2471 |
|
2472 const TDesC8* pDfc0 = &KDfcThread0Name; |
|
2473 if((pR->LatencySet() && !aCb) && !(pDfc0->Compare(*(TDesC8*)thread.iName))) |
|
2474 { |
|
2475 UnLock(); |
|
2476 Panic(ECalledFromDfcThread0); |
|
2477 } |
|
2478 if(!pR->Usage() && !pR->iClientList.IsEmpty()) |
|
2479 { |
|
2480 SPowerResourceClientLevel* pCL = (SPowerResourceClientLevel*)pR->iClientList.First(); |
|
2481 if((pCL != NULL) && (pCL->iClientId != pC->iClientId)) |
|
2482 { |
|
2483 r = KErrAccessDenied; |
|
2484 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2485 UNLOCK_RETURN(r); |
|
2486 } |
|
2487 } |
|
2488 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2489 if(aResourceId & KIdMaskDynamic) |
|
2490 { |
|
2491 //Resource in the process of deregistration |
|
2492 if(((DDynamicPowerResource*)pR)->LockCount() == 0) |
|
2493 { |
|
2494 r = KErrNotFound; |
|
2495 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2496 UNLOCK_RETURN(r); |
|
2497 } |
|
2498 } |
|
2499 #endif |
|
2500 //Validate requested level |
|
2501 TPowerResourceInfoBuf01 buf; |
|
2502 r = pR->GetInfo((TDes8*)buf.Ptr()); |
|
2503 if(r != KErrNone) |
|
2504 { |
|
2505 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2506 UNLOCK_RETURN(r); |
|
2507 } |
|
2508 TPowerResourceInfoV01 *pBuf = (TPowerResourceInfoV01*)buf.Ptr(); |
|
2509 if(((pBuf->iMinLevel > pBuf->iMaxLevel) && ((aNewState > pBuf->iMinLevel) || (aNewState < pBuf->iMaxLevel))) |
|
2510 || ((pBuf->iMaxLevel > pBuf->iMinLevel) && ((aNewState > pBuf->iMaxLevel) || (aNewState < pBuf->iMinLevel)))) |
|
2511 { |
|
2512 r = KErrArgument; |
|
2513 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2514 UNLOCK_RETURN(r); |
|
2515 } |
|
2516 |
|
2517 TPowerRequest* req; |
|
2518 SPowerRequest* pS=NULL; |
|
2519 if(pR->LatencySet() && aCb) |
|
2520 { |
|
2521 // Get request object from free pool, as it is long latency reosurce as client |
|
2522 // will be unblocked once message is sent to controller, so cant use thread message. |
|
2523 if(pC->iReservedRm ==0 && !iRequestPoolCount) |
|
2524 { |
|
2525 r = KErrUnderflow; |
|
2526 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2527 UNLOCK_RETURN(r); |
|
2528 } |
|
2529 |
|
2530 LIST_POP(iRequestPool, pS, iNext); |
|
2531 if(!pS) |
|
2532 UNLOCK_RETURN(KErrCorrupt); //This should not happen |
|
2533 if(pC->iReservedRm==0) |
|
2534 { |
|
2535 iRequestPoolCount--; |
|
2536 pC->iUnderFlowRmCount++; |
|
2537 } |
|
2538 else |
|
2539 pC->iReservedRm--; |
|
2540 req=&pS->iRequest; |
|
2541 pC->iPendingReqCount++; |
|
2542 } |
|
2543 else |
|
2544 req=(TPowerRequest*)&TPowerRequest::Get(); |
|
2545 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2546 if(aResourceId & KIdMaskDynamic) |
|
2547 ((DDynamicPowerResource*)pR)->Lock(); |
|
2548 #endif |
|
2549 req->Level() = aNewState; |
|
2550 req->ResourceId() = aResourceId; |
|
2551 req->ClientId() = aClientId; |
|
2552 req->ReqType() = TPowerRequest::EChange; |
|
2553 req->Resource() = pR; |
|
2554 if(aCb) |
|
2555 { |
|
2556 aCb->iResult = KErrNone; |
|
2557 aCb->iResourceId = aResourceId; |
|
2558 aCb->iClientId = aClientId; |
|
2559 } |
|
2560 req->ResourceCb() = aCb; |
|
2561 if(pR->LatencySet()) |
|
2562 { |
|
2563 UnLock(); |
|
2564 if(aCb) |
|
2565 { |
|
2566 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2567 if (aCb->iResourceId & KIdMaskResourceWithDependencies) //Dependency resource |
|
2568 { |
|
2569 req->Send(iMsgQDependency); // Send the request to DFC thread. |
|
2570 return KErrNone; |
|
2571 } |
|
2572 else |
|
2573 #endif |
|
2574 { |
|
2575 req->Send(iMsgQ); // Send the request to Resource Controler thread. |
|
2576 return KErrNone; |
|
2577 } |
|
2578 } |
|
2579 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2580 if(aResourceId & KIdMaskResourceWithDependencies) //Dependency resource |
|
2581 { |
|
2582 r = req->SendReceive(iMsgQDependency); // Send the request to DFC thread. |
|
2583 } |
|
2584 #endif |
|
2585 else |
|
2586 { |
|
2587 r = req->SendReceive(iMsgQ); // Block till the controller completes with the request. |
|
2588 } |
|
2589 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2590 Lock(); |
|
2591 if(aResourceId & KIdMaskDynamic) |
|
2592 ((DDynamicPowerResource*)pR)->UnLock(); |
|
2593 UnLock(); |
|
2594 #endif |
|
2595 return r; |
|
2596 } |
|
2597 if(pR->Usage()) |
|
2598 { |
|
2599 r = CheckLevelAndAddClient(pC, req); |
|
2600 if((r != KErrNone)|| !req->RequiresChange()) |
|
2601 { |
|
2602 req->Level() = pR->iCachedLevel; |
|
2603 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2604 if(aResourceId & KIdMaskDynamic) |
|
2605 ((DDynamicPowerResource*)pR)->UnLock(); |
|
2606 #endif |
|
2607 UnLock(); |
|
2608 if(aCb) |
|
2609 { |
|
2610 //Invoke callback function |
|
2611 aCb->iCallback(req->ClientId(), aResourceId, req->Level(), pR->iLevelOwnerId, r, aCb->iParam); |
|
2612 //Mark the callback object to act properly during cancellation of this request. |
|
2613 aCb->iResult = KErrCompletion; |
|
2614 } |
|
2615 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2616 return(r); |
|
2617 } |
|
2618 } |
|
2619 else if(pR->iLevelOwnerId == -1) |
|
2620 { |
|
2621 /* Add client Level */ |
|
2622 if(pC->iReservedCl<=0 && !iClientLevelPoolCount) |
|
2623 { |
|
2624 r = KErrUnderflow; |
|
2625 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2626 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2627 if(aResourceId & KIdMaskDynamic) |
|
2628 ((DDynamicPowerResource*)pR)->UnLock(); |
|
2629 #endif |
|
2630 UnLock(); |
|
2631 return(r); |
|
2632 } |
|
2633 SPowerResourceClientLevel* pSCL=NULL; |
|
2634 LIST_POP(iClientLevelPool, pSCL, iNextInList); |
|
2635 pSCL->iClientId=aClientId; |
|
2636 pSCL->iResourceId=aResourceId; |
|
2637 pSCL->iLevel=aNewState; |
|
2638 LIST_PUSH(pC->iLevelList, pSCL, iNextInList); |
|
2639 pR->iClientList.Add(pSCL); |
|
2640 if(pC->iReservedCl==0) |
|
2641 { |
|
2642 iClientLevelPoolCount--; |
|
2643 pC->iUnderFlowClCount++; |
|
2644 } |
|
2645 else |
|
2646 pC->iReservedCl--; |
|
2647 } |
|
2648 else |
|
2649 { |
|
2650 //Update the level in the client list. |
|
2651 SPowerResourceClientLevel* pSCL = (SPowerResourceClientLevel*)pR->iClientList.First(); |
|
2652 pSCL->iLevel = aNewState; |
|
2653 } |
|
2654 UnLock(); |
|
2655 r = pR->DoRequest(*req); |
|
2656 Lock(); |
|
2657 if(r==KErrNone) |
|
2658 { |
|
2659 //Notification to clients |
|
2660 CompleteNotifications(req->ClientId(), pR, req->Level(), r, aClientId, EFalse); |
|
2661 //Cache the state |
|
2662 pR->iCachedLevel=req->Level(); |
|
2663 pR->iLevelOwnerId=req->ClientId(); |
|
2664 //Update resource details for Idle |
|
2665 if(pR->iIdleListEntry) |
|
2666 { |
|
2667 pR->iIdleListEntry->iLevelOwnerId=req->ClientId(); |
|
2668 pR->iIdleListEntry->iCurrentLevel=req->Level(); |
|
2669 } |
|
2670 } |
|
2671 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2672 if(aResourceId & KIdMaskDynamic) |
|
2673 ((DDynamicPowerResource*)pR)->UnLock(); |
|
2674 #endif |
|
2675 UnLock(); |
|
2676 if(aCb) |
|
2677 { |
|
2678 //Invoke callback function |
|
2679 aCb->iCallback(req->ClientId(), aResourceId, req->Level(), pR->iLevelOwnerId, r, aCb->iParam); |
|
2680 aCb->iResult = KErrCompletion; //Mark the callback object to act properly during cancellation of this request. |
|
2681 } |
|
2682 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::ChangeResourceState, Level = %d", req->Level())); |
|
2683 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
2684 return r; |
|
2685 } |
|
2686 |
|
2687 /** |
|
2688 @publishedPartner |
|
2689 @prototype 9.5 |
|
2690 |
|
2691 Request the state of the resource synchronously |
|
2692 |
|
2693 @param aClientId ID of the client which is requesting the resource state. |
|
2694 @param aResourceId ID of the resource whose state is being requested. |
|
2695 @param aCached If ETrue, cached value will be updated in aState. |
|
2696 If EFalse, aState will be updated after the resource |
|
2697 state is read from resource. |
|
2698 @param aState Returns the resource state if operation was successful. This |
|
2699 could be a binary value for a binary resource, an integer level |
|
2700 for a multilevel resource or some platform specific tolen for a |
|
2701 multi-property resource. |
|
2702 @param aLevelOwnerId Returns the Id of the client that is currently holding the resource. |
|
2703 -1 is returned when no client is holding the resource. |
|
2704 |
|
2705 @return KErrNone if operation was successful |
|
2706 KErrAccessDenied if the client ID could not be found in the current list |
|
2707 of registered clients or if the client was registered to be thread |
|
2708 relative and this API is not called from the same thread. |
|
2709 KErrNotFound if this resource ID could not be found in the current list |
|
2710 of controllable resources. |
|
2711 KErrNotReady if the request is issued before the resource controller completes |
|
2712 its internal initialization. |
|
2713 |
|
2714 |
|
2715 @pre Interrupts must be enabled |
|
2716 @pre Kernel must be unlocked |
|
2717 @pre No fast mutex can be held |
|
2718 @pre Call in a thread context but not from null thread or DFC thread1 |
|
2719 @pre Can be used in a device driver |
|
2720 @pre Do not call from DFC thread 0 for long latency resource with caching disabled. |
|
2721 */ |
|
2722 TInt DPowerResourceController::GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TInt& aState, |
|
2723 TInt& aLevelOwnerId) |
|
2724 { |
|
2725 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetResourceState(synchronous)")); |
|
2726 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d, Cached = %d", aClientId, aResourceId,\ |
|
2727 aCached)); |
|
2728 CHECK_CONTEXT(thread) |
|
2729 if(iInitialised <= EResConCreated) |
|
2730 return KErrNotReady; |
|
2731 DThread& thread = Kern::CurrentThread(); |
|
2732 SPowerResourceClient* pC = NULL; |
|
2733 TInt r = KErrNone; |
|
2734 Lock(); |
|
2735 VALIDATE_CLIENT(thread); |
|
2736 if(!aResourceId) |
|
2737 UNLOCK_RETURN(KErrNotFound); |
|
2738 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2739 DStaticPowerResource *pR = NULL; |
|
2740 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
2741 if(aResourceId & KIdMaskDynamic) |
|
2742 { |
|
2743 if(((DDynamicPowerResource*)pR)->LockCount() == 0) |
|
2744 UNLOCK_RETURN(KErrNotFound); |
|
2745 } |
|
2746 #else |
|
2747 if(aResourceId > iStaticResourceArrayEntries) |
|
2748 UNLOCK_RETURN(KErrNotFound); |
|
2749 DStaticPowerResource *pR = iStaticResourceArray[aResourceId-1]; |
|
2750 if(!pR) |
|
2751 UNLOCK_RETURN(KErrNotFound); |
|
2752 #endif |
|
2753 PRM_RESOURCE_GET_STATE_START_TRACE |
|
2754 //Panic if long latency resource called to execute synchronously from DFC thread0 |
|
2755 const TDesC8* pDfc0 = &KDfcThread0Name; |
|
2756 if((!aCached && pR->LatencyGet()) && !(pDfc0->Compare(*(TDesC*)thread.iName))) |
|
2757 { |
|
2758 UnLock(); |
|
2759 Panic(ECalledFromDfcThread0); |
|
2760 } |
|
2761 if(aCached) |
|
2762 { |
|
2763 //Return the cached value. |
|
2764 aState = pR->iCachedLevel; |
|
2765 aLevelOwnerId = pR->iLevelOwnerId; |
|
2766 PRM_RESOURCE_GET_STATE_END_TRACE |
|
2767 UNLOCK_RETURN(KErrNone); |
|
2768 } |
|
2769 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2770 if(aResourceId & KIdMaskDynamic) |
|
2771 ((DDynamicPowerResource*)pR)->Lock(); |
|
2772 #endif |
|
2773 //Call from thread Id. |
|
2774 TPowerRequest* req = (TPowerRequest*)&TPowerRequest::Get(); |
|
2775 req->ResourceId() = aResourceId; |
|
2776 req->ReqType() = TPowerRequest::EGet; |
|
2777 req->ClientId() = aClientId; |
|
2778 req->Resource() = pR; |
|
2779 req->ResourceCb() = NULL; |
|
2780 if(pR->LatencyGet()) |
|
2781 { |
|
2782 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2783 if( req->ResourceId() & KIdMaskResourceWithDependencies ) // Dependency Resource |
|
2784 { |
|
2785 UnLock(); |
|
2786 req->SendReceive(iMsgQDependency); //Send the request to DFC Thread |
|
2787 Lock(); |
|
2788 } |
|
2789 else // Plain resource |
|
2790 #endif |
|
2791 { |
|
2792 UnLock(); |
|
2793 req->SendReceive(iMsgQ); |
|
2794 Lock(); |
|
2795 } |
|
2796 } |
|
2797 else |
|
2798 { |
|
2799 UnLock(); |
|
2800 r = pR->DoRequest(*req); // Call PSL to get the state of resource. |
|
2801 Lock(); |
|
2802 if(r==KErrNone) |
|
2803 { |
|
2804 //Update the cache value and cache for idle thread usage if requested for this resource. |
|
2805 pR->iCachedLevel=req->Level(); |
|
2806 if(pR->iIdleListEntry) |
|
2807 { |
|
2808 SIdleResourceInfo* pI=pR->iIdleListEntry; |
|
2809 pI->iCurrentLevel=req->Level(); |
|
2810 } |
|
2811 } |
|
2812 } |
|
2813 aState = req->Level(); |
|
2814 aLevelOwnerId = pR->iLevelOwnerId; |
|
2815 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2816 if(aResourceId & KIdMaskDynamic) |
|
2817 ((DDynamicPowerResource*)pR)->UnLock(); |
|
2818 #endif |
|
2819 UnLock(); |
|
2820 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetResourceState(synchronous), Level = %d",\ |
|
2821 aState)); |
|
2822 if(pR->LatencyGet()) //For long latency resource btrace is done in controller thread. |
|
2823 return r; |
|
2824 PRM_RESOURCE_GET_STATE_END_TRACE |
|
2825 return r; |
|
2826 } |
|
2827 |
|
2828 /** |
|
2829 @publishedPartner |
|
2830 @prototype 9.5 |
|
2831 |
|
2832 Request the state of the resource asynchrounously for long latency resource and |
|
2833 synchronously for instantaneous resource |
|
2834 |
|
2835 @param aClientId ID of the client which is requesting the resource state. |
|
2836 @param aResourceId ID of the resource whose state is being requested. |
|
2837 @param aCached If ETrue, cached value will be updated in aState |
|
2838 If EFalse, will be updated after the resource state is read from resource |
|
2839 @param aCb For long latency resource: |
|
2840 A pointer to a resource callback object which encapsulates a callback function |
|
2841 to be called whenever the state of the resource is available for the long |
|
2842 latency resource (executes in the context of resource manager) |
|
2843 For instantaneous resource: |
|
2844 A pointer to a resource callback object which encapsulates a callback |
|
2845 function to be called after the resource state is read. This is executed |
|
2846 synchronously in the context of the calling thread. |
|
2847 NOTE: The client must create the callback object in kernel heap or |
|
2848 data section. |
|
2849 |
|
2850 @return KErrNone if the operation was successful |
|
2851 KErrArgument if callback object is NULL |
|
2852 KErrAccessDenied if the client ID could not be found in the current list |
|
2853 of registered clients or if the client was registered to be thread |
|
2854 relative and this API is not called from the same thread. |
|
2855 KErrNotFound if this resource ID could not be found in the current list |
|
2856 of controllable resources. |
|
2857 KErrNotReady if the request is issued before the resource controller completes |
|
2858 its internal initialisation |
|
2859 KErrUnderflow if the client has exceeded the reserved number of TPowerRequest |
|
2860 and the TPowerRequest free pool is empty for long latency resource. |
|
2861 KErrCorrupt if internal data structure is corrupt. |
|
2862 |
|
2863 @pre Interrupts must be enabled |
|
2864 @pre Kernel must be unlocked |
|
2865 @pre No fast mutex can be held |
|
2866 @pre Call in a thread context but not from null thread or DFC thread1 |
|
2867 @pre Can be used in a device driver |
|
2868 */ |
|
2869 TInt DPowerResourceController::GetResourceState(TUint aClientId, TUint aResourceId, TBool aCached, TPowerResourceCb& aCb) |
|
2870 { |
|
2871 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetResourceState(asynchronous)")); |
|
2872 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d, Cached = %d", aClientId, aResourceId, \ |
|
2873 aCached)); |
|
2874 CHECK_CONTEXT(thread) |
|
2875 if(iInitialised <= EResConCreated) |
|
2876 return KErrNotReady; |
|
2877 DThread& thread = Kern::CurrentThread(); |
|
2878 SPowerResourceClient* pC = NULL; |
|
2879 TInt r = KErrNone; |
|
2880 Lock(); |
|
2881 VALIDATE_CLIENT(thread); |
|
2882 if(!aResourceId) |
|
2883 UNLOCK_RETURN(KErrNotFound); |
|
2884 if(!&aCb) //Need to specify a callback for this asynchronous API |
|
2885 UNLOCK_RETURN(KErrArgument); |
|
2886 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2887 DStaticPowerResource *pR = NULL; |
|
2888 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
2889 if(aResourceId & KIdMaskDynamic) |
|
2890 { |
|
2891 //Dynamic resource in process of deregistration |
|
2892 if(((DDynamicPowerResource*)pR)->LockCount() == 0) |
|
2893 UNLOCK_RETURN(KErrNotFound); |
|
2894 } |
|
2895 #else |
|
2896 if(aResourceId > iStaticResourceArrayEntries) |
|
2897 UNLOCK_RETURN(KErrNotFound); |
|
2898 DStaticPowerResource *pR = iStaticResourceArray[aResourceId-1]; |
|
2899 if(!pR) |
|
2900 UNLOCK_RETURN(KErrNotFound); |
|
2901 #endif |
|
2902 if(&aCb) |
|
2903 { |
|
2904 aCb.iResult = KErrNone; |
|
2905 aCb.iResourceId = aResourceId; |
|
2906 aCb.iClientId = aClientId; |
|
2907 } |
|
2908 PRM_RESOURCE_GET_STATE_START_TRACE |
|
2909 if(aCached) //Call the callback directly |
|
2910 { |
|
2911 UnLock(); |
|
2912 aCb.iCallback(aClientId, aResourceId, pR->iCachedLevel, pR->iLevelOwnerId, KErrNone, aCb.iParam); |
|
2913 aCb.iResult = KErrCompletion; //Mark the callback object to act properly during cancellation of this request. |
|
2914 #ifdef PRM_INSTRUMENTATION_MACRO |
|
2915 TInt aState = pR->iCachedLevel; |
|
2916 PRM_RESOURCE_GET_STATE_END_TRACE |
|
2917 #endif |
|
2918 return(KErrNone); |
|
2919 } |
|
2920 TPowerRequest* req=NULL; |
|
2921 if(pR->LatencyGet()) |
|
2922 { |
|
2923 //Check the client quota of requests |
|
2924 if(pC->iReservedRm==0 && !iRequestPoolCount) |
|
2925 UNLOCK_RETURN(KErrUnderflow); |
|
2926 if(pC->iReservedRm ==0) |
|
2927 { |
|
2928 iRequestPoolCount--; |
|
2929 pC->iUnderFlowRmCount++; |
|
2930 } |
|
2931 else |
|
2932 pC->iReservedRm--; |
|
2933 //Get the request from pool |
|
2934 SPowerRequest* pS; |
|
2935 LIST_POP(iRequestPool, pS, iNext); |
|
2936 if(!pS) |
|
2937 UNLOCK_RETURN(KErrCorrupt); //This should not be called |
|
2938 req = &pS->iRequest; |
|
2939 //Increment pending request count of the client |
|
2940 pC->iPendingReqCount++; |
|
2941 } |
|
2942 else |
|
2943 //Asynchronous instantaneous resource execute in the context of client thread. |
|
2944 req = (TPowerRequest*)&TPowerRequest::Get(); |
|
2945 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2946 if(aResourceId & KIdMaskDynamic) |
|
2947 ((DDynamicPowerResource*)pR)->Lock(); |
|
2948 #endif |
|
2949 UnLock(); |
|
2950 req->ReqType() = TPowerRequest::EGet; |
|
2951 req->ResourceId() = aResourceId; |
|
2952 req->ClientId() = aClientId; |
|
2953 req->Resource() = pR; |
|
2954 req->ResourceCb() = &aCb; |
|
2955 if(pR->LatencyGet()) |
|
2956 { |
|
2957 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2958 if( req->ResourceId() & KIdMaskResourceWithDependencies ) // Dependency Resource |
|
2959 { |
|
2960 req->Send(iMsgQDependency); // Send the request to DFC thread. |
|
2961 } |
|
2962 else // Plain resource |
|
2963 #endif |
|
2964 { |
|
2965 req->Send(iMsgQ); |
|
2966 } |
|
2967 } |
|
2968 else |
|
2969 { |
|
2970 r = pR->DoRequest(*req); |
|
2971 Lock(); |
|
2972 if(r == KErrNone) |
|
2973 { |
|
2974 //Update the cache value and cache for idle thread usage if requested for this resource. |
|
2975 pR->iCachedLevel = req->Level(); |
|
2976 if(pR->iIdleListEntry) |
|
2977 pR->iIdleListEntry->iCurrentLevel=req->Level(); |
|
2978 } |
|
2979 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
2980 if(aResourceId & KIdMaskDynamic) |
|
2981 ((DDynamicPowerResource*)pR)->UnLock(); |
|
2982 #endif |
|
2983 UnLock(); |
|
2984 // Call the client callback function directly as it is already executing in the context of client thread. |
|
2985 aCb.iCallback(aClientId, aResourceId, req->Level(), pR->iLevelOwnerId, r, aCb.iParam); |
|
2986 aCb.iResult = KErrCompletion; //Mark the callback object to act properly during cancellation of this request. |
|
2987 } |
|
2988 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetResourceState(asynchronous), Level = %d", \ |
|
2989 req->Level())); |
|
2990 if(pR->LatencyGet()) |
|
2991 return r; |
|
2992 #ifdef PRM_INSTRUMENTATION_MACRO |
|
2993 TInt aState = req->Level(); |
|
2994 PRM_RESOURCE_GET_STATE_END_TRACE |
|
2995 #endif |
|
2996 return r; |
|
2997 } |
|
2998 |
|
2999 |
|
3000 /** |
|
3001 @publishedPartner |
|
3002 @prototype 9.5 |
|
3003 |
|
3004 Cancel an asynchronous request(or its callback). |
|
3005 |
|
3006 @param aClientId ID of the client which is requesting the cancellation of the request. |
|
3007 @param aResourceId ID for the resource which the request that is being cancelled operates |
|
3008 upon. |
|
3009 @param aCb A reference to the resource callback object specified with the request |
|
3010 that is being cancelled. |
|
3011 |
|
3012 @return KErrCancel if the request was cancelled. |
|
3013 KErrNotFound if this resource ID could not be found in the current list of controllable |
|
3014 resources. |
|
3015 KErrCompletion if request is no longer pending. |
|
3016 KErrAccessDenied if the client ID could not be found in the current list of registered |
|
3017 clients or if the client was registered to be thread relative and this API is not called |
|
3018 from the same thread or if client is not the same that requested the resource state change. |
|
3019 KErrInUse if the request cannot be cancelled as processing of the request already started |
|
3020 and will run to completion. |
|
3021 |
|
3022 @pre Interrupts must be enabled |
|
3023 @pre Kernel must be unlocked |
|
3024 @pre No fast mutex can be held |
|
3025 @pre Call in a thread context but not from null thread or DFC thread1 |
|
3026 @pre Can be used in a device driver |
|
3027 */ |
|
3028 TInt DPowerResourceController::CancelAsyncRequestCallBack(TUint aClientId, TUint aResourceId, TPowerResourceCb& aCb) |
|
3029 { |
|
3030 TInt r = KErrInUse; |
|
3031 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::CancelAsyncRequestCallBack")); |
|
3032 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d", aClientId, aResourceId)); |
|
3033 DThread& thread = Kern::CurrentThread(); |
|
3034 CHECK_CONTEXT(thread) |
|
3035 SPowerResourceClient* pC = NULL; |
|
3036 Lock(); |
|
3037 VALIDATE_CLIENT(thread); |
|
3038 if((!aResourceId) || (aCb.iResourceId != aResourceId)) |
|
3039 UNLOCK_RETURN(KErrNotFound); |
|
3040 #ifdef PRM_INSTRUMENTATION_MACRO |
|
3041 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3042 DStaticPowerResource *pR = NULL; |
|
3043 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
3044 #else |
|
3045 DStaticPowerResource *pR = iStaticResourceArray[aResourceId-1]; |
|
3046 if(!pR) |
|
3047 UNLOCK_RETURN(KErrNotFound); |
|
3048 #endif |
|
3049 #endif |
|
3050 if(aCb.iClientId != aClientId) |
|
3051 { |
|
3052 __KTRACE_OPT(KRESMANAGER, Kern::Printf("aCb.iClientId = 0x%x, aClientId = 0x%x", aCb.iClientId, aClientId)); |
|
3053 r = KErrAccessDenied; |
|
3054 PRM_RESOURCE_CANCEL_LONGLATENCY_OPERATION_TRACE |
|
3055 UNLOCK_RETURN(r); |
|
3056 } |
|
3057 if(aCb.iResult == KErrCompletion) |
|
3058 { |
|
3059 r = KErrCompletion; |
|
3060 PRM_RESOURCE_CANCEL_LONGLATENCY_OPERATION_TRACE |
|
3061 UNLOCK_RETURN(r); |
|
3062 } |
|
3063 //Search in the controller message queue for this message |
|
3064 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3065 if(aResourceId & KIdMaskResourceWithDependencies) //long latency resource with dependency and will be processed in dependency thread. |
|
3066 { |
|
3067 //Search in the controller message queue for this message |
|
3068 for(SDblQueLink* pRM = iMsgQDependency->iQ.First(); pRM != &(iMsgQDependency->iQ.iA); pRM = pRM->iNext) |
|
3069 { |
|
3070 TMessageBase* pMsgQ = (TMessageBase*)pRM; |
|
3071 TPowerRequest* pReq=(TPowerRequest*)pMsgQ; |
|
3072 if(pReq->ResourceCb() == &aCb) |
|
3073 { |
|
3074 r = KErrCancel; |
|
3075 pRM->Deque(); |
|
3076 pMsgQ->iState = TMessageBase::EFree; //Reset the state |
|
3077 MoveRequestToFreePool(pReq); |
|
3078 PRM_RESOURCE_CANCEL_LONGLATENCY_OPERATION_TRACE |
|
3079 UNLOCK_RETURN(r); |
|
3080 } |
|
3081 } |
|
3082 } |
|
3083 else // long latency resource without dependency and will be processed in RC thread. |
|
3084 #endif |
|
3085 { |
|
3086 for(SDblQueLink* pRM = iMsgQ->iQ.First(); pRM != &(iMsgQ->iQ.iA); pRM = pRM->iNext) |
|
3087 { |
|
3088 TMessageBase* pMsgQ = (TMessageBase*)pRM; |
|
3089 TPowerRequest* pReq=(TPowerRequest*)pMsgQ; |
|
3090 if(pReq->ResourceCb() == &aCb) |
|
3091 { |
|
3092 r = KErrCancel; |
|
3093 pRM->Deque(); |
|
3094 pMsgQ->iState = TMessageBase::EFree; //Reset the state |
|
3095 MoveRequestToFreePool(pReq); |
|
3096 PRM_RESOURCE_CANCEL_LONGLATENCY_OPERATION_TRACE |
|
3097 UNLOCK_RETURN(r); |
|
3098 } |
|
3099 } |
|
3100 } |
|
3101 PRM_RESOURCE_CANCEL_LONGLATENCY_OPERATION_TRACE |
|
3102 UNLOCK_RETURN(r); |
|
3103 } |
|
3104 |
|
3105 /** |
|
3106 @publishedPartner |
|
3107 @prototype 9.5 |
|
3108 |
|
3109 Request notification of changes to the state of a resource. |
|
3110 |
|
3111 @param aClientId ID of the client which is requesting the notification. |
|
3112 @param aResourceId ID of the resource for which notification of state changes |
|
3113 is being requested. |
|
3114 @param aN A reference to a notification object which encapsulates a callback |
|
3115 function to be called whenever a resource state change takes place. |
|
3116 NOTE: The client must create the notification object in kernel heap |
|
3117 or data section. |
|
3118 |
|
3119 @return KErrNone if the operation of requesting a notification was successful. |
|
3120 KErrNotFound if this resource ID could not be found in the current list |
|
3121 of controllable resources. |
|
3122 KErrAccessDenied if the client ID could not be found in the current |
|
3123 list of registered clients or if the client was registered to be |
|
3124 thread relative and this API is not called from the same thread. |
|
3125 KErrInUse if the passed notification object is used already. |
|
3126 NOTE: This API should return immediately; however the notification will |
|
3127 only happen when a resource change occurs.Notification request is idempotent, |
|
3128 if the same notification has already been requested for this resource ID, |
|
3129 the API returns with no further action.Notifications remain queued until they are cancelled. |
|
3130 |
|
3131 @pre Interrupts must be enabled |
|
3132 @pre Kernel must be unlocked |
|
3133 @pre No fast mutex can be held |
|
3134 @pre Call in a thread context but not from null thread or DFC thread1 |
|
3135 @pre Can be used in a device driver |
|
3136 */ |
|
3137 TInt DPowerResourceController::RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN) |
|
3138 { |
|
3139 TInt r = KErrNone; |
|
3140 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RequestNotification(unconditional)")); |
|
3141 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d", aClientId, aResourceId)); |
|
3142 DThread& thread = Kern::CurrentThread(); |
|
3143 CHECK_CONTEXT(thread) |
|
3144 SPowerResourceClient* pC = NULL; |
|
3145 Lock(); |
|
3146 VALIDATE_CLIENT(thread); |
|
3147 if((!aResourceId)) |
|
3148 { |
|
3149 r = KErrNotFound; |
|
3150 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3151 UNLOCK_RETURN(r); |
|
3152 } |
|
3153 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3154 DStaticPowerResource *pR = NULL; |
|
3155 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
3156 #else |
|
3157 if(aResourceId > iStaticResourceArrayEntries) |
|
3158 { |
|
3159 r = KErrNotFound; |
|
3160 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3161 UNLOCK_RETURN(r); |
|
3162 } |
|
3163 |
|
3164 DStaticPowerResource *pR = iStaticResourceArray[aResourceId-1]; |
|
3165 if(!pR) |
|
3166 { |
|
3167 r = KErrNotFound; |
|
3168 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3169 UNLOCK_RETURN(r); |
|
3170 } |
|
3171 #endif |
|
3172 if(aN.iRegistered) //Check if the same notification object is used already |
|
3173 { |
|
3174 r = KErrInUse; |
|
3175 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3176 UNLOCK_RETURN(r); |
|
3177 } |
|
3178 aN.iRegistered++; |
|
3179 aN.iType = DPowerResourceNotification::EUnconditional; |
|
3180 aN.iOwnerId=(TUint16)aClientId; |
|
3181 aN.iCallback.iClientId= aClientId; |
|
3182 aN.iCallback.iResourceId=aResourceId; |
|
3183 //Add to resource notification list |
|
3184 pR->iNotificationList.Add(&(aN.iNotificationLink)); |
|
3185 //Add to client notification list |
|
3186 LIST_PUSH(pC->iNotificationList, &aN, iNextInClient); |
|
3187 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3188 UNLOCK_RETURN(KErrNone); |
|
3189 } |
|
3190 |
|
3191 /** |
|
3192 @publishedPartner |
|
3193 @prototype 9.5 |
|
3194 |
|
3195 Request notification when the state of a resource reaches a specified threshold or |
|
3196 goes above or below that threshold (for multilevel resource only) based on direction. |
|
3197 In other words it is issued when a threshold on the specified resource state is crossed |
|
3198 in the direction specified. |
|
3199 |
|
3200 @param aClientId ID of the client which is requesting the notification. |
|
3201 @param aResourceId ID for the resource whose notification of state changes is |
|
3202 being requested. |
|
3203 @param aN A reference to a notification object which encapsulates a callback |
|
3204 function to be called whenever the conditions to issue the notification |
|
3205 (specified in the API) are met. |
|
3206 NOTE: The client must create the notification object in kernel heap |
|
3207 or data section. |
|
3208 @param aThreshold The level of the resource state that will trigger the notification |
|
3209 when reached. |
|
3210 @param aDirection Specifies the direction of change of the resource state that will |
|
3211 trigger a notification. EFalse means the notification will be issued |
|
3212 when the resource state change to a specified threshold value or below |
|
3213 the specified threshold, ETrue means the notification will be issued |
|
3214 when the resource state change to a specified threshold value or above |
|
3215 the specified threshold. |
|
3216 |
|
3217 |
|
3218 |
|
3219 @return KErrNone if the operation of requesting a notification was successful. |
|
3220 KErrNotFound if this resource ID could not be found in the current list |
|
3221 of controllable reosurces. |
|
3222 KErrAccessDenied if the client ID could not be found in the list of |
|
3223 registered clients or if the client was registered to be thread |
|
3224 relative and this API is not called from the same thread. |
|
3225 KErrInUse if the passed notification object is used already. |
|
3226 KErrArgument if the specified threshold is out of range. |
|
3227 NOTE: This API should return immediately; however the notification will only |
|
3228 happen when a resource change occurs. Notification request is idempotent, |
|
3229 if the same notification has already been requested for this resource ID, |
|
3230 the API returns with no further action. Notification remain queued until they are cancelled. |
|
3231 |
|
3232 @pre Interrupts must be enabled |
|
3233 @pre Kernel must be unlocked |
|
3234 @pre No fast mutex can be held |
|
3235 @pre Call in a thread context but not from null thread or DFC thread1 |
|
3236 @pre Can be used in a device driver |
|
3237 */ |
|
3238 TInt DPowerResourceController::RequestNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN, |
|
3239 TInt aThreshold, TBool aDirection) |
|
3240 { |
|
3241 TInt r = KErrNone; |
|
3242 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RequestNotification(conditional)")); |
|
3243 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d, Threshold = %d, Direction = %d", \ |
|
3244 aClientId, aResourceId, aThreshold, aDirection)); |
|
3245 DThread& thread = Kern::CurrentThread(); |
|
3246 CHECK_CONTEXT(thread) |
|
3247 Lock(); |
|
3248 SPowerResourceClient* pC = NULL; |
|
3249 VALIDATE_CLIENT(thread); |
|
3250 if(!aResourceId) |
|
3251 { |
|
3252 r = KErrNotFound; |
|
3253 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3254 UNLOCK_RETURN(r); |
|
3255 } |
|
3256 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3257 DStaticPowerResource *pR = NULL; |
|
3258 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
3259 #else |
|
3260 if(aResourceId > iStaticResourceArrayEntries) |
|
3261 { |
|
3262 r = KErrNotFound; |
|
3263 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3264 UNLOCK_RETURN(r); |
|
3265 } |
|
3266 |
|
3267 DStaticPowerResource *pR = iStaticResourceArray[aResourceId-1]; |
|
3268 if(!pR) |
|
3269 { |
|
3270 r = KErrNotFound; |
|
3271 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3272 UNLOCK_RETURN(r); |
|
3273 } |
|
3274 #endif |
|
3275 if(aN.iRegistered) //Check if the same notification object is used already |
|
3276 { |
|
3277 r = KErrInUse; |
|
3278 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3279 UNLOCK_RETURN(r); |
|
3280 } |
|
3281 |
|
3282 //Validate threshold for correctness |
|
3283 TPowerResourceInfoBuf01 buf; |
|
3284 r = pR->GetInfo((TDes8*)buf.Ptr()); |
|
3285 if(r != KErrNone) |
|
3286 { |
|
3287 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3288 UNLOCK_RETURN(r); |
|
3289 } |
|
3290 TPowerResourceInfoV01 *pBuf = (TPowerResourceInfoV01*)buf.Ptr(); |
|
3291 if(((pBuf->iMinLevel > pBuf->iMaxLevel) && ((aThreshold > pBuf->iMinLevel) || (aThreshold < pBuf->iMaxLevel))) || |
|
3292 ((pBuf->iMaxLevel > pBuf->iMinLevel) && ((aThreshold > pBuf->iMaxLevel) || (aThreshold < pBuf->iMinLevel)))) |
|
3293 { |
|
3294 r = KErrArgument; |
|
3295 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3296 UNLOCK_RETURN(r); |
|
3297 } |
|
3298 aN.iRegistered++; |
|
3299 aN.iType = DPowerResourceNotification::EConditional; |
|
3300 aN.iThreshold = aThreshold; |
|
3301 aN.iDirection = aDirection; |
|
3302 aN.iOwnerId = (TUint16)aClientId; |
|
3303 aN.iCallback.iClientId = aClientId; |
|
3304 aN.iCallback.iResourceId = aResourceId; |
|
3305 //Store the current level of the resource as will be used for issuing notification |
|
3306 aN.iPreviousLevel = pR->iCachedLevel; |
|
3307 //Add to resource notification list |
|
3308 pR->iNotificationList.Add(&(aN.iNotificationLink)); |
|
3309 //Add to client notification list |
|
3310 LIST_PUSH(pC->iNotificationList, &aN, iNextInClient); |
|
3311 PRM_POSTNOTIFICATION_REGISTER_TRACE |
|
3312 UNLOCK_RETURN(KErrNone); |
|
3313 } |
|
3314 |
|
3315 /** |
|
3316 @publishedPartner |
|
3317 @prototype 9.5 |
|
3318 |
|
3319 Cancel and remove from queue a previously issued request for notification on a |
|
3320 resource state change. |
|
3321 |
|
3322 @param aClientId ID of the client which is requesting to cancel the notification |
|
3323 @param aResourceId for the resource whose pending notification of state changes |
|
3324 is being cancelled. |
|
3325 @param aN A reference to the notification object that was associated with |
|
3326 the notification request that is being cancelled. This will be |
|
3327 used to identify the notification that is being cancelled. |
|
3328 |
|
3329 @return KErrCancel if the notification request was successfully cancelled. |
|
3330 KErrNotFound if the specified notification object is |
|
3331 not found in the current list of notification objects for the |
|
3332 specified resource. |
|
3333 KErrAccessDenied if the client requesting the cancellation is not the same |
|
3334 which registered the notification or if the resource id does not match or |
|
3335 if the client ID could not be found in the list of registered clients or |
|
3336 if the client was registered to be thread relative and this API is |
|
3337 not called from the same thread. |
|
3338 |
|
3339 @pre Interrupts must be enabled |
|
3340 @pre Kernel must be unlocked |
|
3341 @pre No fast mutex can be held |
|
3342 @pre Call in a thread context but not from null thread or DFC thread1 |
|
3343 @pre Can be used in a device driver |
|
3344 */ |
|
3345 TInt DPowerResourceController::CancelNotification(TUint aClientId, TUint aResourceId, DPowerResourceNotification& aN) |
|
3346 { |
|
3347 TInt r = KErrCancel; |
|
3348 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::CancelNotification")); |
|
3349 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, ResourceId = %d", aClientId, aResourceId)); |
|
3350 DThread& thread = Kern::CurrentThread(); |
|
3351 CHECK_CONTEXT(thread) |
|
3352 SPowerResourceClient* pC = NULL; |
|
3353 Lock(); |
|
3354 VALIDATE_CLIENT(thread); |
|
3355 |
|
3356 if(!aN.iRegistered) |
|
3357 { |
|
3358 r = KErrNotFound; |
|
3359 PRM_POSTNOTIFICATION_DEREGISTER_TRACE |
|
3360 UNLOCK_RETURN(r); |
|
3361 } |
|
3362 //Remove from the client list |
|
3363 TBool found = EFalse; |
|
3364 DPowerResourceNotification* pCNL = pC->iNotificationList; |
|
3365 DPowerResourceNotification* pCNLNext = pCNL; |
|
3366 if(pCNL == &aN) |
|
3367 { |
|
3368 if(pCNL->iOwnerId != (TUint16)aClientId) |
|
3369 { |
|
3370 r = KErrAccessDenied; |
|
3371 PRM_POSTNOTIFICATION_DEREGISTER_TRACE |
|
3372 UNLOCK_RETURN(r); |
|
3373 } |
|
3374 found = ETrue; |
|
3375 } |
|
3376 else |
|
3377 { |
|
3378 while(pCNLNext) |
|
3379 { |
|
3380 if(pCNLNext == &aN) |
|
3381 { |
|
3382 if(pCNL->iOwnerId != (TUint16)aClientId) |
|
3383 { |
|
3384 r = KErrAccessDenied; |
|
3385 PRM_POSTNOTIFICATION_DEREGISTER_TRACE |
|
3386 UNLOCK_RETURN(r); |
|
3387 } |
|
3388 pCNL->iNextInClient = pCNLNext->iNextInClient; |
|
3389 pCNL = pCNLNext; |
|
3390 found = ETrue; |
|
3391 break; |
|
3392 } |
|
3393 pCNL = pCNLNext; |
|
3394 pCNLNext = pCNLNext->iNextInClient; |
|
3395 } |
|
3396 } |
|
3397 if(!found) |
|
3398 { |
|
3399 r = KErrNotFound; |
|
3400 PRM_POSTNOTIFICATION_DEREGISTER_TRACE |
|
3401 UNLOCK_RETURN(r); |
|
3402 } |
|
3403 if(pCNL->iCallback.iResourceId != aResourceId) |
|
3404 { |
|
3405 r = KErrAccessDenied; |
|
3406 PRM_POSTNOTIFICATION_DEREGISTER_TRACE |
|
3407 UNLOCK_RETURN(r); |
|
3408 } |
|
3409 //Remove from resource list |
|
3410 pCNL->iNotificationLink.Deque(); |
|
3411 pCNL->iCallback.Cancel(); |
|
3412 //Remove from client list |
|
3413 LIST_REMOVE(pC->iNotificationList, pCNL, iNextInClient, DPowerResourceNotification); |
|
3414 pCNL->iRegistered--; |
|
3415 PRM_POSTNOTIFICATION_DEREGISTER_TRACE |
|
3416 UNLOCK_RETURN(KErrCancel); |
|
3417 } |
|
3418 |
|
3419 /** |
|
3420 @publishedPartner |
|
3421 @prototype 9.5 |
|
3422 |
|
3423 Request pre-allocation of specified number of client level and request message objects. |
|
3424 |
|
3425 @param aClientId ID of the client which is requesting the pre-allocation. |
|
3426 @param aNumCl Number of client level objects that needs to be pre-allocated |
|
3427 for this client. |
|
3428 @param aNumRm Number of request message objects that needs to be pre-allocated |
|
3429 for this client. |
|
3430 |
|
3431 @return KErrNone if the allocation was successful |
|
3432 KErrAccessDenied if the client ID could not be found in the list of |
|
3433 registered clients or if the client was registered to be thread |
|
3434 relative and this API is not called from the same thread. |
|
3435 KErrNoMemory if there is no sufficient memory for allocation of requested |
|
3436 number of objects. |
|
3437 |
|
3438 @pre Interrupts must be enabled |
|
3439 @pre Kernel must be unlocked |
|
3440 @pre No fast mutex can be held |
|
3441 @pre Call in a thread context but not from null thread or DFC thread1 |
|
3442 @pre Can be used in a device driver |
|
3443 */ |
|
3444 TInt DPowerResourceController::AllocReserve(TUint aClientId, TUint8 aNumCl, TUint8 aNumRm) |
|
3445 { |
|
3446 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::AllocReserve")); |
|
3447 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x, Numclients = %d, NumResource = %d", aClientId, aNumCl, aNumRm)); |
|
3448 DThread& thread = Kern::CurrentThread(); |
|
3449 CHECK_CONTEXT(thread) |
|
3450 SPowerResourceClient* pC = NULL; |
|
3451 Lock(); |
|
3452 VALIDATE_CLIENT(thread); |
|
3453 //Call from thread Id. |
|
3454 TPowerRequest* req = (TPowerRequest*)&TPowerRequest::Get(); |
|
3455 req->ReqType() = TPowerRequest::EAllocReserve; |
|
3456 req->ClientId() = aClientId; |
|
3457 req->RequestCount() = aNumRm; |
|
3458 req->ClientLevelCount() = aNumCl; |
|
3459 |
|
3460 UnLock(); |
|
3461 req->SendReceive(iMsgQ); |
|
3462 return (req->ReturnCode()); |
|
3463 } |
|
3464 /** |
|
3465 @internalComponent |
|
3466 @prototype 9.5 |
|
3467 |
|
3468 This function runs in the context of the RC thread and |
|
3469 handles creation of memory pools. |
|
3470 */ |
|
3471 TInt DPowerResourceController::HandleReservationOfObjects(TPowerRequest& aRequest) |
|
3472 { |
|
3473 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::AllocReserve")); |
|
3474 |
|
3475 SPowerResourceClientLevel* pCL = NULL; |
|
3476 SPowerRequest* pR = NULL; |
|
3477 |
|
3478 Lock(); |
|
3479 TInt clientPoolCount = iClientLevelPoolCount; |
|
3480 TInt requestPoolCount = iRequestPoolCount; |
|
3481 SPowerResourceClient* pC; |
|
3482 if(aRequest.ClientId() & USER_SIDE_CLIENT_BIT_MASK) |
|
3483 pC = iUserSideClientList[(TUint16)(aRequest.ClientId() & ID_INDEX_BIT_MASK)]; |
|
3484 else |
|
3485 pC = iClientList[(TUint16)(aRequest.ClientId() & ID_INDEX_BIT_MASK)]; |
|
3486 UnLock(); |
|
3487 |
|
3488 if(clientPoolCount < aRequest.ClientLevelCount()) |
|
3489 { |
|
3490 //Grow the client level pool |
|
3491 // coverity[alloc_fn] |
|
3492 pCL = new SPowerResourceClientLevel[iClientLevelPoolGrowBy + aRequest.ClientLevelCount()]; |
|
3493 if(!pCL) |
|
3494 return(KErrNoMemory); |
|
3495 } |
|
3496 if(requestPoolCount < aRequest.RequestCount()) |
|
3497 { |
|
3498 //Grow the request pool |
|
3499 // coverity[alloc_fn] |
|
3500 pR = new SPowerRequest[iRequestPoolGrowBy + aRequest.RequestCount()]; |
|
3501 if(!pR) |
|
3502 { |
|
3503 if(pCL) //If client level is allocated delete the same. |
|
3504 delete []pCL; |
|
3505 return(KErrNoMemory); |
|
3506 } |
|
3507 } |
|
3508 //Push the memory to list and adjust the counter. |
|
3509 Lock(); |
|
3510 TUint count; |
|
3511 if(pCL) |
|
3512 { |
|
3513 for(count = 0;count<(TUint)(iClientLevelPoolGrowBy+aRequest.ClientLevelCount());count++) |
|
3514 LIST_PUSH(iClientLevelPool, &pCL[count], iNextInList); |
|
3515 iClientLevelPoolCount= (TUint16)(iClientLevelPoolCount + iClientLevelPoolGrowBy); |
|
3516 pC->iReservedCl= (TUint8)(pC->iReservedCl + aRequest.ClientLevelCount()); |
|
3517 } |
|
3518 else |
|
3519 { |
|
3520 //Reserve memory from free pool to this client |
|
3521 iClientLevelPoolCount = (TUint16)(iClientLevelPoolCount - aRequest.ClientLevelCount()); |
|
3522 pC->iReservedCl = (TUint8)(pC->iReservedCl + aRequest.ClientLevelCount()); |
|
3523 } |
|
3524 |
|
3525 if(pR) |
|
3526 { |
|
3527 for(count=0;count<(TUint)(iRequestPoolGrowBy+aRequest.RequestCount());count++) |
|
3528 LIST_PUSH(iRequestPool, &pR[count], iNext); |
|
3529 iRequestPoolCount = (TUint16)(iRequestPoolCount + iRequestPoolGrowBy); |
|
3530 pC->iReservedRm =(TUint8)(pC->iReservedRm + aRequest.RequestCount()); |
|
3531 } |
|
3532 else |
|
3533 { |
|
3534 //Reserve memory from free pool to this client |
|
3535 iRequestPoolCount = (TUint16)(iRequestPoolCount - aRequest.RequestCount()); |
|
3536 pC->iReservedRm = (TUint8)(pC->iReservedRm + aRequest.RequestCount()); |
|
3537 } |
|
3538 UnLock(); |
|
3539 #ifdef PRM_INSTRUMENTATION_MACRO |
|
3540 TUint size =0; |
|
3541 if(pCL) |
|
3542 size = (iClientLevelPoolGrowBy+aRequest.ClientLevelCount())*sizeof(SPowerResourceClientLevel); |
|
3543 if(pR) |
|
3544 size += (iRequestPoolGrowBy+aRequest.RequestCount())*sizeof(SPowerRequest); |
|
3545 if(size) |
|
3546 PRM_MEMORY_USAGE_TRACE |
|
3547 #endif |
|
3548 return(KErrNone); |
|
3549 } |
|
3550 |
|
3551 /* Register the proxy client to resource controller. |
|
3552 This is called as the result of new user side client opening a channel.*/ |
|
3553 TInt DPowerResourceController::RegisterProxyClient(TUint& aClientId, const TDesC8& aName) |
|
3554 { |
|
3555 GET_CRITICAL_SECTION_COUNT |
|
3556 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RegisterProxyClient")); |
|
3557 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Proxy client name %S", &aName)); |
|
3558 |
|
3559 DThread& t = Kern::CurrentThread(); |
|
3560 CHECK_CONTEXT(t) |
|
3561 //If number of expected user side clients is set to 0 during initial configuration |
|
3562 //then dont allow to configure user side clients. |
|
3563 if(!iUserSideClientList.GrowBy()) |
|
3564 return KErrNotSupported; |
|
3565 //Maximum allowable length of a client's name is 32 characters. |
|
3566 if (aName.Length() > KMaxClientNameLength) return KErrTooBig; |
|
3567 |
|
3568 SPowerResourceClient *pC = NULL; |
|
3569 Lock(); |
|
3570 #ifdef DEBUG_VERSION |
|
3571 if(!iUserSideClientList.Find(pC, (TDesC8&)aName)) |
|
3572 { |
|
3573 UnLock(); |
|
3574 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3575 return KErrAlreadyExists; |
|
3576 } |
|
3577 #endif |
|
3578 TPowerRequest* req = (TPowerRequest*)&TPowerRequest::Get(); |
|
3579 req->ReqType() = TPowerRequest::ERegisterUsersideClient; |
|
3580 UnLock(); |
|
3581 req->SendReceive(iMsgQ); |
|
3582 if(req->ReturnCode() == KErrNone) |
|
3583 { |
|
3584 pC = iUserSideClientList[(TUint16)(req->ClientId() & ID_INDEX_BIT_MASK)]; |
|
3585 pC->iName=&aName; |
|
3586 //Store the current thread Id; |
|
3587 pC->iThreadId = t.iId; |
|
3588 aClientId = pC->iClientId; |
|
3589 } |
|
3590 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RegisterProxyClient, clientId = 0x%x", aClientId)); |
|
3591 PRM_CLIENT_REGISTER_TRACE |
|
3592 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3593 return KErrNone; |
|
3594 } |
|
3595 |
|
3596 /* Deregister the specified user side client from resource controller. |
|
3597 This is called as the result of client closing the channel. */ |
|
3598 TInt DPowerResourceController::DeregisterProxyClient(TUint aClientId) |
|
3599 { |
|
3600 GET_CRITICAL_SECTION_COUNT |
|
3601 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::DeregisterProxyClient")); |
|
3602 __KTRACE_OPT(KRESMANAGER, Kern::Printf("ClientId = 0x%x", aClientId)); |
|
3603 DThread& t = Kern::CurrentThread(); |
|
3604 CHECK_CONTEXT(t) |
|
3605 //Get the index from client ID |
|
3606 if(!(aClientId & USER_SIDE_CLIENT_BIT_MASK)) |
|
3607 return KErrArgument; |
|
3608 Lock(); |
|
3609 SPowerResourceClient* pC = iUserSideClientList[(TUint16)(aClientId & ID_INDEX_BIT_MASK)]; |
|
3610 if(!pC) |
|
3611 { |
|
3612 UnLock(); |
|
3613 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3614 return KErrNotFound; |
|
3615 } |
|
3616 if(pC->iClientId != aClientId) |
|
3617 { |
|
3618 __KTRACE_OPT(KRESMANAGER, Kern::Printf("Client ID does not match")); |
|
3619 UNLOCK_RETURN(KErrNotFound); |
|
3620 } |
|
3621 if(pC->iClientId & CLIENT_THREAD_RELATIVE_BIT_MASK) |
|
3622 { |
|
3623 if(pC->iThreadId != t.iId) |
|
3624 { |
|
3625 UnLock(); |
|
3626 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3627 return KErrAccessDenied; |
|
3628 } |
|
3629 } |
|
3630 //Check for any pending request |
|
3631 if(pC->iPendingReqCount) |
|
3632 { |
|
3633 UnLock(); |
|
3634 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3635 Panic(EClientHasPendingAsyncRequest); |
|
3636 } |
|
3637 //Check for notification request |
|
3638 if(pC->iNotificationList) |
|
3639 { |
|
3640 UnLock(); |
|
3641 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3642 Panic(EClientHasNotificationObject); |
|
3643 } |
|
3644 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3645 if(pC->iDynamicResCount) |
|
3646 { |
|
3647 UnLock(); |
|
3648 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3649 Panic(DPowerResourceController::EClientHasDynamicResourceRegistered); |
|
3650 } |
|
3651 #endif |
|
3652 ResourceStateChangeOfClientLevels(pC); |
|
3653 //Add reserved request to pool |
|
3654 iRequestPoolCount = (TUint16)(iRequestPoolCount + pC->iReservedRm); |
|
3655 PRM_CLIENT_DEREGISTER_TRACE |
|
3656 //Increment the free pool count for client level and request level. |
|
3657 iUserSideClientList.Remove(pC, (TUint16)(pC->iClientId & ID_INDEX_BIT_MASK)); |
|
3658 pC->iName = NULL; |
|
3659 iUserSideClientCount--; //Decrement client count |
|
3660 LIST_PUSH(iClientPool, pC, iNextInList); |
|
3661 UnLock(); |
|
3662 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3663 return KErrNone; |
|
3664 } |
|
3665 |
|
3666 /* This is called from power controller to cache the state of resource whose |
|
3667 state information it is interested in for accessing from null thread. This |
|
3668 list needs to be accessed from the Idle thread using direct access. */ |
|
3669 TInt DPowerResourceController::RegisterResourcesForIdle(TInt aPowerControllerId, TUint aNumResources, TPtr* aBuf) |
|
3670 { |
|
3671 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::RegisterResourceForIdle")); |
|
3672 __KTRACE_OPT(KRESMANAGER, Kern::Printf("PowerControllerId = 0x%x, NumResources = %d", aPowerControllerId, \ |
|
3673 aNumResources)); |
|
3674 #ifdef DEBUG_VERSION //Surrounding with macro to avoid warnings. |
|
3675 DThread& t = Kern::CurrentThread(); |
|
3676 CHECK_CONTEXT(t) |
|
3677 #endif |
|
3678 if(!aBuf) |
|
3679 return KErrArgument; |
|
3680 if((TUint)aPowerControllerId != iPowerControllerId) |
|
3681 return KErrAccessDenied; |
|
3682 if(iListForIdle) //Only one list is allowed. |
|
3683 return KErrInUse; |
|
3684 if((TUint)(aBuf->MaxLength() - aBuf->Length()) < (sizeof(SIdleResourceInfo) * aNumResources)) |
|
3685 return KErrArgument; |
|
3686 GET_CRITICAL_SECTION_COUNT |
|
3687 Lock(); |
|
3688 SIdleResourceInfo* pS=(SIdleResourceInfo*)aBuf; |
|
3689 DStaticPowerResource* pR=NULL; |
|
3690 TUint count=0, id=0; |
|
3691 for(count=0;count<aNumResources;count++) //Check for valid resource ID. |
|
3692 { |
|
3693 #ifndef PRM_ENABLE_EXTENDED_VERSION |
|
3694 if((!pS->iResourceId) || (pS->iResourceId > iStaticResourceArrayEntries) || (!iStaticResourceArray[pS->iResourceId-1])) |
|
3695 { |
|
3696 UnLock(); |
|
3697 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3698 return KErrNotFound; |
|
3699 } |
|
3700 #else |
|
3701 if(pS->iResourceId & KIdMaskDynamic) |
|
3702 { |
|
3703 UnLock(); |
|
3704 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3705 return KErrNotSupported; |
|
3706 } |
|
3707 if((!pS->iResourceId) || ((pS->iResourceId & KIdMaskResourceWithDependencies) && |
|
3708 (pS->iResourceId > iStaticResDependencyCount)) || (pS->iResourceId > iStaticResourceArrayEntries) |
|
3709 || (!iStaticResourceArray[pS->iResourceId-1])) |
|
3710 { |
|
3711 UnLock(); |
|
3712 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3713 return KErrNotFound; |
|
3714 } |
|
3715 #endif |
|
3716 pS++; |
|
3717 } |
|
3718 pS = (SIdleResourceInfo*)aBuf; |
|
3719 for(count=0;count<aNumResources;count++) |
|
3720 { |
|
3721 id=pS->iResourceId; |
|
3722 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3723 if(id & KIdMaskResourceWithDependencies) //Dependency resource |
|
3724 pR = iStaticResDependencyArray[(id & ID_INDEX_BIT_MASK)-1]; |
|
3725 else |
|
3726 #endif |
|
3727 pR=iStaticResourceArray[id-1]; |
|
3728 pR->iIdleListEntry=pS; |
|
3729 pS++; |
|
3730 } |
|
3731 iListForIdle=(SIdleResourceInfo*)aBuf; |
|
3732 UnLock(); |
|
3733 LOCK_AND_CRITICAL_SECTION_COUNT_CHECK |
|
3734 return KErrNone; |
|
3735 } |
|
3736 |
|
3737 /** |
|
3738 @publishedPartner |
|
3739 @prototype 9.6 |
|
3740 |
|
3741 Request to deregister client level from the specified resource for the specified client. |
|
3742 |
|
3743 @param aClientId ID of the client which is requesting the deregistration of client level. |
|
3744 @param aResourceId ID of the resource from which to remove the specified client's level. |
|
3745 |
|
3746 @return KErrNone if successful |
|
3747 KErrAccessDenied if the client ID could not be found in the list of registered clients or |
|
3748 if the client was registered to be thread relative and this API is not |
|
3749 called from the same thread. |
|
3750 KErrNotFound if the resource ID could not be found in the current list of controllable |
|
3751 resources or if the client is not holding any level with the specified |
|
3752 resource (no client level found for the specified client). |
|
3753 |
|
3754 @pre Interrupts must be enabled |
|
3755 @pre Kernel must be unlocked |
|
3756 @pre No fast mutex can be held |
|
3757 @pre Call in a thread context but not from null thread or DFC thread1 |
|
3758 @pre Can be used in a device driver. |
|
3759 */ |
|
3760 TInt DPowerResourceController::DeRegisterClientLevelFromResource(TUint aClientId, TUint aResourceId) |
|
3761 { |
|
3762 TInt r = KErrNone; |
|
3763 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::DeRegisterClientLevelFromResource\n")); |
|
3764 __KTRACE_OPT(KRESMANAGER, Kern::Printf("aClientId = 0x%x, aResourceId = 0x%x\n", aClientId, aResourceId)); |
|
3765 DThread& thread = Kern::CurrentThread(); |
|
3766 CHECK_CONTEXT(thread) |
|
3767 SPowerResourceClient* pC = NULL; |
|
3768 Lock(); |
|
3769 VALIDATE_CLIENT(thread); |
|
3770 //Validate resource |
|
3771 if((!aResourceId)) |
|
3772 { |
|
3773 UNLOCK_RETURN(KErrNotFound); |
|
3774 } |
|
3775 DStaticPowerResource *pR = NULL; |
|
3776 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3777 GET_RESOURCE_FROM_LIST(aResourceId, pR) |
|
3778 if(aResourceId & KIdMaskDynamic) |
|
3779 ((DDynamicPowerResource*)pR)->Lock(); |
|
3780 #else |
|
3781 if(aResourceId > iStaticResourceArrayEntries) |
|
3782 { |
|
3783 UNLOCK_RETURN(KErrNotFound); |
|
3784 } |
|
3785 pR = iStaticResourceArray[aResourceId - 1]; |
|
3786 if(!pR) |
|
3787 UNLOCK_RETURN(KErrNotFound); |
|
3788 #endif |
|
3789 //Need to change the state of the resource if the client is holding the current resource. |
|
3790 if((pR->iLevelOwnerId == (TInt)aClientId) || (pR->Sense() == DStaticPowerResource::ECustom)) |
|
3791 { |
|
3792 //If Longlatency resource then process it in the resource controller thread |
|
3793 TPowerRequest* req = (TPowerRequest*)&TPowerRequest::Get(); |
|
3794 req->ResourceId() = aResourceId; |
|
3795 req->ReqType() = TPowerRequest::ESetDefaultLevel; |
|
3796 req->ClientId() = aClientId; |
|
3797 req->Resource() = pR; |
|
3798 req->ResourceCb() = NULL; |
|
3799 #ifdef PRM_INSTRUMENTATION_MACRO |
|
3800 //Setting to current state as exact state will be known only before calling the PSL. |
|
3801 TInt aNewState = pR->iCachedLevel; |
|
3802 PRM_CLIENT_CHANGE_STATE_START_TRACE |
|
3803 #endif |
|
3804 if(pR->LatencySet()) |
|
3805 { |
|
3806 UnLock(); |
|
3807 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3808 if(pR->iResourceId & KIdMaskResourceWithDependencies) //Dependency resource |
|
3809 { |
|
3810 r = req->SendReceive(iMsgQDependency); // Send the request to DFC thread. |
|
3811 } |
|
3812 else |
|
3813 #endif |
|
3814 { |
|
3815 r = req->SendReceive(iMsgQ); //Long latency resource request are processed in controller thread. |
|
3816 } |
|
3817 Lock(); |
|
3818 } |
|
3819 else if(pR->Usage()) |
|
3820 { |
|
3821 //Shared resource |
|
3822 //Not checking the return value here because there is no allocation of client levels. |
|
3823 CheckLevelAndAddClient(pC, req); |
|
3824 } |
|
3825 else |
|
3826 { |
|
3827 //Single user set it to default |
|
3828 req->ClientId() = -1; |
|
3829 req->ReqType() = TPowerRequest::ESetDefaultLevel; |
|
3830 } |
|
3831 //Change the state of resource for instantaneous resource. |
|
3832 if((!pR->LatencySet()) && ((!pR->Usage()) || (pR->Usage() && req->RequiresChange()))) |
|
3833 { |
|
3834 UnLock(); |
|
3835 r = pR->DoRequest(*req); |
|
3836 Lock(); |
|
3837 if(r == KErrNone) |
|
3838 { |
|
3839 //Complete notifications |
|
3840 CompleteNotifications(req->ClientId(), pR, req->Level(), KErrNone, req->ClientId(), EFalse); |
|
3841 //Update the cache |
|
3842 pR->iLevelOwnerId = req->ClientId(); |
|
3843 pR->iCachedLevel = req->Level(); |
|
3844 if(pR->iIdleListEntry) |
|
3845 { |
|
3846 pR->iIdleListEntry->iLevelOwnerId = req->ClientId(); |
|
3847 pR->iIdleListEntry->iCurrentLevel = req->Level(); |
|
3848 } |
|
3849 } |
|
3850 } |
|
3851 #ifdef PRM_INSTRUMENTATION_MACRO |
|
3852 if(!pR->LatencySet()) |
|
3853 { |
|
3854 aNewState = req->Level(); |
|
3855 PRM_CLIENT_CHANGE_STATE_END_TRACE |
|
3856 } |
|
3857 #endif |
|
3858 } |
|
3859 //Remove clientLevel from client |
|
3860 r = KErrNotFound; |
|
3861 for(SPowerResourceClientLevel* pCL = pC->iLevelList; pCL != NULL; pCL= pCL->iNextInList) |
|
3862 { |
|
3863 if(pCL->iResourceId == aResourceId) |
|
3864 { |
|
3865 LIST_REMOVE(pC->iLevelList, pCL, iNextInList, SPowerResourceClientLevel); |
|
3866 //Remove from Resource |
|
3867 pCL->Deque(); |
|
3868 LIST_PUSH(iClientLevelPool,pCL,iNextInList); // back to free pool |
|
3869 if(pC->iUnderFlowClCount > 0) |
|
3870 { |
|
3871 pC->iUnderFlowClCount--; |
|
3872 iClientLevelPoolCount++; |
|
3873 } |
|
3874 else |
|
3875 pC->iReservedCl++; |
|
3876 r = KErrNone; |
|
3877 break; |
|
3878 } |
|
3879 } |
|
3880 #ifdef PRM_ENABLE_EXTENDED_VERSION |
|
3881 if(aResourceId & KIdMaskDynamic) |
|
3882 ((DDynamicPowerResource*)pR)->UnLock(); |
|
3883 #endif |
|
3884 UNLOCK_RETURN(r); |
|
3885 } |
|
3886 |
|
3887 /** |
|
3888 @publishedPartner |
|
3889 @prototype 9.5 |
|
3890 |
|
3891 Interface to provide extended functionality.This provides support |
|
3892 to register and deregister dynamic resources and handling of resource dependency, registering |
|
3893 and deregistering resource dependency. |
|
3894 This is not supported in basic version |
|
3895 |
|
3896 @pre Interrupts must be enabled |
|
3897 @pre Kernel must be unlocked |
|
3898 @pre No fast mutex can be held |
|
3899 @pre Call in a thread context but not from null thread or DFC thread1 |
|
3900 @pre Can be used in a device driver. |
|
3901 */ |
|
3902 TInt DPowerResourceController::GetInterface(TUint aClientId, TUint aInterfaceId, TAny* aParam1, TAny* aParam2, |
|
3903 TAny* aParam3) |
|
3904 { |
|
3905 __KTRACE_OPT(KRESMANAGER, Kern::Printf(">DPowerResourceController::GetInterface")); |
|
3906 CHECK_CONTEXT(thread) |
|
3907 if((iInitialised != EResConStartupCompleted) && (aInterfaceId != KResManControlIoGetVersion)) |
|
3908 return KErrNotSupported; |
|
3909 TInt r = KErrNone; |
|
3910 DThread& thread = Kern::CurrentThread(); |
|
3911 Lock(); |
|
3912 SPowerResourceClient* pC = NULL; |
|
3913 VALIDATE_CLIENT(thread); |
|
3914 #ifndef PRM_ENABLE_EXTENDED_VERSION |
|
3915 if(aInterfaceId == KResManControlIoGetVersion) |
|
3916 { |
|
3917 if(!aParam1) |
|
3918 r = KErrArgument; |
|
3919 else |
|
3920 *(TUint*)aParam1 = KResControllerBasicVersion; |
|
3921 } |
|
3922 else |
|
3923 r = KErrNotSupported; |
|
3924 (void) aParam2; |
|
3925 (void) aParam3; |
|
3926 #else |
|
3927 //User side client is not allowed to register/deregister dynamic resource and dependencies |
|
3928 if((aClientId & USER_SIDE_CLIENT_BIT_MASK) && (aInterfaceId >= KResManControlIoRegisterDynamicResource) && |
|
3929 (aInterfaceId <= KResManControlIoDeregisterDependency)) |
|
3930 return KErrAccessDenied; |
|
3931 switch (aInterfaceId) |
|
3932 { |
|
3933 case KResManControlIoGetVersion: |
|
3934 { |
|
3935 if(!aParam1) |
|
3936 r = KErrArgument; |
|
3937 else |
|
3938 *(TUint*)aParam1 = KResControllerExtendedVersion; |
|
3939 break; |
|
3940 } |
|
3941 case KResManControlIoRegisterDynamicResource: |
|
3942 { |
|
3943 r = RegisterDynamicResource(pC, (DDynamicPowerResource *)aParam1, (TUint*)aParam2); |
|
3944 break; |
|
3945 } |
|
3946 case KResManControlIoDeregisterDynamicResource: |
|
3947 { |
|
3948 r = DeregisterDynamicResource(pC, (TUint)aParam1, (TInt*)aParam2); |
|
3949 break; |
|
3950 } |
|
3951 case KResManControlIoRegisterDependency: |
|
3952 { |
|
3953 |
|
3954 r = RegisterResourceDependency(pC, (SResourceDependencyInfo*)aParam1, (SResourceDependencyInfo*)aParam2); |
|
3955 break; |
|
3956 } |
|
3957 case KResManControlIoDeregisterDependency: |
|
3958 { |
|
3959 r = DeregisterResourceDependency(pC, (TUint)aParam1, (TUint)aParam2); |
|
3960 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetInterface")); |
|
3961 return(r); |
|
3962 } |
|
3963 case KResManControlIoGetNumDependents: |
|
3964 { |
|
3965 r = GetNumDependentsForResource((TUint)aParam1, (TUint*)aParam2); |
|
3966 break; |
|
3967 } |
|
3968 case KResManControlIoGetDependentsId: |
|
3969 { |
|
3970 r = GetDependentsIdForResource((TUint)aParam1, (TAny*)aParam2, (TUint*)aParam3); |
|
3971 break; |
|
3972 } |
|
3973 default: |
|
3974 { |
|
3975 r = KErrNotSupported; |
|
3976 break; |
|
3977 } |
|
3978 } |
|
3979 #endif |
|
3980 __KTRACE_OPT(KRESMANAGER, Kern::Printf("<DPowerResourceController::GetInterface")); |
|
3981 UNLOCK_RETURN(r); |
|
3982 } |
|
3983 |