|
1 // Copyright (c) 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 "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: Adheres to the UsbMan USB Class Controller API and talks to mass storage file server |
|
14 // |
|
15 // |
|
16 |
|
17 #include <barsc.h> |
|
18 #include <barsread.h> |
|
19 #include <usb_std.h> |
|
20 #include <cusbclasscontrollerplugin.h> |
|
21 #include <centralrepository.h> |
|
22 #include <usbpammscfile.rsg> |
|
23 #include <data_caging_path_literals.hrh> |
|
24 #include "usbmscfileclasscontroller.h" |
|
25 #include "usbmscfile.h" |
|
26 #include "usbmscfileclasscontroller_crkeys.h" |
|
27 #include "debug.h" |
|
28 |
|
29 // Panic category |
|
30 #ifdef _DEBUG |
|
31 _LIT( KMsCcPanicCategory, "UsbMscFileCc" ); |
|
32 #endif |
|
33 |
|
34 _LIT( KUsbMsResource, "\\private\\101fe1db\\usbpammscfile.rsc" ); |
|
35 |
|
36 /** |
|
37 Panic codes for the USB MSC File Class Controller. |
|
38 */ |
|
39 enum TMscFileCcPanic |
|
40 { |
|
41 //Class called while in an illegal state |
|
42 EBadApiCall = 0, |
|
43 EUnusedFunction = 1, |
|
44 }; |
|
45 |
|
46 |
|
47 static TInt CreateServerProcess() |
|
48 { |
|
49 TRACE_FUNC |
|
50 |
|
51 RProcess server; |
|
52 TInt result = server.Create( KMscFileServerFileName, KNullDesC ); |
|
53 if ( result != KErrNone ) |
|
54 { |
|
55 return result; |
|
56 } |
|
57 |
|
58 TRequestStatus stat; |
|
59 |
|
60 server.Rendezvous( stat ); |
|
61 if ( stat != KRequestPending ) |
|
62 { |
|
63 server.Kill( 0 ); // abort startup |
|
64 } |
|
65 else |
|
66 { |
|
67 server.Resume(); // logon OK - start the server |
|
68 server.SetPriority( EPriorityForeground ); |
|
69 } |
|
70 User::WaitForRequest( stat ); // wait for start or death |
|
71 |
|
72 // we can't use the 'exit reason' if the server panicked as this |
|
73 // is the panic 'reason' and may be '0' which cannot be distinguished |
|
74 // from KErrNone |
|
75 result = ( server.ExitType() == EExitPanic ) ? KErrGeneral : stat.Int(); |
|
76 |
|
77 server.Close(); |
|
78 |
|
79 return result; |
|
80 } |
|
81 |
|
82 /** |
|
83 Start MSC File Server |
|
84 */ |
|
85 static TInt StartServer() |
|
86 { |
|
87 TInt result; |
|
88 |
|
89 TFindServer findMscFileServer( KMscFileServerName ); |
|
90 TFullName name; |
|
91 |
|
92 result = findMscFileServer.Next( name ); |
|
93 if ( result != KErrNone ) |
|
94 { |
|
95 result = CreateServerProcess(); |
|
96 } |
|
97 |
|
98 TRACE_INFO(( _L( "Server process created: %d" ), result )) |
|
99 return result; |
|
100 } |
|
101 |
|
102 /** |
|
103 Constructs a CUsbMscFileClassController object |
|
104 |
|
105 @param aOwner USB Device that owns and manages the class |
|
106 @return A new CUsbMscFileClassController object |
|
107 */ |
|
108 CUsbMscFileClassController* CUsbMscFileClassController::NewL( |
|
109 MUsbClassControllerNotify& aOwner) |
|
110 { |
|
111 TRACE_FUNC |
|
112 |
|
113 CUsbMscFileClassController* r = new (ELeave) CUsbMscFileClassController(aOwner); |
|
114 CleanupStack::PushL(r); |
|
115 r->ConstructL(); |
|
116 CleanupStack::Pop(); |
|
117 return r; |
|
118 } |
|
119 |
|
120 /** |
|
121 Destructor |
|
122 */ |
|
123 CUsbMscFileClassController::~CUsbMscFileClassController() |
|
124 { |
|
125 Cancel(); |
|
126 } |
|
127 |
|
128 /** |
|
129 Constructor. |
|
130 |
|
131 @param aOwner USB Device that owns and manages the class |
|
132 */ |
|
133 CUsbMscFileClassController::CUsbMscFileClassController( |
|
134 MUsbClassControllerNotify& aOwner ) |
|
135 : CUsbClassControllerPlugIn( aOwner, KMsStartupPriority ) |
|
136 { |
|
137 // Intentionally left blank |
|
138 } |
|
139 |
|
140 /** |
|
141 2nd Phase Construction. |
|
142 */ |
|
143 void CUsbMscFileClassController::ConstructL() |
|
144 { |
|
145 TRACE_FUNC |
|
146 |
|
147 ReadMassStorageConfigL(); |
|
148 } |
|
149 |
|
150 /** |
|
151 Called by UsbMan when it wants to start the mass storage class. |
|
152 |
|
153 @param aStatus The caller's request status, filled in with an error code |
|
154 */ |
|
155 void CUsbMscFileClassController::Start( TRequestStatus& aStatus ) |
|
156 { |
|
157 TRACE_FUNC_ENTRY |
|
158 |
|
159 // The service state should always be idle when this function is called |
|
160 // (guaranteed by CUsbSession). |
|
161 __ASSERT_DEBUG( iState == EUsbServiceIdle, |
|
162 User::Panic( KMsCcPanicCategory, EBadApiCall ) ); |
|
163 |
|
164 TRequestStatus* reportStatus = &aStatus; |
|
165 |
|
166 iState = EUsbServiceStarting; |
|
167 |
|
168 TInt ret = StartServer(); |
|
169 if ( ret != KErrNone ) |
|
170 { |
|
171 iState = EUsbServiceIdle; |
|
172 User::RequestComplete( reportStatus, ret ); |
|
173 TRACE_ERROR(( _L( "Error %d Can't start server." ), ret )) |
|
174 return; |
|
175 } |
|
176 |
|
177 TRAP( ret, SetupUnitsL() ); |
|
178 if (ret != KErrNone) |
|
179 { |
|
180 iState = EUsbServiceIdle; |
|
181 User::RequestComplete( reportStatus, ret ); |
|
182 TRACE_ERROR(( _L( "Error %d in SetupUnitsL." ), ret )) |
|
183 return; |
|
184 } |
|
185 |
|
186 |
|
187 // Connect to USB Mass Storage server |
|
188 ret = iMscFile.Connect(); |
|
189 |
|
190 if ( ret != KErrNone ) |
|
191 { |
|
192 iState = EUsbServiceIdle; |
|
193 User::RequestComplete( reportStatus, ret ); |
|
194 TRACE_ERROR(( _L( "Error %d connecting to msc file server" ), ret )) |
|
195 return; |
|
196 } |
|
197 |
|
198 // StartL mass storage device |
|
199 ret = iMscFile.Start( iMsConfig ); |
|
200 |
|
201 if (ret != KErrNone) |
|
202 { |
|
203 iState = EUsbServiceIdle; |
|
204 User::RequestComplete( reportStatus, ret ); |
|
205 TRACE_ERROR(( _L( "Error %d starting msc file server" ), ret )) |
|
206 return; |
|
207 } |
|
208 |
|
209 iState = EUsbServiceStarted; |
|
210 |
|
211 User::RequestComplete(reportStatus, KErrNone); |
|
212 TRACE_FUNC_EXIT |
|
213 } |
|
214 |
|
215 /** |
|
216 Called by UsbMan when it wants to stop the USB ACM class. |
|
217 |
|
218 @param aStatus KErrNone on success or a system wide error code |
|
219 */ |
|
220 void CUsbMscFileClassController::Stop( TRequestStatus& aStatus ) |
|
221 { |
|
222 TRACE_FUNC_ENTRY |
|
223 |
|
224 // The service state should always be started when this function is called |
|
225 // (guaranteed by CUsbSession) |
|
226 __ASSERT_DEBUG( iState == EUsbServiceStarted, |
|
227 User::Panic( KMsCcPanicCategory, EBadApiCall ) ); |
|
228 |
|
229 TRequestStatus* reportStatus = &aStatus; |
|
230 |
|
231 TInt ret = iMscFile.Stop(); |
|
232 |
|
233 if ( ret != KErrNone ) |
|
234 { |
|
235 iState = EUsbServiceStarted; |
|
236 User::RequestComplete( reportStatus, ret ); |
|
237 TRACE_ERROR(( _L( "Error %d stopping msc file server" ), ret )) |
|
238 return; |
|
239 } |
|
240 |
|
241 ret = iMscFile.Shutdown(); |
|
242 if ( ret != KErrNone ) |
|
243 { |
|
244 User::RequestComplete( reportStatus, ret ); |
|
245 TRACE_ERROR(( _L( "Error %d stopping msc file server" ), ret )) |
|
246 } |
|
247 else |
|
248 { |
|
249 User::RequestComplete( reportStatus, KErrNone ); |
|
250 } |
|
251 iMscFile.Close(); |
|
252 |
|
253 iState = EUsbServiceIdle; |
|
254 TRACE_FUNC_EXIT |
|
255 } |
|
256 |
|
257 /** |
|
258 Gets information about the descriptor which this class provides. Never called |
|
259 by usbMan. |
|
260 |
|
261 @param aDescriptorInfo Descriptor info structure filled in by this function |
|
262 */ |
|
263 void CUsbMscFileClassController::GetDescriptorInfo(TUsbDescriptor& /*aDescriptorInfo*/) const |
|
264 { |
|
265 __ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction)); |
|
266 } |
|
267 |
|
268 /** |
|
269 Standard active object RunL. Never called because this class has no |
|
270 asynchronous requests. |
|
271 */ |
|
272 void CUsbMscFileClassController::RunL() |
|
273 { |
|
274 __ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction) ); |
|
275 } |
|
276 |
|
277 /** |
|
278 Standard active object cancellation function. Never called because this |
|
279 class has no asynchronous requests. |
|
280 */ |
|
281 void CUsbMscFileClassController::DoCancel() |
|
282 { |
|
283 __ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction) ); |
|
284 } |
|
285 |
|
286 /** |
|
287 Standard active object error function. Never called because this class has |
|
288 no asynchronous requests, and hence its RunL is never called. |
|
289 |
|
290 @param aError The error code (unused) |
|
291 @return Always KErrNone to avoid an active scheduler panic |
|
292 */ |
|
293 TInt CUsbMscFileClassController::RunError(TInt /*aError*/) |
|
294 { |
|
295 __ASSERT_DEBUG( EFalse, User::Panic(KMsCcPanicCategory, EUnusedFunction) ); |
|
296 return KErrNone; |
|
297 } |
|
298 |
|
299 /** |
|
300 Read mass storage configuration info from the resource file |
|
301 */ |
|
302 void CUsbMscFileClassController::ReadMassStorageConfigL() |
|
303 { |
|
304 TRACE_FUNC_ENTRY |
|
305 |
|
306 // Try to connect to file server |
|
307 RFs fs; |
|
308 LEAVE_IF_ERROR( fs.Connect() ); |
|
309 CleanupClosePushL( fs ); |
|
310 |
|
311 TFileName fileName; |
|
312 const TDriveNumber KResourceDrive = EDriveZ; |
|
313 TDriveUnit driveUnit( KResourceDrive ); |
|
314 TDriveName drive = driveUnit.Name(); |
|
315 fileName.Insert( 0, drive ); |
|
316 |
|
317 fileName += KUsbMsResource; |
|
318 |
|
319 RResourceFile resource; |
|
320 TRAPD( err, resource.OpenL( fs, fileName ) ); |
|
321 |
|
322 if ( err != KErrNone ) |
|
323 { |
|
324 TRACE_ERROR(( _L( "Error %d opening resource file" ), err )) |
|
325 CleanupStack::PopAndDestroy( &fs ); |
|
326 return; |
|
327 } |
|
328 |
|
329 CleanupClosePushL( resource ); |
|
330 |
|
331 resource.ConfirmSignatureL( KUsbMsResourceVersion ); |
|
332 |
|
333 HBufC8* msConfigBuf = 0; |
|
334 TRAPD( ret, msConfigBuf = resource.AllocReadL( USBMS_CONFIG ) ); |
|
335 if ( ret != KErrNone ) |
|
336 { |
|
337 TRACE_ERROR(( _L( "Error %d opening mass storage config" ), ret )) |
|
338 CleanupStack::PopAndDestroy(2, &fs); |
|
339 return; |
|
340 } |
|
341 CleanupStack::PushL( msConfigBuf ); |
|
342 |
|
343 // The format of the USB resource structure is: |
|
344 |
|
345 /* |
|
346 * STRUCT USBMASSSTORAGE_CONFIG |
|
347 * { |
|
348 * LTEXT vendorId; // no more than 8 characters |
|
349 * LTEXT productId; // no more than 16 characters |
|
350 * LTEXT productRev; // no more than 4 characters |
|
351 * }; |
|
352 */ |
|
353 |
|
354 // Note that the resource must be read in this order! |
|
355 |
|
356 TResourceReader reader; |
|
357 reader.SetBuffer( msConfigBuf ); |
|
358 |
|
359 TPtrC vendorId = reader.ReadTPtrC(); |
|
360 TPtrC productId = reader.ReadTPtrC(); |
|
361 TPtrC productRev = reader.ReadTPtrC(); |
|
362 |
|
363 // populate iMsConfig, truncate if exceeding limit |
|
364 ConfigItem( vendorId, iMsConfig.iVendorId, 8 ); |
|
365 ConfigItem( productId, iMsConfig.iProductId, 16 ); |
|
366 ConfigItem( productRev, iMsConfig.iProductRev, 4 ); |
|
367 |
|
368 // Debugging |
|
369 TRACE_INFO(( _L( "vendorId = %s" ), &vendorId )) |
|
370 TRACE_INFO(( _L( "productId = %s" ), &productId )) |
|
371 TRACE_INFO(( _L( "productRev = %s" ), &productRev )) |
|
372 |
|
373 CleanupStack::PopAndDestroy( 3, &fs ); // msConfigBuf, resource, fs |
|
374 TRACE_FUNC_EXIT |
|
375 } |
|
376 |
|
377 /** |
|
378 Utility. Copies the data from TPtr to TBuf and checks data length |
|
379 to make sure the source does not exceed the capacity of the target |
|
380 */ |
|
381 void CUsbMscFileClassController::ConfigItem( const TPtrC& source, |
|
382 TDes& target, |
|
383 TInt maxLength ) |
|
384 { |
|
385 if ( source.Length() < maxLength ) |
|
386 { |
|
387 maxLength = source.Length(); |
|
388 } |
|
389 |
|
390 target.Copy( source.Ptr(), maxLength ); |
|
391 } |
|
392 |
|
393 void CUsbMscFileClassController::SetupUnitsL() |
|
394 { |
|
395 RFs fs; |
|
396 RUsbMscFile mscFile; |
|
397 |
|
398 LEAVE_IF_ERROR( mscFile.Connect() ); |
|
399 CleanupClosePushL( mscFile ); |
|
400 CRepository* repository = CRepository::NewLC(KCRUidUsbPhoneAsModemMscFileClassController); |
|
401 |
|
402 RArray<TUint32> lunKeys; |
|
403 CleanupClosePushL(lunKeys); |
|
404 |
|
405 repository->FindL(KCRMscFileLogicalUnitNumberColumn, KCRMscFileColumnMask, lunKeys); |
|
406 |
|
407 |
|
408 TInt count = lunKeys.Count(); |
|
409 for (TInt i=0; i<count; i++) |
|
410 { |
|
411 TUint32 lunKey = lunKeys[i]; |
|
412 TUint32 fullNameKey = ((lunKey&KCRMscFileRowMask)|KCRMscFileImageFullNameColumn); |
|
413 TRACE_INFO( (_L( "lunKey=%d,fullNameKey=%d" ), lunKey, fullNameKey) ) |
|
414 |
|
415 TInt lun = 0; |
|
416 LEAVE_IF_ERROR(repository->Get(lunKey, lun)); |
|
417 |
|
418 TFileName fullName; |
|
419 LEAVE_IF_ERROR(repository->Get(fullNameKey, fullName)); |
|
420 |
|
421 TRACE_INFO( (_L("lun=%d, fullName=%S"), lun, &fullName) ); |
|
422 |
|
423 TInt protocol = 0; // It is not used. Bulk Transport(0x50), SCSI transparent command Set(0x06), PDT CD/DVD device(0x05) is supported only. |
|
424 |
|
425 LEAVE_IF_ERROR(mscFile.SetupLogicalUnit( fullName, protocol, lun )); |
|
426 } |
|
427 CleanupStack::PopAndDestroy( 3 ); // mscFile, repository, lunKeys |
|
428 } |