|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 #include <kern_priv.h> // For DMutex |
|
21 #include "isiuserchannel.h" // For DISIUserChanneel |
|
22 #include "isiroutertrace.h" // For C_TRACE, ASSERT_RESET.. and fault codes |
|
23 #include "misichannelrouterif.h" // For MISIChannelRouterIf |
|
24 #include "memapi.h" // For MemApi |
|
25 #include "isimsgqueue.h" // For DISIMsgQueue |
|
26 |
|
27 const TInt KFirstParam( 0 ); |
|
28 const TInt KSecondParam( 1 ); |
|
29 const TInt KThirdParam( 2 ); |
|
30 const TInt KNoParams( 0 ); |
|
31 const TInt KOneParam( 1 ); |
|
32 const TInt KTwoParams( 2 ); |
|
33 const TInt KThreeParams( 3 ); |
|
34 const TInt KFirstRequest( 0 ); |
|
35 const TInt KDestStartOffset( 0 ); |
|
36 |
|
37 enum TISIUserChannelFaults |
|
38 { |
|
39 EISIUserChannelMemAllocFail = 0x01, |
|
40 EISIUserChannelMemAllocFail1, |
|
41 EISIUserChannelMemAllocFail2, |
|
42 EISIUserChannelMemAllocFail3, |
|
43 EISIUserChannelWrongRequest, |
|
44 EISIUserChannelWrongRequest1, |
|
45 EISIUserChannelWrongRequest2, |
|
46 EISIUserChannelWrongRequest3, |
|
47 EISIUserChannelWrongRequest4, |
|
48 EISIUserChannelWrongRequest5, |
|
49 EISIUserChannelWrongRequest6, |
|
50 EISIUserChannelReqOverTheLimits, |
|
51 EISIUserChannelDesWriteFailed, |
|
52 EISIUserChannelSameRequest, |
|
53 EISIUserChannelNullParam, |
|
54 EISIUserChannelNullParam2, |
|
55 EISIUserChannelDesReadFailed, |
|
56 EISIUserChannelfNotThreadContext, |
|
57 EISIUserChannelfNotThreadContext2, |
|
58 EISIUserChannelfNotThreadContext3, |
|
59 EISIUserChannelfNotThreadContext4, |
|
60 EISIUserChannelfNotThreadContext5, |
|
61 }; |
|
62 |
|
63 const TInt KISILddEmptyRxQueuePriori( 1 ); |
|
64 const TInt KISILddCompleteRequestPriori( 1 ); |
|
65 |
|
66 |
|
67 // user<> kernel interaction() done in LDD DFC thread |
|
68 // |
|
69 // kernel<>kernel interaction() done in Extension DFC thread |
|
70 // |
|
71 // DEMAND_PAGING |
|
72 // Receive (write k>u) is done only in LDD thread context to allow Extension thread to continue when dp swaps. |
|
73 // Send ((write u>k) is not done at the moment in LDD thread context only. Check is it possible to happend (not to be in usable memory after send (unlikely?)). |
|
74 |
|
75 DISIUserChannel::DISIUserChannel( |
|
76 // None |
|
77 ) : iThread( &Kern::CurrentThread()), |
|
78 iObjId( KNotInitializedId ), |
|
79 iUID( KNotInitializedUID ) |
|
80 { |
|
81 C_TRACE( ( _T( "DISIUserChannel::DISIUserChannel>" ) ) ); |
|
82 iRouterIf = MISIChannelRouterIf::GetIf(); |
|
83 ASSERT_RESET_ALWAYS( iRouterIf, ( EISIUserChannelMemAllocFail | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
84 iCompletionThread = iRouterIf->GetDfcThread( MISIChannelRouterIf::EISIUserRequestCompletionThread ); |
|
85 iEmptyRxQueueDfc = new TDfc( EmptyRxQueueDfc, this, iCompletionThread, KISILddEmptyRxQueuePriori ); |
|
86 ASSERT_RESET_ALWAYS( iEmptyRxQueueDfc, ( EISIUserChannelMemAllocFail2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
87 iCompleteChannelRequestDfc = new TDfc( CompleteChannelRequestDfc, this, iCompletionThread, KISILddCompleteRequestPriori ); |
|
88 ASSERT_RESET_ALWAYS( iCompleteChannelRequestDfc, ( EISIUserChannelMemAllocFail3 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
89 iRequests = new DISIUserAsyncRequests( EISILastAsyncRequest ); |
|
90 C_TRACE( ( _T( "DISIUserChannel::DISIUserChannel<" ) ) ); |
|
91 } |
|
92 |
|
93 DISIUserChannel::~DISIUserChannel( |
|
94 // None |
|
95 ) |
|
96 { |
|
97 C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x>" ), this ) ); |
|
98 // owned starts |
|
99 if( iEmptyRxQueueDfc ) |
|
100 { |
|
101 C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iEmptyRxQueueDfc 0x%x" ), this, iObjId, iEmptyRxQueueDfc ) ); |
|
102 iEmptyRxQueueDfc->Cancel(); |
|
103 delete iEmptyRxQueueDfc; |
|
104 iEmptyRxQueueDfc = NULL; |
|
105 } |
|
106 if( iCompleteChannelRequestDfc ) |
|
107 { |
|
108 C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iCompleteChannelRequestDfc 0x%x" ), this, iObjId, iCompleteChannelRequestDfc ) ); |
|
109 iCompleteChannelRequestDfc->Cancel(); |
|
110 delete iCompleteChannelRequestDfc; |
|
111 iCompleteChannelRequestDfc = NULL; |
|
112 } |
|
113 if( iRx ) |
|
114 { |
|
115 C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iRx 0x%x" ), this, iObjId, iRx ) ); |
|
116 delete iRx; |
|
117 iRx = NULL; |
|
118 } |
|
119 if( iReceiveBufPtr ) |
|
120 { |
|
121 C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iReceiveBufPtr 0x%x" ), this, iObjId, iReceiveBufPtr ) ); |
|
122 iReceiveBufPtr = NULL; |
|
123 } |
|
124 if( iRequests ) |
|
125 { |
|
126 delete iRequests; |
|
127 iRequests = NULL; |
|
128 } |
|
129 // owned ends |
|
130 iRouterIf = NULL; |
|
131 Kern::SafeClose( reinterpret_cast<DObject*&>(iThread), NULL ); |
|
132 C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x<" ), this ) ); |
|
133 } |
|
134 |
|
135 /* |
|
136 * Executed in user thread context thread inside CS, cannot be pre-empted. |
|
137 * Channel can not be used before creation, so no need to synch if congesting only btw the creating user thread and one thread. |
|
138 */ |
|
139 TInt DISIUserChannel::DoCreate( |
|
140 TInt, //aUnit, // Not used at the moment |
|
141 const TDesC8*, //anInfo, // Not used at the moment. |
|
142 const TVersion& // aVer // Not used at the moment. |
|
143 ) |
|
144 { |
|
145 C_TRACE( ( _T( "DISIUserChannel::DoCreate 0x%x 0x%x>" ), this, iObjId ) ); |
|
146 if( !Kern::CurrentThreadHasCapability( ECapabilityCommDD, __PLATSEC_DIAGNOSTIC_STRING( "Check by: ISI Router" ) ) ) return KErrPermissionDenied; |
|
147 iRx = new DISIMsgQueue( KISILddRxQueueSize ); |
|
148 ASSERT_RESET_ALWAYS( iRx, ( EISIUserChannelMemAllocFail1 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
149 // Other DFC functions handling user<>kernel copying done in ldd DFC. Ldd DFC function priority is 1. |
|
150 iMainThread = iRouterIf->GetDfcThread( MISIChannelRouterIf::EISIUserMainThread ); |
|
151 SetDfcQ( iMainThread ); |
|
152 iMsgQ.Receive(); |
|
153 DObject* thread = reinterpret_cast<DObject*>( iThread ); |
|
154 // Open is needed to increase ref count to calling thread that is decreased in Kern::SafeClose |
|
155 // Possible returns KErrNone ? KErrGeneral |
|
156 TInt threadOpen( thread->Open() ); |
|
157 TRACE_ASSERT_INFO( threadOpen == KErrNone, iObjId ); |
|
158 C_TRACE( ( _T( "DISIUserChannel::DoCreate 0x%x 0x%x<" ), this, iObjId ) ); |
|
159 return threadOpen; |
|
160 } |
|
161 |
|
162 void DISIUserChannel::HandleMsg( |
|
163 TMessageBase* aMsg |
|
164 ) |
|
165 { |
|
166 C_TRACE( ( _T( "DISIUserChannel::HandleMsg 0x%x 0x%x 0x%x>" ), this, aMsg, iObjId ) ); |
|
167 TThreadMessage& m= *( static_cast< TThreadMessage* >( aMsg ) ); |
|
168 TInt id( m.iValue ); |
|
169 if( static_cast<TInt>( ECloseMsg ) == id ) |
|
170 { |
|
171 C_TRACE( ( _T( "DISIUserChannel::HandleMsg ECloseMsg 0x%x 0x%x" ), this, aMsg ) ); |
|
172 m.Complete( HandleSyncRequest( EISIDisconnect, NULL ), EFalse ); |
|
173 } |
|
174 else if( KMaxTInt == id ) |
|
175 { |
|
176 C_TRACE( ( _T( "DISIUserChannel::HandleMsg cancel 0x%x 0x%x" ), this, aMsg ) ); |
|
177 DoCancel( id, m.Int0() ); |
|
178 m.Complete( KErrNone, ETrue ); |
|
179 } |
|
180 else |
|
181 { |
|
182 ASSERT_RESET_ALWAYS( ( KErrNotFound < id ), ( EISIUserChannelWrongRequest | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
183 C_TRACE( ( _T( "DISIUserChannel::HandleMsg request 0x%x %d 0x%x" ), this, id, aMsg ) ); |
|
184 TInt completeValue( KErrNone ); |
|
185 TInt ulen( KErrNotFound ); |
|
186 switch ( id ) |
|
187 { |
|
188 case EISIDisconnect: |
|
189 { |
|
190 ulen = KNoParams; |
|
191 break; |
|
192 } |
|
193 case EISISend: |
|
194 { |
|
195 ulen = KOneParam; |
|
196 break; |
|
197 } |
|
198 case EISIConnect: |
|
199 { |
|
200 ulen = KTwoParams; |
|
201 break; |
|
202 } |
|
203 case EISIAsyncReceive: |
|
204 { |
|
205 ulen = KThreeParams; |
|
206 break; |
|
207 } |
|
208 default: |
|
209 { |
|
210 ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest1 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
211 break; |
|
212 } |
|
213 } |
|
214 TUint32* table[ KThreeParams ]; |
|
215 completeValue = Kern::ThreadRawRead( iThread, m.Ptr0(), table, ulen * sizeof( TAny* ) ); |
|
216 |
|
217 if( completeValue == KErrNone ) |
|
218 { |
|
219 switch( id ) |
|
220 { |
|
221 // All asynchronous requests. |
|
222 case EISIAsyncReceive: |
|
223 { |
|
224 // No need to check return value in async functions, completed to user |
|
225 HandleAsyncRequest( id, table ); |
|
226 break; |
|
227 } |
|
228 case EISIDisconnect: |
|
229 case EISIConnect: |
|
230 case EISISend: |
|
231 { |
|
232 completeValue = HandleSyncRequest( id, table ); |
|
233 break; |
|
234 } |
|
235 default: |
|
236 { |
|
237 ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
238 break; |
|
239 } |
|
240 } |
|
241 } |
|
242 m.Complete( completeValue, ETrue ); |
|
243 } |
|
244 C_TRACE( ( _T( "DISIUserChannel::HandleMsg 0x%x 0x%x 0x%x<" ), this, aMsg, iObjId ) ); |
|
245 } |
|
246 |
|
247 TInt DISIUserChannel::Request( |
|
248 TInt aReqNo, |
|
249 TAny* a1, |
|
250 TAny* //a2 |
|
251 ) |
|
252 { |
|
253 C_TRACE( ( _T( "DISIUserChannel::Request 0x%x %d 0x%x 0x%x>" ), this, aReqNo, a1, iObjId ) ); |
|
254 // Programmer errors. |
|
255 ASSERT_RESET_ALWAYS( aReqNo >= ( TInt ) EMinRequestId, ( EISIUserChannelWrongRequest3 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
256 ASSERT_RESET_ALWAYS( ( aReqNo <= EISILastAsyncRequest || aReqNo == KMaxTInt ), ( EISIUserChannelWrongRequest4 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
257 // Wrong API usage e.g. called function when interface is not open so panic the client thread. |
|
258 TInt result( KErrNotFound ); |
|
259 // All request go in kernel context and with ::DoControl call. |
|
260 TThreadMessage& m=Kern::Message(); |
|
261 m.iValue = aReqNo; |
|
262 m.iArg[ KFirstParam ] = a1; |
|
263 m.iArg[ KSecondParam ] = NULL; |
|
264 result = m.SendReceive( &iMsgQ ); |
|
265 C_TRACE( ( _T( "DISIUserChannel::Request 0x%x %d 0x%x<" ), this, aReqNo, a1, iObjId ) ); |
|
266 return result; |
|
267 } |
|
268 |
|
269 TInt DISIUserChannel::HandleSyncRequest( |
|
270 TInt aRequest, |
|
271 TAny* a1 |
|
272 ) |
|
273 { |
|
274 C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x %d 0x%x 0x%x>" ), this, aRequest, a1, iObjId ) ); |
|
275 ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext5 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
276 TInt error( KErrNotSupported ); |
|
277 switch( aRequest ) |
|
278 { |
|
279 case EISIDisconnect: |
|
280 { |
|
281 C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISIDisconnect" ), this ) ); |
|
282 Disconnect(); |
|
283 error = KErrNone; |
|
284 break; |
|
285 } |
|
286 case EISISend: |
|
287 { |
|
288 C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISISend" ), this ) ); |
|
289 TUint32* tablePtr = reinterpret_cast<TUint32*>( a1 ); |
|
290 TAny* firstParam = reinterpret_cast<TAny*>( tablePtr[ KFirstParam ] ); |
|
291 TRACE_ASSERT_INFO( firstParam, ( iObjId << KObjIdShift | ( EISIUserChannelNullParam2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ) ); |
|
292 TInt msgLength( Kern::ThreadGetDesLength( iThread, firstParam ) ); |
|
293 C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISISend 0x%x %d" ), this, firstParam, msgLength ) ); |
|
294 if( msgLength > 0 && msgLength < KMaxISIMsgSize ) |
|
295 { |
|
296 TDes8& sendBlock = MemApi::AllocBlock( msgLength ); |
|
297 ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadDesRead( iThread, firstParam, sendBlock, 0, KChunkShiftBy0 ), ( EISIUserChannelDesReadFailed | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
298 TRACE_ASSERT_INFO( sendBlock.Length() == msgLength, iObjId << KObjIdShift ); |
|
299 C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest EISISend 0x%x 0x%x" ), this, &sendBlock ) ); |
|
300 error = iRouterIf->Send( sendBlock, iObjId ); |
|
301 } |
|
302 else |
|
303 { |
|
304 error = ( msgLength > KMaxISIMsgSize ) ? KErrNoMemory : KErrBadDescriptor; |
|
305 TRACE_ASSERT_INFO( 0, iObjId << KObjIdShift | (TUint16)msgLength ); |
|
306 } |
|
307 break; |
|
308 } |
|
309 case EISIConnect: |
|
310 { |
|
311 TUint32* tablePtr = reinterpret_cast<TUint32*>( a1 ); |
|
312 iUID = tablePtr[ KFirstParam ]; |
|
313 TUint8* objIdPtr = reinterpret_cast<TUint8*>( tablePtr[ KSecondParam ] ); |
|
314 C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest EISIConnect 0x%x 0x%x 0x%x" ), this, iUID, objIdPtr ) ); |
|
315 iRouterIf->Connect( iUID, iObjId, this ); |
|
316 C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest received iObjId is 0x%x" ), iObjId ) ); |
|
317 ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadRawWrite( iThread, objIdPtr, &iObjId, sizeof(TUint8), iThread ), |
|
318 EISIUserChannelDesWriteFailed | iObjId << KObjIdShift | EDISIUserChannelTraceId << KClassIdentifierShift ); |
|
319 error = KErrNone; |
|
320 break; |
|
321 } |
|
322 default: |
|
323 { |
|
324 ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest5 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
325 break; |
|
326 } |
|
327 } |
|
328 C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x %d 0x%x 0x%x<" ), this, aRequest, a1, iObjId ) ); |
|
329 return error; |
|
330 } |
|
331 |
|
332 void DISIUserChannel::HandleAsyncRequest( |
|
333 TInt aRequest, |
|
334 TAny* a1 |
|
335 ) |
|
336 { |
|
337 C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x %d 0x%x 0x%x>" ), this, aRequest, a1, iObjId ) ); |
|
338 |
|
339 ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext4 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
340 TUint32* tablePtr = reinterpret_cast<TUint32*>( a1 ); |
|
341 TRACE_ASSERT_INFO( tablePtr[ KFirstParam ], (TUint16)aRequest ); |
|
342 TRequestStatus* requestStatus = reinterpret_cast<TRequestStatus*>( tablePtr[ KFirstParam ] ); |
|
343 if( iRequests->IsPending( aRequest ) ) |
|
344 { |
|
345 C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest existing 0x%x request 0x%x" ), this, aRequest ) ); |
|
346 // Should not give same request object twice before completing the first one. |
|
347 ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelSameRequest | iObjId << KObjIdShift | static_cast<TUint8>( aRequest ) << KExtraInfoShift ) ); |
|
348 } |
|
349 else |
|
350 { |
|
351 C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x handling %d" ), this, aRequest ) ); |
|
352 iRequests->SetPending( aRequest, requestStatus ); |
|
353 switch( aRequest ) |
|
354 { |
|
355 case EISIAsyncReceive: |
|
356 { |
|
357 iReceiveBufPtr = reinterpret_cast<TAny*>( tablePtr[ KSecondParam ] ); |
|
358 iNeededBufLen = reinterpret_cast<TUint16*>( tablePtr[ KThirdParam ] ); |
|
359 C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x EISIAsyncReceive 0x%x" ), this, iReceiveBufPtr ) ); |
|
360 iEmptyRxQueueDfc->Enque(); |
|
361 break; |
|
362 } |
|
363 default: |
|
364 { |
|
365 ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
366 break; |
|
367 } |
|
368 } |
|
369 } |
|
370 C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x %d 0x%x 0x%x<" ), this, aRequest, a1, iObjId ) ); |
|
371 } |
|
372 |
|
373 |
|
374 void DISIUserChannel::DoCancel( |
|
375 TInt aRequest, |
|
376 TInt aMask ) |
|
377 { |
|
378 C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x %d 0x%x 0x%x>" ), this, aRequest, aMask, iObjId ) ); |
|
379 switch( aMask&aRequest ) |
|
380 { |
|
381 case EISIAsyncReceive: |
|
382 { |
|
383 C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x EISIAsyncReceive 0x%x " ), this, iReceiveBufPtr ) ); |
|
384 iReceiveBufPtr = NULL; |
|
385 break; |
|
386 } |
|
387 default: |
|
388 { |
|
389 ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest6 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
390 break; |
|
391 } |
|
392 } |
|
393 EnqueChannelRequestCompleteDfc( aMask&aRequest, KErrCancel ); |
|
394 C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x %d 0x%x 0x%x<" ), this, aRequest, aMask, iObjId ) ); |
|
395 } |
|
396 |
|
397 |
|
398 void DISIUserChannel::Disconnect( |
|
399 // None |
|
400 ) |
|
401 { |
|
402 C_TRACE( ( _T( "DISIUserChannel::Disconnect 0x%x 0x%x>" ), this, iObjId ) ); |
|
403 ResetQueues(); |
|
404 for( TInt i( 0 ); i < iRequests->iRequestCompletedList.Count(); ++i ) |
|
405 { |
|
406 C_TRACE( ( _T( "DISIUserChannel::CancelRequests req to cancel %d" ), i ) ); |
|
407 DoCancel( KMaxTInt, i ); |
|
408 } |
|
409 iRouterIf->Disconnect( iObjId ); |
|
410 iRouterIf->FreeDfcThread( iMainThread ); |
|
411 iRouterIf->FreeDfcThread( iCompletionThread ); |
|
412 C_TRACE( ( _T( "DISIUserChannel::Disconnect 0x%x 0x%x<" ), this, iObjId ) ); |
|
413 } |
|
414 |
|
415 void DISIUserChannel::ResetQueues( |
|
416 // None |
|
417 ) |
|
418 { |
|
419 C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x 0x%x>" ), this, iObjId ) ); |
|
420 if( iRx ) |
|
421 { |
|
422 C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x iRx 0x%x" ), this, iRx ) ); |
|
423 while( iRx->Count() ) |
|
424 { |
|
425 MemApi::DeallocBlock( iRx->Get() ); |
|
426 } |
|
427 } |
|
428 C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x 0x%x<" ), this, iObjId ) ); |
|
429 } |
|
430 |
|
431 // This is called in 1...N thread contextes |
|
432 void DISIUserChannel::ReceiveMsg( |
|
433 const TDesC8& aMessage |
|
434 ) |
|
435 { |
|
436 C_TRACE( ( _T( "DISIUserChannel::ReceiveMsg 0x%x 0x%x 0x%x>" ), this, &aMessage, iObjId ) ); |
|
437 // Can only be called from thread context. |
|
438 ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext3 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
439 iRx->Add( aMessage ); |
|
440 iEmptyRxQueueDfc->Enque(); |
|
441 C_TRACE( ( _T( "DISIUserChannel::ReceiveMsg 0x%x 0x%x 0x%x<" ), this, &aMessage, iObjId ) ); |
|
442 } |
|
443 |
|
444 DISIUserChannel::DISIUserAsyncRequests::DISIUserAsyncRequests( |
|
445 const TInt aSize |
|
446 ) |
|
447 { |
|
448 C_TRACE( ( _T( "DISIUserAsyncRequests::DISIUserAsyncRequests size %d>" ), aSize ) ); |
|
449 iRequestLock = new NFastMutex(); |
|
450 C_TRACE( ( _T( "DISIUserAsyncRequests::DISIUserAsyncRequests<" ) ) ); |
|
451 } |
|
452 |
|
453 DISIUserChannel::DISIUserAsyncRequests::~DISIUserAsyncRequests() |
|
454 { |
|
455 |
|
456 C_TRACE( ( _T( "DISIUserAsyncRequests::~DISIUserAsyncRequests>" ) ) ); |
|
457 iRequestCompletedList.Close(); |
|
458 delete iRequestLock; |
|
459 C_TRACE( ( _T( "DISIUserAsyncRequests::~DISIUserAsyncRequests<" ) ) ); |
|
460 |
|
461 } |
|
462 |
|
463 TBool DISIUserChannel::DISIUserAsyncRequests::IsPending( |
|
464 const TUint aRequest |
|
465 ) |
|
466 { |
|
467 C_TRACE( ( _T( "DISIUserAsyncRequests::IsPending %d>" ), aRequest ) ); |
|
468 ASSERT_RESET_ALWAYS( ( EISILastAsyncRequest > aRequest && EISIAsyncReceive <= aRequest ), ( EISIUserChannelReqOverTheLimits | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
469 TBool ret( EFalse ); |
|
470 NKern::FMWait( iRequestLock ); |
|
471 ret = ( iRequestStatusList[ aRequest ] ) ? ETrue : EFalse; |
|
472 NKern::FMSignal( iRequestLock ); |
|
473 C_TRACE( ( _T( "DISIUserAsyncRequests::IsPending %d %d<" ), aRequest, ret ) ); |
|
474 return ret; |
|
475 } |
|
476 |
|
477 void DISIUserChannel::DISIUserAsyncRequests::SetPending( |
|
478 const TUint aRequest, |
|
479 TRequestStatus* aStatus |
|
480 ) |
|
481 { |
|
482 C_TRACE( ( _T( "DISIUserAsyncRequests::SetPending %d 0x%x>" ), aRequest, aStatus ) ); |
|
483 ASSERT_RESET_ALWAYS( aRequest, ( EISIUserChannelNullParam | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
484 ASSERT_RESET_ALWAYS( aStatus, ( EISIUserChannelNullParam | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
485 ASSERT_RESET_ALWAYS( ( EISILastAsyncRequest > aRequest && EISIAsyncReceive <= aRequest ), ( EISIUserChannelReqOverTheLimits | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
486 // Note asserts must be done before holding the lock. |
|
487 NKern::FMWait( iRequestLock ); |
|
488 iRequestStatusList[ aRequest ] = aStatus; |
|
489 NKern::FMSignal( iRequestLock ); |
|
490 C_TRACE( ( _T( "DISIUserAsyncRequests::SetPending %d 0x%x<" ), aRequest, aStatus ) ); |
|
491 } |
|
492 |
|
493 void DISIUserChannel::EmptyRxQueueDfc( |
|
494 TAny* aPtr // Pointer to self |
|
495 ) |
|
496 { |
|
497 C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc>" ) ) ); |
|
498 DISIUserChannel& chTmp = *reinterpret_cast<DISIUserChannel*>( aPtr ); |
|
499 C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc 0x%x 0x%x>" ), &chTmp, chTmp.iObjId ) ); |
|
500 if( chTmp.iRequests->IsPending( EISIAsyncReceive ) && ( chTmp.iRx->Count() > 0 ) ) |
|
501 { |
|
502 TDes8& tmpDes = chTmp.iRx->Get(); |
|
503 TInt desMaxLen( Kern::ThreadGetDesMaxLength( chTmp.iThread, chTmp.iReceiveBufPtr ) ); |
|
504 // If user descriptor legth is enough and length get not failed. |
|
505 if( desMaxLen >= tmpDes.Length() ) |
|
506 { |
|
507 // Write to user address space (iReceiveBufPtr) the content of tmpDes starting from zero offset as 8bit descriptor data. |
|
508 TInt writeError( Kern::ThreadDesWrite( chTmp.iThread, chTmp.iReceiveBufPtr, tmpDes, KDestStartOffset, KChunkShiftBy0, chTmp.iThread ) ); |
|
509 if( writeError == KErrNone ) |
|
510 { |
|
511 C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc write 0x%x k->u 0x%x ok" ), &tmpDes, chTmp.iReceiveBufPtr ) ); |
|
512 chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, writeError ); |
|
513 MemApi::DeallocBlock( tmpDes ); |
|
514 } |
|
515 // Write unsuccesfull don't deallocate the block. |
|
516 else |
|
517 { |
|
518 C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc write 0x%x k->u 0x%x NOK, reason %d" ), &tmpDes, chTmp.iReceiveBufPtr, writeError ) ); |
|
519 TRACE_ASSERT_INFO( 0, chTmp.iObjId << KObjIdShift | (TUint16)writeError ); |
|
520 // Roll the message back to que. |
|
521 chTmp.iRx->RollBack( tmpDes ); |
|
522 chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, writeError ); |
|
523 } |
|
524 } |
|
525 // If descriptor invalid. |
|
526 else |
|
527 { |
|
528 TRACE_WARNING( 0, chTmp.iObjId << KObjIdShift | (TUint16)tmpDes.Length() ); |
|
529 // Roll the message back to que. |
|
530 chTmp.iRx->RollBack( tmpDes ); |
|
531 // If invalid content. |
|
532 if( KErrBadDescriptor == desMaxLen ) |
|
533 { |
|
534 TRACE_ASSERT_INFO( 0, chTmp.iObjId << KObjIdShift | (TUint16)desMaxLen ); |
|
535 C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc invalid descriptor 0x%x" ), chTmp.iObjId ) ); |
|
536 chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, KErrBadDescriptor ); |
|
537 } |
|
538 // If length too small (if other assert). |
|
539 else |
|
540 { |
|
541 TUint16 neededLength( tmpDes.Length() ); |
|
542 TRACE_WARNING( 0, chTmp.iObjId << KObjIdShift | (TUint16)desMaxLen ); |
|
543 C_TRACE( ( _T( "DISAUserChannel::EmptyRxQueueDfc descriptor length too small length %d needed %d" ), desMaxLen, neededLength ) ); |
|
544 ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadRawWrite( chTmp.iThread, chTmp.iNeededBufLen, &neededLength, sizeof(TUint16), chTmp.iThread ), |
|
545 EISIUserChannelDesWriteFailed | chTmp.iObjId << KObjIdShift | EDISIUserChannelTraceId << KClassIdentifierShift ); |
|
546 chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, KErrOverflow ); |
|
547 } |
|
548 } |
|
549 } |
|
550 else |
|
551 { |
|
552 C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc no receive active or no message" ) ) ); |
|
553 } |
|
554 C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc 0x%x<" ), chTmp.iObjId ) ); |
|
555 } |
|
556 |
|
557 // called in router ext context |
|
558 void DISIUserChannel::EnqueChannelRequestCompleteDfc( |
|
559 TInt aRequest, |
|
560 TInt aStatusToComplete |
|
561 ) |
|
562 { |
|
563 C_TRACE( ( _T( "DISIUserChannel::EnqueChannelRequestCompleteDfc 0x%x %d %d 0x%x>" ), this, aRequest, aStatusToComplete, iObjId ) ); |
|
564 ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
565 //TODO check the error code |
|
566 iRequests->iRequestCompletedList.Append( aRequest ); |
|
567 iRequests->iRequestCompletionValueList[ aRequest ] = aStatusToComplete; |
|
568 iCompleteChannelRequestDfc->Enque(); |
|
569 C_TRACE( ( _T( "DISIUserChannel::EnqueChannelRequestCompleteDfc 0x%x %d %d 0x%x<" ), this, aRequest, aStatusToComplete, iObjId ) ); |
|
570 } |
|
571 |
|
572 // Run in ISI user channel kernel thread context. |
|
573 void DISIUserChannel::CompleteChannelRequestDfc( |
|
574 TAny* aPtr |
|
575 ) |
|
576 { |
|
577 C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc>" ) ) ); |
|
578 // Make sure that user side is accessed only by ldd DFCThread. |
|
579 ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); |
|
580 DISIUserChannel* chPtr = reinterpret_cast<DISIUserChannel*>( aPtr ); |
|
581 C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc 0x%x 0x%x" ), chPtr, chPtr->iObjId ) ); |
|
582 TInt request = chPtr->iRequests->iRequestCompletedList[ KFirstRequest ]; |
|
583 TRequestStatus* status( chPtr->iRequests->iRequestStatusList[ request ] ); |
|
584 Kern::RequestComplete( chPtr->iThread, status, chPtr->iRequests->iRequestCompletionValueList[ request ] ); |
|
585 chPtr->iRequests->iRequestCompletedList.Remove( KFirstRequest ); |
|
586 chPtr->iRequests->iRequestStatusList[ request ] = NULL; |
|
587 chPtr->iRequests->iRequestCompletionValueList[ request ] = KNotInitializedStatus; |
|
588 |
|
589 if( chPtr->iRequests->iRequestCompletedList.Count() != 0 ) |
|
590 { |
|
591 CompleteChannelRequestDfc( chPtr ); |
|
592 } |
|
593 C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc 0x%x 0x%x<" ), chPtr, chPtr->iObjId ) ); |
|
594 } |