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