|
1 // Copyright (c) 1998-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\display\display.cpp |
|
15 // LDD for a Display driver with GCE support |
|
16 // LDD for a Display driver with GCE support |
|
17 // |
|
18 // |
|
19 |
|
20 /** |
|
21 @file |
|
22 @internalTechnology |
|
23 @prototype |
|
24 */ |
|
25 |
|
26 |
|
27 #include <drivers/display.h> |
|
28 #include <kernel/kern_priv.h> |
|
29 |
|
30 |
|
31 |
|
32 static const char KDisplayLddPanic[]="DISPLAY/GCE LDD"; |
|
33 |
|
34 |
|
35 /************************************************************************************ |
|
36 * DDisplayLdd LDD class implementation |
|
37 ************************************************************************************/ |
|
38 DDisplayLdd::DDisplayLdd() |
|
39 { |
|
40 __DEBUG_PRINT("DDisplayLdd::DDisplayLdd()\n"); |
|
41 // store the pointer to the current thread for request completion |
|
42 iClient = &Kern::CurrentThread(); |
|
43 __NK_ASSERT_DEBUG(iClient); |
|
44 // Open a reference on the client thread so it's control block can't disappear until the driver has finished with it. |
|
45 iClient->Open(); |
|
46 iCurrentPostCount = 0; |
|
47 iRequestedPostCount = 0; |
|
48 iCompositionBuffIdx = 0; |
|
49 iUnit = -1; |
|
50 iThreadOpenCount = 0; |
|
51 } |
|
52 |
|
53 |
|
54 DDisplayLdd::~DDisplayLdd() |
|
55 { |
|
56 __DEBUG_PRINT("DDisplayLdd::~DDisplayLdd() \n"); |
|
57 // cancel outstanding requests |
|
58 for(TInt k = 0; k < KPendingReqArraySize ; k++) |
|
59 { |
|
60 if(iPendingReq[k].iStatus) |
|
61 { |
|
62 CompleteRequest(iPendingReq[k].iOwningThread,iPendingReq[k].iStatus,KErrCancel); |
|
63 } |
|
64 } |
|
65 |
|
66 //Close User Buffer chunks not yet destroyed. |
|
67 for(TInt i = 0; i < KDisplayUBMax; i++) |
|
68 { |
|
69 if(iUserBuffer[i].iChunk != 0) |
|
70 { |
|
71 Kern::ChunkClose(iUserBuffer[i].iChunk); |
|
72 iUserBuffer[i].iChunk= NULL; |
|
73 } |
|
74 } |
|
75 |
|
76 Kern::SafeClose((DObject*&)iClient, NULL); |
|
77 |
|
78 __ASSERT_DEBUG(iThreadOpenCount==0,Kern::Fault(KDisplayLddPanic,__LINE__)); |
|
79 |
|
80 // Clear the 'units open mask' in the LDD factory. |
|
81 if (iUnit>=0) |
|
82 ((DDisplayLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse); |
|
83 } |
|
84 |
|
85 |
|
86 /** |
|
87 LDD second stage constructor |
|
88 */ |
|
89 TInt DDisplayLdd::DoCreate(TInt aUnit, const TDesC8* /* anInfo*/, const TVersion& aVer) |
|
90 { |
|
91 |
|
92 __DEBUG_PRINT("DDisplayLdd::DoCreate()\n"); |
|
93 |
|
94 if( !Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) |
|
95 && !Kern::CurrentThreadHasCapability(ECapabilityReadDeviceData, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) |
|
96 && !Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) |
|
97 && !Kern::CurrentThreadHasCapability(ECapabilityProtServ, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) ) |
|
98 { |
|
99 return KErrPermissionDenied; |
|
100 } |
|
101 |
|
102 // Check that the display driver version specified by the client is compatible. |
|
103 if (!Kern::QueryVersionSupported(RDisplayChannel::VersionRequired(),aVer)) |
|
104 { |
|
105 return(KErrNotSupported); |
|
106 } |
|
107 |
|
108 // Check that a channel hasn't already been opened on this unit. |
|
109 TInt r=((DDisplayLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory. |
|
110 if (r!=KErrNone) |
|
111 { |
|
112 return r; |
|
113 } |
|
114 |
|
115 Pdd()->iLdd = this; |
|
116 |
|
117 r = Pdd()->CreateChannelSetup(aUnit); |
|
118 if ( r!= KErrNone) |
|
119 { |
|
120 return r; |
|
121 } |
|
122 |
|
123 // set up user buffer nodes |
|
124 for (TInt node = 0; node < KDisplayUBMax; node++) |
|
125 { |
|
126 iUserBuffer[node].iType = EBufferTypeUser; |
|
127 iUserBuffer[node].iBufferId = (node + 1); |
|
128 iUserBuffer[node].iFree = ETrue; |
|
129 iUserBuffer[node].iState = EBufferFree; |
|
130 iUserBuffer[node].iAddress = 0; |
|
131 iUserBuffer[node].iSize = 0; |
|
132 iUserBuffer[node].iHandle = 0; |
|
133 iUserBuffer[node].iChunk = 0; |
|
134 iUserBuffer[node].iOffset = 0; |
|
135 iUserBuffer[node].iPendingRequest = 0; |
|
136 } |
|
137 |
|
138 //Initialise pending queue for asynchronous requests |
|
139 for(int k = 0; k < KPendingReqArraySize; k++) |
|
140 { |
|
141 iPendingReq[k].iStatus = 0; |
|
142 iPendingReq[k].iOwningThread = 0; |
|
143 } |
|
144 |
|
145 Pdd()->SetGceMode(); |
|
146 SetDfcQ(Pdd()->DfcQ(aUnit)); |
|
147 iMsgQ.Receive(); |
|
148 |
|
149 return KErrNone; |
|
150 } |
|
151 |
|
152 |
|
153 /** |
|
154 * All driver's client requests (synchronous and asynchronous) are sent as |
|
155 * kernel messages by generic kernel to logical channel. This function |
|
156 * catches messages sent by the generic kernel |
|
157 * |
|
158 * @param aMsg KErnel side thread messaging |
|
159 */ |
|
160 void DDisplayLdd::HandleMsg(TMessageBase* aMsg) |
|
161 { |
|
162 TThreadMessage& m = *(TThreadMessage*)aMsg ; |
|
163 TInt id = m.iValue ; |
|
164 DThread* client = m.Client(); |
|
165 |
|
166 // close message |
|
167 if (id == (TInt)ECloseMsg) |
|
168 { |
|
169 //Device specific cleanup operations |
|
170 Pdd()->CloseMsg(); |
|
171 |
|
172 // cancel outstanding requests |
|
173 for(int k = 0; k < KPendingReqArraySize; k++) |
|
174 { |
|
175 if(iPendingReq[k].iStatus) |
|
176 { |
|
177 CompleteRequest(iPendingReq[k].iOwningThread,iPendingReq[k].iStatus,KErrCancel); |
|
178 } |
|
179 } |
|
180 Pdd()->SetLegacyMode(); |
|
181 m.Complete(KErrNone, EFalse); |
|
182 return; |
|
183 } |
|
184 // cancel |
|
185 if (id == KMaxTInt) |
|
186 { |
|
187 // DoCancel |
|
188 TInt req = m.Int0() >> 1; |
|
189 DoCancel(req); |
|
190 m.Complete(KErrNone,ETrue); |
|
191 return; |
|
192 } |
|
193 // asynchronous request |
|
194 else if (id < 0) |
|
195 { |
|
196 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
197 TInt r = DoRequest(~id,pS,m.Ptr1(),m.Ptr2(), client); |
|
198 m.Complete(r, ETrue); |
|
199 } |
|
200 // synchronous request |
|
201 else |
|
202 { |
|
203 TInt r = DoControl(id,m.Ptr0(),m.Ptr1(), client); |
|
204 m.Complete(r,ETrue); |
|
205 } |
|
206 } |
|
207 |
|
208 |
|
209 /** |
|
210 Cancel outstanding request. |
|
211 |
|
212 @param aReqNumber Any value from the RDisplayChannel::TRequest enumeration. |
|
213 */ |
|
214 void DDisplayLdd::DoCancel(TUint aReqNumber) |
|
215 { |
|
216 __DEBUG_PRINT2("DDisplayLdd::DoCancel %d\n",aReqNumber); |
|
217 |
|
218 switch (aReqNumber) |
|
219 { |
|
220 case RDisplayChannel::ECtrlCancelGetCompositionBuffer: |
|
221 case RDisplayChannel::ECtrlCancelPostUserBuffer: |
|
222 case RDisplayChannel::ECtrlCancelWaitForPost: |
|
223 if(iPendingReq[aReqNumber].iStatus) |
|
224 { |
|
225 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel); |
|
226 |
|
227 iPendingReq[aReqNumber].iStatus = 0; |
|
228 iPendingReq[aReqNumber].iOwningThread = 0; |
|
229 } |
|
230 break; |
|
231 } |
|
232 |
|
233 } |
|
234 |
|
235 /** |
|
236 Asynchronous request processing. |
|
237 |
|
238 @param aFunction request function number |
|
239 @param apRqStat pointer to the user's request status object. |
|
240 @param apArg1 pointer to the 1st parameter |
|
241 @param apArg2 pointer to the 2nd parameter |
|
242 |
|
243 @return request scheduling result, system-wide error code. |
|
244 */ |
|
245 TInt DDisplayLdd::DoRequest(TInt aReqNumber, TRequestStatus* aRqStat, TAny* aArg1, TAny* aArg2, DThread* aClient) |
|
246 { |
|
247 TUint count; |
|
248 TInt pack[2]; |
|
249 TInt r = KErrNone; |
|
250 TBufferNode* node = 0; |
|
251 TInt buffer_id = 0; |
|
252 |
|
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. |
|
254 r=aClient->Open(); |
|
255 __ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KDisplayLddPanic,__LINE__)); |
|
256 #ifdef _DEBUG |
|
257 __e32_atomic_add_ord32(&iThreadOpenCount, 1); |
|
258 #endif |
|
259 |
|
260 // check if this request is valid |
|
261 if(aReqNumber >= 0 && aReqNumber <= RDisplayChannel::EReqWaitForPost) |
|
262 { |
|
263 // cancel outstanding request |
|
264 if(iPendingReq[aReqNumber].iStatus) |
|
265 { |
|
266 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,KErrCancel); |
|
267 iPendingReq[aReqNumber].iStatus = 0; |
|
268 iPendingReq[aReqNumber].iOwningThread = 0; |
|
269 } |
|
270 |
|
271 // store request and client |
|
272 iPendingReq[aReqNumber].iStatus = aRqStat; |
|
273 iPendingReq[aReqNumber].iOwningThread = aClient; |
|
274 } |
|
275 |
|
276 switch (aReqNumber) |
|
277 { |
|
278 case RDisplayChannel::EReqGetCompositionBuffer: |
|
279 |
|
280 if(aArg1 == 0 ) |
|
281 { |
|
282 r = KErrGeneral; |
|
283 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,r); |
|
284 iPendingReq[aReqNumber].iStatus = 0; |
|
285 iPendingReq[aReqNumber].iOwningThread = 0; |
|
286 } |
|
287 else |
|
288 { |
|
289 TInt index; |
|
290 TBool found = EFalse; |
|
291 |
|
292 for(index =0; index< KDisplayCBMax; index++) |
|
293 { |
|
294 if(iCompositionBuffer[index].iState == EBufferFree || iCompositionBuffer[index].iState == EBufferCompose ) |
|
295 { |
|
296 __DEBUG_PRINT2("EReqGetCompositionBuffer: Getting iCompositionBuffer[%d] \n", index); |
|
297 |
|
298 iCompositionBuffIdx = index; |
|
299 r = Kern::ThreadRawWrite(aClient, aArg1, &iCompositionBuffIdx, sizeof(TInt), aClient); |
|
300 if ( r == KErrNone) |
|
301 { |
|
302 iCompositionBuffer[iCompositionBuffIdx].iState = EBufferCompose; |
|
303 CompleteRequest(iPendingReq[aReqNumber].iOwningThread,iPendingReq[aReqNumber].iStatus,r); |
|
304 iPendingReq[aReqNumber].iStatus = 0; |
|
305 iPendingReq[aReqNumber].iOwningThread = 0; |
|
306 found = ETrue; |
|
307 break; |
|
308 } |
|
309 } |
|
310 } |
|
311 if(!found) //There are no free buffers schedule request for completion |
|
312 { |
|
313 //Case of a single composition buffer. |
|
314 if (iDisplayInfo.iNumCompositionBuffers == 1) |
|
315 { |
|
316 iCompositionBuffIdx = 0; |
|
317 r = Kern::ThreadRawWrite(aClient, aArg1, &iCompositionBuffIdx, sizeof(TInt), aClient); |
|
318 __DEBUG_PRINT("EReqGetCompositionBuffer The single Composition buffer is currently being used\n"); |
|
319 break; |
|
320 } |
|
321 |
|
322 |
|
323 for( index=0; index< KDisplayCBMax; index++) |
|
324 { |
|
325 if(iCompositionBuffer[index].iState == EBufferActive) |
|
326 { |
|
327 iCompositionBuffIdx = index; |
|
328 r = Kern::ThreadRawWrite(aClient, aArg1,&iCompositionBuffIdx, sizeof(TInt), aClient); |
|
329 __DEBUG_PRINT2("EReqGetCompositionBuffer No composition buffer available. Next available is iCompositionBuffIdx %d.\n",iCompositionBuffIdx ); |
|
330 break; |
|
331 } |
|
332 } |
|
333 } |
|
334 } |
|
335 break; |
|
336 |
|
337 case RDisplayChannel::EReqPostUserBuffer: |
|
338 r= Kern::ThreadRawRead(aClient, aArg1, &pack, (sizeof(TInt)*2)); |
|
339 if ( r == KErrNone) |
|
340 { |
|
341 r = KErrArgument; |
|
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; |
|
361 |
|
362 case RDisplayChannel::EReqWaitForPost: |
|
363 r= Kern::ThreadRawRead(aClient, aArg1, &count, sizeof(RDisplayChannel::TPostCount)); |
|
364 if ( r == KErrNone) |
|
365 { |
|
366 iRequestedPostCount = count; |
|
367 //Any post operation increases iCurrentPostCount instantly but the actual post completes later on. |
|
368 if( ! Pdd()->PostPending() ) |
|
369 { |
|
370 RequestComplete(RDisplayChannel::EReqWaitForPost, KErrNone); |
|
371 } |
|
372 } |
|
373 break; |
|
374 |
|
375 default: |
|
376 r = KErrNotSupported; |
|
377 break; |
|
378 } |
|
379 return r; |
|
380 } |
|
381 |
|
382 |
|
383 /** |
|
384 Synchronous requests processing. |
|
385 |
|
386 @param aFunction request function number, |
|
387 @param apArg1 pointer to the 1st parameter |
|
388 @param apArg2 pointer to the 2n parameter |
|
389 |
|
390 @return request processing result |
|
391 */ |
|
392 TInt DDisplayLdd::DoControl(TInt aFunction, TAny* aArg1, TAny* aArg2, DThread* aClient) |
|
393 { |
|
394 TInt r = KErrNotSupported; |
|
395 TBool changedRot = ETrue; |
|
396 TBufferNode* node = 0; |
|
397 TInt buffer_id; |
|
398 TInt pack[2] = {0,0}; |
|
399 TInt handle, offset; |
|
400 TInt index = 0; |
|
401 |
|
402 TPckgBuf<RDisplayChannel::TDisplayInfo> pckgInfo(iDisplayInfo); |
|
403 |
|
404 switch (aFunction) |
|
405 { |
|
406 case RDisplayChannel::ECtrlGetDisplayInfo: |
|
407 r=Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&pckgInfo, sizeof(pckgInfo), aClient); |
|
408 break; |
|
409 |
|
410 case RDisplayChannel::ECtrlPostCompositionBuffer: |
|
411 node = &iCompositionBuffer[iCompositionBuffIdx]; |
|
412 r = Pdd()->PostCompositionBuffer(node); |
|
413 if(r == KErrNone) |
|
414 { |
|
415 ++iCurrentPostCount; |
|
416 r=Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient); |
|
417 } |
|
418 else |
|
419 { |
|
420 r = KErrGeneral; |
|
421 } |
|
422 break; |
|
423 |
|
424 case RDisplayChannel::ECtrlPostLegacyBuffer: |
|
425 r= Pdd()->PostLegacyBuffer(); |
|
426 if ( r == KErrNone) |
|
427 { |
|
428 ++iCurrentPostCount; |
|
429 r = Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&iCurrentPostCount, sizeof(RDisplayChannel::TPostCount), aClient); |
|
430 } |
|
431 break; |
|
432 |
|
433 case RDisplayChannel::ECtrlRegisterUserBuffer: |
|
434 node = FindUserBufferNode(0); |
|
435 if(node) |
|
436 { |
|
437 r= Kern::ThreadRawRead(aClient, aArg1, &pack, (sizeof(TInt)*2)); |
|
438 if(r == KErrNone) |
|
439 { |
|
440 handle = pack[0]; |
|
441 offset = pack[1]; |
|
442 r = CheckAndOpenUserBuffer(node, handle, offset, aClient); |
|
443 |
|
444 if(r == KErrNone) |
|
445 { |
|
446 r= Kern::ThreadRawWrite(aClient, aArg2, (const TAny *)&node->iBufferId, sizeof(TInt), aClient); |
|
447 } |
|
448 } |
|
449 } |
|
450 else |
|
451 { |
|
452 r = KErrTooBig; |
|
453 } |
|
454 break; |
|
455 |
|
456 case RDisplayChannel::ECtrlDeregisterUserBuffer: |
|
457 r= Kern::ThreadRawRead(aClient, aArg1, &buffer_id, sizeof(TInt)); |
|
458 if ( r == KErrNone) |
|
459 { |
|
460 r = KErrArgument; |
|
461 if ( (buffer_id > 0) && (buffer_id <= KDisplayUBMax) ) |
|
462 { |
|
463 node = FindUserBufferNode(buffer_id); |
|
464 if(node && (!(node->iFree) && node->iChunk ) ) |
|
465 { |
|
466 if(node->iState==EBufferFree || node->iState==EBufferCompose ) |
|
467 { |
|
468 r = FreeUserBufferNode(node); |
|
469 } |
|
470 else |
|
471 { |
|
472 r = KErrInUse; |
|
473 } |
|
474 } |
|
475 } |
|
476 } |
|
477 break; |
|
478 |
|
479 case RDisplayChannel::ECtrlPostCount: |
|
480 r= Kern::ThreadRawWrite(aClient, aArg1, (const TAny *)&iCurrentPostCount, sizeof(TUint), aClient); |
|
481 break; |
|
482 |
|
483 case RDisplayChannel::ECtrlSetRotation: |
|
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 }; |
|
530 return r; |
|
531 } |
|
532 |
|
533 |
|
534 /** |
|
535 Open a shared Chunk for the User buffer and then set the appropriate values for the |
|
536 User buffer node attributes. |
|
537 |
|
538 */ |
|
539 TInt DDisplayLdd::CheckAndOpenUserBuffer(TBufferNode* aNode, TInt aHandle, TInt aOffset, DThread* aClient) |
|
540 { |
|
541 |
|
542 TInt size = 0; |
|
543 DChunk* chunk = 0; |
|
544 TLinAddr kernelAddress = 0; |
|
545 TUint32 mapAttr = 0; |
|
546 TUint32 physicalAddress = 0; |
|
547 TUint32 *physicalPageList = 0; |
|
548 TInt r = KErrBadHandle; |
|
549 |
|
550 NKern::ThreadEnterCS(); |
|
551 chunk = Kern::OpenSharedChunk(aClient, aHandle, EFalse); |
|
552 NKern::ThreadLeaveCS(); |
|
553 if(chunk) |
|
554 { |
|
555 // Using iOffsetBetweenLines rather than iWidth as the controller may be using stride |
|
556 size = iDisplayInfo.iNormal.iOffsetBetweenLines * iDisplayInfo.iNormal.iHeight; |
|
557 |
|
558 r = Kern::ChunkPhysicalAddress(chunk, aOffset, size, kernelAddress, mapAttr, physicalAddress, physicalPageList); |
|
559 if( r == KErrNone ) |
|
560 { |
|
561 aNode->iChunk = chunk; |
|
562 aNode->iFree = EFalse; |
|
563 aNode->iState = EBufferCompose; |
|
564 aNode->iAddress = (TUint32)kernelAddress; |
|
565 aNode->iHandle = aHandle; |
|
566 aNode->iPhysicalAddress = physicalAddress; |
|
567 } |
|
568 else |
|
569 { // we have an error here, close the chunk |
|
570 r = KErrArgument; |
|
571 Kern::ChunkClose(chunk); |
|
572 } |
|
573 } |
|
574 return (r); |
|
575 } |
|
576 |
|
577 |
|
578 /** |
|
579 Return any free buffer when trying to register a User buffer( aBufferId ==0 ) |
|
580 or return the specified User buffer( used by Deregister and PostUserBuffer). |
|
581 In the second case checks about the state of the user buffer are specific to |
|
582 each case. |
|
583 |
|
584 */ |
|
585 TBufferNode* DDisplayLdd::FindUserBufferNode(TInt aBufferId) |
|
586 { |
|
587 TBufferNode* node = 0; |
|
588 |
|
589 if(aBufferId == 0) |
|
590 { |
|
591 for(TInt i = 0; i < KDisplayUBMax; i++) |
|
592 { |
|
593 if(iUserBuffer[i].iFree) |
|
594 { |
|
595 node = &iUserBuffer[i]; |
|
596 break; |
|
597 } |
|
598 } |
|
599 } |
|
600 else |
|
601 { |
|
602 node = &iUserBuffer[aBufferId-1]; |
|
603 } |
|
604 return (node); |
|
605 } |
|
606 |
|
607 |
|
608 /** |
|
609 Free user buffer by reseting all the appropriate fields and closing the corresponding chunk. |
|
610 */ |
|
611 TInt DDisplayLdd::FreeUserBufferNode(TBufferNode* aNode) |
|
612 { |
|
613 __DEBUG_PRINT2("FreeUserBufferNode with aNode->iAddress %08x.\n",aNode->iAddress ); |
|
614 TInt r = KErrNone; |
|
615 NKern::ThreadEnterCS(); |
|
616 if(aNode->iChunk != 0) |
|
617 { |
|
618 r= Kern::ChunkClose(aNode->iChunk); |
|
619 } |
|
620 if( r== KErrNone) |
|
621 { |
|
622 aNode->iState = EBufferFree; |
|
623 aNode->iFree = ETrue; |
|
624 aNode->iAddress = 0; |
|
625 aNode->iSize = 0; |
|
626 aNode->iHandle = 0; |
|
627 aNode->iChunk = 0; |
|
628 } |
|
629 else |
|
630 { |
|
631 __DEBUG_PRINT("Failed to close chunk\n"); |
|
632 } |
|
633 NKern::ThreadLeaveCS(); |
|
634 |
|
635 return r; |
|
636 } |
|
637 |
|
638 |
|
639 /** |
|
640 Calls CompleteRequest( which internally sends a Kern::RequestComplete message )for the specified request and with the reason passed, |
|
641 in case such an asynchronous request is pending. Also resets the pending queue fields for that request if it was actually pending. |
|
642 Called by both the LDD and PDD. |
|
643 |
|
644 */ |
|
645 TInt DDisplayLdd::RequestComplete(TInt aRequest, TInt aReason) |
|
646 { |
|
647 TBool flag = EFalse; |
|
648 |
|
649 switch (aRequest) |
|
650 { |
|
651 case RDisplayChannel::EReqGetCompositionBuffer: |
|
652 { |
|
653 __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqGetCompositionBuffer request and reason %d\n",aReason ); |
|
654 |
|
655 if(iPendingReq[RDisplayChannel::EReqGetCompositionBuffer].iStatus) |
|
656 { |
|
657 __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqGetCompositionBuffer \n"); |
|
658 flag = ETrue; |
|
659 } |
|
660 break; |
|
661 } |
|
662 |
|
663 case RDisplayChannel::EReqWaitForPost: |
|
664 { |
|
665 __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqWaitForPost request and reason %d\n",aReason ); |
|
666 |
|
667 if((iPendingReq[RDisplayChannel::EReqWaitForPost].iStatus != 0) && (iCurrentPostCount >= iRequestedPostCount) ) |
|
668 { |
|
669 __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqWaitForPost \n"); |
|
670 flag = ETrue; |
|
671 } |
|
672 break; |
|
673 } |
|
674 |
|
675 case RDisplayChannel::EReqPostUserBuffer: |
|
676 { |
|
677 __DEBUG_PRINT2("RequestComplete() called with a RDisplayChannel::EReqPostUserBuffer request and reason %d\n",aReason ); |
|
678 |
|
679 if((iPendingReq[RDisplayChannel::EReqPostUserBuffer].iStatus != 0) ) |
|
680 { |
|
681 __DEBUG_PRINT("RequestComplete(): Calling CompleteRequest EReqPostUserBuffer \n"); |
|
682 flag = ETrue; |
|
683 } |
|
684 break; |
|
685 } |
|
686 default: |
|
687 __DEBUG_PRINT("RequestComplete() called for an unknown request\n"); |
|
688 return KErrGeneral; |
|
689 |
|
690 } |
|
691 |
|
692 if (flag) |
|
693 { |
|
694 CompleteRequest(iPendingReq[aRequest].iOwningThread,iPendingReq[aRequest].iStatus,aReason); |
|
695 iPendingReq[aRequest].iStatus = 0; |
|
696 iPendingReq[aRequest].iOwningThread = 0; |
|
697 } |
|
698 |
|
699 return KErrNone; |
|
700 } |
|
701 |
|
702 |
|
703 /** |
|
704 Complete an asynchronous request back to the client. |
|
705 @param aThread The client thread which issued the request. |
|
706 @param aStatus The TRequestStatus instance that will receive the request status code. |
|
707 @param aReason The request status code. |
|
708 @pre The thread must be in a critical section. |
|
709 */ |
|
710 void DDisplayLdd::CompleteRequest(DThread* aThread, TRequestStatus*& aStatus, TInt aReason) |
|
711 { |
|
712 Kern::RequestComplete(aThread,aStatus,aReason); // Complete the request back to the client. |
|
713 |
|
714 aThread->AsyncClose(); // Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference. |
|
715 |
|
716 #ifdef _DEBUG |
|
717 __e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1)); |
|
718 #endif |
|
719 |
|
720 } |
|
721 |
|
722 |
|
723 |
|
724 /** |
|
725 static factory function for the LDD. |
|
726 |
|
727 @return pointer to the created (or existing) instance of the class |
|
728 */ |
|
729 DDisplayLdd* DDisplayLdd::CreateInstance() |
|
730 { |
|
731 __DEBUG_PRINT("DDisplayLdd::CreateInstance()\n"); |
|
732 // create LDD channel instance |
|
733 DDisplayLdd* obj = new DDisplayLdd(); |
|
734 return obj; |
|
735 |
|
736 } |
|
737 |
|
738 |
|
739 /************************************************************************************ |
|
740 * LDD factory, DDisplayLddFactory class implementation |
|
741 ************************************************************************************/ |
|
742 |
|
743 /** |
|
744 Constructor |
|
745 */ |
|
746 DDisplayLddFactory::DDisplayLddFactory() |
|
747 { |
|
748 __DEBUG_PRINT("DDisplayLddFactory::DDisplayLddFactory() \n"); |
|
749 |
|
750 iParseMask = KDeviceAllowPhysicalDevice | KDeviceAllowUnit ; |
|
751 |
|
752 iVersion = TVersion( KDisplayChMajorVersionNumber, |
|
753 KDisplayChMinorVersionNumber, |
|
754 KDisplayChBuildVersionNumber); |
|
755 |
|
756 iUnitsOpenMask =0; |
|
757 } |
|
758 |
|
759 |
|
760 /** |
|
761 Destructor |
|
762 */ |
|
763 DDisplayLddFactory::~DDisplayLddFactory() |
|
764 { |
|
765 } |
|
766 |
|
767 |
|
768 /** |
|
769 static factory function for the LDD factory. |
|
770 |
|
771 @return pointer to the created instance of the class |
|
772 */ |
|
773 DDisplayLddFactory* DDisplayLddFactory::CreateInstance() |
|
774 |
|
775 { |
|
776 __DEBUG_PRINT("DDisplayLddFactory::CreateInstance() \n"); |
|
777 |
|
778 DDisplayLddFactory* obj = new DDisplayLddFactory; |
|
779 return obj; |
|
780 } |
|
781 |
|
782 |
|
783 /** |
|
784 Set our name and return error code |
|
785 */ |
|
786 TInt DDisplayLddFactory::Install() |
|
787 |
|
788 { |
|
789 __DEBUG_PRINT("DDisplayLddFactory::Install() \n"); |
|
790 return SetName(&RDisplayChannel::Name()); |
|
791 } |
|
792 |
|
793 |
|
794 void DDisplayLddFactory::GetCaps(TDes8& /*aDes*/) const |
|
795 |
|
796 { |
|
797 //No action. |
|
798 } |
|
799 |
|
800 |
|
801 /** |
|
802 LDD factory function. Creates LDD object. |
|
803 |
|
804 @param aChannel A pointer to an LDD channel object which will be initialised on return. |
|
805 |
|
806 @return KErrNone if object successfully allocated, KErrNoMemory if not. |
|
807 */ |
|
808 TInt DDisplayLddFactory::Create(DLogicalChannelBase*& aChannel) |
|
809 { |
|
810 __DEBUG_PRINT("DDisplayLddFactory::Create \n"); |
|
811 aChannel = DDisplayLdd::CreateInstance(); |
|
812 return (!aChannel)? KErrNoMemory : KErrNone; |
|
813 } |
|
814 |
|
815 |
|
816 |
|
817 /** |
|
818 Check whether a channel is currently open on the specified unit. |
|
819 @param aUnit The number of the unit to be checked. |
|
820 @return ETrue if a channel is open on the specified channel, EFalse otherwise. |
|
821 @pre The unit info. mutex must be held. |
|
822 */ |
|
823 TBool DDisplayLddFactory::IsUnitOpen(TInt aUnit) |
|
824 { |
|
825 return(iUnitsOpenMask&(1<<aUnit)); |
|
826 } |
|
827 |
|
828 |
|
829 /** |
|
830 Attempt to change the state of the channel open status for a particular channel. |
|
831 @param aUnit The number of the unit to be updated. |
|
832 @param aIsOpenSetting The required new state for the channel open status: either ETrue to set the status to open or |
|
833 EFalse to set the status to closed. |
|
834 @return KErrNone if the status was updated successfully, KErrInUse if an attempt has been made to set the channnel status |
|
835 to open while it is already open. |
|
836 */ |
|
837 TInt DDisplayLddFactory::SetUnitOpen(TInt aUnit,TBool aIsOpenSetting) |
|
838 { |
|
839 |
|
840 NKern::FMWait(&iUnitInfoMutex); // Acquire the unit info. mutex. |
|
841 |
|
842 // Fail a request to open an channel that is already open |
|
843 if (aIsOpenSetting && IsUnitOpen(aUnit)) |
|
844 { |
|
845 NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex. |
|
846 return(KErrInUse); |
|
847 } |
|
848 |
|
849 // Update the open status as requested |
|
850 if (aIsOpenSetting) |
|
851 iUnitsOpenMask|=(1<<aUnit); |
|
852 else |
|
853 iUnitsOpenMask&=~(1<<aUnit); |
|
854 |
|
855 NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex. |
|
856 return(KErrNone); |
|
857 } |
|
858 |
|
859 |
|
860 /** |
|
861 "Standard LDD" entrypoint. |
|
862 |
|
863 Is called on CreateLogicalDevice() if the user calls LoadLogicalDevice(). Creates LDD factory. |
|
864 |
|
865 @return pointer to the LDD factory object. |
|
866 */ |
|
867 DECLARE_STANDARD_LDD() |
|
868 { |
|
869 __DEBUG_PRINT("DECLARE_STANDARD_LDD() \n"); |
|
870 DDisplayLddFactory* pLDDFactory = DDisplayLddFactory::CreateInstance(); |
|
871 return pLDDFactory; |
|
872 } |
|
873 |
|
874 |
|
875 |
|
876 |