133 iUserBuffer[node].iChunk = 0; |
158 iUserBuffer[node].iChunk = 0; |
134 iUserBuffer[node].iOffset = 0; |
159 iUserBuffer[node].iOffset = 0; |
135 iUserBuffer[node].iPendingRequest = 0; |
160 iUserBuffer[node].iPendingRequest = 0; |
136 } |
161 } |
137 |
162 |
138 //Initialise pending queue for asynchronous requests |
163 //Initialise pending queue for asynchronous requests and queue of TClientRequests |
139 for(int k = 0; k < KPendingReqArraySize; k++) |
164 for(TInt k = 0; k < KPendingReqArraySize; k++) |
140 { |
165 { |
141 iPendingReq[k].iStatus = 0; |
166 |
142 iPendingReq[k].iOwningThread = 0; |
167 iPendingIndex[k]=0; |
143 } |
168 |
|
169 for(TInt i = 0; i < KMaxQueuedRequests; i++) |
|
170 { |
|
171 iPendingReq[k][i].iTClientReq = 0; |
|
172 iPendingReq[k][i].iOwningThread = 0; |
|
173 |
|
174 |
|
175 r = Kern::CreateClientRequest(iClientRequest[k][i]); |
|
176 if (r != KErrNone) |
|
177 { |
|
178 return r; |
|
179 } |
|
180 } |
|
181 } |
|
182 |
|
183 r = Kern::MutexCreate(iClientRequestMutex, KClientRequestMutex, KMutexOrder); |
|
184 if (r != KErrNone) |
|
185 { |
|
186 return r; |
|
187 } |
|
188 |
144 |
189 |
145 Pdd()->SetGceMode(); |
190 Pdd()->SetGceMode(); |
146 SetDfcQ(Pdd()->DfcQ(aUnit)); |
191 SetDfcQ(Pdd()->DfcQ(aUnit)); |
147 iMsgQ.Receive(); |
192 iMsgQ.Receive(); |
148 |
193 |
149 return KErrNone; |
194 return KErrNone; |
150 } |
195 } |
151 |
196 |
152 |
197 |
153 /** |
198 /** |
154 * All driver's client requests (synchronous and asynchronous) are sent as |
199 Override DLogicalChannel::SendMsg to process a client message before and after sending the message |
155 * kernel messages by generic kernel to logical channel. This function |
200 to the DFC thread for processing by HandleMsg(). |
156 * catches messages sent by the generic kernel |
201 |
157 * |
202 This function is called in the context of the client thread. |
158 * @param aMsg KErnel side thread messaging |
203 |
|
204 The function is used to pin client data in the context of the client thread, so that data can be safely |
|
205 accessed from kernel threads without the possibility of taking page faults. |
|
206 |
|
207 @param aMsg The message to process. |
|
208 The iValue member of this distinguishes the message type: |
|
209 iValue==ECloseMsg, channel close message |
|
210 iValue==KMaxTInt, a 'DoCancel' message |
|
211 iValue>=0, a 'DoControl' message with function number equal to iValue |
|
212 iValue<0, a 'DoRequest' message with function number equal to ~iValue |
|
213 |
|
214 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error |
|
215 codes. |
|
216 |
|
217 */ |
|
218 |
|
219 TInt DDisplayLdd::SendMsg(TMessageBase* aMsg) |
|
220 { |
|
221 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
222 TInt id = m.iValue; |
|
223 |
|
224 TInt r = KErrNone; |
|
225 // close msg or cancel |
|
226 if (id == (TInt)ECloseMsg || id == KMaxTInt) |
|
227 { |
|
228 r = DLogicalChannel::SendMsg(aMsg); |
|
229 } |
|
230 //asynchronous request |
|
231 else if (id < 0) |
|
232 { |
|
233 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
234 r = SendRequest(aMsg); |
|
235 if (r != KErrNone) |
|
236 Kern::RequestComplete(pS,r); |
|
237 } |
|
238 // synchronous request |
|
239 else{ |
|
240 r = SendControl(aMsg); |
|
241 } |
|
242 |
|
243 return r; |
|
244 } |
|
245 |
|
246 |
|
247 /** |
|
248 Validate, pre-process, send and post-process data for an asynchronous client request, so that data can be safely |
|
249 accessed from kernel threads without the possibility of taking page faults. |
|
250 |
|
251 This function is called in the context of the client thread. |
|
252 |
|
253 @param aMsg The message to process. |
|
254 The iValue member of this distinguishes the message type: |
|
255 iValue==ECloseMsg, channel close message |
|
256 iValue==KMaxTInt, a 'DoCancel' message |
|
257 iValue>=0, a 'DoControl' message with function number equal to iValue |
|
258 iValue<0, a 'DoRequest' message with function number equal to ~iValue |
|
259 |
|
260 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error |
|
261 codes. |
|
262 */ |
|
263 TInt DDisplayLdd::SendRequest(TMessageBase* aMsg) |
|
264 { |
|
265 TThreadMessage& m =*(TThreadMessage*)aMsg; |
|
266 TInt aReqNumber = ~m.iValue; |
|
267 TRequestStatus* pS =(TRequestStatus*)m.Ptr0(); |
|
268 |
|
269 #ifdef _GCE_DISPLAY_DEBUG |
|
270 DThread* client = m.Client(); |
|
271 #endif |
|
272 |
|
273 TInt r = KErrNotSupported; |
|
274 TInt pendingIndex; |
|
275 |
|
276 /*Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. |
|
277 Using thread local copies is possible even for asynchronous requests, since the values to be returned are known |
|
278 when processing the request( inside DoRequest ) and not at a later stage.*/ |
|
279 |
|
280 TInt kernelCompBuffIdx; |
|
281 TInt kernelpack[2]; |
|
282 RDisplayChannel::TPostCount kernelCount; |
|
283 |
|
284 |
|
285 //In asynchronous requests m.Ptr0 is used for the TRequestStatus object. |
|
286 TAny* userConfigData1 = m.Ptr1(); |
|
287 TAny* userConfigData2 = m.Ptr2(); |
|
288 |
|
289 /* |
|
290 If the client request needs to pass some data to the DFC thread then we copy these to a thread local |
|
291 copy(created in the thread supervisor stack) and then update the message to point to that local copy. |
|
292 If the client will have to read a value updated in the DFC thread, then the message should just be |
|
293 updated and point to the local copy. After the request has completed the updated data will be copied |
|
294 from the local copy to the client, in the context of the client thread. |
|
295 */ |
|
296 |
|
297 switch (aReqNumber) |
|
298 { |
|
299 case RDisplayChannel::EReqGetCompositionBuffer: //Client should read data updated in the DFC thread. |
|
300 m.iArg[1] = &kernelCompBuffIdx; |
|
301 break; |
|
302 |
|
303 case RDisplayChannel::EReqPostUserBuffer: //Both the client and DFC thread need to read data. |
|
304 umemget32(&kernelpack, userConfigData1, (sizeof(TInt)*2) ); |
|
305 m.iArg[1] = &kernelpack; |
|
306 m.iArg[2] = &kernelCount; |
|
307 break; |
|
308 |
|
309 case RDisplayChannel::EReqWaitForPost: //Client data should be passed to the DFC thread. |
|
310 umemget32(&kernelCount, userConfigData1, sizeof(RDisplayChannel::TPostCount) ); |
|
311 m.iArg[1] = &kernelCount; |
|
312 break; |
|
313 default: |
|
314 return KErrNotSupported; |
|
315 |
|
316 } |
|
317 |
|
318 /* |
|
319 The TClientRequest objects associated with each asynchronous request need to be accessed by both the client and DFC |
|
320 threads. To resolve the potential synchronization problem we maintain two seperate pointers(iClientRequest and |
|
321 iPendingReq.iClientReq )to the same TClientRequest object. iClientRequestMutex is used to synchronise access to |
|
322 iClientRequest from different client threads. The first client thread that acquires the mutex will set the status |
|
323 of an available TClientRequest object and send the message(call SendMsg). Consequently method DoRequest is queued for |
|
324 execution by the DFC thread. DoRequest initialy saves iClientRequest to iPendingReq.iClientReq and queues the request. |
|
325 Only then, the mutex is signaled. Another client thread trying to access iClientRequest will block in the mutex until |
|
326 DoRequest has updated iPendingReq.iClientReq. Even more the DFC thread only accesses iClientRequest in DoRequest and |
|
327 then iPendingReq.iClientReq is only used, so synchronizing access to iPendingReq.iClientReq is handled by the DFC queue. |
|
328 */ |
|
329 |
|
330 // Need to be in critical section whilst holding a DMutex |
|
331 NKern::ThreadEnterCS(); |
|
332 |
|
333 Kern::MutexWait(*iClientRequestMutex); |
|
334 //Save the TRequestStatus in any available TClientRequest object for that asynchronous request. |
|
335 |
|
336 for( TInt k=0; k< KMaxQueuedRequests; k++) |
|
337 { |
|
338 //setStatus will return KErrInUse if a previous client request hasn't completed yet. |
|
339 r = iClientRequest[aReqNumber][k]->SetStatus(pS); |
|
340 if( r == KErrNone) |
|
341 { |
|
342 pendingIndex = k; |
|
343 //The current available index for this pending request will be passed as |
|
344 //another message argument to the DFC thread. |
|
345 m.iArg[3] = (TAny*) pendingIndex; |
|
346 break; |
|
347 } |
|
348 } |
|
349 |
|
350 if (r == KErrNone) |
|
351 { |
|
352 r = DLogicalChannel::SendMsg(aMsg); |
|
353 } |
|
354 else |
|
355 { |
|
356 __DEBUG_PRINT3("Client %08x trying to issue asynchronous request %d", client, aReqNumber); |
|
357 //Fail if there aren't any available TClientRequest object |
|
358 __ASSERT_DEBUG(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__)); |
|
359 } |
|
360 |
|
361 Kern::MutexSignal(*iClientRequestMutex); |
|
362 |
|
363 NKern::ThreadLeaveCS(); |
|
364 |
|
365 //Copy config data from local copies to client, in context of client thread |
|
366 switch (aReqNumber) |
|
367 { |
|
368 case RDisplayChannel::EReqGetCompositionBuffer: |
|
369 __DEBUG_PRINT2("EReqGetCompositionBuffer: kernelCompBuffIdx returned =%d",kernelCompBuffIdx); |
|
370 umemput32(userConfigData1, &kernelCompBuffIdx, sizeof(TInt) ); |
|
371 break; |
|
372 |
|
373 case RDisplayChannel::EReqPostUserBuffer: |
|
374 __DEBUG_PRINT2("EReqPostUserBuffer: kernelCount returned = %d",kernelCount); |
|
375 umemput32(userConfigData2, &kernelCount, sizeof(RDisplayChannel::TPostCount) ); |
|
376 break; |
|
377 } |
|
378 return r; |
|
379 } |
|
380 |
|
381 |
|
382 /** |
|
383 Validate, pre-process, send and post-process data for a synchronous client request, so that data can be safely |
|
384 accessed from kernel threads without the possibility of taking page faults. |
|
385 |
|
386 This function is called in the context of the client thread. |
|
387 |
|
388 @param aMsg The message to process. |
|
389 The iValue member of this distinguishes the message type: |
|
390 iValue==ECloseMsg, channel close message |
|
391 iValue==KMaxTInt, a 'DoCancel' message |
|
392 iValue>=0, a 'DoControl' message with function number equal to iValue |
|
393 iValue<0, a 'DoRequest' message with function number equal to ~iValue |
|
394 |
|
395 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error |
|
396 codes. |
|
397 */ |
|
398 |
|
399 TInt DDisplayLdd::SendControl(TMessageBase* aMsg) |
|
400 { |
|
401 TThreadMessage& m = *(TThreadMessage*)aMsg; |
|
402 TInt aReqNumber = m.iValue; |
|
403 |
|
404 |
|
405 //Use thread local copies of the configuration data that need to be exchanged between the client and DFC thread. |
|
406 |
|
407 RDisplayChannel::TPostCount kernelPostCount; |
|
408 RDisplayChannel::TDisplayRotation kernelRotation; |
|
409 |
|
410 TPckgBuf<RDisplayChannel::TDisplayInfo> pckgInfo(iDisplayInfo); |
|
411 |
|
412 TInt kernelpack[2]; |
|
413 TInt kernelBufferId; |
|
414 TBool kernelRotChanged; |
|
415 TInt kernelIndex; |
|
416 |
|
417 TAny* userConfigData0 = m.Ptr0(); |
|
418 TAny* userConfigData1 = m.Ptr1(); |
|
419 |
|
420 |
|
421 switch (aReqNumber) |
|
422 { |
|
423 //iDisplayInfo doesn't change after the driver initialisation so copy in client thread context |
|
424 case RDisplayChannel::ECtrlGetDisplayInfo: |
|
425 umemput32(userConfigData0, &pckgInfo, sizeof(TPckgBuf<RDisplayChannel::TDisplayInfo>) ); |
|
426 return KErrNone; |
|
427 |
|
428 case RDisplayChannel::ECtrlPostCompositionBuffer: //Client should read data updated in the DFC thread. |
|
429 m.iArg[1] = &kernelPostCount; |
|
430 break; |
|
431 |
|
432 case RDisplayChannel::ECtrlPostLegacyBuffer: //Client should read data updated in the DFC thread. |
|
433 m.iArg[1] = &kernelPostCount; |
|
434 break; |
|
435 |
|
436 case RDisplayChannel::ECtrlRegisterUserBuffer: //Both the client and DFC thread need to read data. |
|
437 umemget32(&kernelpack, userConfigData0, (sizeof(TInt)*2) ); |
|
438 m.iArg[0] = &kernelpack; |
|
439 m.iArg[1] = &kernelBufferId; |
|
440 break; |
|
441 |
|
442 case RDisplayChannel::ECtrlDeregisterUserBuffer: //Client data should be passed to the DFC thread. |
|
443 umemget32(&kernelBufferId, userConfigData0, sizeof(TInt) ); |
|
444 m.iArg[0] = &kernelBufferId; |
|
445 break; |
|
446 |
|
447 case RDisplayChannel::ECtrlSetRotation: //Both the client and DFC thread need to read data. |
|
448 umemget32(&kernelRotation, userConfigData0, sizeof(RDisplayChannel::TDisplayRotation) ); |
|
449 m.iArg[0] = &kernelRotation; |
|
450 m.iArg[1] = &kernelRotChanged; |
|
451 break; |
|
452 |
|
453 case RDisplayChannel::ECtrlCurrentRotation: //Client should read data updated in the DFC thread. |
|
454 m.iArg[0] = &kernelRotation; |
|
455 break; |
|
456 |
|
457 case RDisplayChannel::ECtrlGetCompositionBufferInfo: //Both the client and DFC thread need to read data. |
|
458 umemget32(&kernelIndex, userConfigData0, sizeof(TInt) ); |
|
459 m.iArg[0] = &kernelIndex; |
|
460 m.iArg[1] = &kernelpack; |
|
461 break; |
|
462 |
|
463 #ifdef _DEBUG |
|
464 case RDisplayChannel::ECtrlCreateUserBuffer: |
|
465 m.iArg[0] = userConfigData0; |
|
466 m.iArg[1] = userConfigData1; |
|
467 break; |
|
468 #endif // _DEBUG |
|
469 |
|
470 default: |
|
471 return KErrNotSupported; |
|
472 |
|
473 } |
|
474 |
|
475 TInt r = DLogicalChannel::SendMsg(aMsg); |
|
476 if (r != KErrNone) |
|
477 { |
|
478 return r; |
|
479 } |
|
480 |
|
481 //Copy config data from local copies to client, in context of client thread |
|
482 switch (aReqNumber) |
|
483 { |
|
484 case RDisplayChannel::ECtrlPostCompositionBuffer: |
|
485 __DEBUG_PRINT2("ECtrlPostCompositionBuffer =%d", kernelPostCount ); |
|
486 umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) ); |
|
487 break; |
|
488 |
|
489 case RDisplayChannel::ECtrlPostLegacyBuffer: |
|
490 __DEBUG_PRINT2("ECtrlPostLegacyBuffer=%d", kernelPostCount ); |
|
491 umemput32(userConfigData1, &kernelPostCount, sizeof(RDisplayChannel::TPostCount) ); |
|
492 break; |
|
493 |
|
494 case RDisplayChannel::ECtrlRegisterUserBuffer: |
|
495 __DEBUG_PRINT2("ECtrlRegisterUserBuffer kernelBufferId=%d", kernelBufferId ); |
|
496 umemput32(userConfigData1, &kernelBufferId, sizeof(TInt) ); |
|
497 break; |
|
498 |
|
499 case RDisplayChannel::ECtrlSetRotation: |
|
500 __DEBUG_PRINT2("ECtrlSetRotation kernelRotChanged=%d", kernelRotChanged ); |
|
501 umemput32(userConfigData1, &kernelRotChanged, sizeof(TBool) ); |
|
502 break; |
|
503 |
|
504 case RDisplayChannel::ECtrlCurrentRotation: |
|
505 __DEBUG_PRINT2("ECtrlCurrentRotation kernelRotation=%d", kernelRotation ); |
|
506 umemput32(userConfigData0, &kernelRotation, sizeof(RDisplayChannel::TDisplayRotation) ); |
|
507 break; |
|
508 |
|
509 case RDisplayChannel::ECtrlGetCompositionBufferInfo: |
|
510 __DEBUG_PRINT3("ECtrlGetCompositionBufferInfo kernelpack[0] =%d and kernelpack[1] =%d", kernelpack[0], kernelpack[1]); |
|
511 umemput32(userConfigData1, &kernelpack, (sizeof(TInt)*2) ); |
|
512 break; |
|
513 } |
|
514 return r; |
|
515 } |
|
516 |
|
517 |
|
518 /** |
|
519 All driver's client requests (synchronous and asynchronous) are sent as |
|
520 kernel messages by generic kernel to logical channel. This function |
|
521 catches messages sent by the generic kernel. |
|
522 |
|
523 @param aMsg Kernel side thread message to process. |
|
524 |
|
525 The iValue member of this distinguishes the message type: |
|
526 iValue==ECloseMsg, channel close message |
|
527 iValue==KMaxTInt, a 'DoCancel' message |
|
528 iValue>=0, a 'DoControl' message with function number equal to iValue |
|
529 iValue<0, a 'DoRequest' message with function number equal to ~iValue |
159 */ |
530 */ |
160 void DDisplayLdd::HandleMsg(TMessageBase* aMsg) |
531 void DDisplayLdd::HandleMsg(TMessageBase* aMsg) |
161 { |
532 { |
162 TThreadMessage& m = *(TThreadMessage*)aMsg ; |
533 TThreadMessage& m = *(TThreadMessage*)aMsg ; |
163 TInt id = m.iValue ; |
534 TInt id = m.iValue ; |
217 |
594 |
218 switch (aReqNumber) |
595 switch (aReqNumber) |
219 { |
596 { |
220 case RDisplayChannel::ECtrlCancelGetCompositionBuffer: |
597 case RDisplayChannel::ECtrlCancelGetCompositionBuffer: |
221 case RDisplayChannel::ECtrlCancelPostUserBuffer: |
598 case RDisplayChannel::ECtrlCancelPostUserBuffer: |
222 case RDisplayChannel::ECtrlCancelWaitForPost: |
599 case RDisplayChannel::ECtrlCancelWaitForPost: |
223 if(iPendingReq[aReqNumber].iStatus) |
600 TInt pendingIndex = iPendingIndex[aReqNumber]; |
|
601 if(iPendingReq[aReqNumber][pendingIndex].iTClientReq) |
224 { |
602 { |
225 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel); |
603 if( iPendingReq[aReqNumber][pendingIndex].iTClientReq->IsReady() ) |
226 |
604 { |
227 iPendingReq[aReqNumber].iStatus = 0; |
605 CompleteRequest(iPendingReq[aReqNumber][pendingIndex].iOwningThread,iPendingReq[aReqNumber][pendingIndex].iTClientReq,KErrCancel); |
228 iPendingReq[aReqNumber].iOwningThread = 0; |
606 } |
229 } |
607 } |
230 break; |
608 break; |
231 } |
609 } |
232 |
610 |
233 } |
611 } |
234 |
612 |
235 /** |
613 /** |
236 Asynchronous request processing. |
614 Asynchronous request processing. |
237 |
615 |
238 @param aFunction request function number |
616 @param aFunction Request function number |
239 @param apRqStat pointer to the user's request status object. |
617 @param apArg1 Pointer to kernel message argument 1. |
240 @param apArg1 pointer to the 1st parameter |
618 @param apArg2 Pointer to kernel message argument 2. |
241 @param apArg2 pointer to the 2nd parameter |
619 @param aPendingIndex Index pointing to the appropriate TClientRequest object to use. |
242 |
620 @param aClient Pointer to the client thread that issued the asynchronous request. |
243 @return request scheduling result, system-wide error code. |
621 |
244 */ |
622 @return request scheduling result, system-wide error code. |
245 TInt DDisplayLdd::DoRequest(TInt aReqNumber, TRequestStatus* aRqStat, TAny* aArg1, TAny* aArg2, DThread* aClient) |
623 */ |
|
624 TInt DDisplayLdd::DoRequest(TInt aReqNumber, TAny* aArg1, TAny* aArg2, TInt aPendingIndex, DThread* aClient) |
246 { |
625 { |
247 TUint count; |
626 |
248 TInt pack[2]; |
627 TInt pack[2]; |
249 TInt r = KErrNone; |
628 TInt r = KErrNone; |
250 TBufferNode* node = 0; |
629 TBufferNode* node = 0; |
251 TInt buffer_id = 0; |
630 TInt buffer_id = 0; |
252 |
631 |
|
632 TInt* configBufferIdx ; |
|
633 RDisplayChannel::TPostCount* postCount; |
|
634 TInt* configPack; |
|
635 |
|
636 __DEBUG_PRINT5("DoRequest: iClientRequest[aReqNumber=%d][aPendingIndex=%d] is %08x and aClient=%08x\n",aReqNumber, aPendingIndex,iClientRequest[aReqNumber][aPendingIndex], aClient); |
|
637 |
253 // Open a reference on the client thread while the request is pending so it's control block can't disappear until this driver has finished with it. |
638 // Open a reference on the client thread while the request is pending so it's control block can't disappear until this driver has finished with it. |
254 r=aClient->Open(); |
639 r=aClient->Open(); |
255 __ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__)); |
640 __ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__)); |
256 #ifdef _DEBUG |
641 #ifdef _DEBUG |
257 __e32_atomic_add_ord32(&iThreadOpenCount, 1); |
642 __e32_atomic_add_ord32(&iThreadOpenCount, 1); |
258 #endif |
643 #endif |
259 |
644 |
260 // check if this request is valid |
645 for(TInt i = 0; i < KMaxQueuedRequests; i++) |
261 if(aReqNumber >= 0 && aReqNumber <= RDisplayChannel::EReqWaitForPost) |
646 { |
262 { |
647 //Don't cancel the asyncrhonous request we currently process. |
|
648 if (i == aPendingIndex) |
|
649 { |
|
650 continue; |
|
651 } |
263 // cancel outstanding request |
652 // cancel outstanding request |
264 if(iPendingReq[aReqNumber].iStatus) |
653 if(iPendingReq[aReqNumber][i].iTClientReq) |
265 { |
654 { |
266 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel); |
655 //If IsReady() returns true, setStatus has been called for that TCientRequest but QueueRequestComplete hasn't. |
267 iPendingReq[aReqNumber].iStatus = 0; |
656 //In that case we want to cancel this outstanding request. Given that all QueueRequestComplete calls execute |
268 iPendingReq[aReqNumber].iOwningThread = 0; |
657 // in the same DFC thread we currently run, there is no need to synchronise request completion calls. |
|
658 if(iPendingReq[aReqNumber][i].iTClientReq->IsReady() ) |
|
659 { |
|
660 CompleteRequest(iPendingReq[aReqNumber][i].iOwningThread,iPendingReq[aReqNumber][i].iTClientReq,KErrCancel); |
|
661 break; |
|
662 } |
269 } |
663 } |
270 |
|
271 // store request and client |
|
272 iPendingReq[aReqNumber].iStatus = aRqStat; |
|
273 iPendingReq[aReqNumber].iOwningThread = aClient; |
|
274 } |
664 } |
275 |
665 // store index, request and client |
|
666 iPendingIndex[aReqNumber] = aPendingIndex; |
|
667 iPendingReq[aReqNumber][aPendingIndex].iTClientReq = iClientRequest[aReqNumber][aPendingIndex]; |
|
668 iPendingReq[aReqNumber][aPendingIndex].iOwningThread = aClient; |
|
669 |
|
670 #ifdef _DEBUG |
|
671 __e32_atomic_add_ord32(&iAsyncReqCount, 1); |
|
672 #endif |
|
673 |
276 switch (aReqNumber) |
674 switch (aReqNumber) |
277 { |
675 { |
278 case RDisplayChannel::EReqGetCompositionBuffer: |
676 case RDisplayChannel::EReqGetCompositionBuffer: //DFC thread updates a value the client thread should read. |
279 |
677 { |
280 if(aArg1 == 0 ) |
678 configBufferIdx = (TInt*) aArg1; |
281 { |
679 |
282 r = KErrGeneral; |
680 TInt index; |
283 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,r); |
681 TBool found = EFalse; |
284 iPendingReq[aReqNumber].iStatus = 0; |
682 |
285 iPendingReq[aReqNumber].iOwningThread = 0; |
683 for(index = 0; index < (TInt) iDisplayInfo.iNumCompositionBuffers; index++) |
286 } |
684 { |
287 else |
685 if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose ) |
288 { |
686 { |
289 TInt index; |
687 __DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index); |
290 TBool found = EFalse; |
688 |
291 |
689 iCompositionBuffIdx = index; |
292 for(index =0; index< KDisplayCBMax; index++) |
690 *configBufferIdx = iCompositionBuffIdx; |
293 { |
691 iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose; |
294 if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose ) |
692 CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread,iPendingReq[aReqNumber][aPendingIndex].iTClientReq,r); |
295 { |
693 found = ETrue; |
296 __DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index); |
694 break; |
297 |
695 } |
298 iCompositionBuffIdx = index; |
696 } |
299 r = Kern::ThreadRawWrite(aClient, aArg1, &iCompositionBuffIdx, sizeof(TInt), aClient); |
697 if(!found) //There are no free buffers schedule request for completion |
300 if ( r == KErrNone) |
698 { |
301 { |
699 //Case of a single composition buffer. |
302 iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose; |
700 if (iDisplayInfo.iNumCompositionBuffers == 1) |
303 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,r); |
701 { |
304 iPendingReq[aReqNumber].iStatus = 0; |
702 iCompositionBuffIdx = 0; |
305 iPendingReq[aReqNumber].iOwningThread = 0; |
703 *configBufferIdx = iCompositionBuffIdx; |
306 found = ETrue; |
704 CompleteRequest(iPendingReq[aReqNumber][aPendingIndex].iOwningThread, iPendingReq[aReqNumber][aPendingIndex].iTClientReq, r); |
307 break; |
705 __DEBUG_PRINT("EReqGetCompositionBuffer The single Composition buffer is currently being used\n"); |
308 } |
706 break; |
|
707 } |
|
708 |
|
709 |
|
710 for( index=0; index< KDisplayCBMax; index++) |
|
711 { |
|
712 if(iCompositionBuffer[index].iState == EBufferActive) |
|
713 { |
|
714 iCompositionBuffIdx = index; |
|
715 *configBufferIdx = iCompositionBuffIdx; |
|
716 __DEBUG_PRINT2("EReqGetCompositionBuffer No composition buffer available. Next available is iCompositionBuffIdx %d.\n",iCompositionBuffIdx ); |
|
717 break; |
309 } |
718 } |
310 } |
719 } |
311 if(!found) //There are no free buffers schedule request for completion |
720 } |
312 { |
721 |
313 //Case of a single composition buffer. |
722 break; |
314 if (iDisplayInfo.iNumCompositionBuffers == 1) |
723 } |
315 { |
724 |
316 iCompositionBuffIdx = 0; |
725 case RDisplayChannel::EReqPostUserBuffer: //DFC thread should read client message data and update a value the client will read. |
317 r = Kern::ThreadRawWrite(aClient, aArg1, &iCompositionBuffIdx, sizeof(TInt), aClient); |
726 configPack = (TInt*) aArg1; |
318 __DEBUG_PRINT("EReqGetCompositionBuffer The single Composition buffer is currently being used\n"); |
727 pack[0] = *configPack; |
319 break; |
728 configPack++; |
320 } |
729 pack[1] = *configPack; |
321 |
730 |
322 |
731 r = KErrArgument; |
323 for( index=0; index< KDisplayCBMax; index++) |
732 buffer_id = pack[0]; |
324 { |
733 if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) ) |
325 if(iCompositionBuffer[index].iState == EBufferActive) |
734 { |
326 { |
735 node = FindUserBufferNode(buffer_id); |
327 iCompositionBuffIdx = index; |
736 if(node && (!(node->iFree) && node->iChunk ) ) |
328 r = Kern::ThreadRawWrite(aClient, aArg1,&iCompositionBuffIdx, sizeof(TInt), aClient); |
737 { |
329 __DEBUG_PRINT2("EReqGetCompositionBuffer No composition buffer available. Next available is iCompositionBuffIdx %d.\n",iCompositionBuffIdx ); |
738 __DEBUG_PRINT2("EReqPostUserBuffer Posting buffer id: %d \n",buffer_id ); |
330 break; |
739 r = Pdd()->PostUserBuffer(node); |
331 } |
740 if(r == KErrNone) |
332 } |
741 { |
333 } |
742 postCount = (RDisplayChannel::TPostCount*) aArg2; |
334 } |
743 ++iCurrentPostCount; |
335 break; |
744 *postCount= iCurrentPostCount; |
336 |
745 break; |
337 case RDisplayChannel::EReqPostUserBuffer: |
746 } |
338 r= Kern::ThreadRawRead(aClient, aArg1, &pack, (sizeof(TInt)*2)); |
747 } |
339 if ( r == KErrNone) |
748 } |
340 { |
749 RequestComplete(RDisplayChannel::EReqPostUserBuffer, r); |
341 r = KErrArgument; |
750 |
342 buffer_id = pack[0]; |
|
343 if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) ) |
|
344 { |
|
345 node = FindUserBufferNode(buffer_id); |
|
346 if(node && (!(node->iFree) && node->iChunk ) ) |
|
347 { |
|
348 __DEBUG_PRINT2("EReqPostUserBuffer Posting buffer id: %d \n",buffer_id ); |
|
349 r = Pdd()->PostUserBuffer(node); |
|
350 if(r == KErrNone) |
|
351 { |
|
352 ++iCurrentPostCount; |
|
353 r=Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient); |
|
354 break; |
|
355 } |
|
356 } |
|
357 } |
|
358 RequestComplete(RDisplayChannel::EReqPostUserBuffer, r); |
|
359 } |
|
360 break; |
751 break; |
361 |
752 |
362 case RDisplayChannel::EReqWaitForPost: |
753 case RDisplayChannel::EReqWaitForPost: //DFC thread should read client message data. |
363 r= Kern::ThreadRawRead(aClient, aArg1, &count, sizeof(RDisplayChannel::TPostCount)); |
754 postCount = (RDisplayChannel::TPostCount*) aArg1; |
364 if ( r == KErrNone) |
755 iRequestedPostCount = *postCount; |
365 { |
756 |
366 iRequestedPostCount = count; |
757 //Any post operation increases iCurrentPostCount instantly but the actual post completes later on. |
367 //Any post operation increases iCurrentPostCount instantly but the actual post completes later on. |
758 if( ! Pdd()->PostPending() ) |
368 if( ! Pdd()->PostPending() ) |
759 { |
369 { |
760 RequestComplete(RDisplayChannel::EReqWaitForPost, KErrNone); |
370 RequestComplete(RDisplayChannel::EReqWaitForPost, KErrNone); |
761 } |
371 } |
|
372 } |
|
373 break; |
762 break; |
374 |
763 |
375 default: |
764 default: |
376 r = KErrNotSupported; |
765 __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number |
377 break; |
|
378 } |
766 } |
379 return r; |
767 return r; |
380 } |
768 } |
381 |
769 |
382 |
770 |
383 /** |
771 /** |
384 Synchronous requests processing. |
772 Synchronous requests processing. |
385 |
773 |
386 @param aFunction request function number, |
774 @param aFunction Request function number, |
387 @param apArg1 pointer to the 1st parameter |
775 @param apArg1 Pointer to kernel message argument 0. |
388 @param apArg2 pointer to the 2n parameter |
776 @param apArg2 Pointer to kernel message argument 1. |
|
777 @param aClient Pointer to the client thread that issued the synchronous request. |
389 |
778 |
390 @return request processing result |
779 @return request processing result |
391 */ |
780 */ |
392 TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient) |
781 TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient) |
393 { |
782 { |
394 TInt r = KErrNotSupported; |
783 TInt r = KErrNone; |
395 TBool changedRot = ETrue; |
784 TBool changedRot = ETrue; |
396 TBufferNode* node = 0; |
785 TBufferNode* node = 0; |
397 TInt buffer_id; |
786 TInt buffer_id; |
398 TInt pack[2] = {0,0}; |
787 TInt pack[2] = {0,0}; |
399 TInt handle, offset; |
788 TInt handle, offset; |
400 TInt index = 0; |
789 TInt index = 0; |
401 |
790 |
402 TPckgBuf<RDisplayChannel::TDisplayInfo> pckgInfo(iDisplayInfo); |
791 RDisplayChannel::TPostCount *postCount ; |
403 |
792 RDisplayChannel::TDisplayRotation *rotation; |
|
793 |
|
794 TInt *configPack; |
|
795 TInt *bufferId; |
|
796 |
|
797 TBool *rotationChanged; |
|
798 TInt *idx; |
|
799 |
404 switch (aFunction) |
800 switch (aFunction) |
405 { |
801 { |
406 case RDisplayChannel::ECtrlGetDisplayInfo: |
802 case RDisplayChannel::ECtrlPostCompositionBuffer: //DFC thread updates a value the client thread should read. |
407 r=Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&pckgInfo, sizeof(pckgInfo), aClient); |
803 postCount = (RDisplayChannel::TPostCount*) aArg2; |
408 break; |
804 |
409 |
|
410 case RDisplayChannel::ECtrlPostCompositionBuffer: |
|
411 node = &iCompositionBuffer[iCompositionBuffIdx]; |
805 node = &iCompositionBuffer[iCompositionBuffIdx]; |
412 r = Pdd()->PostCompositionBuffer(node); |
806 r = Pdd()->PostCompositionBuffer(node); |
413 if(r == KErrNone) |
807 if(r == KErrNone) |
414 { |
808 { |
415 ++iCurrentPostCount; |
809 ++iCurrentPostCount; |
416 r=Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient); |
810 *postCount = iCurrentPostCount; |
417 } |
811 } |
418 else |
812 else |
419 { |
813 { |
420 r = KErrGeneral; |
814 r = KErrGeneral; |
421 } |
815 } |
422 break; |
816 break; |
423 |
817 |
424 case RDisplayChannel::ECtrlPostLegacyBuffer: |
818 case RDisplayChannel::ECtrlPostLegacyBuffer: //DFC thread updates a value the client thread should read. |
|
819 postCount = (RDisplayChannel::TPostCount*) aArg2; |
425 r= Pdd()->PostLegacyBuffer(); |
820 r= Pdd()->PostLegacyBuffer(); |
426 if ( r == KErrNone) |
821 if ( r == KErrNone) |
427 { |
822 { |
428 ++iCurrentPostCount; |
823 ++iCurrentPostCount; |
429 r = Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient); |
824 *postCount = iCurrentPostCount; |
430 } |
825 } |
431 break; |
826 break; |
432 |
827 |
433 case RDisplayChannel::ECtrlRegisterUserBuffer: |
828 case RDisplayChannel::ECtrlRegisterUserBuffer: //DFC thread should read client message data and update a value the client will read. |
434 node = FindUserBufferNode(0); |
829 node = FindUserBufferNode(0); |
435 if(node) |
830 if(node) |
436 { |
831 { |
437 r= Kern::ThreadRawRead(aClient, aArg1, &pack, (sizeof(TInt)*2)); |
832 configPack = (TInt*) aArg1; |
438 if(r == KErrNone) |
833 handle = *configPack; |
439 { |
834 configPack++; |
440 handle = pack[0]; |
835 offset = *configPack; |
441 offset = pack[1]; |
836 r = CheckAndOpenUserBuffer(node, handle, offset, aClient); |
442 r = CheckAndOpenUserBuffer(node, handle, offset, aClient); |
837 |
443 |
838 if(r == KErrNone) |
444 if(r == KErrNone) |
839 { |
445 { |
840 bufferId = (TInt*) aArg2; |
446 r= Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&node->iBufferId, sizeof(TInt), aClient); |
841 *bufferId = node->iBufferId; |
447 } |
842 } |
448 } |
|
449 } |
843 } |
450 else |
844 else |
451 { |
845 { |
452 r = KErrTooBig; |
846 r = KErrTooBig; |
453 } |
847 } |
454 break; |
848 break; |
455 |
849 |
456 case RDisplayChannel::ECtrlDeregisterUserBuffer: |
850 case RDisplayChannel::ECtrlDeregisterUserBuffer: //DFC thread should read client message data. |
457 r= Kern::ThreadRawRead(aClient, aArg1, &buffer_id, sizeof(TInt)); |
851 bufferId = (TInt*) aArg1; |
458 if ( r == KErrNone) |
852 buffer_id = *bufferId; |
|
853 |
|
854 |
|
855 r = KErrArgument; |
|
856 if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) ) |
|
857 { |
|
858 node = FindUserBufferNode(buffer_id); |
|
859 if(node && (!(node->iFree) && node->iChunk ) ) |
|
860 { |
|
861 if(node->iState==EBufferFree || node->iState==EBufferCompose ) |
|
862 { |
|
863 r = FreeUserBufferNode(node); |
|
864 } |
|
865 else |
|
866 { |
|
867 r = KErrInUse; |
|
868 } |
|
869 } |
|
870 } |
|
871 break; |
|
872 |
|
873 case RDisplayChannel::ECtrlSetRotation: //DFC thread should read client message data and update a value the client will read. |
|
874 { |
|
875 RDisplayChannel::TDisplayRotation rot; |
|
876 RDisplayChannel::TDisplayRotation previousRot = iCurrentRotation; |
|
877 |
|
878 rotation = (RDisplayChannel::TDisplayRotation*) aArg1; |
|
879 rot = *rotation; |
|
880 |
|
881 __DEBUG_PRINT3("ECtrlSetRotation previousRot= %d and rot =%d \n",previousRot, rot ); |
|
882 |
|
883 r = Pdd()->SetRotation(rot); |
|
884 changedRot = (previousRot != iCurrentRotation); |
|
885 if( r == KErrNone) |
|
886 { |
|
887 rotationChanged = (TBool*) aArg2; |
|
888 *rotationChanged = changedRot ; |
|
889 } |
|
890 break; |
|
891 } |
|
892 |
|
893 case RDisplayChannel::ECtrlCurrentRotation: //DFC thread updates a value the client thread should read. |
|
894 rotation = (RDisplayChannel::TDisplayRotation*) aArg1; |
|
895 *rotation = iCurrentRotation; |
|
896 break; |
|
897 |
|
898 case RDisplayChannel::ECtrlGetCompositionBufferInfo: //DFC thread should read client message data and update a value the client will read. |
|
899 idx = ( TInt * ) aArg1; |
|
900 index = *idx; |
|
901 |
|
902 if( (index >= (TInt) iDisplayInfo.iNumCompositionBuffers ) || (index < 0 ) ) |
|
903 { |
|
904 r = KErrArgument; |
|
905 break; |
|
906 } |
|
907 r = Kern::MakeHandleAndOpen(aClient, iCompositionBuffer[index].iChunk); |
|
908 |
|
909 if(r >= KErrNone) |
459 { |
910 { |
460 r = KErrArgument; |
911 pack[0] = r; |
461 if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) ) |
912 pack[1] = iCompositionBuffer[index].iOffset; |
|
913 |
|
914 configPack = (TInt * ) aArg2; |
|
915 *configPack = pack[0]; |
|
916 configPack++; |
|
917 *configPack = pack[1]; |
|
918 |
|
919 r = KErrNone; |
|
920 } |
|
921 break; |
|
922 |
|
923 #ifdef _DEBUG |
|
924 case RDisplayChannel::ECtrlCreateUserBuffer: |
|
925 { |
|
926 TUint32 chunkMapAttr; |
|
927 TLinAddr chunkBase; |
|
928 TPhysAddr physicalAddr; |
|
929 RDisplayChannel::TBufferFormat bufferFormat; |
|
930 |
|
931 // Read the information from the user thread pertaining to the buffer to be allocated |
|
932 Kern::ThreadRawRead(aClient, aArg1, &bufferFormat, sizeof(bufferFormat)); |
|
933 |
|
934 // Allocate a chunk that can be used as a user buffer. Don't worry about the # of bytes |
|
935 // per pixel as this is UDEB only test code - just set it to 4 and that will ensure that |
|
936 // it is large enough |
|
937 TChunkCreateInfo chunkCreateInfo; |
|
938 chunkCreateInfo.iType = TChunkCreateInfo::ESharedKernelSingle; |
|
939 #ifndef __WINS__ |
|
940 chunkCreateInfo.iMapAttr = EMapAttrFullyBlocking; |
|
941 #endif // ! __WINS__ |
|
942 chunkCreateInfo.iOwnsMemory = ETrue; |
|
943 chunkCreateInfo.iDestroyedDfc = NULL; |
|
944 chunkCreateInfo.iMaxSize = (bufferFormat.iSize.iWidth * bufferFormat.iSize.iHeight * 4); |
|
945 |
|
946 if ((r = Kern::ChunkCreate(chunkCreateInfo, iChunk, chunkBase, chunkMapAttr)) == KErrNone) |
|
947 { |
|
948 // Commit some contiguous physical RAM for use in the chunk |
|
949 r = Kern::ChunkCommitContiguous(iChunk, 0, chunkCreateInfo.iMaxSize, physicalAddr); |
|
950 |
|
951 // And open a handle to the chunk that will be returned to user side for use in the user |
|
952 // side's RChunk object |
|
953 if (r == KErrNone) |
|
954 r = Kern::MakeHandleAndOpen(aClient, iChunk); |
|
955 else |
462 { |
956 { |
463 node = FindUserBufferNode(buffer_id); |
957 Kern::ChunkClose(iChunk); |
464 if(node && (!(node->iFree) && node->iChunk ) ) |
958 iChunk = NULL; |
465 { |
|
466 if(node->iState==EBufferFree || node->iState==EBufferCompose ) |
|
467 { |
|
468 r = FreeUserBufferNode(node); |
|
469 } |
|
470 else |
|
471 { |
|
472 r = KErrInUse; |
|
473 } |
|
474 } |
|
475 } |
959 } |
476 } |
960 } |
477 break; |
961 |
478 |
962 break; |
479 case RDisplayChannel::ECtrlPostCount: |
963 } |
480 r= Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&iCurrentPostCount, sizeof(TUint), aClient); |
964 #endif // _DEBUG |
481 break; |
965 |
482 |
966 default: |
483 case RDisplayChannel::ECtrlSetRotation: |
967 __NK_ASSERT_ALWAYS(EFalse); // we already validated the request number |
484 { |
|
485 RDisplayChannel::TDisplayRotation rot; |
|
486 TInt previousRot = iCurrentRotation; |
|
487 r= Kern::ThreadRawRead(aClient, aArg1, &rot, sizeof(RDisplayChannel::TDisplayRotation)); |
|
488 if ( r == KErrNone) |
|
489 { |
|
490 r = Pdd()->SetRotation((TInt)rot); |
|
491 changedRot=(previousRot!=iCurrentRotation); |
|
492 if( r == KErrNone) |
|
493 { |
|
494 r= Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&changedRot, sizeof(TBool), aClient); |
|
495 } |
|
496 } |
|
497 } |
|
498 break; |
|
499 |
|
500 case RDisplayChannel::ECtrlCurrentRotation: |
|
501 r=Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&iCurrentRotation, sizeof(RDisplayChannel::TDisplayRotation), aClient); |
|
502 break; |
|
503 |
|
504 case RDisplayChannel::ECtrlGetCompositionBufferInfo: |
|
505 { |
|
506 r= Kern::ThreadRawRead(aClient, aArg1, &index, sizeof(TInt)); |
|
507 if ( r == KErrNone) |
|
508 { |
|
509 if( (index >= KDisplayCBMax ) || (index < 0 ) ) |
|
510 { |
|
511 r = KErrArgument; |
|
512 break; |
|
513 } |
|
514 r = Kern::MakeHandleAndOpen(aClient, iCompositionBuffer[index].iChunk); |
|
515 |
|
516 if(r >= KErrNone) |
|
517 { |
|
518 pack[0] = r; |
|
519 pack[1] = iCompositionBuffer[index].iOffset; |
|
520 r=Kern::ThreadRawWrite(aClient, aArg2, &pack, (sizeof(TInt)*2), aClient); |
|
521 } |
|
522 } |
|
523 break; |
|
524 } |
|
525 |
|
526 default: |
|
527 r = KErrNotSupported; |
|
528 break; |
|
529 }; |
968 }; |
530 return r; |
969 return r; |
531 } |
970 } |
532 |
971 |
533 |
972 |