usbmgmt/usbmgrtest/usbmsapp/usbmsapp.cpp
changeset 0 c9bc50fca66e
equal deleted inserted replaced
-1:000000000000 0:c9bc50fca66e
       
     1 /*
       
     2 * Copyright (c) 2004-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 * USB Mass Storage Sample Application
       
    16 *
       
    17 */
       
    18 
       
    19 /**
       
    20  @file
       
    21  @publishedPartner
       
    22 */
       
    23 
       
    24 #include "usbmsapp.h"
       
    25 
       
    26 #include <e32std.h>
       
    27 #include <e32svr.h>
       
    28 #include <e32cons.h>
       
    29 #include <f32file.h>
       
    30 #include <usbman.h>
       
    31 
       
    32 #include <d32usbc.h>
       
    33 
       
    34 #include <usbmsshared.h>
       
    35 
       
    36 //////////////////////////////////////////////////////////////////////////////
       
    37 
       
    38 _LIT(KTxtApp,"USBMSEXAMPLEAPP");
       
    39 _LIT(KMsFsy, "MSFS.FSY");
       
    40 _LIT(KMsFs, "MassStorageFileSystem");
       
    41 _LIT(KOk,"OK");
       
    42 _LIT(KError,"Error");
       
    43 _LIT(KBytesTransferredFmt, "%c:%d/%d ");
       
    44 _LIT(KErrFmt, "Property not found (%d)\r");
       
    45 _LIT8(KDefPwd,"123");
       
    46 
       
    47 //Mass Storage Device States xRef cedar/generic/base/f32/smassstorage/inc/usbmsshared.h
       
    48 _LIT(KUsbMsDriveStateDisconnected, "Disconnected");
       
    49 _LIT(KUsbMsDriveStateConnecting, "Connecting");
       
    50 _LIT(KUsbMsDriveStateConnected, "Connected");
       
    51 _LIT(KUsbMsDriveStateDisconnecting, "Disconnecting");
       
    52 _LIT(KUsbMsDriveStateActive, "Active");
       
    53 _LIT(KUsbMsDriveStateLocked, "Locked");
       
    54 _LIT(KUsbMsDriveStateMediaNotPresent, "Media Not Present");
       
    55 _LIT(KUsbMsDriveStateRemoved, "Removed");
       
    56 _LIT(KUsbMsDriveStateError, "Error");
       
    57 _LIT(KUsbMsDriveStateUnkown, "Unkown");
       
    58 
       
    59 //Usb Device States
       
    60 _LIT(KEUsbDeviceStateUndefined,"Undefined");
       
    61 _LIT(KEUsbDeviceStateDefault,"Default");
       
    62 _LIT(KEUsbDeviceStateAttached,"Attached");
       
    63 _LIT(KEUsbDeviceStatePowered,"Powered");
       
    64 _LIT(KEUsbDeviceStateConfigured,"Configured");
       
    65 _LIT(KEUsbDeviceStateAddress,"Address");
       
    66 _LIT(KEUsbDeviceStateSuspended ,"Suspended");
       
    67 
       
    68 //////////////////////////////////////////////////////////////////////////////
       
    69 
       
    70 /**
       
    71 Console shared by main routine and active objects.
       
    72 */
       
    73 LOCAL_D CConsoleBase* console = NULL;
       
    74 
       
    75 /**
       
    76 File system resource shared by main routine and active objects.
       
    77 */
       
    78 LOCAL_D RFs fs;
       
    79 
       
    80 /**
       
    81 Currently selected drive, index into PropertyHandlers' objects.
       
    82 */
       
    83 LOCAL_D TInt selectedDriveIndex = 0;
       
    84 
       
    85 /**
       
    86 Command line text buffer, sufficiently large so that it will
       
    87 hold any reasonable input.
       
    88 */
       
    89 LOCAL_D TBuf<0x40> mountList;
       
    90 
       
    91 static TFixedArray<TBool, KMaxDrives>                   msfsMountedList;  ///< 'true' entry corresponds to the drive with mounted MSFS.FSY
       
    92 static TFixedArray<CFileSystemDescriptor*, KMaxDrives>  unmountedFsList;  ///< every non-NULL entry corresponds to the unmounted original FS for the drive
       
    93 
       
    94 /**
       
    95 */
       
    96 LOCAL_D TMediaPassword  password(KDefPwd);
       
    97 
       
    98 //////////////////////////////////////////////////////////////////////////////
       
    99 
       
   100 /**
       
   101 Move cursor to row 'row', column 0.
       
   102 Erase 'count' rows starting with 'row'.
       
   103 */
       
   104 LOCAL_C void Clear(int row, int count=1)
       
   105 	{
       
   106 	_LIT(KBlank,"                                        ");
       
   107 	for(TInt i=0; i<count; i++)
       
   108 		{
       
   109 		console->SetPos(0,row+i);
       
   110 		console->Printf(KBlank);
       
   111 		}
       
   112 	console->SetPos(0,row);
       
   113 	}
       
   114 
       
   115 /**
       
   116 Display the user's drive selection.
       
   117 */
       
   118 LOCAL_C void ShowDriveSelection()
       
   119 	{
       
   120 	Clear(15);
       
   121 	if(PropertyHandlers::allDrivesStatus.Length()/2 > selectedDriveIndex)
       
   122 		{
       
   123 		console->Printf(_L("Selected Drive: %c"),
       
   124 					'A' + PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   125 		}
       
   126 	else
       
   127 		{
       
   128 		console->Printf(_L("Selected Drive: (none)"));
       
   129 		}
       
   130 	}
       
   131 
       
   132 //-----------------------------------------------------------------------------
       
   133 /**
       
   134     Tries to restore the original FS on the drive using the FS descriptor provided
       
   135     @return standard error code.
       
   136 */
       
   137 LOCAL_C TInt DoRestoreFS(RFs& aFs, TInt aDrive, CFileSystemDescriptor* apFsDesc)
       
   138     {
       
   139     TInt nRes;
       
   140     RDebug::Print(_L("# DoRestoreFS drv:%d\n"), aDrive);
       
   141     //-- 1. check that there is no FS installed   
       
   142     TBuf<128>   fsName;
       
   143     nRes = aFs.FileSystemName(fsName, aDrive);
       
   144     if(nRes == KErrNone)
       
   145         {//-- probably no file system installed at all
       
   146         RDebug::Print(_L("# This drive already has FS intalled:%S \n"), &fsName);
       
   147         return KErrAlreadyExists;
       
   148         }
       
   149         
       
   150     TPtrC ptrN  (apFsDesc->FsName());
       
   151     TPtrC ptrExt(apFsDesc->PrimaryExtName());
       
   152     RDebug::Print(_L("# Mounting FS:%S, Prim ext:%S, synch:%d\n"), &ptrN, &ptrExt, apFsDesc->DriveIsSynch());
       
   153 
       
   154     if(ptrExt.Length() >0)
       
   155         {//-- there is a primary extension to be mounted
       
   156         nRes = aFs.AddExtension(ptrExt);
       
   157         if(nRes != KErrNone && nRes != KErrAlreadyExists)
       
   158             {
       
   159             return nRes;
       
   160             }
       
   161 
       
   162         nRes = aFs.MountFileSystem(ptrN, ptrExt, aDrive, apFsDesc->DriveIsSynch());
       
   163         }
       
   164     else
       
   165         {
       
   166         nRes = aFs.MountFileSystem(ptrN, aDrive, apFsDesc->DriveIsSynch());
       
   167         }
       
   168 
       
   169     if(nRes != KErrNone)
       
   170         {
       
   171         RDebug::Print(_L("# Mount failed! code:%d\n"),nRes);    
       
   172         }
       
   173 
       
   174     return nRes;
       
   175     }
       
   176 
       
   177 
       
   178 //-----------------------------------------------------------------------------
       
   179 /**
       
   180     Dismounts the originally mounted FS and optional primary extension from the drive and stores 
       
   181     this information in the FS descriptor
       
   182 
       
   183     @return on success returns a pointer to the instantinated FS descriptor
       
   184 */
       
   185 LOCAL_C CFileSystemDescriptor* DoDismountOrginalFS(RFs& aFs, TInt aDrive)
       
   186     {
       
   187     TInt        nRes;
       
   188     TBuf<128>   fsName;
       
   189     TBuf<128>   primaryExtName;
       
   190     TBool       bDrvSync = EFalse;
       
   191 
       
   192     RDebug::Print(_L("# DoDismountOrginalFS drv:%d\n"), aDrive);
       
   193 
       
   194     //-- 1. get file system name
       
   195     nRes = aFs.FileSystemName(fsName, aDrive);
       
   196     if(nRes != KErrNone)
       
   197         {//-- probably no file system installed at all
       
   198         return NULL;
       
   199         }
       
   200 
       
   201     //-- 2. find out if the drive sync/async
       
   202     TPckgBuf<TBool> drvSyncBuf;
       
   203     nRes = aFs.QueryVolumeInfoExt(aDrive, EIsDriveSync, drvSyncBuf);
       
   204     if(nRes == KErrNone)
       
   205         {
       
   206         bDrvSync = drvSyncBuf();
       
   207         }
       
   208 
       
   209     //-- 3. find out primary extension name if it is present; we will need to add it againt when mounting the FS
       
   210     //-- other extensions (non-primary) are not supported yet
       
   211     nRes = aFs.ExtensionName(primaryExtName, aDrive, 0);
       
   212     if(nRes != KErrNone)
       
   213         {   
       
   214         primaryExtName.SetLength(0);
       
   215         }
       
   216 
       
   217     //-- 3.1 check if the drive has non-primary extensions, fail in this case, because this FS can't be mounted back normally
       
   218     nRes = aFs.ExtensionName(primaryExtName, aDrive, 1);
       
   219     if(nRes == KErrNone)
       
   220         {   
       
   221         RDebug::Print(_L("Non-primary extensions are not supported!\n"));
       
   222         return NULL;
       
   223         }
       
   224 
       
   225     RDebug::Print(_L("# DoDismountOrginalFS FS:%S, Prim ext:%S, synch:%d\n"), &fsName, &primaryExtName, bDrvSync);
       
   226 
       
   227     //-- create FS descriptor and dismount the FS
       
   228     CFileSystemDescriptor* pFsDesc = NULL; 
       
   229     
       
   230     TRAP(nRes, pFsDesc = CFileSystemDescriptor::NewL(fsName, primaryExtName, bDrvSync));
       
   231     if(nRes != KErrNone)
       
   232         return NULL; //-- OOM ?
       
   233 
       
   234     nRes = aFs.DismountFileSystem(fsName, aDrive);
       
   235     if(nRes != KErrNone)
       
   236         {
       
   237         delete pFsDesc;
       
   238         pFsDesc = NULL;
       
   239         RDebug::Print(_L("# DoDismountOrginalFS Dismounting Err:%d\n"), nRes);
       
   240         }
       
   241     
       
   242     return pFsDesc;
       
   243 }
       
   244 
       
   245 /**
       
   246 Unmount FAT and mount MSFS.
       
   247 @param driveNumber
       
   248 */
       
   249 LOCAL_C void MountMsFs(TInt driveNumber)
       
   250 	{
       
   251 	TInt x = console->WhereX();
       
   252 	TInt y = console->WhereY();
       
   253 	Clear(11,2);
       
   254 	RDebug::Print(_L("UsbMsExampleApp::MountMsFs driveNumber=%d\n"), driveNumber);
       
   255 
       
   256 	//-- 1. try dismounting the original FS
       
   257     CFileSystemDescriptor* fsDesc = DoDismountOrginalFS(fs, driveNumber);
       
   258     unmountedFsList[driveNumber] = fsDesc; 
       
   259   
       
   260     if(fsDesc)
       
   261         {
       
   262         TPtrC ptrN(fsDesc->FsName());
       
   263         RDebug::Print(_L("drv:%d FS:%S Dismounted OK"),driveNumber, &ptrN);
       
   264 	   	console->Printf(_L("%S Dismount %c: %S\n"), &ptrN, 'A' + driveNumber, &KOk);
       
   265         }
       
   266     else
       
   267         {
       
   268         RDebug::Print(_L("drv:%d Dismount FS Failed!"),driveNumber);
       
   269         }
       
   270 
       
   271     //-- 2. try to mount the "MSFS"
       
   272     TInt error;
       
   273     error = fs.MountFileSystem(KMsFs, driveNumber);
       
   274 	RDebug::Print(_L("MSFS Mount:   %S (%d)"), (error?&KError:&KOk), error);
       
   275 
       
   276 	if (!error)
       
   277 		msfsMountedList[driveNumber] = ETrue;
       
   278 
       
   279 	// restore console position
       
   280 	console->Printf(_L("MSFS Mount %c:   %S (%d)"), 'A' + driveNumber, (error?&KError:&KOk), error);
       
   281 	console->SetPos(x,y);
       
   282 	}
       
   283 
       
   284 /**
       
   285 Unmount MSFS and mount FAT.
       
   286 @param driveNumber
       
   287 */
       
   288 LOCAL_C TInt RestoreMount(TInt driveNumber)
       
   289 	{
       
   290 	TInt err = KErrNone;
       
   291 	TInt x = console->WhereX();
       
   292 	TInt y = console->WhereY();
       
   293 	Clear(11,2);
       
   294 
       
   295     //-- 1. try dismounting the "MSFS"
       
   296 	if (msfsMountedList[driveNumber])
       
   297 		{
       
   298 		err = fs.DismountFileSystem(KMsFs, driveNumber);
       
   299 		RDebug::Print(_L("MSFS Dismount:%S (%d)"), (err?&KError:&KOk), err);
       
   300 		if (err)
       
   301 			return err;
       
   302 
       
   303 		msfsMountedList[driveNumber] = EFalse;
       
   304 		console->Printf(_L("MSFS Dismount:%S (%d)\n"), (err?&KError:&KOk), err);
       
   305         }
       
   306 
       
   307     //-- 2. try to mount the original FS back
       
   308     CFileSystemDescriptor* fsDesc = unmountedFsList[driveNumber];
       
   309     if(fsDesc)
       
   310         {
       
   311         err = DoRestoreFS(fs, driveNumber, fsDesc);
       
   312 
       
   313         TPtrC ptrN(fsDesc->FsName());
       
   314         RDebug::Print(_L("%S Mount:    %S (%d)"), &ptrN, (err?&KError:&KOk), err);      
       
   315         delete fsDesc;
       
   316         unmountedFsList[driveNumber] = NULL;
       
   317        	console->Printf(_L("FAT Mount:    %S (%d)"), (err?&KError:&KOk), err);
       
   318         }
       
   319    
       
   320     // restore console position
       
   321 	console->SetPos(x,y);
       
   322 	return err;
       
   323 	}
       
   324 
       
   325 /**
       
   326 Return a string description of the Drive Status
       
   327 @param DriveStatus
       
   328 @return a descriptor containing the description of the Drive Status
       
   329  */
       
   330 LOCAL_C const TDesC& DriveStatusDescription(TInt & aDriveStatus)
       
   331   {
       
   332  	switch(aDriveStatus)
       
   333 		{
       
   334 		case EUsbMsDriveState_Disconnected:
       
   335 			return KUsbMsDriveStateDisconnected;
       
   336 
       
   337 		case EUsbMsDriveState_Connecting:
       
   338 			return KUsbMsDriveStateConnecting;
       
   339 
       
   340 		case EUsbMsDriveState_Connected:
       
   341 			return KUsbMsDriveStateConnected;
       
   342 
       
   343 		case EUsbMsDriveState_Disconnecting:
       
   344 			return KUsbMsDriveStateDisconnecting;
       
   345 
       
   346 		case EUsbMsDriveState_Active:
       
   347 			return KUsbMsDriveStateActive;
       
   348 
       
   349 		case EUsbMsDriveState_Locked:
       
   350 			return KUsbMsDriveStateLocked;
       
   351 
       
   352 		case EUsbMsDriveState_MediaNotPresent:
       
   353 			return KUsbMsDriveStateMediaNotPresent;
       
   354 
       
   355 		case EUsbMsDriveState_Removed:
       
   356 			return KUsbMsDriveStateRemoved;
       
   357 
       
   358 		case EUsbMsDriveState_Error:
       
   359 			return KUsbMsDriveStateError;
       
   360 
       
   361 		default :
       
   362 			return KUsbMsDriveStateUnkown;
       
   363 
       
   364 		}
       
   365   }
       
   366 
       
   367 /**
       
   368 Return a string description of the Usb Device State
       
   369 @param aUsbState Usb Device State
       
   370 @return the descriptor containing the device state description
       
   371  */
       
   372 LOCAL_C const TDesC& UsbStateDescription(TUsbDeviceState& aUsbState)
       
   373   {
       
   374 	switch(aUsbState)
       
   375 		{
       
   376 		case EUsbDeviceStateDefault:
       
   377 			return KEUsbDeviceStateDefault;
       
   378 
       
   379 		case EUsbDeviceStateAttached:
       
   380 			return KEUsbDeviceStateAttached;
       
   381 
       
   382 		case EUsbDeviceStatePowered:
       
   383 			return KEUsbDeviceStatePowered;
       
   384 
       
   385 		case EUsbDeviceStateConfigured:
       
   386 			return KEUsbDeviceStateConfigured;
       
   387 
       
   388 		case EUsbDeviceStateAddress:
       
   389 			return KEUsbDeviceStateAddress;
       
   390 
       
   391  		case  EUsbDeviceStateSuspended:
       
   392 			return KEUsbDeviceStateSuspended;
       
   393 
       
   394 		case EUsbDeviceStateUndefined:
       
   395 		default :
       
   396 			return KEUsbDeviceStateUndefined;
       
   397 		}
       
   398 
       
   399   }
       
   400 
       
   401 //////////////////////////////////////////////////////////////////////////////
       
   402 
       
   403 CPropertyWatch* CPropertyWatch::NewLC(TUsbMsDriveState_Subkey aSubkey, PropertyHandlers::THandler aHandler)
       
   404 	{
       
   405 	CPropertyWatch* me=new(ELeave) CPropertyWatch(aHandler);
       
   406 	CleanupStack::PushL(me);
       
   407 	me->ConstructL(aSubkey);
       
   408 	return me;
       
   409 	}
       
   410 
       
   411 CPropertyWatch::CPropertyWatch(PropertyHandlers::THandler aHandler)
       
   412 	: CActive(0), iHandler(aHandler)
       
   413 	{}
       
   414 
       
   415 void CPropertyWatch::ConstructL(TUsbMsDriveState_Subkey aSubkey)
       
   416 	{
       
   417 	User::LeaveIfError(iProperty.Attach(KUsbMsDriveState_Category, aSubkey));
       
   418 	CActiveScheduler::Add(this);
       
   419 	// initial subscription and process current property value
       
   420 	RunL();
       
   421 	}
       
   422 
       
   423 CPropertyWatch::~CPropertyWatch()
       
   424 	{
       
   425 	Cancel();
       
   426 	iProperty.Close();
       
   427 	}
       
   428 
       
   429 void CPropertyWatch::DoCancel()
       
   430 	{
       
   431 	iProperty.Cancel();
       
   432 	}
       
   433 
       
   434 void CPropertyWatch::RunL()
       
   435 	{
       
   436 	// resubscribe before processing new value to prevent missing updates
       
   437 	iProperty.Subscribe(iStatus);
       
   438 	SetActive();
       
   439 
       
   440 	iHandler(iProperty);
       
   441 	}
       
   442 
       
   443 //////////////////////////////////////////////////////////////////////////////
       
   444 
       
   445 CUsbWatch* CUsbWatch::NewLC(RUsb& aUsb)
       
   446 	{
       
   447 	CUsbWatch* me=new(ELeave) CUsbWatch(aUsb);
       
   448 	CleanupStack::PushL(me);
       
   449 	me->ConstructL();
       
   450 	return me;
       
   451 	}
       
   452 
       
   453 CUsbWatch::CUsbWatch(RUsb& aUsb)
       
   454 	:
       
   455 	CActive(0),
       
   456 	iUsb(aUsb),
       
   457 	iUsbDeviceState(EUsbDeviceStateUndefined),
       
   458 	iIsConfigured(EFalse)
       
   459 	{}
       
   460 
       
   461 void CUsbWatch::ConstructL()
       
   462 	{
       
   463 	CActiveScheduler::Add(this);
       
   464 	RunL();
       
   465 	}
       
   466 
       
   467 CUsbWatch::~CUsbWatch()
       
   468 	{
       
   469 	Cancel();
       
   470 	}
       
   471 
       
   472 void CUsbWatch::DoCancel()
       
   473 	{
       
   474 	iUsb.DeviceStateNotificationCancel();
       
   475 	}
       
   476 
       
   477 static TBool IsDriveConnected(TInt driveStatusIndex)
       
   478 	{
       
   479 	TInt driveStatus = PropertyHandlers::allDrivesStatus[2*driveStatusIndex+1];
       
   480 	return driveStatus == EUsbMsDriveState_Connected
       
   481 		|| driveStatus >= EUsbMsDriveState_Active;
       
   482 	}
       
   483 
       
   484 static TChar DriveNumberToLetter(TInt driveNumber)
       
   485 	{
       
   486 	TChar driveLetter = '?';
       
   487 	fs.DriveToChar(driveNumber, driveLetter);
       
   488 	return driveLetter;
       
   489 	}
       
   490 
       
   491 static TBool IsDriveInMountList(TUint driveLetter)
       
   492 	{
       
   493 	TUint16 driveLetter16 = static_cast<TUint16>(driveLetter);
       
   494 	return(!mountList.Length() || KErrNotFound != mountList.Find(&driveLetter16, 1));
       
   495 	}
       
   496 
       
   497 void CUsbWatch::RunL()
       
   498 	{
       
   499 	RDebug::Print(_L("CUsbWatch DeviceStateNotification: iUsbDeviceState=%d %s"), iUsbDeviceState, &UsbStateDescription(iUsbDeviceState));
       
   500 
       
   501 	// If the cable is disconnected, unmount all the connected drives.
       
   502 	if(iIsConfigured && (iUsbDeviceState == EUsbDeviceStateUndefined))
       
   503 		{
       
   504 		for(TInt i=0; i<PropertyHandlers::allDrivesStatus.Length()/2; i++)
       
   505 			{
       
   506 			if(IsDriveConnected(i))
       
   507 				{
       
   508 				RDebug::Print(_L("CUsbWatch calling UnmountMsFs"));
       
   509 				RestoreMount(PropertyHandlers::allDrivesStatus[2*i]);
       
   510 				}
       
   511 			}
       
   512 
       
   513 		iIsConfigured = EFalse;
       
   514 		}
       
   515 
       
   516   	if(iUsbDeviceState == EUsbDeviceStateConfigured)
       
   517   		{
       
   518   		iIsConfigured = ETrue;
       
   519   		}
       
   520 
       
   521 	const TUint stateMask = 0xFF;
       
   522 	iUsb.DeviceStateNotification(stateMask, iUsbDeviceState, iStatus);
       
   523 	SetActive();
       
   524 	}
       
   525 
       
   526 //////////////////////////////////////////////////////////////////////////////
       
   527 
       
   528 TUsbMsDrivesStatus PropertyHandlers::allDrivesStatus;
       
   529 TUsbMsBytesTransferred PropertyHandlers::iKBytesRead;
       
   530 TUsbMsBytesTransferred PropertyHandlers::iKBytesWritten;
       
   531 
       
   532 /**
       
   533 Handle a publish event for the Bytes Read property.
       
   534 */
       
   535 void PropertyHandlers::Read(RProperty& aProperty)
       
   536 	{
       
   537 	Transferred(aProperty, iKBytesRead);
       
   538 	}
       
   539 
       
   540 /**
       
   541 Handle a publish event for the Bytes Written property.
       
   542 */
       
   543 void PropertyHandlers::Written(RProperty& aProperty)
       
   544 	{
       
   545 	Transferred(aProperty, iKBytesWritten);
       
   546 	}
       
   547 
       
   548 /**
       
   549 Helper function for Read and Written
       
   550 */
       
   551 void PropertyHandlers::Transferred(RProperty& aProperty, TUsbMsBytesTransferred& aReadOrWritten)
       
   552 	{
       
   553 	console->SetPos(0,1);
       
   554 	console->Printf(_L("KB R/W:  "));
       
   555 	TInt err = aProperty.Get(aReadOrWritten);
       
   556 	if(err == KErrNone)
       
   557 		{
       
   558 		for(TInt i=0; i<allDrivesStatus.Length()/2; i++)
       
   559 			{
       
   560 			console->Printf(KBytesTransferredFmt,
       
   561 				static_cast<char>(DriveNumberToLetter(allDrivesStatus[2*i])), iKBytesRead[i], iKBytesWritten[i]);
       
   562 			}
       
   563 		}
       
   564 	else
       
   565 		{
       
   566 		console->Printf(KErrFmt, err);
       
   567 		}
       
   568 	}
       
   569 
       
   570 /**
       
   571 Handle a publish event for the Drive Status property.
       
   572 */
       
   573 void PropertyHandlers::DriveStatus(RProperty& aProperty)
       
   574 	{
       
   575 	RDebug::Print(_L(">> PropertyHandlers::DriveStatus"));
       
   576 	TInt err = aProperty.Get(allDrivesStatus);
       
   577 	console->SetPos(0,0);
       
   578 	if(err == KErrNone)
       
   579 		{
       
   580 		TInt numDrives = allDrivesStatus.Length()/2;
       
   581 		console->Printf(_L("Status:  "));
       
   582 		for(TInt i=0; i<numDrives; i++)
       
   583 			{
       
   584 			TInt driveNumber = allDrivesStatus[2*i];
       
   585 			TInt driveStatus = allDrivesStatus[2*i+1];
       
   586 			TChar driveLetter = DriveNumberToLetter(driveNumber);
       
   587 
       
   588 
       
   589 			RDebug::Print(_L("PropertyHandlers::DriveStatus: drive %c: = %d %S"),
       
   590 						static_cast<char>(driveLetter), driveStatus, &DriveStatusDescription(driveStatus));
       
   591 			console->Printf(_L("%c:%d %S          "), static_cast<char>(driveLetter), driveStatus, &DriveStatusDescription(driveStatus));
       
   592 
       
   593 			if(IsDriveInMountList(driveLetter))
       
   594 				{
       
   595 				if(driveStatus == EUsbMsDriveState_Connecting)
       
   596 					{
       
   597 					MountMsFs(driveNumber);
       
   598 					}
       
   599 				else if(driveStatus == EUsbMsDriveState_Disconnected)
       
   600 					{
       
   601 					RestoreMount(driveNumber);
       
   602 					}
       
   603 				else
       
   604 					{
       
   605 					RDebug::Print(_L("PropertyHandlers::DriveStatus: nothing to do"));
       
   606 					}
       
   607 				}
       
   608 			else
       
   609 				{
       
   610 				RDebug::Print(_L("PropertyHandlers::DriveStatus: %c: is not in mountList\n"),
       
   611 				(TUint) driveLetter);
       
   612 				}
       
   613 			}
       
   614 		}
       
   615 	else
       
   616 		{
       
   617 		console->Printf(KErrFmt, err);
       
   618 		}
       
   619 
       
   620 	RDebug::Print(_L("<< PropertyHandlers::DriveStatus"));
       
   621 	}
       
   622 
       
   623 //////////////////////////////////////////////////////////////////////////////
       
   624 
       
   625 CMessageKeyProcessor::CMessageKeyProcessor(CConsoleBase* aConsole)
       
   626 	: CActive(CActive::EPriorityUserInput), iConsole(aConsole)
       
   627 	{
       
   628 	}
       
   629 
       
   630 CMessageKeyProcessor* CMessageKeyProcessor::NewLC(CConsoleBase* aConsole
       
   631 												 )
       
   632 	{
       
   633 	CMessageKeyProcessor* self=new (ELeave) CMessageKeyProcessor(aConsole);
       
   634 	CleanupStack::PushL(self);
       
   635 	self->ConstructL();
       
   636 	return self;
       
   637 	}
       
   638 
       
   639 CMessageKeyProcessor* CMessageKeyProcessor::NewL(CConsoleBase* aConsole
       
   640 												)
       
   641 	{
       
   642 	CMessageKeyProcessor* self = NewLC(aConsole);
       
   643 	CleanupStack::Pop();
       
   644 	return self;
       
   645 	}
       
   646 
       
   647 void CMessageKeyProcessor::ConstructL()
       
   648 	{
       
   649 	// Add to active scheduler
       
   650 	CActiveScheduler::Add(this);
       
   651 	RequestCharacter();
       
   652 	}
       
   653 
       
   654 
       
   655 CMessageKeyProcessor::~CMessageKeyProcessor()
       
   656 	{
       
   657 	// Make sure we're cancelled
       
   658 	Cancel();
       
   659 	}
       
   660 
       
   661 void  CMessageKeyProcessor::DoCancel()
       
   662 	{
       
   663 	iConsole->ReadCancel();
       
   664 	}
       
   665 
       
   666 void  CMessageKeyProcessor::RunL()
       
   667 	{
       
   668 	  // Handle completed request
       
   669 	ProcessKeyPress(TChar(iConsole->KeyCode()));
       
   670 	}
       
   671 
       
   672 void CMessageKeyProcessor::RequestCharacter()
       
   673 	{
       
   674 	  // A request is issued to the CConsoleBase to accept a
       
   675 	  // character from the keyboard.
       
   676 	iConsole->Read(iStatus);
       
   677 	SetActive();
       
   678 	}
       
   679 
       
   680 void CMessageKeyProcessor::ProcessKeyPress(TChar aChar)
       
   681 	{
       
   682 	TInt error = KErrNone;
       
   683 
       
   684 	aChar.UpperCase();
       
   685 	switch(aChar)
       
   686 		{
       
   687 		case 'Q':
       
   688 		case EKeyEscape:
       
   689 			for(TInt j=0; j<KMaxDrives; j++)
       
   690 				{
       
   691 				error = RestoreMount(j);
       
   692 				if (error)
       
   693 					{
       
   694 					// Mount is busy/locked and can not be restored.
       
   695 					break;
       
   696 					}
       
   697 				}
       
   698 			CActiveScheduler::Stop();
       
   699 			return;
       
   700 
       
   701 		case 'D':
       
   702 			if(++selectedDriveIndex >= PropertyHandlers::allDrivesStatus.Length()/2)
       
   703 				{
       
   704 				selectedDriveIndex = 0;
       
   705 				}
       
   706 			ShowDriveSelection();
       
   707 			break;
       
   708 
       
   709 		case 'M':
       
   710 			if(PropertyHandlers::allDrivesStatus.Length())
       
   711 				{
       
   712 				MountMsFs(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   713 				}
       
   714 			break;
       
   715 
       
   716 		case 'U':
       
   717 			if(PropertyHandlers::allDrivesStatus.Length())
       
   718 				{
       
   719 				RestoreMount(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   720 				}
       
   721 			break;
       
   722 
       
   723 		case 'L':
       
   724 			{
       
   725 			_LIT(KEmpty, "");
       
   726 			TMediaPassword nul;
       
   727 			nul.Copy(KEmpty);
       
   728 			error = fs.LockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   729 				nul, password, ETrue);
       
   730 			console->SetPos(0,9);
       
   731 			console->Printf(_L("LockDrive %S (%d)"), (error?&KError:&KOk), error);
       
   732 			break;
       
   733 			}
       
   734 
       
   735 		case 'N':
       
   736 			error = fs.UnlockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   737 				password, ETrue);
       
   738 			Clear(9);
       
   739 			console->Printf(_L("UnlockDrive %S (%d)"), (error?&KError:&KOk), error);
       
   740 			break;
       
   741 
       
   742 		case 'C':
       
   743 			error = fs.ClearPassword(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   744 				password);
       
   745 			Clear(9);
       
   746 			console->Printf(_L("ClearPassword %S (%d)"), (error?&KError:&KOk), error);
       
   747 			break;
       
   748 		}
       
   749 	RequestCharacter();
       
   750 	}
       
   751 
       
   752 
       
   753 //-----------------------------------------------------------------------------
       
   754 
       
   755 CFileSystemDescriptor::~CFileSystemDescriptor()
       
   756     {
       
   757     iFsName.Close();
       
   758     iPrimaryExtName.Close();
       
   759     }
       
   760 
       
   761 //-----------------------------------------------------------------------------
       
   762 CFileSystemDescriptor* CFileSystemDescriptor::NewL(const TDesC& aFsName, const TDesC& aPrimaryExtName, TBool aDrvSynch)
       
   763     {
       
   764     CFileSystemDescriptor* pSelf = new (ELeave) CFileSystemDescriptor;
       
   765 
       
   766     CleanupStack::PushL(pSelf);
       
   767     
       
   768     pSelf->iFsName.CreateMaxL(aFsName.Length());
       
   769     pSelf->iFsName.Copy(aFsName);
       
   770     
       
   771     pSelf->iPrimaryExtName.CreateMaxL(aPrimaryExtName.Length());
       
   772     pSelf->iPrimaryExtName.Copy(aPrimaryExtName);
       
   773 
       
   774     pSelf->iDriveSynch = aDrvSynch;
       
   775 
       
   776     CleanupStack::Pop();
       
   777 
       
   778     return pSelf;
       
   779     }
       
   780 
       
   781 
       
   782 
       
   783 
       
   784 
       
   785 
       
   786 
       
   787 
       
   788 //////////////////////////////////////////////////////////////////////////////
       
   789 
       
   790 /**
       
   791 Initialize mass storage. Enter Active Scheduler. Shutdown mass storage.
       
   792 */
       
   793 LOCAL_C void RunAppL()
       
   794 	{
       
   795     TInt error = KErrUnknown;
       
   796 	TRequestStatus status;
       
   797 
       
   798 	PropertyHandlers::allDrivesStatus.Fill(0);
       
   799 
       
   800 	RDebug::Print(_L("USBMSEXAMPLEAPP: Creating console\n"));
       
   801 	console = Console::NewL(KTxtApp,TSize(KConsFullScreen,KConsFullScreen));
       
   802 	CleanupStack::PushL(console);
       
   803 
       
   804 	console->SetPos(0,2);
       
   805 	console->Printf(_L("========================================"));
       
   806 
       
   807 	RDebug::Print(_L("USBMSEXAMPLEAPP: Getting CommandLine\n"));
       
   808 	// Command line: list of drive letters to auto-mount (all if not specified)
       
   809 	User::CommandLine(mountList);
       
   810 	mountList.UpperCase();
       
   811 
       
   812 	RDebug::Print(_L("USBMSEXAMPLEAPP: Creating CActiveScheduler\n"));
       
   813 	CActiveScheduler* sched = new(ELeave) CActiveScheduler;
       
   814 	CleanupStack::PushL(sched);
       
   815 	CActiveScheduler::Install(sched);
       
   816 
       
   817 	RDebug::Print(_L("USBMSEXAMPLEAPP: Connecting to file system\n"));
       
   818 	User::LeaveIfError(fs.Connect());
       
   819 	CleanupClosePushL(fs);
       
   820 
       
   821 	_LIT(KMountAllDefault,"(all)");
       
   822 	console->SetPos(0,3);
       
   823 	console->Printf(_L("Drives to auto-mount: %S"),
       
   824 		(mountList.Length() ? &mountList : &KMountAllDefault));
       
   825 
       
   826 #if defined(__WINS__)
       
   827 	_LIT(KDriverFileName,"TESTUSBC.LDD");
       
   828 	error = User::LoadLogicalDevice(KDriverFileName);
       
   829 	console->SetPos(0,4);
       
   830 	console->Printf(_L("Load %S: %S (%d)"),
       
   831 				&KDriverFileName, (error?&KError:&KOk), error);
       
   832 #endif
       
   833 
       
   834 	console->SetPos(0,5);
       
   835 	RDebug::Print(_L("USBMSEXAMPLEAPP: Add MS file system\n"));
       
   836 	// Add MS file system
       
   837 	error = fs.AddFileSystem(KMsFsy);
       
   838 	console->Printf(_L("Add MS File System: %S (%d)"),
       
   839 				(error?&KError:&KOk), error);
       
   840 
       
   841 	RUsb usb;
       
   842 	error = usb.Connect();
       
   843 	User::LeaveIfError(error);
       
   844 	CleanupClosePushL(usb);
       
   845 
       
   846 	console->SetPos(0,6);
       
   847 	RDebug::Print(_L("USBMSEXAMPLEAPP: Find the class controller\n"));
       
   848 
       
   849     // Find the personality that supports the massstorage uid
       
   850 	TInt personalityId=-1;
       
   851 	RArray<TInt> personalityIds;
       
   852 	usb.GetPersonalityIds(personalityIds);
       
   853 	for (TInt i=0; i < personalityIds.Count(); i++)
       
   854 	    {
       
   855     	TBool supported=EFalse;
       
   856         User::LeaveIfError(usb.ClassSupported(personalityIds[i], KUsbMsClassControllerUID, supported));
       
   857 
       
   858         HBufC* localizedPersonalityDescriptor;
       
   859         User::LeaveIfError(usb.GetDescription(personalityIds[i],localizedPersonalityDescriptor));
       
   860         console->Printf(_L("USB Personality id=%d - '%S' %s\n"),
       
   861         	personalityIds[i], localizedPersonalityDescriptor,
       
   862         	supported?_S("*"):_S(""));
       
   863 
       
   864         if(supported)
       
   865         	{
       
   866         	personalityId = personalityIds[i];
       
   867         	}
       
   868         delete localizedPersonalityDescriptor;
       
   869 		}
       
   870 	personalityIds.Close();
       
   871 
       
   872 	if(personalityId != -1)
       
   873 		{
       
   874 		RDebug::Print(_L("USBMSEXAMPLEAPP: Start USB\n"));
       
   875 		usb.TryStart(personalityId, status);
       
   876 		User::WaitForRequest(status);
       
   877 		if(status.Int() != KErrNone)
       
   878 			{
       
   879 			console->Printf(_L("USB Service failed to start (%d)"), status.Int());
       
   880 			}
       
   881 		else
       
   882 			{
       
   883 			TUsbServiceState currentState;
       
   884 			User::LeaveIfError(usb.GetServiceState(currentState));
       
   885 			if(EUsbServiceStarted != currentState)
       
   886 				{
       
   887 				console->Printf(_L("USB Service failed to enter EUsbServiceStarted"));
       
   888 				User::Leave(KErrUnknown);
       
   889 				}
       
   890 			console->Printf(_L("USB Service Started, personality id=%d"), personalityId);
       
   891 			}
       
   892 		}
       
   893 	else
       
   894 		{
       
   895 		console->Printf(_L("USBMS class controller not found"));
       
   896 		}
       
   897 
       
   898     console->SetPos(0,14);
       
   899     TBuf16<8> lpwd;
       
   900     lpwd.Copy(password);
       
   901     console->Printf(_L("Password: %S"), &lpwd);
       
   902 
       
   903     RDebug::Print(_L("USBMSEXAMPLEAPP: Create active objects\n"));
       
   904 
       
   905 	CMessageKeyProcessor::NewLC(console);
       
   906 	CPropertyWatch::NewLC(EUsbMsDriveState_KBytesRead, PropertyHandlers::Read);
       
   907 	CPropertyWatch::NewLC(EUsbMsDriveState_KBytesWritten, PropertyHandlers::Written);
       
   908 	CPropertyWatch::NewLC(EUsbMsDriveState_DriveStatus, PropertyHandlers::DriveStatus);
       
   909 	CUsbWatch::NewLC(usb);
       
   910 
       
   911 	ShowDriveSelection();
       
   912 
       
   913 	console->SetPos(0,16);
       
   914 	_LIT(KMsgTitleB,"Menu: q=quit d=chg drv m=mount u=unmount\n      l=lock n=unlock c=clr pwd");
       
   915 	console->Printf(KMsgTitleB);
       
   916 
       
   917 	RDebug::Print(_L("USBMSEXAMPLEAPP: Start CActiveScheduler\n"));
       
   918 	CActiveScheduler::Start();
       
   919 
       
   920 	RDebug::Print(_L("Shutting down. Unmounting all mounted drives\n"));
       
   921 
       
   922 	for(TInt j=0; j<PropertyHandlers::allDrivesStatus.Length()/2; j++)
       
   923 		{
       
   924 		if(IsDriveConnected(j))
       
   925 			{
       
   926 			RestoreMount(PropertyHandlers::allDrivesStatus[2*j]);
       
   927 			}
       
   928 		}
       
   929 
       
   930 	usb.TryStop(status);
       
   931 	User::WaitForRequest(status);
       
   932 	RDebug::Print(_L("USB TryStop returned %d\n"), status.Int());
       
   933 
       
   934 	error = fs.RemoveFileSystem(KMsFs);
       
   935 	RDebug::Print(_L("RemoveFileSystem returned %d\n"), error);
       
   936 
       
   937 #if defined(__WINS__)
       
   938 	error = User::FreeLogicalDevice(KDriverFileName);
       
   939 	RDebug::Print(_L("FreeLogicalDevice returned %d\n"), error);
       
   940 #endif
       
   941 
       
   942 	CleanupStack::PopAndDestroy();	// CUsbWatch
       
   943 	CleanupStack::PopAndDestroy();	// CPropertyWatch
       
   944 	CleanupStack::PopAndDestroy();	// CPropertyWatch
       
   945 	CleanupStack::PopAndDestroy();	// CPropertyWatch
       
   946 	CleanupStack::PopAndDestroy();	// CMessageKeyProcessor
       
   947 	CleanupStack::PopAndDestroy(&usb);
       
   948 	CleanupStack::PopAndDestroy(&fs);
       
   949 	CleanupStack::PopAndDestroy(sched);
       
   950 	CleanupStack::PopAndDestroy(console);
       
   951 	}
       
   952 
       
   953 
       
   954 /**
       
   955 Application entry point.
       
   956 */
       
   957 GLDEF_C TInt E32Main()
       
   958 	{
       
   959 	__UHEAP_MARK;
       
   960 	CTrapCleanup* cleanup=CTrapCleanup::New();
       
   961 
       
   962 	TRAPD(error,RunAppL());
       
   963 	__ASSERT_ALWAYS(!error, User::Panic(KTxtApp, error));
       
   964 
       
   965 	delete cleanup;
       
   966 	__UHEAP_MARKEND;
       
   967 	return 0;
       
   968 	}