kerneltest/f32test/shostmassstorage/testclient/usbtestclient/usbtestclient.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     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 the License "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 // USB Mass Storage Application - also used as an improvised boot loader mechanism
       
    15 // 
       
    16 //
       
    17 
       
    18 
       
    19 
       
    20 /**
       
    21  @file
       
    22 */
       
    23 
       
    24 #include "usbtestclient.h"
       
    25 
       
    26 #include <e32std.h>
       
    27 #include <e32svr.h>
       
    28 #include <e32cons.h>
       
    29 
       
    30 #include <usbmsshared.h>
       
    31 
       
    32 #include <d32usbc.h>
       
    33 #include <d32otgdi.h>
       
    34 
       
    35 #include <nkern/nk_trace.h>
       
    36 #include <hal.h>
       
    37 
       
    38 #include "rusbmassstorage.h"
       
    39 
       
    40 enum
       
    41 	{
       
    42 	EUsbDeviceStateUndefined  = EUsbcDeviceStateUndefined,
       
    43 	EUsbDeviceStateConfigured = EUsbcDeviceStateConfigured,
       
    44 	};
       
    45 
       
    46 static CConsoleBase* console = NULL;
       
    47 static RFs fs;
       
    48 static TInt selectedDriveIndex = 0;
       
    49 static TBuf<0x40> mountList;
       
    50 
       
    51 static TFixedArray<TBool, KMaxDrives>                   msfsMountedList;  ///< 'true' entry corresponds to the drive with mounted MSFS.FSY
       
    52 static TFixedArray<CFileSystemDescriptor*, KMaxDrives>  unmountedFsList;  ///< every non-NULL entry corresponds to the unmounted original FS for the drive
       
    53 
       
    54 _LIT(KMsFsy, "USBTESTMSCLIENT.FSY");
       
    55 _LIT(KMsFs, "MassStorageFileSystem");
       
    56 _LIT(KOk,"OK");
       
    57 _LIT(KError,"Error");
       
    58 _LIT(KBytesTransferredFmt, "%c:%d/%d ");
       
    59 _LIT(KErrFmt, "Error: %d\r");
       
    60 
       
    61 _LIT(KTxtApp,"USB TEST CLIENT");
       
    62 _LIT(KDefPwd,"123");
       
    63 
       
    64 //-- if defined, some useful information will be printed out via RDebug interface
       
    65 //#define LOGGING_ENABLED
       
    66 
       
    67 //-----------------------------------------------------------------------------
       
    68 /**
       
    69     prints a line to the console and copies it to the debug log if LOGGING_ENABLED
       
    70 */
       
    71 void LogPrint(TRefByValue<const TDesC> aFmt,...)
       
    72     {
       
    73     VA_LIST list;
       
    74     VA_START(list, aFmt);
       
    75 
       
    76     TBuf<0x100> buf;
       
    77     buf.FormatList(aFmt, list); //-- ignore overflows
       
    78 
       
    79     if(console)
       
    80         console->Write(buf);
       
    81 
       
    82 #ifdef LOGGING_ENABLED
       
    83     //-- print out the line via RDebug::Print
       
    84     const TInt bufLen = buf.Length();
       
    85     if(bufLen >0 && buf[bufLen-1] == '\n')
       
    86         {
       
    87         buf.Insert(bufLen-1, _L("\r"));
       
    88         }
       
    89     else
       
    90         {
       
    91         buf.Append(_L("\r\n"));
       
    92         }
       
    93 
       
    94     RDebug::RawPrint(buf);
       
    95 #endif
       
    96     }
       
    97 
       
    98 //-----------------------------------------------------------------------------
       
    99 /**
       
   100     prints a line to the debug log if LOGGING_ENABLED
       
   101 */
       
   102 void Log(TRefByValue<const TDesC> aFmt,...)
       
   103     {
       
   104 #ifdef LOGGING_ENABLED
       
   105 
       
   106     VA_LIST list;
       
   107     VA_START(list, aFmt);
       
   108 
       
   109     TBuf<0x100> buf;
       
   110     buf.FormatList(aFmt, list); //-- ignore overflows
       
   111 
       
   112     //-- print out the line via RDebug::Print
       
   113     const TInt bufLen = buf.Length();
       
   114     if(bufLen >0 && buf[bufLen-1] == '\n')
       
   115         {
       
   116         buf.Insert(bufLen-1, _L("\r"));
       
   117         }
       
   118 
       
   119     RDebug::RawPrint(buf);
       
   120 #else
       
   121     (void)aFmt;
       
   122 #endif
       
   123     }
       
   124 
       
   125 
       
   126 //-----------------------------------------------------------------------------
       
   127 
       
   128 static void Clear(int row, int count=1)
       
   129 	{
       
   130 	_LIT(KBlank,"                                        ");
       
   131 	for(TInt i=0; i<count; i++)
       
   132 		{
       
   133 		console->SetPos(0,row+i);
       
   134 		console->Printf(KBlank);
       
   135 		}
       
   136 	console->SetPos(0,row);
       
   137 	}
       
   138 
       
   139 
       
   140 static void ShowDriveSelection()
       
   141 	{
       
   142 	console->SetPos(0,15);
       
   143 	if(PropertyHandlers::allDrivesStatus.Length()/2 > selectedDriveIndex)
       
   144 		{
       
   145 		LogPrint(_L("Selected Drive: %c"), 'A' + PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   146 		}
       
   147 	else
       
   148 		{
       
   149 		LogPrint(_L("Selected Drive: (none)"));
       
   150 		}
       
   151 	}
       
   152 
       
   153 
       
   154 
       
   155 class CPeriodUpdate : public CActive
       
   156 	{
       
   157 public:
       
   158 	static CPeriodUpdate* NewLC();
       
   159 private:
       
   160 	CPeriodUpdate();
       
   161 	void ConstructL();
       
   162 	~CPeriodUpdate();
       
   163 	void RunL();
       
   164 	void DoCancel();
       
   165 
       
   166 	RTimer iTimer;
       
   167 	TUint iUpTime;
       
   168 	};
       
   169 
       
   170 CPeriodUpdate* CPeriodUpdate::NewLC()
       
   171 	{
       
   172 	CPeriodUpdate* me=new(ELeave) CPeriodUpdate();
       
   173 	CleanupStack::PushL(me);
       
   174 	me->ConstructL();
       
   175 	return me;
       
   176 	}
       
   177 
       
   178 CPeriodUpdate::CPeriodUpdate()
       
   179 	: CActive(0), iUpTime(0)
       
   180 	{}
       
   181 
       
   182 void CPeriodUpdate::ConstructL()
       
   183 	{
       
   184 	CActiveScheduler::Add(this);
       
   185 	iTimer.CreateLocal();
       
   186 	RunL();
       
   187 	}
       
   188 
       
   189 CPeriodUpdate::~CPeriodUpdate()
       
   190 	{
       
   191 	Cancel();
       
   192 	}
       
   193 
       
   194 void CPeriodUpdate::DoCancel()
       
   195 	{
       
   196 	}
       
   197 
       
   198 void CPeriodUpdate::RunL()
       
   199 	{
       
   200 	SetActive();
       
   201 	// Print RAM usage & up time
       
   202 
       
   203 	iUpTime++;
       
   204 	TUint totmins=(iUpTime/60);
       
   205 	TUint tothrs=(totmins/60);
       
   206 	TInt mem=0;
       
   207 	if (HAL::Get(HALData::EMemoryRAMFree, mem)==KErrNone)
       
   208 		{
       
   209 		console->SetPos(0,22);
       
   210 		console->Printf(_L("mem (bytes) : %d\n"), mem);
       
   211 		console->Printf(_L("up time     : %dh:%dm:%ds\n"),
       
   212 					tothrs, totmins%60, iUpTime%60);
       
   213 		}
       
   214 	iTimer.After(iStatus, 1000000);
       
   215 	}
       
   216 
       
   217 //-----------------------------------------------------------------------------
       
   218 /**
       
   219     Dismounts the originally mounted FS and optional primary extension from the drive and stores
       
   220     this information in the FS descriptor
       
   221 
       
   222     @return on success returns a pointer to the instantinated FS descriptor
       
   223 */
       
   224 static CFileSystemDescriptor* DoDismountOrginalFS(RFs& aFs, TInt aDrive)
       
   225     {
       
   226     TInt        nRes;
       
   227     TBuf<128>   fsName;
       
   228     TBuf<128>   primaryExtName;
       
   229     TBool       bDrvSync = EFalse;
       
   230 
       
   231     Log(_L("# DoDismountOrginalFS drv:%d\n"), aDrive);
       
   232 
       
   233     //-- 1. get file system name
       
   234     nRes = aFs.FileSystemName(fsName, aDrive);
       
   235     if(nRes != KErrNone)
       
   236         {//-- probably no file system installed at all
       
   237         return NULL;
       
   238         }
       
   239 
       
   240     //-- 2. find out if the drive sync/async
       
   241     TPckgBuf<TBool> drvSyncBuf;
       
   242     nRes = aFs.QueryVolumeInfoExt(aDrive, EIsDriveSync, drvSyncBuf);
       
   243     if(nRes == KErrNone)
       
   244         {
       
   245         bDrvSync = drvSyncBuf();
       
   246         }
       
   247 
       
   248     //-- 3. find out primary extension name if it is present; we will need to add it againt when mounting the FS
       
   249     //-- other extensions (non-primary) are not supported yet
       
   250     nRes = aFs.ExtensionName(primaryExtName, aDrive, 0);
       
   251     if(nRes != KErrNone)
       
   252         {
       
   253         primaryExtName.SetLength(0);
       
   254         }
       
   255 
       
   256     //-- 3.1 check if the drive has non-primary extensions, fail in this case, because this FS can't be mounted back normally
       
   257     nRes = aFs.ExtensionName(primaryExtName, aDrive, 1);
       
   258     if(nRes == KErrNone)
       
   259         {
       
   260         LogPrint(_L("Non-primary extensions are not supported!\n"));
       
   261         return NULL;
       
   262         }
       
   263 
       
   264     Log(_L("# DoDismountOrginalFS FS:%S, Prim ext:%S, synch:%d\n"), &fsName, &primaryExtName, bDrvSync);
       
   265 
       
   266     //-- create FS descriptor and dismount the FS
       
   267     CFileSystemDescriptor* pFsDesc = NULL;
       
   268 
       
   269     TRAP(nRes, pFsDesc = CFileSystemDescriptor::NewL(fsName, primaryExtName, bDrvSync));
       
   270     if(nRes != KErrNone)
       
   271         return NULL; //-- OOM ?
       
   272 
       
   273     nRes = aFs.DismountFileSystem(fsName, aDrive);
       
   274     if(nRes != KErrNone)
       
   275         {
       
   276         delete pFsDesc;
       
   277         pFsDesc = NULL;
       
   278         Log(_L("# DoDismountOrginalFS Dismounting Err:%d\n"), nRes);
       
   279         }
       
   280 
       
   281     return pFsDesc;
       
   282 }
       
   283 
       
   284 //-----------------------------------------------------------------------------
       
   285 /**
       
   286     Tries to restore the original FS on the drive using the FS descriptor provided
       
   287     @return standard error code.
       
   288 */
       
   289 static TInt DoRestoreFS(RFs& aFs, TInt aDrive, CFileSystemDescriptor* apFsDesc)
       
   290     {
       
   291     TInt nRes;
       
   292 
       
   293     Log(_L("# DoRestoreFS drv:%d\n"), aDrive);
       
   294 
       
   295     //-- 1. check that there is no FS installed
       
   296         {
       
   297         TBuf<128>   fsName;
       
   298         nRes = aFs.FileSystemName(fsName, aDrive);
       
   299         if(nRes == KErrNone)
       
   300             {//-- probably no file system installed at all
       
   301             Log(_L("# This drive already has FS intalled:%S \n"), &fsName);
       
   302             return KErrAlreadyExists;
       
   303             }
       
   304         }
       
   305 
       
   306     TPtrC ptrN  (apFsDesc->FsName());
       
   307     TPtrC ptrExt(apFsDesc->PrimaryExtName());
       
   308     Log(_L("# Mounting FS:%S, Prim ext:%S, synch:%d\n"), &ptrN, &ptrExt, apFsDesc->DriveIsSynch());
       
   309 
       
   310     if(ptrExt.Length() >0)
       
   311         {//-- there is a primary extension to be mounted
       
   312         nRes = aFs.AddExtension(ptrExt);
       
   313         if(nRes != KErrNone && nRes != KErrAlreadyExists)
       
   314             {
       
   315             return nRes;
       
   316             }
       
   317 
       
   318         nRes = aFs.MountFileSystem(ptrN, ptrExt, aDrive, apFsDesc->DriveIsSynch());
       
   319         }
       
   320     else
       
   321         {
       
   322         nRes = aFs.MountFileSystem(ptrN, aDrive, apFsDesc->DriveIsSynch());
       
   323         }
       
   324 
       
   325     if(nRes != KErrNone)
       
   326         {
       
   327         Log(_L("# Mount failed! code:%d\n"),nRes);
       
   328         }
       
   329 
       
   330     return nRes;
       
   331     }
       
   332 
       
   333 
       
   334 //-----------------------------------------------------------------------------
       
   335 /**
       
   336     Dismount the original FS from the drive and mount MsFS instead
       
   337 */
       
   338 static void MountMsFs(TInt driveNumber)
       
   339 	{
       
   340 	TInt x = console->WhereX();
       
   341 	TInt y = console->WhereY();
       
   342 
       
   343     //-- 1. try dismounting the original FS
       
   344     CFileSystemDescriptor* fsDesc = DoDismountOrginalFS(fs, driveNumber);
       
   345     unmountedFsList[driveNumber] = fsDesc;
       
   346 
       
   347     console->SetPos(0, 10);
       
   348 
       
   349     if(fsDesc)
       
   350         {
       
   351         TPtrC ptrN(fsDesc->FsName());
       
   352         LogPrint(_L("drv:%d FS:%S Dismounted OK"),driveNumber, &ptrN);
       
   353         }
       
   354     else
       
   355         {
       
   356         LogPrint(_L("drv:%d Dismount FS Failed!"),driveNumber);
       
   357         }
       
   358 
       
   359     console->ClearToEndOfLine();
       
   360 
       
   361     //-- 2. try to mount the "MSFS"
       
   362     TInt error;
       
   363     error = fs.MountFileSystem(KMsFs, driveNumber);
       
   364 	console->SetPos(0, 11);
       
   365 	LogPrint(_L("MSFS Mount:   %S (%d)"), (error?&KError:&KOk), error);
       
   366 	console->ClearToEndOfLine();
       
   367 
       
   368 	if (!error)
       
   369 		msfsMountedList[driveNumber] = ETrue;
       
   370 
       
   371 	// restore console position
       
   372 	console->SetPos(x,y);
       
   373 	}
       
   374 
       
   375 //-----------------------------------------------------------------------------
       
   376 /**
       
   377     Dismount MsFS and mount the original FS
       
   378 */
       
   379 static TInt RestoreMount(TInt driveNumber)
       
   380 	{
       
   381 	TInt err = KErrNone;
       
   382 
       
   383 	TInt x = console->WhereX();
       
   384 	TInt y = console->WhereY();
       
   385 
       
   386     //-- 1. try dismounting the "MSFS"
       
   387 	if (msfsMountedList[driveNumber])
       
   388 		{
       
   389 		err = fs.DismountFileSystem(KMsFs, driveNumber);
       
   390 		console->SetPos(0, 11);
       
   391 		LogPrint(_L("MSFS Dismount:%S (%d)"), (err?&KError:&KOk), err);
       
   392 		console->ClearToEndOfLine();
       
   393 		if (err)
       
   394 			return err;
       
   395 
       
   396 		msfsMountedList[driveNumber] = EFalse;
       
   397         }
       
   398 
       
   399     //-- 2. try to mount the original FS back
       
   400     CFileSystemDescriptor* fsDesc = unmountedFsList[driveNumber];
       
   401     if(fsDesc)
       
   402         {
       
   403         err = DoRestoreFS(fs, driveNumber, fsDesc);
       
   404 
       
   405         TPtrC ptrN(fsDesc->FsName());
       
   406         console->SetPos(0, 10);
       
   407         LogPrint(_L("%S Mount:    %S (%d)"), &ptrN, (err?&KError:&KOk), err);
       
   408         console->ClearToEndOfLine();
       
   409 
       
   410         delete fsDesc;
       
   411         unmountedFsList[driveNumber] = NULL;
       
   412         }
       
   413 
       
   414 
       
   415     // restore console position
       
   416 	console->SetPos(x,y);
       
   417 	return err;
       
   418 	}
       
   419 
       
   420 //////////////////////////////////////////////////////////////////////////////
       
   421 //
       
   422 // CPropertyWatch
       
   423 // An active object that tracks changes to the KUsbMsDriveState properties
       
   424 //
       
   425 //////////////////////////////////////////////////////////////////////////////
       
   426 
       
   427 CPropertyWatch* CPropertyWatch::NewLC(TUsbMsDriveState_Subkey aSubkey, PropertyHandlers::THandler aHandler)
       
   428 	{
       
   429 	CPropertyWatch* me=new(ELeave) CPropertyWatch(aHandler);
       
   430 	CleanupStack::PushL(me);
       
   431 	me->ConstructL(aSubkey);
       
   432 	return me;
       
   433 	}
       
   434 
       
   435 CPropertyWatch::CPropertyWatch(PropertyHandlers::THandler aHandler)
       
   436 	: CActive(0), iHandler(aHandler)
       
   437 	{}
       
   438 
       
   439 void CPropertyWatch::ConstructL(TUsbMsDriveState_Subkey aSubkey)
       
   440 	{
       
   441 	User::LeaveIfError(iProperty.Attach(KUsbMsDriveState_Category, aSubkey));
       
   442 	CActiveScheduler::Add(this);
       
   443 	// initial subscription and process current property value
       
   444 	RunL();
       
   445 	}
       
   446 
       
   447 CPropertyWatch::~CPropertyWatch()
       
   448 	{
       
   449 	Cancel();
       
   450 	iProperty.Close();
       
   451 	}
       
   452 
       
   453 void CPropertyWatch::DoCancel()
       
   454 	{
       
   455 	iProperty.Cancel();
       
   456 	}
       
   457 
       
   458 void CPropertyWatch::RunL()
       
   459 	{
       
   460 	// resubscribe before processing new value to prevent missing updates
       
   461 	iProperty.Subscribe(iStatus);
       
   462 	SetActive();
       
   463 
       
   464 	iHandler(iProperty);
       
   465 	}
       
   466 
       
   467 //////////////////////////////////////////////////////////////////////////////
       
   468 //
       
   469 // CUsbWatch
       
   470 //
       
   471 //////////////////////////////////////////////////////////////////////////////
       
   472 
       
   473 CUsbWatch* CUsbWatch::NewLC(RUsb& aUsb)
       
   474 	{
       
   475 	CUsbWatch* me=new(ELeave) CUsbWatch(aUsb);
       
   476 	CleanupStack::PushL(me);
       
   477 	me->ConstructL();
       
   478 	return me;
       
   479 	}
       
   480 
       
   481 CUsbWatch::CUsbWatch(RUsb& aUsb)
       
   482 	:
       
   483 	CActive(0),
       
   484 	iUsb(aUsb),
       
   485 	iUsbDeviceState(EUsbDeviceStateUndefined),
       
   486 	iWasConfigured(EFalse)
       
   487 	{}
       
   488 
       
   489 void CUsbWatch::ConstructL()
       
   490 	{
       
   491 	CActiveScheduler::Add(this);
       
   492 	RunL();
       
   493 	}
       
   494 
       
   495 CUsbWatch::~CUsbWatch()
       
   496 	{
       
   497 	Cancel();
       
   498 //	iUsb.DeviceStateNotificationCancel();
       
   499 	iUsb.AlternateDeviceStatusNotifyCancel();
       
   500 	}
       
   501 
       
   502 void CUsbWatch::DoCancel()
       
   503 	{
       
   504 //	iUsb.DeviceStateNotificationCancel();
       
   505 	iUsb.AlternateDeviceStatusNotifyCancel();
       
   506 	}
       
   507 
       
   508 static TBool IsDriveConnected(TInt driveStatusIndex)
       
   509 	{
       
   510 	TInt driveStatus = PropertyHandlers::allDrivesStatus[2*driveStatusIndex+1];
       
   511 	return driveStatus >= EUsbMsDriveState_Connected ? ETrue : EFalse;
       
   512 	}
       
   513 
       
   514 static TChar DriveNumberToLetter(TInt driveNumber)
       
   515 	{
       
   516 	TChar driveLetter = '?';
       
   517 	fs.DriveToChar(driveNumber, driveLetter);
       
   518 	return driveLetter;
       
   519 	}
       
   520 
       
   521 static TBool IsDriveInMountList(TUint driveLetter)
       
   522 	{
       
   523 	TUint16 driveLetter16 = static_cast<TUint16>(driveLetter);
       
   524 	return(!mountList.Length() || KErrNotFound != mountList.Find(&driveLetter16, 1));
       
   525 	}
       
   526 
       
   527 void CUsbWatch::RunL()
       
   528 	{
       
   529 //	RDebug::Print(_L(">> CUsbWatch[%d] %d"), iUsbDeviceState, iWasConfigured);
       
   530 
       
   531 //	const TUint stateMask = 0xFF;
       
   532 //	iUsb.DeviceStateNotification(stateMask, iUsbDeviceState, iStatus);
       
   533 	iUsb.AlternateDeviceStatusNotify(iStatus, iUsbDeviceState);
       
   534 	SetActive();
       
   535 
       
   536 	//RDebug::Print(_L("CUsbWatch DeviceStateNotification: iUsbDeviceState=%d"), iUsbDeviceState);
       
   537 
       
   538 	// If the cable is disconnected, unmount all the connected drives.
       
   539 	if(iWasConfigured && iUsbDeviceState == EUsbDeviceStateUndefined)
       
   540 		{
       
   541 		for(TInt i=0; i<PropertyHandlers::allDrivesStatus.Length()/2; i++)
       
   542 			{
       
   543 			if(IsDriveConnected(i))
       
   544 				{
       
   545 				//RDebug::Print(_L("CUsbWatch calling RestoreMount"));
       
   546 				RestoreMount(PropertyHandlers::allDrivesStatus[2*i]);
       
   547 				}
       
   548 			}
       
   549 		iWasConfigured = EFalse;
       
   550 		}
       
   551 
       
   552     // If cable is connected, mount all drives in the auto-mount list. This is
       
   553     // done for performance, since if this is not done here, mounting will
       
   554     // happen later after each drive enters the Connecting state.
       
   555 	if (iUsbDeviceState == EUsbDeviceStateConfigured)
       
   556 		{
       
   557 		for (TInt i=0; i<PropertyHandlers::allDrivesStatus.Length()/2; i++)
       
   558 			{
       
   559 			TInt driveNumber = PropertyHandlers::allDrivesStatus[2*i];
       
   560 			if (!IsDriveConnected(i) && IsDriveInMountList(DriveNumberToLetter(driveNumber)))
       
   561 				{
       
   562 				//RDebug::Print(_L("CUsbWatch calling MountMsFs"));
       
   563 				MountMsFs(driveNumber);
       
   564 				}
       
   565 			}
       
   566 		iWasConfigured = ETrue;
       
   567 		}
       
   568 	}
       
   569 
       
   570 //////////////////////////////////////////////////////////////////////////////
       
   571 //
       
   572 // PropertyHandlers
       
   573 //
       
   574 //////////////////////////////////////////////////////////////////////////////
       
   575 
       
   576 TBuf8<16> PropertyHandlers::allDrivesStatus;
       
   577 TUsbMsBytesTransferred PropertyHandlers::iKBytesRead;
       
   578 TUsbMsBytesTransferred PropertyHandlers::iKBytesWritten;
       
   579 TInt PropertyHandlers::iMediaError;
       
   580 
       
   581 void PropertyHandlers::Read(RProperty& aProperty)
       
   582 	{
       
   583 	Transferred(aProperty, iKBytesRead);
       
   584 	}
       
   585 
       
   586 void PropertyHandlers::Written(RProperty& aProperty)
       
   587 	{
       
   588 	Transferred(aProperty, iKBytesWritten);
       
   589 	}
       
   590 
       
   591 void PropertyHandlers::Transferred(RProperty& aProperty, TUsbMsBytesTransferred& aReadOrWritten)
       
   592 	{
       
   593 	console->SetPos(0,1);
       
   594 	console->Printf(_L("KB R/W:  "));
       
   595 	TInt err = aProperty.Get(aReadOrWritten);
       
   596 	if(err == KErrNone)
       
   597 		{
       
   598 		for(TInt i = 0; i < allDrivesStatus.Length()/2; i++)
       
   599 			{
       
   600 			console->Printf(KBytesTransferredFmt,
       
   601 				(char)DriveNumberToLetter(allDrivesStatus[2*i]), iKBytesRead[i], iKBytesWritten[i]);
       
   602 			}
       
   603 		console->ClearToEndOfLine();
       
   604 		}
       
   605 	else
       
   606 		{
       
   607 		console->Printf(KErrFmt, err);
       
   608 		}
       
   609 	}
       
   610 
       
   611 void PropertyHandlers::DriveStatus(RProperty& aProperty)
       
   612 	{
       
   613 //	RDebug::Print(_L(">> PropertyHandlers::DriveStatus"));
       
   614 	TInt err = aProperty.Get(allDrivesStatus);
       
   615 	console->SetPos(0,0);
       
   616 	if(err == KErrNone)
       
   617 		{
       
   618 		console->Printf(_L("Status:  "));
       
   619 		for(TInt i = 0; i < allDrivesStatus.Length()/2; i++)
       
   620 			{
       
   621 			TInt driveNumber = allDrivesStatus[2*i];
       
   622 			TInt driveStatus = allDrivesStatus[2*i+1];
       
   623 			TChar driveLetter = DriveNumberToLetter(driveNumber);
       
   624 
       
   625 //			RDebug::Print(_L("%c:%d   "), (char)driveLetter, driveStatus);
       
   626 
       
   627 			switch(driveStatus)
       
   628 				{
       
   629 				case EUsbMsDriveState_Disconnected:
       
   630 					{
       
   631 					LogPrint(_L("%c:%d:Disconnected "), (char)driveLetter, driveStatus);
       
   632 					break;
       
   633 					}
       
   634 				case EUsbMsDriveState_Connecting:
       
   635 					{
       
   636 					LogPrint(_L("%c:%d:Connecting   "), (char)driveLetter, driveStatus);
       
   637 					break;
       
   638 					}
       
   639 				case EUsbMsDriveState_Connected:
       
   640 					{
       
   641 					LogPrint(_L("%c:%d:Connected    "), (char)driveLetter, driveStatus);
       
   642 					break;
       
   643 					}
       
   644 				case EUsbMsDriveState_Disconnecting:
       
   645 					{
       
   646 					LogPrint(_L("%c:%d:Disconnecting"), (char)driveLetter, driveStatus);
       
   647 					break;
       
   648 					}
       
   649 				case EUsbMsDriveState_Active:
       
   650 					{
       
   651 					LogPrint(_L("%c:%d:Active       "), (char)driveLetter, driveStatus);
       
   652 					break;
       
   653 					}
       
   654 				case EUsbMsDriveState_Locked:
       
   655 					{
       
   656 					LogPrint(_L("%c:%d:Locked       "), (char)driveLetter, driveStatus);
       
   657 					break;
       
   658 					}
       
   659 				case EUsbMsDriveState_MediaNotPresent:
       
   660 					{
       
   661 					LogPrint(_L("%c:%d:Not Present  "), (char)driveLetter, driveStatus);
       
   662 					break;
       
   663 					}
       
   664 				case EUsbMsDriveState_Removed:
       
   665 					{
       
   666 					LogPrint(_L("%c:%d:Removed      "), (char)driveLetter, driveStatus);
       
   667 					break;
       
   668 					}
       
   669 				case EUsbMsDriveState_Error:
       
   670 					{
       
   671 					LogPrint(_L("%c:%d:Error        "), (char)driveLetter, driveStatus);
       
   672 					break;
       
   673 					}
       
   674 				default :
       
   675 					{
       
   676 					LogPrint(_L("%c:%d:Unknown      "), (char)driveLetter, driveStatus);
       
   677 					break;
       
   678 					}
       
   679 				}
       
   680 
       
   681 			if(IsDriveInMountList(driveLetter))
       
   682 				{
       
   683 				if (driveStatus == EUsbMsDriveState_Connecting)
       
   684 					{
       
   685 					MountMsFs(driveNumber);
       
   686 					}
       
   687 				else if (driveStatus == EUsbMsDriveState_Disconnected)
       
   688 					{
       
   689 					RestoreMount(driveNumber);
       
   690 					}
       
   691 				else
       
   692 					{
       
   693 					//RDebug::Print(_L("PropertyHandlers::DriveStatus: nothing to do"));
       
   694 					}
       
   695 				}
       
   696 			else
       
   697 				{
       
   698 				//RDebug::Print(_L("PropertyHandlers::DriveStatus: %c: is not in mountList\n"), driveLetter);
       
   699 				}
       
   700 			}
       
   701 		}
       
   702 	else
       
   703 		{
       
   704 		LogPrint(KErrFmt, err);
       
   705 		}
       
   706 
       
   707 	//RDebug::Print(_L("<< PropertyHandlers::DriveStatus"));
       
   708 	}
       
   709 
       
   710 void PropertyHandlers::MediaError(RProperty& aProperty)
       
   711 	{
       
   712 	TInt err = aProperty.Get(iMediaError);
       
   713 	if (err != KErrNone)
       
   714 		{
       
   715 		// RDebug::Printf("RProperty::Get returned %d", err);
       
   716 		return;
       
   717 		}
       
   718 
       
   719 	//RDebug::Printf("PropertyHandlers::MediaError %x", iMediaError);
       
   720 
       
   721 	TInt x = console->WhereX();
       
   722 	TInt y = console->WhereY();
       
   723 	Clear(27,1);
       
   724 	LogPrint(_L("Media Error %x"), iMediaError);
       
   725 	// restore console position
       
   726 	console->SetPos(x,y);
       
   727 	}
       
   728 
       
   729 //////////////////////////////////////////////////////////////////////////////
       
   730 //
       
   731 // CMessageKeyProcessor
       
   732 //
       
   733 //////////////////////////////////////////////////////////////////////////////
       
   734 CMessageKeyProcessor::CMessageKeyProcessor(CConsoleBase* aConsole)
       
   735 	: CActive(CActive::EPriorityUserInput), iConsole(aConsole)
       
   736 	{
       
   737 	}
       
   738 
       
   739 CMessageKeyProcessor* CMessageKeyProcessor::NewLC(CConsoleBase* aConsole)
       
   740 	{
       
   741 	CMessageKeyProcessor* self=new (ELeave) CMessageKeyProcessor(aConsole);
       
   742 	CleanupStack::PushL(self);
       
   743 	self->ConstructL();
       
   744 	return self;
       
   745 	}
       
   746 
       
   747 CMessageKeyProcessor* CMessageKeyProcessor::NewL(CConsoleBase* aConsole)
       
   748 	{
       
   749 	CMessageKeyProcessor* self = NewLC(aConsole);
       
   750 	CleanupStack::Pop();
       
   751 	return self;
       
   752 	}
       
   753 
       
   754 void CMessageKeyProcessor::ConstructL()
       
   755 	{
       
   756 	// Add to active scheduler
       
   757 	CActiveScheduler::Add(this);
       
   758 	RequestCharacter();
       
   759 	}
       
   760 
       
   761 void CMessageKeyProcessor::MakePassword(TMediaPassword &aPassword)
       
   762 	{
       
   763 	//  Create password with same format as eshell and S60
       
   764 	TBuf<3> password(KDefPwd);
       
   765 
       
   766 	// fill aPassword with contents of password, not converting to ASCII
       
   767 	const TInt byteLen = password.Length() * 2;
       
   768 	aPassword.Copy(reinterpret_cast<const TUint8 *>(password.Ptr()), byteLen);
       
   769 	}
       
   770 
       
   771 CMessageKeyProcessor::~CMessageKeyProcessor()
       
   772 	{
       
   773 	// Make sure we're cancelled
       
   774 	Cancel();
       
   775 	}
       
   776 
       
   777 void  CMessageKeyProcessor::DoCancel()
       
   778 	{
       
   779 	iConsole->ReadCancel();
       
   780 	}
       
   781 
       
   782 void  CMessageKeyProcessor::RunL()
       
   783 	{
       
   784 	  // Handle completed request
       
   785 	ProcessKeyPress(TChar(iConsole->KeyCode()));
       
   786 	}
       
   787 
       
   788 void CMessageKeyProcessor::RequestCharacter()
       
   789 	{
       
   790 	  // A request is issued to the CConsoleBase to accept a
       
   791 	  // character from the keyboard.
       
   792 	iConsole->Read(iStatus);
       
   793 	SetActive();
       
   794 	}
       
   795 
       
   796 void CMessageKeyProcessor::ProcessKeyPress(TChar aChar)
       
   797 	{
       
   798 
       
   799 	TInt error = KErrNone;
       
   800 
       
   801     aChar.UpperCase();
       
   802 	switch(aChar)
       
   803 		{
       
   804 		case 'Q':
       
   805 		case EKeyEscape:
       
   806 			{
       
   807 			TInt err = KErrNone;
       
   808 			for(TInt j=0; j<KMaxDrives; j++)
       
   809 				{
       
   810 				err = RestoreMount(j);
       
   811 
       
   812 				if (err)
       
   813 					{
       
   814 					// Mount is busy/locked and can not be restored.
       
   815 					break;
       
   816 					}
       
   817 
       
   818 				}
       
   819 
       
   820 			if (err == KErrNone)
       
   821 				{
       
   822 				CActiveScheduler::Stop();
       
   823 				return;
       
   824 				}
       
   825 
       
   826 			}
       
   827 			break;
       
   828 
       
   829 #if defined(_DEBUG)
       
   830 		case 'T':
       
   831 			iTraceEnable = !iTraceEnable;
       
   832 			if (iTraceEnable)	// 0x44008401
       
   833 				User::SetDebugMask(KHARDWARE|KDLL|KSCRATCH|KPOWER|KMEMTRACE);
       
   834 			else
       
   835 				User::SetDebugMask(0);
       
   836 			break;
       
   837 #endif
       
   838 
       
   839 		case 'D':
       
   840 			if(++selectedDriveIndex >= PropertyHandlers::allDrivesStatus.Length()/2)
       
   841 				{
       
   842 				selectedDriveIndex = 0;
       
   843 				}
       
   844 			ShowDriveSelection();
       
   845 			break;
       
   846 
       
   847 		case 'M':
       
   848 			if(PropertyHandlers::allDrivesStatus.Length())
       
   849 				{
       
   850 				MountMsFs(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   851 				}
       
   852 			break;
       
   853 
       
   854 		case 'U':
       
   855 			if(PropertyHandlers::allDrivesStatus.Length())
       
   856 				{
       
   857 				RestoreMount(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   858 				}
       
   859 			break;
       
   860 
       
   861 		case 'L':
       
   862 			{
       
   863 			// lock unprotected drive
       
   864 			TMediaPassword password;
       
   865 			MakePassword(password);
       
   866 
       
   867 			_LIT(KEmpty, "");
       
   868 			TMediaPassword nul;
       
   869 			nul.Copy(KEmpty);
       
   870 			error = fs.LockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   871                                  nul, password, ETrue);
       
   872 			console->SetPos(0,9);
       
   873 			LogPrint(_L("LockDrive %S (%d)"), (error?&KError:&KOk), error);
       
   874 			break;
       
   875 			}
       
   876 
       
   877 		case 'I':
       
   878             {
       
   879             // lock password protected drive
       
   880             TMediaPassword password;
       
   881             MakePassword(password);
       
   882             error = fs.LockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   883                                  password, password, ETrue);
       
   884             console->SetPos(0,9);
       
   885             LogPrint(_L("LockDrive %S (%d)"), (error?&KError:&KOk), error);
       
   886             break;
       
   887             }
       
   888 
       
   889         case 'N':
       
   890             {
       
   891             TMediaPassword password;
       
   892             MakePassword(password);
       
   893             error = fs.UnlockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   894                                    password, ETrue);
       
   895             Clear(9);
       
   896             LogPrint(_L("UnlockDrive %S (%d)"), (error?&KError:&KOk), error);
       
   897             }
       
   898 			break;
       
   899 
       
   900         case 'C':
       
   901             {
       
   902             TMediaPassword password;
       
   903             MakePassword(password);
       
   904             error = fs.ClearPassword(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   905                                      password);
       
   906             Clear(9);
       
   907             LogPrint(_L("ClearPassword %S (%d)"), (error?&KError:&KOk), error);
       
   908             }
       
   909 			break;
       
   910 		default:
       
   911 			break;
       
   912 		}
       
   913 	RequestCharacter();
       
   914 	}
       
   915 
       
   916 
       
   917 //////////////////////////////////////////////////////////////////////////////
       
   918 //
       
   919 // Application entry point
       
   920 //
       
   921 //////////////////////////////////////////////////////////////////////////////
       
   922 static void RunAppL()
       
   923 	{
       
   924 
       
   925     TInt error = KErrUnknown;
       
   926 
       
   927 	//RDebug::Print(_L("USBMSAPP: Creating console\n"));
       
   928 	console = Console::NewL(KTxtApp,TSize(KConsFullScreen,KConsFullScreen));
       
   929 	CleanupStack::PushL(console);
       
   930 
       
   931 	console->SetPos(0,2);
       
   932 	console->Printf(_L("========================================"));
       
   933 
       
   934 	// Command line: list of drive letters to auto-mount (all if not specified)
       
   935 	User::CommandLine(mountList);
       
   936 	mountList.UpperCase();
       
   937 
       
   938 	CActiveScheduler* sched = new(ELeave) CActiveScheduler;
       
   939 	CleanupStack::PushL(sched);
       
   940 	CActiveScheduler::Install(sched);
       
   941 
       
   942 	fs.Connect();
       
   943 	CleanupClosePushL(fs);
       
   944 
       
   945 	_LIT(KMountAllDefault,"(all)");
       
   946 	console->SetPos(0,3);
       
   947 	LogPrint(_L("Drives to auto-mount: %S"), (mountList.Length() ? &mountList : &KMountAllDefault));
       
   948 
       
   949 	// Add MS file system
       
   950 	error = fs.AddFileSystem(KMsFsy);
       
   951 	if(error != KErrNone && error != KErrAlreadyExists)
       
   952 		{
       
   953 		//RDebug::Print(_L("AddFileSystem failed, err=%d\n"), error);
       
   954 		User::Leave(error);
       
   955 		}
       
   956 	console->SetPos(0,4);
       
   957 	LogPrint(_L("MSFS file system:\tAdded OK\n"));
       
   958 
       
   959 	RUsb usb;
       
   960 
       
   961 	// Load the logical device
       
   962 	_LIT(KDriverFileName,"EUSBC.LDD");
       
   963 	error = User::LoadLogicalDevice(KDriverFileName);
       
   964 	if (error != KErrAlreadyExists)
       
   965 		User::LeaveIfError(error);
       
   966 
       
   967 	error = usb.Open(0);
       
   968 	User::LeaveIfError(error);
       
   969 
       
   970 	_LIT(KOtgdiLddFilename, "otgdi");
       
   971 	// Check for OTG support
       
   972 	TBuf8<KUsbDescSize_Otg> otg_desc;
       
   973 	error = usb.GetOtgDescriptor(otg_desc);
       
   974 	if (!(error == KErrNotSupported || error == KErrNone))
       
   975 		{
       
   976 		LogPrint(_L("Error %d while fetching OTG descriptor"), error);
       
   977 		User::Leave(-1);
       
   978 		return;
       
   979 		}
       
   980 
       
   981 	// On an OTG device we have to start the OTG driver, otherwise the Client
       
   982 	// stack will remain disabled forever.
       
   983 	if (error == KErrNotSupported)
       
   984 	{
       
   985 		CleanupClosePushL(usb);
       
   986 		User::Leave(-1);
       
   987 	}
       
   988 
       
   989 	error = User::LoadLogicalDevice(KOtgdiLddFilename);
       
   990 	if (error != KErrNone)
       
   991 		{
       
   992 		LogPrint(_L("Error %d on loading OTG LDD"), error);
       
   993 		User::Leave(-1);
       
   994 		return;
       
   995 		}
       
   996 
       
   997 	RUsbOtgDriver iOtgPort;
       
   998 
       
   999 	error = iOtgPort.Open();
       
  1000 	if (error != KErrNone)
       
  1001 		{
       
  1002 		LogPrint(_L("Error %d on opening OTG port"), error);
       
  1003 		User::Leave(-1);
       
  1004 		return;
       
  1005 		}
       
  1006 	error = iOtgPort.StartStacks();
       
  1007 	if (error != KErrNone)
       
  1008 		{
       
  1009 		LogPrint(_L("Error %d on starting USB stack"), error);
       
  1010 		User::Leave(-1);
       
  1011 		return;
       
  1012 		}
       
  1013 
       
  1014 	CleanupClosePushL(usb);
       
  1015 
       
  1016 //		RDebug::Print(_L("USBMSAPP: Create active objects\n"));
       
  1017 	CMessageKeyProcessor::NewLC(console);
       
  1018 	CPropertyWatch::NewLC(EUsbMsDriveState_KBytesRead, PropertyHandlers::Read);
       
  1019 	CPropertyWatch::NewLC(EUsbMsDriveState_KBytesWritten, PropertyHandlers::Written);
       
  1020 	CPropertyWatch::NewLC(EUsbMsDriveState_DriveStatus, PropertyHandlers::DriveStatus);
       
  1021 	CPropertyWatch::NewLC(EUsbMsDriveState_MediaError, PropertyHandlers::MediaError);
       
  1022 	CUsbWatch::NewLC(usb);
       
  1023 	CPeriodUpdate::NewLC();
       
  1024 
       
  1025 	RUsbMassStorage UsbMs;
       
  1026 	TBuf<8>  t_vendorId(_L("vendor"));
       
  1027 	TBuf<16> t_productId(_L("product"));
       
  1028 	TBuf<4>  t_productRev(_L("1.00"));
       
  1029 
       
  1030 	TMassStorageConfig msConfig;
       
  1031 	msConfig.iVendorId.Copy(t_vendorId);
       
  1032 	msConfig.iProductId.Copy(t_productId);
       
  1033 	msConfig.iProductRev.Copy(t_productRev);
       
  1034 
       
  1035 //   	console->Printf(_L("Connect to Mass Storage"));
       
  1036 	error = UsbMs.Connect();
       
  1037 	User::LeaveIfError(error);
       
  1038 
       
  1039 //   	console->Printf(_L("Start Mass Storage"));
       
  1040 	error = UsbMs.Start(msConfig);
       
  1041 	User::LeaveIfError(error);
       
  1042 
       
  1043 	TBuf8<KUsbDescSize_Device> deviceDescriptor;
       
  1044 	error = usb.GetDeviceDescriptor(deviceDescriptor);
       
  1045 	User::LeaveIfError(error);
       
  1046 
       
  1047 	const TInt KUsbSpecOffset = 2;
       
  1048 	const TInt KUsbDeviceClassOffset = 4;
       
  1049 	const TInt KUsbVendorIdOffset = 8;
       
  1050 	const TInt KUsbProductIdOffset = 10;
       
  1051 	const TInt KUsbDevReleaseOffset = 12;
       
  1052 	//Change the USB spec number to 2.00
       
  1053 	deviceDescriptor[KUsbSpecOffset]   = 0x00;
       
  1054 	deviceDescriptor[KUsbSpecOffset+1] = 0x02;
       
  1055 	//Change the Device Class, Device SubClass and Device Protocol
       
  1056 	deviceDescriptor[KUsbDeviceClassOffset] = 0x00;
       
  1057 	deviceDescriptor[KUsbDeviceClassOffset+1] = 0x00;
       
  1058 	deviceDescriptor[KUsbDeviceClassOffset+2] = 0x00;
       
  1059 	//Change the device vendor ID (VID) to 0x0E22 (Symbian)
       
  1060 	deviceDescriptor[KUsbVendorIdOffset]   = 0x22;   // little endian
       
  1061 	deviceDescriptor[KUsbVendorIdOffset+1] = 0x0E;
       
  1062 	//Change the device product ID (PID) to 0x1111
       
  1063 	deviceDescriptor[KUsbProductIdOffset]   = 0x12;
       
  1064 	deviceDescriptor[KUsbProductIdOffset+1] = 0x11;
       
  1065 	//Change the device release number to 3.05
       
  1066 	deviceDescriptor[KUsbDevReleaseOffset]   = 0x05;
       
  1067 	deviceDescriptor[KUsbDevReleaseOffset+1] = 0x03;
       
  1068 	error = usb.SetDeviceDescriptor(deviceDescriptor);
       
  1069 	User::LeaveIfError(error);
       
  1070 
       
  1071 	// Remove possible Remote-Wakup support in Configuration descriptor,
       
  1072 	// so that we can use the MSC device also easily for Chapter9 testing.
       
  1073 	TBuf8<KUsbDescSize_Config> configDescriptor;
       
  1074 	error = usb.GetConfigurationDescriptor(configDescriptor);
       
  1075 	User::LeaveIfError(error);
       
  1076 	const TInt KConfDesc_AttribOffset = 7;
       
  1077 	configDescriptor[KConfDesc_AttribOffset] &= ~KUsbDevAttr_RemoteWakeup;
       
  1078 	error = usb.SetConfigurationDescriptor(configDescriptor);
       
  1079 	User::LeaveIfError(error);
       
  1080 
       
  1081 	_LIT16(productID_L, "Symbian USB Mass Storage Device (Base)");
       
  1082 	TBuf16<KUsbStringDescStringMaxSize / 2> productID(productID_L);
       
  1083 	error = usb.SetProductStringDescriptor(productID);
       
  1084 	User::LeaveIfError(error);
       
  1085 
       
  1086 	TRequestStatus enum_status;
       
  1087 	console->SetPos(0,5);
       
  1088 	LogPrint(_L("Re-enumerating...\n"));
       
  1089 	usb.ReEnumerate(enum_status);
       
  1090 	User::LeaveIfError(error);
       
  1091 	console->SetPos(0,5);
       
  1092 	User::WaitForRequest(enum_status);
       
  1093 	if(enum_status.Int() == KErrNone)
       
  1094 		LogPrint(_L("Re-enumeration Done\n"));
       
  1095 	else
       
  1096 		LogPrint(_L("Re-enumeration not successfully done\n"));
       
  1097 
       
  1098 
       
  1099     console->SetPos(0,14);
       
  1100     TBuf<3>password(KDefPwd);
       
  1101     LogPrint(_L("Password: %S"), &password);
       
  1102 
       
  1103 	ShowDriveSelection();
       
  1104 
       
  1105 	console->SetPos(0,17);
       
  1106 
       
  1107 	_LIT(KMsgTitleB,"Menu: q=quit  d=chg drv\n      m=mount u=unmount\n       l=lock i=lock n=unlock\n      c=clr pwd");
       
  1108 
       
  1109 
       
  1110 	//RDebug::Print(_L("USBMSAPP: Start CActiveScheduler\n"));
       
  1111 
       
  1112 	console->Printf(KMsgTitleB);
       
  1113 
       
  1114 	CActiveScheduler::Start();
       
  1115 
       
  1116 	error = UsbMs.Stop();
       
  1117 	User::LeaveIfError(error);
       
  1118 	UsbMs.Close();
       
  1119 	error = fs.RemoveFileSystem(KMsFs);
       
  1120 	User::LeaveIfError(error);
       
  1121 
       
  1122 	CleanupStack::PopAndDestroy(11);
       
  1123 
       
  1124 	iOtgPort.StopStacks();
       
  1125 	iOtgPort.Close();
       
  1126 	error = User::FreeLogicalDevice(RUsbOtgDriver::Name());
       
  1127 	User::LeaveIfError(error);
       
  1128 
       
  1129 	error = User::FreeLogicalDevice(_L("USBC"));
       
  1130 	User::LeaveIfError(error);
       
  1131 
       
  1132 	}
       
  1133 
       
  1134 GLDEF_C TInt E32Main()
       
  1135 	{
       
  1136 	__UHEAP_MARK;
       
  1137 	CTrapCleanup* cleanup=CTrapCleanup::New();
       
  1138 
       
  1139     msfsMountedList.Reset();
       
  1140     unmountedFsList.Reset();
       
  1141 
       
  1142 
       
  1143 	TRAPD(error,RunAppL());
       
  1144 	__ASSERT_ALWAYS(!error, User::Panic(KTxtApp, error));
       
  1145 
       
  1146 	delete cleanup;
       
  1147 	__UHEAP_MARKEND;
       
  1148 	return 0;
       
  1149 	}
       
  1150 
       
  1151 
       
  1152 //-----------------------------------------------------------------------------
       
  1153 
       
  1154 CFileSystemDescriptor::~CFileSystemDescriptor()
       
  1155     {
       
  1156     iFsName.Close();
       
  1157     iPrimaryExtName.Close();
       
  1158     }
       
  1159 
       
  1160 //-----------------------------------------------------------------------------
       
  1161 CFileSystemDescriptor* CFileSystemDescriptor::NewL(const TDesC& aFsName, const TDesC& aPrimaryExtName, TBool aDrvSynch)
       
  1162     {
       
  1163     CFileSystemDescriptor* pSelf = new (ELeave) CFileSystemDescriptor;
       
  1164 
       
  1165     CleanupStack::PushL(pSelf);
       
  1166 
       
  1167     pSelf->iFsName.CreateMaxL(aFsName.Length());
       
  1168     pSelf->iFsName.Copy(aFsName);
       
  1169 
       
  1170     pSelf->iPrimaryExtName.CreateMaxL(aPrimaryExtName.Length());
       
  1171     pSelf->iPrimaryExtName.Copy(aPrimaryExtName);
       
  1172 
       
  1173     pSelf->iDriveSynch = aDrvSynch;
       
  1174 
       
  1175     CleanupStack::Pop();
       
  1176 
       
  1177     return pSelf;
       
  1178     }