|
1 /* |
|
2 * Copyright (c) 2007-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 "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 @file |
|
20 @internalComponent |
|
21 */ |
|
22 |
|
23 #include "fdcproxy.h" |
|
24 #include <ecom/ecom.h> |
|
25 #include "utils.h" |
|
26 #include <usbhost/internal/fdcplugin.h> |
|
27 #include <usbhost/internal/fdcinterface.h> |
|
28 #include "fdf.h" |
|
29 #include "utils.h" |
|
30 |
|
31 #ifdef __FLOG_ACTIVE |
|
32 _LIT8(KLogComponent, "fdf "); |
|
33 #endif |
|
34 |
|
35 #ifdef __FLOG_ACTIVE |
|
36 #define LOG Log() |
|
37 #else |
|
38 #define LOG |
|
39 #endif |
|
40 |
|
41 #ifdef _DEBUG |
|
42 #define INVARIANT Invariant() |
|
43 #else |
|
44 #define INVARIANT |
|
45 #endif |
|
46 |
|
47 PANICCATEGORY("fdcproxy"); |
|
48 |
|
49 |
|
50 |
|
51 CFdcProxy* CFdcProxy::NewL(CFdf& aFdf, CImplementationInformation& aImplInfo) |
|
52 { |
|
53 LOG_STATIC_FUNC_ENTRY |
|
54 |
|
55 CFdcProxy* self = new(ELeave) CFdcProxy(aFdf); |
|
56 CleanupStack::PushL(self); |
|
57 self->ConstructL(aImplInfo); |
|
58 #ifdef __FLOG_ACTIVE |
|
59 self->INVARIANT; |
|
60 #endif |
|
61 CleanupStack::Pop(self); |
|
62 return self; |
|
63 } |
|
64 |
|
65 |
|
66 void CFdcProxy::ConstructL(CImplementationInformation& aImplInfo) |
|
67 { |
|
68 LOG_FUNC |
|
69 |
|
70 LOGTEXT2(_L8("\t\tFDC implementation UID: 0x%08x"), aImplInfo.ImplementationUid()); |
|
71 LOGTEXT2(_L("\t\tFDC display name: \"%S\""), &aImplInfo.DisplayName()); |
|
72 LOGTEXT2(_L8("\t\tFDC default_data: \"%S\""), &aImplInfo.DataType()); |
|
73 LOGTEXT2(_L8("\t\tFDC version: %d"), aImplInfo.Version()); |
|
74 LOGTEXT2(_L8("\t\tFDC disabled: %d"), aImplInfo.Disabled()); |
|
75 TDriveName drvName = aImplInfo.Drive().Name(); |
|
76 LOGTEXT2(_L8("\t\tFDC drive: %S"), &drvName); |
|
77 LOGTEXT2(_L8("\t\tFDC rom only: %d"), aImplInfo.RomOnly()); |
|
78 LOGTEXT2(_L8("\t\tFDC rom based: %d"), aImplInfo.RomBased()); |
|
79 LOGTEXT2(_L8("\t\tFDC vendor ID: %08x"), (TUint32)aImplInfo.VendorId()); |
|
80 |
|
81 // Before PREQ2080 a reference to the CImplementationInformation object was held. This is no longer |
|
82 // possible because as soon as REComSession::ListImplementations() is called the reference will be |
|
83 // invalid. |
|
84 iImplementationUid = aImplInfo.ImplementationUid(); |
|
85 iVersion = aImplInfo.Version(); |
|
86 iDefaultData.CreateL(aImplInfo.DataType()); |
|
87 iRomBased = aImplInfo.RomBased(); |
|
88 } |
|
89 |
|
90 CFdcProxy::CFdcProxy(CFdf& aFdf) |
|
91 : iFdf(aFdf), |
|
92 i0thInterface(-1) // -1 means unassigned |
|
93 { |
|
94 LOG_FUNC |
|
95 } |
|
96 |
|
97 |
|
98 CFdcProxy::~CFdcProxy() |
|
99 { |
|
100 LOG_FUNC |
|
101 INVARIANT; |
|
102 |
|
103 // Only executed when the FDF is finally shutting down. |
|
104 // By this time detachment of all devices should have been signalled to |
|
105 // all FDCs and the FDC plugins should have been cleaned up. |
|
106 // If is safe to assert this because iPlugin and iDeviceIds are not |
|
107 // allocated on construction so this doesn't have to safe against partial |
|
108 // construction. |
|
109 ASSERT_DEBUG(!iPlugin); |
|
110 ASSERT_DEBUG(iDeviceIds.Count() == 0); |
|
111 iDeviceIds.Close(); |
|
112 iDefaultData.Close(); |
|
113 |
|
114 INVARIANT; |
|
115 } |
|
116 |
|
117 |
|
118 TInt CFdcProxy::NewFunction(TUint aDeviceId, |
|
119 const RArray<TUint>& aInterfaces, |
|
120 const TUsbDeviceDescriptor& aDeviceDescriptor, |
|
121 const TUsbConfigurationDescriptor& aConfigurationDescriptor) |
|
122 { |
|
123 LOG_FUNC |
|
124 LOGTEXT2(_L8("\taDeviceId = %d"), aDeviceId); |
|
125 INVARIANT; |
|
126 |
|
127 // Create a plugin object if required, call Mfi1NewFunction on it, and |
|
128 // update our iDeviceIds. |
|
129 TRAPD(err, NewFunctionL(aDeviceId, aInterfaces, aDeviceDescriptor, aConfigurationDescriptor)); |
|
130 INVARIANT; |
|
131 LOGTEXT2(_L8("\terr = %d"), err); |
|
132 return err; |
|
133 } |
|
134 |
|
135 |
|
136 void CFdcProxy::NewFunctionL(TUint aDeviceId, |
|
137 const RArray<TUint>& aInterfaces, |
|
138 const TUsbDeviceDescriptor& aDeviceDescriptor, |
|
139 const TUsbConfigurationDescriptor& aConfigurationDescriptor) |
|
140 { |
|
141 LOG_FUNC |
|
142 |
|
143 // We may already have aDeviceId in our collection of device IDs, if the |
|
144 // device is offering multiple Functions of the same type. In this case we |
|
145 // don't want to add the device ID again. |
|
146 // If we already know about this device, then we should definitely have |
|
147 // already made iPlugin- this is checked in the invariant. |
|
148 // However, if we don't know this device, we may still already have made |
|
149 // iPlugin, to handle some other device. So we have to do some logic |
|
150 // around creating the objects we need. |
|
151 |
|
152 TBool alreadyKnowThisDevice = EFalse; |
|
153 const TUint count = iDeviceIds.Count(); |
|
154 for ( TUint ii = 0 ; ii < count ; ++ii ) |
|
155 { |
|
156 if ( iDeviceIds[ii] == aDeviceId ) |
|
157 { |
|
158 alreadyKnowThisDevice = ETrue; |
|
159 break; |
|
160 } |
|
161 } |
|
162 LOGTEXT2(_L8("\talreadyKnowThisDevice = %d"), alreadyKnowThisDevice); |
|
163 |
|
164 TArrayRemove arrayRemove(iDeviceIds, aDeviceId); |
|
165 if ( !alreadyKnowThisDevice ) |
|
166 { |
|
167 // We add the device ID to our array first because it's failable. |
|
168 // Logically, it should be done *after* we call Mfi1NewFunction on the |
|
169 // plugin, but we can't have the failable step of adding the device ID |
|
170 // to the array after telling the FDC. |
|
171 LEAVEIFERRORL(iDeviceIds.Append(aDeviceId)); |
|
172 // This cleanup item removes aDeviceId from iDeviceIds on a leave. |
|
173 CleanupRemovePushL(arrayRemove); |
|
174 } |
|
175 |
|
176 TBool neededToMakePlugin = EFalse; |
|
177 CFdcPlugin* plugin = iPlugin; |
|
178 MFdcInterfaceV1* iface = iInterface; |
|
179 if ( !plugin ) |
|
180 { |
|
181 neededToMakePlugin = ETrue; |
|
182 LOGTEXT2(_L8("\t\tFDC implementation UID: 0x%08x"), iImplementationUid); |
|
183 plugin = CFdcPlugin::NewL(iImplementationUid, *this); |
|
184 CleanupStack::PushL(plugin); |
|
185 iface = reinterpret_cast<MFdcInterfaceV1*>(plugin->GetInterface(TUid::Uid(KFdcInterfaceV1))); |
|
186 } |
|
187 ASSERT_DEBUG(iface); |
|
188 TInt err = KErrNone; |
|
189 |
|
190 // Log the interfaces they're being offered. |
|
191 #ifdef __FLOG_ACTIVE |
|
192 const TUint ifCount = aInterfaces.Count(); |
|
193 LOGTEXT2(_L8("\toffering %d interfaces:"), ifCount); |
|
194 for ( TUint ii = 0 ; ii < ifCount ; ++ii ) |
|
195 { |
|
196 LOGTEXT2(_L8("\t\tinterface %d"), aInterfaces[ii]); |
|
197 } |
|
198 #endif |
|
199 |
|
200 iInMfi1NewFunction = ETrue; |
|
201 // Check that the FDC always claims the 0th interface. |
|
202 ASSERT_DEBUG(i0thInterface == -1); |
|
203 i0thInterface = aInterfaces[0]; |
|
204 err = iface->Mfi1NewFunction( aDeviceId, |
|
205 aInterfaces.Array(), // actually pass them a TArray for const access |
|
206 aDeviceDescriptor, |
|
207 aConfigurationDescriptor); |
|
208 LOGTEXT2(_L8("\terr = %d"), err); |
|
209 iInMfi1NewFunction = EFalse; |
|
210 // The implementation of Mfi1NewFunction may not leave. |
|
211 // ASSERT_ALWAYS(leave_err == KErrNone); |
|
212 // This is set back to -1 when the FDC claims the 0th interface. |
|
213 ASSERT_DEBUG(i0thInterface == -1); |
|
214 |
|
215 // If this leaves, then: |
|
216 // (a) aDeviceId will be removed from iDeviceIds (if we needed to add it). |
|
217 // (b) the FDF will get the leave code. |
|
218 // If this doesn't leave, then iPlugin, iInterface and iDeviceIds are |
|
219 // populated OK and the FDF will get KErrNone. |
|
220 LEAVEIFERRORL(err); |
|
221 |
|
222 if ( neededToMakePlugin ) |
|
223 { |
|
224 CLEANUPSTACK_POP1(plugin); |
|
225 // Now everything failable has been done we can assign iPlugin and |
|
226 // iInterface. |
|
227 ASSERT_DEBUG(plugin); |
|
228 ASSERT_DEBUG(iface); |
|
229 iPlugin = plugin; |
|
230 iInterface = iface; |
|
231 } |
|
232 if ( !alreadyKnowThisDevice ) |
|
233 { |
|
234 CLEANUPSTACK_POP1(&arrayRemove); |
|
235 } |
|
236 } |
|
237 |
|
238 |
|
239 // Called by the FDF whenever a device is detached. |
|
240 // We check if the device is relevant to us. If it is, we signal its |
|
241 // detachment to the plugin. |
|
242 void CFdcProxy::DeviceDetached(TUint aDeviceId) |
|
243 { |
|
244 LOG_FUNC |
|
245 LOGTEXT2(_L8("\taDeviceId = %d"), aDeviceId); |
|
246 INVARIANT; |
|
247 |
|
248 const TUint count = iDeviceIds.Count(); |
|
249 for ( TUint ii = 0 ; ii < count ; ++ii ) |
|
250 { |
|
251 if ( iDeviceIds[ii] == aDeviceId ) |
|
252 { |
|
253 LOGTEXT(_L8("\tmatching device id- calling Mfi1DeviceDetached!")); |
|
254 ASSERT_DEBUG(iInterface); |
|
255 iInterface->Mfi1DeviceDetached(aDeviceId); |
|
256 // The implementation of Mfi1DeviceDetached may not leave. |
|
257 // ASSERT_ALWAYS(err == KErrNone); |
|
258 iDeviceIds.Remove(ii); |
|
259 break; |
|
260 } |
|
261 } |
|
262 |
|
263 LOGTEXT2(_L8("\tiDeviceIds.Count() = %d"), iDeviceIds.Count()); |
|
264 if ( iDeviceIds.Count() == 0 ) |
|
265 { |
|
266 delete iPlugin; |
|
267 iPlugin = NULL; |
|
268 iInterface = NULL; |
|
269 |
|
270 // If an FDC was loaded and then unloaded and an upgrade of the FDC installed then when the FDC is |
|
271 // loaded again ECom will load the original version and not the new version unless we do a FinalClose() |
|
272 // to release cached handles |
|
273 #pragma message("ECom defect DEF122443 raised") |
|
274 REComSession::FinalClose(); |
|
275 } |
|
276 |
|
277 INVARIANT; |
|
278 } |
|
279 |
|
280 |
|
281 #ifdef _DEBUG |
|
282 void CFdcProxy::Invariant() const |
|
283 { |
|
284 // If the class invariant fails hopefully it will be clear why from |
|
285 // inspection of this object dump. |
|
286 LOG; |
|
287 |
|
288 // Either these are all 0 or none of them are: |
|
289 // iDeviceIds.Count, iPlugin, iInterface |
|
290 |
|
291 ASSERT_DEBUG( |
|
292 ( |
|
293 iDeviceIds.Count() != 0 && iPlugin && iInterface |
|
294 ) |
|
295 || |
|
296 ( |
|
297 iDeviceIds.Count() == 0 && !iPlugin && !iInterface |
|
298 ) |
|
299 ); |
|
300 |
|
301 // Each device ID appears only once in the device ID array. |
|
302 const TUint count = iDeviceIds.Count(); |
|
303 for ( TUint ii = 0 ; ii < count ; ++ii ) |
|
304 { |
|
305 for ( TUint jj = ii+1 ; jj < count ; ++jj ) |
|
306 { |
|
307 ASSERT_DEBUG(iDeviceIds[ii] != iDeviceIds[jj]); |
|
308 } |
|
309 } |
|
310 } |
|
311 |
|
312 |
|
313 void CFdcProxy::Log() const |
|
314 { |
|
315 LOGTEXT2(_L8("\tLogging CFdcProxy 0x%08x:"), this); |
|
316 const TUint count = iDeviceIds.Count(); |
|
317 LOGTEXT2(_L8("\t\tiDeviceIds.Count() = %d"), count); |
|
318 for ( TUint i = 0 ; i < count ; ++i ) |
|
319 { |
|
320 LOGTEXT3(_L8("\t\t\tiDeviceIds[%d] = %d"), i, iDeviceIds[i]); |
|
321 } |
|
322 LOGTEXT2(_L8("\t\tiPlugin = 0x%08x"), iPlugin); |
|
323 LOGTEXT2(_L8("\t\tiInterface = 0x%08x"), iInterface); |
|
324 } |
|
325 #endif // _DEBUG |
|
326 |
|
327 |
|
328 const TDesC8& CFdcProxy::DefaultDataField() const |
|
329 { |
|
330 return iDefaultData; |
|
331 } |
|
332 |
|
333 TUid CFdcProxy::ImplUid() const |
|
334 { |
|
335 return iImplementationUid; |
|
336 } |
|
337 |
|
338 TInt CFdcProxy::Version() const |
|
339 { |
|
340 return iVersion; |
|
341 } |
|
342 |
|
343 |
|
344 TInt CFdcProxy::DeviceCount() const |
|
345 { |
|
346 return iDeviceIds.Count(); |
|
347 } |
|
348 |
|
349 |
|
350 // If a FD has been uninstalled from the device then its proxy needs to be deleted from the proxy list |
|
351 // maintained by the FDF. However if the FD is in use by an attached peripheral it can't be deleted |
|
352 // until that device is removed. Hence this function marks it for deletion upon device detachment. |
|
353 // This situation will also occur if a FD upgrade is installed onto the device and the original FD (the one that |
|
354 // is being upgraded) is in use. |
|
355 void CFdcProxy::MarkForDeletion() |
|
356 { |
|
357 iMarkedForDeletion = ETrue; |
|
358 } |
|
359 |
|
360 |
|
361 |
|
362 // If a FD is installed and a device attached which uses it, then if while the device is still attached that FD is |
|
363 // uninstalled then the FD proxy is marked for deletion when the device detaches. However in the situation where the |
|
364 // FD is re-installed while the device still remains attached then the FD proxy should not be deleted when the device |
|
365 // eventually detaches. Hence this function is to undo the mark for deletion that was placed upon the proxy when the FD |
|
366 // was uninstalled. |
|
367 void CFdcProxy::UnmarkForDeletion() |
|
368 { |
|
369 iMarkedForDeletion = EFalse; |
|
370 } |
|
371 |
|
372 |
|
373 TBool CFdcProxy::MarkedForDeletion() const |
|
374 { |
|
375 return iMarkedForDeletion; |
|
376 } |
|
377 |
|
378 |
|
379 TBool CFdcProxy::RomBased() const |
|
380 { |
|
381 return iRomBased; |
|
382 } |
|
383 |
|
384 |
|
385 TUint32 CFdcProxy::MfpoTokenForInterface(TUint8 aInterface) |
|
386 { |
|
387 LOG_FUNC |
|
388 |
|
389 // This function must only be called from an implementation of |
|
390 // Mfi1NewInterface. |
|
391 ASSERT_ALWAYS(iInMfi1NewFunction); |
|
392 // Support our check that the FDC claims the 0th interface. |
|
393 if ( aInterface == i0thInterface ) |
|
394 { |
|
395 i0thInterface = -1; |
|
396 } |
|
397 |
|
398 return iFdf.TokenForInterface(aInterface); |
|
399 } |
|
400 |
|
401 |
|
402 const RArray<TUint>& CFdcProxy::MfpoGetSupportedLanguagesL(TUint aDeviceId) |
|
403 { |
|
404 LOG_FUNC |
|
405 |
|
406 CheckDeviceIdL(aDeviceId); |
|
407 |
|
408 return iFdf.GetSupportedLanguagesL(aDeviceId); |
|
409 } |
|
410 |
|
411 |
|
412 TInt CFdcProxy::MfpoGetManufacturerStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString) |
|
413 { |
|
414 LOG_FUNC |
|
415 |
|
416 TRAPD(err, |
|
417 CheckDeviceIdL(aDeviceId); |
|
418 iFdf.GetManufacturerStringDescriptorL(aDeviceId, aLangId, aString) |
|
419 ); |
|
420 |
|
421 #ifdef __FLOG_ACTIVE |
|
422 if ( !err ) |
|
423 { |
|
424 LOGTEXT2(_L("\taString = \"%S\""), &aString); |
|
425 } |
|
426 #endif |
|
427 LOGTEXT2(_L8("\terr = %d"), err); |
|
428 return err; |
|
429 } |
|
430 |
|
431 |
|
432 TInt CFdcProxy::MfpoGetProductStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString) |
|
433 { |
|
434 LOG_FUNC |
|
435 |
|
436 TRAPD(err, |
|
437 CheckDeviceIdL(aDeviceId); |
|
438 iFdf.GetProductStringDescriptorL(aDeviceId, aLangId, aString) |
|
439 ); |
|
440 |
|
441 #ifdef __FLOG_ACTIVE |
|
442 if ( !err ) |
|
443 { |
|
444 LOGTEXT2(_L("\taString = \"%S\""), &aString); |
|
445 } |
|
446 #endif |
|
447 LOGTEXT2(_L8("\terr = %d"), err); |
|
448 return err; |
|
449 } |
|
450 |
|
451 |
|
452 TInt CFdcProxy::MfpoGetSerialNumberStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString) |
|
453 { |
|
454 LOG_FUNC |
|
455 |
|
456 TRAPD(err, |
|
457 CheckDeviceIdL(aDeviceId); |
|
458 iFdf.GetSerialNumberStringDescriptorL(aDeviceId, aLangId, aString) |
|
459 ); |
|
460 |
|
461 #ifdef __FLOG_ACTIVE |
|
462 if ( !err ) |
|
463 { |
|
464 LOGTEXT2(_L("\taString = \"%S\""), &aString); |
|
465 } |
|
466 #endif |
|
467 LOGTEXT2(_L8("\terr = %d"), err); |
|
468 return err; |
|
469 } |
|
470 |
|
471 /** |
|
472 Leaves with KErrNotFound if aDeviceId is not on our array of device IDs. |
|
473 Used to ensure that FDCs can only request strings etc from devices that are |
|
474 'their business'. |
|
475 */ |
|
476 void CFdcProxy::CheckDeviceIdL(TUint aDeviceId) const |
|
477 { |
|
478 LOG_FUNC |
|
479 LOGTEXT2(_L8("\taDeviceId = %d"), aDeviceId); |
|
480 |
|
481 TBool found = EFalse; |
|
482 const TUint count = iDeviceIds.Count(); |
|
483 for ( TUint i = 0 ; i < count ; ++i ) |
|
484 { |
|
485 if ( iDeviceIds[i] == aDeviceId ) |
|
486 { |
|
487 found = ETrue; |
|
488 break; |
|
489 } |
|
490 } |
|
491 if ( !found ) |
|
492 { |
|
493 LEAVEL(KErrNotFound); |
|
494 } |
|
495 } |
|
496 |
|
497 |