kerneltest/e32utils/usbmsapp/usbmsapp.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2006-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  @file
       
    20 */
       
    21 
       
    22 #include "usbmsapp.h"
       
    23 
       
    24 #include <e32std.h>
       
    25 #include <e32std_private.h>
       
    26 #include <e32svr.h>
       
    27 #include <e32cons.h>
       
    28 #include <f32file.h>
       
    29 
       
    30 #include <usbmsshared.h>
       
    31 #include <massstorage.h>
       
    32 
       
    33 TBool gSharedChunkLdd = EFalse;
       
    34 #include <d32usbcsc.h>
       
    35 #include <d32usbc.h>
       
    36 
       
    37 #ifdef BUILD_OTG_USBMSAPP
       
    38 #include <d32otgdi.h>
       
    39 #endif
       
    40 
       
    41 #include <nkern/nk_trace.h>
       
    42 #include <hal.h>
       
    43 
       
    44 #ifdef USB_BOOT_LOADER
       
    45 
       
    46 #include "usbbootvar.h"
       
    47 #include <rebootdrv.h>
       
    48 #define KNANDLDRLDD_NAME _L("REBOOT.LDD")
       
    49 static RReboot* RebootDrv;
       
    50 
       
    51 
       
    52 /// Global number of seconds to delay before reboot
       
    53 static TInt gRebootDelay = 0;
       
    54 
       
    55 #endif
       
    56 
       
    57 enum
       
    58 	{
       
    59 	EUsbDeviceStateUndefined  = EUsbcDeviceStateUndefined,
       
    60 	EUsbDeviceStateConfigured = EUsbcDeviceStateConfigured,
       
    61 	};
       
    62 
       
    63 static CConsoleBase* console = NULL;
       
    64 static RFs fs;
       
    65 static TInt selectedDriveIndex = 0;
       
    66 static TBuf<0x40> mountList;
       
    67 
       
    68 static TFixedArray<TBool, KMaxDrives>                   msfsMountedList;  ///< 'true' entry corresponds to the drive with mounted MSFS.FSY
       
    69 static TFixedArray<CFileSystemDescriptor*, KMaxDrives>  unmountedFsList;  ///< every non-NULL entry corresponds to the unmounted original FS for the drive
       
    70 
       
    71 
       
    72 _LIT(KMsFsy, "MSFS.FSY");
       
    73 _LIT(KMsFs, "MassStorageFileSystem");
       
    74 
       
    75 _LIT(KOk,"OK");
       
    76 _LIT(KError,"Error");
       
    77 _LIT(KBytesTransferredFmt, "%c:%d/%d ");
       
    78 _LIT(KErrFmt, "Error: %d\r");
       
    79 
       
    80 #ifndef USB_BOOT_LOADER
       
    81 _LIT(KTxtApp,"USBMSAPP");
       
    82 _LIT(KDefPwd,"123");
       
    83 #endif
       
    84 
       
    85 //-- if defined, some useful information will be printed out via RDebug interface
       
    86 //#define LOGGING_ENABLED
       
    87 
       
    88 //-----------------------------------------------------------------------------
       
    89 /** 
       
    90     prints a line to the console and copies it to the debug log if LOGGING_ENABLED
       
    91 */
       
    92 void LogPrint(TRefByValue<const TDesC> aFmt,...)
       
    93     {
       
    94     VA_LIST list;
       
    95     VA_START(list, aFmt);
       
    96     
       
    97     TBuf<0x100> buf;
       
    98 	// coverity[uninit_use_in_call]
       
    99     buf.FormatList(aFmt, list); //-- ignore overflows
       
   100 
       
   101     if(console)
       
   102         console->Write(buf);
       
   103 
       
   104 #ifdef LOGGING_ENABLED
       
   105     //-- print out the line via RDebug::Print 
       
   106     const TInt bufLen = buf.Length();
       
   107     if(bufLen >0 && buf[bufLen-1] == '\n')
       
   108         {
       
   109         buf.Insert(bufLen-1, _L("\r"));
       
   110         }
       
   111     else
       
   112         {
       
   113         buf.Append(_L("\r\n"));    
       
   114         }
       
   115 
       
   116     RDebug::RawPrint(buf);
       
   117 #endif
       
   118     }
       
   119 
       
   120 //-----------------------------------------------------------------------------
       
   121 /**
       
   122     prints a line to the debug log if LOGGING_ENABLED
       
   123 */
       
   124 void Log(TRefByValue<const TDesC> aFmt,...)
       
   125     {
       
   126 #ifdef LOGGING_ENABLED
       
   127 
       
   128     VA_LIST list;
       
   129     VA_START(list, aFmt);
       
   130     
       
   131     TBuf<0x100> buf;
       
   132     buf.FormatList(aFmt, list); //-- ignore overflows
       
   133     
       
   134     //-- print out the line via RDebug::Print 
       
   135     const TInt bufLen = buf.Length();
       
   136     if(bufLen >0 && buf[bufLen-1] == '\n')
       
   137         {
       
   138         buf.Insert(bufLen-1, _L("\r"));
       
   139         }
       
   140 
       
   141     RDebug::RawPrint(buf);
       
   142 #else
       
   143     (void)aFmt;
       
   144 #endif
       
   145     }
       
   146 
       
   147 
       
   148 //-----------------------------------------------------------------------------
       
   149 
       
   150 static void Clear(int row, int count=1)
       
   151 	{
       
   152 	_LIT(KBlank,"                                        ");
       
   153 	for(TInt i=0; i<count; i++)
       
   154 		{
       
   155 		console->SetPos(0,row+i);
       
   156 		console->Printf(KBlank);
       
   157 		}
       
   158 	console->SetPos(0,row);
       
   159 	}
       
   160 
       
   161 
       
   162 static void ShowDriveSelection()
       
   163 	{
       
   164 	console->SetPos(0,15);
       
   165 	if(PropertyHandlers::allDrivesStatus.Length()/2 > selectedDriveIndex)
       
   166 		{
       
   167 		LogPrint(_L("Selected Drive: %c"), 'A' + PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   168 		}
       
   169 	else
       
   170 		{
       
   171 		LogPrint(_L("Selected Drive: (none)"));
       
   172 		}
       
   173 	}
       
   174 
       
   175 
       
   176 #ifdef USB_BOOT_LOADER
       
   177 
       
   178 static void rebootit()
       
   179 	{
       
   180 	TInt r=User::LoadLogicalDevice(KNANDLDRLDD_NAME);
       
   181 	RebootDrv=new RReboot;
       
   182 	if(!RebootDrv)
       
   183 		{
       
   184 		User::Panic(_L("Loading driver"),1);
       
   185 		}
       
   186 	r=RebootDrv->Open();
       
   187 	if (r!=KErrNone)
       
   188 		{
       
   189 		User::Panic(_L("Opening driver"),r);
       
   190 		}
       
   191 
       
   192 	if (gRebootDelay>0)
       
   193 		{
       
   194 		_LIT(KMsgRebooting,"*** Reboot in %d secs ***\n");
       
   195 		TInt delay=gRebootDelay;
       
   196 		console->SetPos(0,20);
       
   197 			do
       
   198 			{
       
   199 			LogPrint(KMsgRebooting, delay);
       
   200 			User::After(1000000);
       
   201 			} while(--delay);
       
   202 		}
       
   203 	r=RebootDrv->VariantCtrl(KVariantUsbmsVariantRebootReason, NULL);
       
   204 	if (r!=KErrNone)
       
   205 		{
       
   206 		User::Panic(_L("Rebooting"),r);
       
   207 		}
       
   208 	}
       
   209 
       
   210 #endif
       
   211 
       
   212 class CPeriodUpdate : public CActive
       
   213 	{
       
   214 public:
       
   215 	static CPeriodUpdate* NewLC();
       
   216 private:
       
   217 	CPeriodUpdate();
       
   218 	void ConstructL();
       
   219 	~CPeriodUpdate();
       
   220 	void RunL();
       
   221 	void DoCancel();
       
   222 
       
   223 	RTimer iTimer;
       
   224 	TUint iUpTime;
       
   225 	};
       
   226 
       
   227 CPeriodUpdate* CPeriodUpdate::NewLC()
       
   228 	{
       
   229 	CPeriodUpdate* me=new(ELeave) CPeriodUpdate();
       
   230 	CleanupStack::PushL(me);
       
   231 	me->ConstructL();
       
   232 	return me;
       
   233 	}
       
   234 
       
   235 CPeriodUpdate::CPeriodUpdate()
       
   236 	: CActive(0), iUpTime(0)
       
   237 	{}
       
   238 
       
   239 void CPeriodUpdate::ConstructL()
       
   240 	{
       
   241 	CActiveScheduler::Add(this);
       
   242 	iTimer.CreateLocal();
       
   243 	RunL();
       
   244 	}
       
   245 
       
   246 CPeriodUpdate::~CPeriodUpdate()
       
   247 	{
       
   248 	Cancel();
       
   249 	}
       
   250 
       
   251 void CPeriodUpdate::DoCancel()
       
   252 	{
       
   253 	}
       
   254 
       
   255 void CPeriodUpdate::RunL()
       
   256 	{
       
   257 	SetActive();
       
   258 	// Print RAM usage & up time
       
   259 
       
   260 	iUpTime++;
       
   261 	TUint totmins=(iUpTime/60);
       
   262 	TUint tothrs=(totmins/60);
       
   263 	TInt mem=0;
       
   264 	if (HAL::Get(HALData::EMemoryRAMFree, mem)==KErrNone)
       
   265 		{
       
   266 		console->SetPos(0,22);
       
   267 		console->Printf(_L("mem (bytes) : %d\n"), mem);
       
   268 		console->Printf(_L("up time     : %dh:%dm:%ds\n"),
       
   269 					tothrs, totmins%60, iUpTime%60);
       
   270 		}
       
   271 	iTimer.After(iStatus, 1000000);
       
   272 	}
       
   273 
       
   274 //-----------------------------------------------------------------------------
       
   275 /**
       
   276     Dismounts the originally mounted FS and optional primary extension from the drive and stores 
       
   277     this information in the FS descriptor
       
   278 
       
   279     @return on success returns a pointer to the instantinated FS descriptor
       
   280 */
       
   281 static CFileSystemDescriptor* DoDismountOrginalFS(RFs& aFs, TInt aDrive)
       
   282     {
       
   283     TInt        nRes;
       
   284     TBuf<128>   fsName;
       
   285     TBuf<128>   primaryExtName;
       
   286     TBool       bDrvSync = EFalse;
       
   287 
       
   288     Log(_L("# DoDismountOrginalFS drv:%d\n"), aDrive);
       
   289 
       
   290     //-- 1. get file system name
       
   291     nRes = aFs.FileSystemName(fsName, aDrive);
       
   292     if(nRes != KErrNone)
       
   293         {//-- probably no file system installed at all
       
   294         return NULL;
       
   295         }
       
   296 
       
   297     //-- 2. find out if the drive sync/async
       
   298     TPckgBuf<TBool> drvSyncBuf;
       
   299     nRes = aFs.QueryVolumeInfoExt(aDrive, EIsDriveSync, drvSyncBuf);
       
   300     if(nRes == KErrNone)
       
   301         {
       
   302         bDrvSync = drvSyncBuf();
       
   303         }
       
   304 
       
   305     //-- 3. find out primary extension name if it is present; we will need to add it againt when mounting the FS
       
   306     //-- other extensions (non-primary) are not supported yet
       
   307     nRes = aFs.ExtensionName(primaryExtName, aDrive, 0);
       
   308     if(nRes != KErrNone)
       
   309         {   
       
   310         primaryExtName.SetLength(0);
       
   311         }
       
   312 
       
   313     //-- 3.1 check if the drive has non-primary extensions, fail in this case, because this FS can't be mounted back normally
       
   314     nRes = aFs.ExtensionName(primaryExtName, aDrive, 1);
       
   315     if(nRes == KErrNone)
       
   316         {   
       
   317         LogPrint(_L("Non-primary extensions are not supported!\n"));
       
   318         return NULL;
       
   319         }
       
   320 
       
   321     Log(_L("# DoDismountOrginalFS FS:%S, Prim ext:%S, synch:%d\n"), &fsName, &primaryExtName, bDrvSync);
       
   322 
       
   323     //-- create FS descriptor and dismount the FS
       
   324     CFileSystemDescriptor* pFsDesc = NULL; 
       
   325     
       
   326     TRAP(nRes, pFsDesc = CFileSystemDescriptor::NewL(fsName, primaryExtName, bDrvSync));
       
   327     if(nRes != KErrNone)
       
   328         return NULL; //-- OOM ?
       
   329 
       
   330     nRes = aFs.DismountFileSystem(fsName, aDrive);
       
   331     if(nRes != KErrNone)
       
   332         {
       
   333         delete pFsDesc;
       
   334         pFsDesc = NULL;
       
   335         Log(_L("# DoDismountOrginalFS Dismounting Err:%d\n"), nRes);
       
   336         }
       
   337     
       
   338     return pFsDesc;
       
   339 }
       
   340 
       
   341 //-----------------------------------------------------------------------------
       
   342 /**
       
   343     Tries to restore the original FS on the drive using the FS descriptor provided
       
   344     @return standard error code.
       
   345 */
       
   346 static TInt DoRestoreFS(RFs& aFs, TInt aDrive, CFileSystemDescriptor* apFsDesc)
       
   347     {
       
   348     TInt nRes;
       
   349 
       
   350     Log(_L("# DoRestoreFS drv:%d\n"), aDrive);
       
   351 
       
   352     //-- 1. check that there is no FS installed
       
   353         {
       
   354         TBuf<128>   fsName;
       
   355         nRes = aFs.FileSystemName(fsName, aDrive);
       
   356         if(nRes == KErrNone)
       
   357             {//-- probably no file system installed at all
       
   358             Log(_L("# This drive already has FS intalled:%S \n"), &fsName);
       
   359             return KErrAlreadyExists;
       
   360             }
       
   361         }
       
   362 
       
   363     TPtrC ptrN  (apFsDesc->FsName());
       
   364     TPtrC ptrExt(apFsDesc->PrimaryExtName());
       
   365     Log(_L("# Mounting FS:%S, Prim ext:%S, synch:%d\n"), &ptrN, &ptrExt, apFsDesc->DriveIsSynch());
       
   366 
       
   367     if(ptrExt.Length() >0)
       
   368         {//-- there is a primary extension to be mounted
       
   369         nRes = aFs.AddExtension(ptrExt);
       
   370         if(nRes != KErrNone && nRes != KErrAlreadyExists)
       
   371             {
       
   372             return nRes;
       
   373             }
       
   374 
       
   375         nRes = aFs.MountFileSystem(ptrN, ptrExt, aDrive, apFsDesc->DriveIsSynch());
       
   376         }
       
   377     else
       
   378         {
       
   379         nRes = aFs.MountFileSystem(ptrN, aDrive, apFsDesc->DriveIsSynch());
       
   380         }
       
   381 
       
   382     if(nRes != KErrNone)
       
   383         {
       
   384         Log(_L("# Mount failed! code:%d\n"),nRes);    
       
   385         }
       
   386 
       
   387     return nRes;
       
   388     }
       
   389 
       
   390 
       
   391 //-----------------------------------------------------------------------------
       
   392 /**
       
   393     Dismount the original FS from the drive and mount MsFS instead
       
   394 */
       
   395 static void MountMsFs(TInt driveNumber)
       
   396 	{
       
   397 	TInt x = console->WhereX();
       
   398 	TInt y = console->WhereY();
       
   399 
       
   400     //-- 1. try dismounting the original FS
       
   401     CFileSystemDescriptor* fsDesc = DoDismountOrginalFS(fs, driveNumber);
       
   402     unmountedFsList[driveNumber] = fsDesc;
       
   403     
       
   404     console->SetPos(0, 10);
       
   405 
       
   406     if(fsDesc)
       
   407         {
       
   408         TPtrC ptrN(fsDesc->FsName());
       
   409         LogPrint(_L("drv:%d FS:%S Dismounted OK"),driveNumber, &ptrN);
       
   410         }
       
   411     else
       
   412         {
       
   413         LogPrint(_L("drv:%d Dismount FS Failed!"),driveNumber);
       
   414         }
       
   415 
       
   416     console->ClearToEndOfLine();
       
   417 	
       
   418     //-- 2. try to mount the "MSFS"
       
   419     TInt error;
       
   420     error = fs.MountFileSystem(KMsFs, driveNumber);
       
   421 	console->SetPos(0, 11);
       
   422 	LogPrint(_L("MSFS Mount:   %S (%d)"), (error?&KError:&KOk), error);
       
   423 	console->ClearToEndOfLine();
       
   424 
       
   425 	if (!error)
       
   426 		msfsMountedList[driveNumber] = ETrue;
       
   427 
       
   428 	// restore console position
       
   429 	console->SetPos(x,y);
       
   430 	}
       
   431 
       
   432 //-----------------------------------------------------------------------------
       
   433 /**
       
   434     Dismount MsFS and mount the original FS 
       
   435 */
       
   436 static TInt RestoreMount(TInt driveNumber)
       
   437 	{
       
   438 	TInt err = KErrNone;
       
   439 	
       
   440 	TInt x = console->WhereX();
       
   441 	TInt y = console->WhereY();
       
   442 
       
   443     //-- 1. try dismounting the "MSFS"
       
   444 	if (msfsMountedList[driveNumber])
       
   445 		{
       
   446 		err = fs.DismountFileSystem(KMsFs, driveNumber);
       
   447 		console->SetPos(0, 11);
       
   448 		LogPrint(_L("MSFS Dismount:%S (%d)"), (err?&KError:&KOk), err);
       
   449 		console->ClearToEndOfLine();
       
   450 		if (err)
       
   451 			return err;
       
   452 
       
   453 		msfsMountedList[driveNumber] = EFalse;
       
   454         }
       
   455 
       
   456     //-- 2. try to mount the original FS back
       
   457     CFileSystemDescriptor* fsDesc = unmountedFsList[driveNumber];
       
   458     if(fsDesc)
       
   459         {
       
   460         err = DoRestoreFS(fs, driveNumber, fsDesc);
       
   461 
       
   462         TPtrC ptrN(fsDesc->FsName());
       
   463         console->SetPos(0, 10);
       
   464         LogPrint(_L("%S Mount:    %S (%d)"), &ptrN, (err?&KError:&KOk), err);
       
   465         console->ClearToEndOfLine();
       
   466         
       
   467         delete fsDesc;
       
   468         unmountedFsList[driveNumber] = NULL;
       
   469         }
       
   470 
       
   471     
       
   472     // restore console position
       
   473 	console->SetPos(x,y);
       
   474 	return err;
       
   475 	}
       
   476 
       
   477 //////////////////////////////////////////////////////////////////////////////
       
   478 //
       
   479 // CPropertyWatch
       
   480 // An active object that tracks changes to the KUsbMsDriveState properties
       
   481 //
       
   482 //////////////////////////////////////////////////////////////////////////////
       
   483 
       
   484 CPropertyWatch* CPropertyWatch::NewLC(TUsbMsDriveState_Subkey aSubkey, PropertyHandlers::THandler aHandler)
       
   485 	{
       
   486 	CPropertyWatch* me=new(ELeave) CPropertyWatch(aHandler);
       
   487 	CleanupStack::PushL(me);
       
   488 	me->ConstructL(aSubkey);
       
   489 	return me;
       
   490 	}
       
   491 
       
   492 CPropertyWatch::CPropertyWatch(PropertyHandlers::THandler aHandler)
       
   493 	: CActive(0), iHandler(aHandler)
       
   494 	{}
       
   495 
       
   496 void CPropertyWatch::ConstructL(TUsbMsDriveState_Subkey aSubkey)
       
   497 	{
       
   498 	User::LeaveIfError(iProperty.Attach(KUsbMsDriveState_Category, aSubkey));
       
   499 	CActiveScheduler::Add(this);
       
   500 	// initial subscription and process current property value
       
   501 	RunL();
       
   502 	}
       
   503 
       
   504 CPropertyWatch::~CPropertyWatch()
       
   505 	{
       
   506 	Cancel();
       
   507 	iProperty.Close();
       
   508 	}
       
   509 
       
   510 void CPropertyWatch::DoCancel()
       
   511 	{
       
   512 	iProperty.Cancel();
       
   513 	}
       
   514 
       
   515 void CPropertyWatch::RunL()
       
   516 	{
       
   517 	// resubscribe before processing new value to prevent missing updates
       
   518 	iProperty.Subscribe(iStatus);
       
   519 	SetActive();
       
   520 
       
   521 	iHandler(iProperty);
       
   522 	}
       
   523 
       
   524 //////////////////////////////////////////////////////////////////////////////
       
   525 //
       
   526 // CUsbWatch
       
   527 //
       
   528 //////////////////////////////////////////////////////////////////////////////
       
   529 
       
   530 CUsbWatch* CUsbWatch::NewLC(TAny* aUsb)
       
   531 	{
       
   532 	CUsbWatch* me=new(ELeave) CUsbWatch(aUsb);
       
   533 	CleanupStack::PushL(me);
       
   534 	me->ConstructL();
       
   535 	return me;
       
   536 	}
       
   537 
       
   538 CUsbWatch::CUsbWatch(TAny* aUsb)
       
   539 	: 
       
   540 	CActive(0), 
       
   541 	iUsb(aUsb),
       
   542 	iUsbDeviceState(EUsbDeviceStateUndefined),
       
   543 	iWasConfigured(EFalse)
       
   544 	{}
       
   545 
       
   546 void CUsbWatch::ConstructL()
       
   547 	{
       
   548 	CActiveScheduler::Add(this);
       
   549 	RunL();
       
   550 	}
       
   551 
       
   552 CUsbWatch::~CUsbWatch()
       
   553 	{
       
   554 	Cancel();
       
   555 //	iUsb.DeviceStateNotificationCancel();
       
   556 	if (gSharedChunkLdd)
       
   557 		((RDevUsbcScClient*)iUsb)->AlternateDeviceStatusNotifyCancel();
       
   558 	else
       
   559 		((RDevUsbcClient*)iUsb)->AlternateDeviceStatusNotifyCancel();
       
   560 	}
       
   561 
       
   562 void CUsbWatch::DoCancel()
       
   563 	{
       
   564 //	iUsb.DeviceStateNotificationCancel();
       
   565 	if (gSharedChunkLdd)
       
   566 		((RDevUsbcScClient*)iUsb)->AlternateDeviceStatusNotifyCancel();
       
   567 	else
       
   568 		((RDevUsbcClient*)iUsb)->AlternateDeviceStatusNotifyCancel();
       
   569 	}
       
   570 
       
   571 static TBool IsDriveConnected(TInt driveStatusIndex)
       
   572 	{
       
   573 	TInt driveStatus = PropertyHandlers::allDrivesStatus[2*driveStatusIndex+1];
       
   574 	return driveStatus >= EUsbMsDriveState_Connected ? ETrue : EFalse;
       
   575 	}
       
   576 
       
   577 static TChar DriveNumberToLetter(TInt driveNumber)
       
   578 	{
       
   579 	TChar driveLetter = '?';
       
   580 	fs.DriveToChar(driveNumber, driveLetter);
       
   581 	return driveLetter;
       
   582 	}
       
   583 
       
   584 static TBool IsDriveInMountList(TUint driveLetter)
       
   585 	{
       
   586 	TUint16 driveLetter16 = static_cast<TUint16>(driveLetter);
       
   587 	return(!mountList.Length() || KErrNotFound != mountList.Find(&driveLetter16, 1));
       
   588 	}
       
   589 
       
   590 void CUsbWatch::RunL()
       
   591 	{
       
   592 //	RDebug::Print(_L(">> CUsbWatch[%d] %d"), iUsbDeviceState, iWasConfigured);
       
   593 
       
   594 //	const TUint stateMask = 0xFF;
       
   595 //	iUsb.DeviceStateNotification(stateMask, iUsbDeviceState, iStatus);
       
   596 	if (gSharedChunkLdd)
       
   597 		((RDevUsbcScClient*)iUsb)->AlternateDeviceStatusNotify(iStatus, iUsbDeviceState);
       
   598 	else
       
   599 		((RDevUsbcClient*)iUsb)->AlternateDeviceStatusNotify(iStatus, iUsbDeviceState);
       
   600 
       
   601 	SetActive();
       
   602 
       
   603 	//RDebug::Print(_L("CUsbWatch DeviceStateNotification: iUsbDeviceState=%d"), iUsbDeviceState);
       
   604 
       
   605 	// If the cable is disconnected, unmount all the connected drives.
       
   606 	if(iWasConfigured && iUsbDeviceState == EUsbDeviceStateUndefined)
       
   607 		{
       
   608 		for(TInt i=0; i<PropertyHandlers::allDrivesStatus.Length()/2; i++)
       
   609 			{
       
   610 			if(IsDriveConnected(i))
       
   611 				{
       
   612 				//RDebug::Print(_L("CUsbWatch calling RestoreMount"));
       
   613 				RestoreMount(PropertyHandlers::allDrivesStatus[2*i]);
       
   614 #ifdef USB_BOOT_LOADER
       
   615 				// exit and reboot
       
   616 				CActiveScheduler::Stop();
       
   617 #endif
       
   618 				}
       
   619 			}
       
   620 
       
   621 		iWasConfigured = EFalse;
       
   622 		}
       
   623 
       
   624 	// If cable is connected, mount all drives in the auto-mount list.
       
   625 	// This is done for performance, since if this is not done here,
       
   626 	// mounting will happen later after each drive enters the 
       
   627 	// Connecting state.
       
   628 	if(iUsbDeviceState == EUsbDeviceStateConfigured)
       
   629 		{
       
   630 		for(TInt i=0; i<PropertyHandlers::allDrivesStatus.Length()/2; i++)
       
   631 			{
       
   632 			TInt driveNumber = PropertyHandlers::allDrivesStatus[2*i];
       
   633 			if(!IsDriveConnected(i) && IsDriveInMountList(DriveNumberToLetter(driveNumber)))
       
   634 				{
       
   635 				//RDebug::Print(_L("CUsbWatch calling MountMsFs"));
       
   636 				MountMsFs(driveNumber);
       
   637 				}
       
   638 			}
       
   639 
       
   640 		iWasConfigured = ETrue;
       
   641 		}
       
   642 	}
       
   643 
       
   644 //////////////////////////////////////////////////////////////////////////////
       
   645 //
       
   646 // PropertyHandlers
       
   647 //
       
   648 //////////////////////////////////////////////////////////////////////////////
       
   649 
       
   650 TBuf8<16> PropertyHandlers::allDrivesStatus;
       
   651 TUsbMsBytesTransferred PropertyHandlers::iKBytesRead;
       
   652 TUsbMsBytesTransferred PropertyHandlers::iKBytesWritten;
       
   653 TInt PropertyHandlers::iMediaError;
       
   654 
       
   655 void PropertyHandlers::Read(RProperty& aProperty)
       
   656 	{
       
   657 	Transferred(aProperty, iKBytesRead);
       
   658 	}
       
   659 
       
   660 void PropertyHandlers::Written(RProperty& aProperty)
       
   661 	{
       
   662 	Transferred(aProperty, iKBytesWritten);
       
   663 	}
       
   664 
       
   665 void PropertyHandlers::Transferred(RProperty& aProperty, TUsbMsBytesTransferred& aReadOrWritten)
       
   666 	{
       
   667 	console->SetPos(0,1);
       
   668 	console->Printf(_L("KB R/W:  "));
       
   669 	TInt err = aProperty.Get(aReadOrWritten);
       
   670 	if(err == KErrNone)
       
   671 		{
       
   672 		for(TInt i = 0; i < allDrivesStatus.Length()/2; i++)
       
   673 			{
       
   674 			console->Printf(KBytesTransferredFmt, (char)DriveNumberToLetter(allDrivesStatus[2*i]), iKBytesRead[i], iKBytesWritten[i]);
       
   675 			}
       
   676 		console->ClearToEndOfLine();
       
   677 		}
       
   678 	else
       
   679 		{
       
   680 		console->Printf(KErrFmt, err);
       
   681 		}
       
   682 	}
       
   683 
       
   684 void PropertyHandlers::DriveStatus(RProperty& aProperty)
       
   685 	{
       
   686 //	RDebug::Print(_L(">> PropertyHandlers::DriveStatus"));
       
   687 	TInt err = aProperty.Get(allDrivesStatus);
       
   688 	console->SetPos(0,0);
       
   689 	if(err == KErrNone)
       
   690 		{
       
   691 		LogPrint(_L("Status:  "));
       
   692 		for(TInt i = 0; i < allDrivesStatus.Length()/2; i++)
       
   693 			{
       
   694 			TInt driveNumber = allDrivesStatus[2*i];
       
   695 			TInt driveStatus = allDrivesStatus[2*i+1];
       
   696 			TChar driveLetter = DriveNumberToLetter(driveNumber);
       
   697 
       
   698 //			RDebug::Print(_L("%c:%d   "), (char)driveLetter, driveStatus);
       
   699 
       
   700 			switch(driveStatus)
       
   701 				{
       
   702 				case EUsbMsDriveState_Disconnected:
       
   703 					{
       
   704 					LogPrint(_L("%c:%d:Disconnected "), (char)driveLetter, driveStatus);
       
   705 					break;
       
   706 					}
       
   707 				case EUsbMsDriveState_Connecting:
       
   708 					{
       
   709 					LogPrint(_L("%c:%d:Connecting   "), (char)driveLetter, driveStatus);
       
   710 					break;
       
   711 					}
       
   712 				case EUsbMsDriveState_Connected:
       
   713 					{
       
   714 					LogPrint(_L("%c:%d:Connected    "), (char)driveLetter, driveStatus);
       
   715 					break;
       
   716 					}
       
   717 				case EUsbMsDriveState_Disconnecting:
       
   718 					{
       
   719 					LogPrint(_L("%c:%d:Disconnecting"), (char)driveLetter, driveStatus);
       
   720 					break;
       
   721 					}
       
   722 				case EUsbMsDriveState_Active:
       
   723 					{
       
   724 					LogPrint(_L("%c:%d:Active       "), (char)driveLetter, driveStatus);
       
   725 					break;
       
   726 					}
       
   727 				case EUsbMsDriveState_Locked:
       
   728 					{
       
   729 					LogPrint(_L("%c:%d:Locked       "), (char)driveLetter, driveStatus);
       
   730 					break;
       
   731 					}
       
   732 				case EUsbMsDriveState_MediaNotPresent:
       
   733 					{
       
   734 					LogPrint(_L("%c:%d:Not Present  "), (char)driveLetter, driveStatus);
       
   735 					break;
       
   736 					}
       
   737 				case EUsbMsDriveState_Removed:
       
   738 					{
       
   739 					LogPrint(_L("%c:%d:Removed      "), (char)driveLetter, driveStatus);
       
   740 					break;
       
   741 					}
       
   742 				case EUsbMsDriveState_Error:
       
   743 					{
       
   744 					LogPrint(_L("%c:%d:Error        "), (char)driveLetter, driveStatus);
       
   745 					break;
       
   746 					}
       
   747 				default :
       
   748 					{
       
   749 					LogPrint(_L("%c:%d:Unknown      "), (char)driveLetter, driveStatus);
       
   750 					break;
       
   751 					}
       
   752 				}
       
   753 
       
   754 			if(IsDriveInMountList(driveLetter))
       
   755 				{
       
   756 #ifndef USB_BOOT_LOADER
       
   757 				if (driveStatus == EUsbMsDriveState_Connecting)
       
   758 					{
       
   759 					MountMsFs(driveNumber);
       
   760 					}
       
   761 				else if (driveStatus == EUsbMsDriveState_Disconnected)
       
   762 					{
       
   763 					RestoreMount(driveNumber);
       
   764 					}
       
   765 #else
       
   766 				if (driveStatus == EUsbMsDriveState_Disconnecting)
       
   767 					{
       
   768 					RestoreMount(driveNumber);
       
   769 					}
       
   770 				else if (driveStatus == EUsbMsDriveState_Disconnected)
       
   771 					{
       
   772 					static TBool firstTime = ETrue;
       
   773 
       
   774 					if (!firstTime)
       
   775 						{
       
   776 						RDebug::Print(_L("Eject..."));
       
   777 						// Exit and reboot the target upon receipt of an eject
       
   778 						CActiveScheduler::Stop();
       
   779 						rebootit();
       
   780 						}
       
   781 						
       
   782 					firstTime = EFalse;
       
   783 					}
       
   784 #endif
       
   785 				else
       
   786 					{
       
   787 					//RDebug::Print(_L("PropertyHandlers::DriveStatus: nothing to do"));
       
   788 					}
       
   789 				}
       
   790 			else
       
   791 				{
       
   792 				//RDebug::Print(_L("PropertyHandlers::DriveStatus: %c: is not in mountList\n"), driveLetter);
       
   793 				}
       
   794 			}
       
   795 		}
       
   796 	else
       
   797 		{
       
   798 		LogPrint(KErrFmt, err);
       
   799 		}
       
   800 
       
   801 	//RDebug::Print(_L("<< PropertyHandlers::DriveStatus"));
       
   802 	}
       
   803 
       
   804 void PropertyHandlers::MediaError(RProperty& aProperty)
       
   805 	{
       
   806 	TInt err = aProperty.Get(iMediaError);
       
   807 	if(err != KErrNone)
       
   808 		{
       
   809 		// RDebug::Printf("RProperty::Get returned %d", err);
       
   810 		return;
       
   811 		}
       
   812 
       
   813 	//RDebug::Printf("PropertyHandlers::MediaError %x", iMediaError);
       
   814 
       
   815 	TInt x = console->WhereX();
       
   816 	TInt y = console->WhereY();
       
   817 	Clear(27,1);
       
   818 	LogPrint(_L("Media Error %x"), iMediaError);
       
   819 	// restore console position
       
   820 	console->SetPos(x,y);
       
   821 	}
       
   822 
       
   823 //////////////////////////////////////////////////////////////////////////////
       
   824 //
       
   825 // CMessageKeyProcessor
       
   826 //
       
   827 //////////////////////////////////////////////////////////////////////////////
       
   828 CMessageKeyProcessor::CMessageKeyProcessor(CConsoleBase* aConsole)
       
   829 	: CActive(CActive::EPriorityUserInput), iConsole(aConsole)
       
   830 	{
       
   831 	} 
       
   832 
       
   833 CMessageKeyProcessor* CMessageKeyProcessor::NewLC(CConsoleBase* aConsole
       
   834 												 )
       
   835 	{
       
   836 	CMessageKeyProcessor* self=new (ELeave) CMessageKeyProcessor(aConsole);
       
   837 	CleanupStack::PushL(self);
       
   838 	self->ConstructL();
       
   839 	return self;
       
   840 	}
       
   841 
       
   842 CMessageKeyProcessor* CMessageKeyProcessor::NewL(CConsoleBase* aConsole
       
   843 												)
       
   844 	{
       
   845 	CMessageKeyProcessor* self = NewLC(aConsole);
       
   846 	CleanupStack::Pop();
       
   847 	return self;
       
   848 	}
       
   849 
       
   850 void CMessageKeyProcessor::ConstructL()
       
   851 	{
       
   852 	// Add to active scheduler
       
   853 	CActiveScheduler::Add(this);
       
   854 	RequestCharacter();
       
   855 	}
       
   856 
       
   857 #ifndef USB_BOOT_LOADER
       
   858 void CMessageKeyProcessor::MakePassword(TMediaPassword &aPassword)
       
   859 	{
       
   860 	//  Create password with same format as eshell and S60
       
   861 	TBuf<3> password(KDefPwd);
       
   862 
       
   863 	// fill aPassword with contents of password, not converting to ASCII
       
   864 	const TInt byteLen = password.Length() * 2;
       
   865 	aPassword.Copy(reinterpret_cast<const TUint8 *>(password.Ptr()), byteLen);
       
   866 	}
       
   867 #endif
       
   868 
       
   869 
       
   870 CMessageKeyProcessor::~CMessageKeyProcessor()
       
   871 	{
       
   872 	// Make sure we're cancelled
       
   873 	Cancel();
       
   874 	}
       
   875 
       
   876 void  CMessageKeyProcessor::DoCancel()
       
   877 	{
       
   878 	iConsole->ReadCancel();
       
   879 	}
       
   880 
       
   881 void  CMessageKeyProcessor::RunL()
       
   882 	{
       
   883 	  // Handle completed request
       
   884 	ProcessKeyPress(TChar(iConsole->KeyCode()));
       
   885 	}
       
   886 
       
   887 void CMessageKeyProcessor::RequestCharacter()
       
   888 	{
       
   889 	  // A request is issued to the CConsoleBase to accept a
       
   890 	  // character from the keyboard.
       
   891 	iConsole->Read(iStatus); 
       
   892 	SetActive();
       
   893 	}
       
   894 
       
   895 void CMessageKeyProcessor::ProcessKeyPress(TChar aChar)
       
   896 	{
       
   897 #ifndef USB_BOOT_LOADER
       
   898 	TInt error = KErrNone;
       
   899 #endif
       
   900 #if defined(_DEBUG)
       
   901 	static TBool tracetoggle=EFalse;
       
   902 #endif
       
   903 
       
   904 	switch(aChar)
       
   905 		{
       
   906 		case 'q':
       
   907 		case 'Q':
       
   908 		case EKeyEscape:
       
   909 			{
       
   910 			TInt err = KErrNone;
       
   911 			for(TInt j=0; j<KMaxDrives; j++)
       
   912 				{
       
   913 				err = RestoreMount(j);
       
   914 				
       
   915 				if (err)
       
   916 					{
       
   917 					// Mount is busy/locked and can not be restored.
       
   918 					break;
       
   919 					}
       
   920 
       
   921 				}
       
   922 
       
   923 			if (err == KErrNone)
       
   924 				{
       
   925 #ifdef USB_BOOT_LOADER
       
   926 					gRebootDelay=0;	// Force reboot to occur immediately
       
   927 #endif				
       
   928 				CActiveScheduler::Stop();
       
   929 				return;
       
   930 				}
       
   931 
       
   932 			}
       
   933 			break;
       
   934 
       
   935 #if defined(_DEBUG)
       
   936 		case 't':
       
   937 		case 'T':
       
   938 			tracetoggle=!tracetoggle;
       
   939 			if (tracetoggle)	// 0x44008401
       
   940 				User::SetDebugMask(KHARDWARE|KDLL|KSCRATCH|KPOWER|KMEMTRACE);
       
   941 			else
       
   942 				User::SetDebugMask(0);
       
   943 			break;
       
   944 #endif
       
   945 
       
   946 #ifndef USB_BOOT_LOADER
       
   947 		case 'd':
       
   948 		case 'D':
       
   949 			if(++selectedDriveIndex >= PropertyHandlers::allDrivesStatus.Length()/2)
       
   950 				{
       
   951 				selectedDriveIndex = 0;
       
   952 				}
       
   953 			ShowDriveSelection();
       
   954 			break;
       
   955 
       
   956 		case 'm':
       
   957 		case 'M':
       
   958 			if(PropertyHandlers::allDrivesStatus.Length())
       
   959 				{
       
   960 				MountMsFs(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   961 				}
       
   962 			break;
       
   963 
       
   964 		case 'u':
       
   965 		case 'U':
       
   966 			if(PropertyHandlers::allDrivesStatus.Length())
       
   967 				{
       
   968 				RestoreMount(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]);
       
   969 				}
       
   970 			break;
       
   971 
       
   972 		case 'l':
       
   973 			{
       
   974 			// lock unprotected drive
       
   975 			TMediaPassword password;
       
   976 			MakePassword(password);
       
   977 
       
   978 			_LIT(KEmpty, "");
       
   979 			TMediaPassword nul;
       
   980 			nul.Copy(KEmpty);
       
   981 			error = fs.LockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   982                                  nul, password, ETrue);
       
   983 			console->SetPos(0,9);
       
   984 			LogPrint(_L("LockDrive %S (%d)"), (error?&KError:&KOk), error);
       
   985 			break;
       
   986 			}
       
   987 
       
   988 			case 'L':
       
   989             {
       
   990             // lock password protected drive
       
   991             TMediaPassword password;
       
   992             MakePassword(password);
       
   993             error = fs.LockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
   994                                  password, password, ETrue);
       
   995             console->SetPos(0,9);
       
   996             LogPrint(_L("LockDrive %S (%d)"), (error?&KError:&KOk), error);
       
   997             break;
       
   998             }
       
   999 
       
  1000 		case 'n':
       
  1001         case 'N':
       
  1002             {
       
  1003             TMediaPassword password;
       
  1004             MakePassword(password);
       
  1005             error = fs.UnlockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
  1006                                    password, ETrue);
       
  1007             Clear(9);
       
  1008             LogPrint(_L("UnlockDrive %S (%d)"), (error?&KError:&KOk), error);
       
  1009             }
       
  1010 			break;
       
  1011 			
       
  1012 		case 'c':
       
  1013         case 'C':
       
  1014             {
       
  1015             TMediaPassword password;
       
  1016             MakePassword(password);
       
  1017             error = fs.ClearPassword(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2],
       
  1018                                      password);
       
  1019             Clear(9);
       
  1020             LogPrint(_L("ClearPassword %S (%d)"), (error?&KError:&KOk), error);
       
  1021             }
       
  1022 			break;
       
  1023 #endif
       
  1024 
       
  1025 		default:
       
  1026 			break;
       
  1027 		}
       
  1028 	RequestCharacter();
       
  1029 	}
       
  1030 
       
  1031 #ifdef USB_BOOT_LOADER
       
  1032 
       
  1033 static void RunMode()
       
  1034 	{
       
  1035 	RFs fs;
       
  1036 
       
  1037 	TInt r=fs.Connect();
       
  1038 	if (r!=KErrNone)
       
  1039 		{
       
  1040 		RDebug::Print(_L("Help\n"));
       
  1041 		return;
       
  1042 		}
       
  1043 
       
  1044 	TFileName sessionpath = _L("?:\\");
       
  1045 
       
  1046 	TDriveList drivelist;
       
  1047 	fs.DriveList(drivelist);
       
  1048 	for (TInt driveno=EDriveC; driveno<=EDriveZ; driveno++)
       
  1049 		{
       
  1050 		if (!drivelist[driveno])
       
  1051 			continue;
       
  1052 
       
  1053 		sessionpath[0]='A'+driveno;
       
  1054 
       
  1055 		/*
       
  1056 		 If a filename with the format EJECTDELAY.nnn is found, delay any reboot
       
  1057 		 action by "nnn" seconds
       
  1058 		 */
       
  1059 		CDir* dir;
       
  1060 		TFindFile finder(fs);
       
  1061 		r=finder.FindWildByPath(_L("EJECTDELAY.*"),&sessionpath,dir);
       
  1062 		if (r == KErrNone)
       
  1063 			{ // Found one or more files
       
  1064 			TEntry entry;
       
  1065 			entry=(*dir)[0];
       
  1066 
       
  1067 			TParse parser;
       
  1068 			parser.Set(entry.iName, NULL, NULL);
       
  1069 			TPtrC tok = parser.Ext();
       
  1070 			TLex lex(tok);
       
  1071 			lex.SkipAndMark(1);
       
  1072 			tok.Set(lex.NextToken());
       
  1073 			lex.Assign(tok);
       
  1074 
       
  1075 			r=lex.Val(gRebootDelay);
       
  1076 			if (r!=KErrNone)
       
  1077 				continue;
       
  1078 			}
       
  1079 		}
       
  1080 	}
       
  1081 
       
  1082 #endif
       
  1083 
       
  1084 //////////////////////////////////////////////////////////////////////////////
       
  1085 //
       
  1086 // Application entry point
       
  1087 //
       
  1088 //////////////////////////////////////////////////////////////////////////////
       
  1089 static void RunAppL()
       
  1090 	{
       
  1091 #ifdef USB_BOOT_LOADER
       
  1092 	RunMode();
       
  1093 #endif
       
  1094 
       
  1095     TInt error = KErrUnknown;
       
  1096 
       
  1097 	//RDebug::Print(_L("USBMSAPP: Creating console\n"));
       
  1098 
       
  1099 #ifdef USB_BOOT_LOADER
       
  1100 	console = Console::NewL(KVariantUsbmsTitle,TSize(KConsFullScreen,KConsFullScreen));
       
  1101 #else
       
  1102 	console = Console::NewL(KTxtApp,TSize(KConsFullScreen,KConsFullScreen));
       
  1103 #endif
       
  1104 
       
  1105 	CleanupStack::PushL(console);
       
  1106 
       
  1107 	console->SetPos(0,2);
       
  1108 	console->Printf(_L("========================================"));
       
  1109 
       
  1110 	CActiveScheduler* sched = new(ELeave) CActiveScheduler;
       
  1111 	CleanupStack::PushL(sched);
       
  1112 	CActiveScheduler::Install(sched);
       
  1113 
       
  1114 	TBuf<20> KDriverFileName;
       
  1115 	// Load the logical device
       
  1116 	RDevUsbcClient usb;
       
  1117 	RDevUsbcScClient usbsc;
       
  1118 	RChunk gChunk;
       
  1119 
       
  1120 	fs.Connect();
       
  1121 	CleanupClosePushL(fs);
       
  1122 
       
  1123 	_LIT(KMountAllDefault,"(all)");
       
  1124 	console->SetPos(0,3);
       
  1125 	LogPrint(_L("Drives to auto-mount: %S"), (mountList.Length() ? &mountList : &KMountAllDefault));
       
  1126 
       
  1127 	// Add MS file system
       
  1128 	error = fs.AddFileSystem(KMsFsy);
       
  1129 
       
  1130 	if(error != KErrNone && error != KErrAlreadyExists)
       
  1131 		{
       
  1132 		User::Leave(error);
       
  1133 		}
       
  1134 	console->SetPos(0,4);
       
  1135 	LogPrint(_L("MSFS file system:\tAdded OK\n"));
       
  1136 
       
  1137 	if (gSharedChunkLdd)
       
  1138 		{
       
  1139 		KDriverFileName = _L("EUSBCSC.LDD");
       
  1140 		error = User::LoadLogicalDevice(KDriverFileName);
       
  1141 		}
       
  1142 	else
       
  1143 		{
       
  1144 		KDriverFileName = _L("EUSBC.LDD");
       
  1145 		error = User::LoadLogicalDevice(KDriverFileName);
       
  1146 		}
       
  1147 
       
  1148 	if (error != KErrAlreadyExists)
       
  1149 		{
       
  1150 		User::LeaveIfError(error);
       
  1151 		}
       
  1152 
       
  1153 
       
  1154 	if (gSharedChunkLdd)
       
  1155 		{
       
  1156 		error = usbsc.Open(0);
       
  1157 		}
       
  1158 	else
       
  1159 		{
       
  1160 		error = usb.Open(0);
       
  1161 		}
       
  1162 
       
  1163 	User::LeaveIfError(error);
       
  1164 
       
  1165 #ifdef BUILD_OTG_USBMSAPP
       
  1166 
       
  1167 	_LIT(KOtgdiLddFilename, "otgdi");
       
  1168 	// Check for OTG support
       
  1169 	TBuf8<KUsbDescSize_Otg> otg_desc;
       
  1170 		if (gSharedChunkLdd)
       
  1171 		{
       
  1172 		error = usbsc.GetOtgDescriptor(otg_desc);
       
  1173 		}
       
  1174 	else
       
  1175 		{
       
  1176 		error = usb.GetOtgDescriptor(otg_desc);
       
  1177 		}
       
  1178 
       
  1179 	if (!(error == KErrNotSupported || error == KErrNone))
       
  1180 		{
       
  1181 		LogPrint(_L("Error %d while fetching OTG descriptor"), error);
       
  1182 		User::Leave(-1);
       
  1183 		return;
       
  1184 		}
       
  1185 
       
  1186 	// On an OTG device we have to start the OTG driver, otherwise the Client
       
  1187 	// stack will remain disabled forever.
       
  1188 	if (error == KErrNotSupported)
       
  1189 	{
       
  1190 	if (gSharedChunkLdd)
       
  1191 		{
       
  1192 		CleanupClosePushL(usbsc);
       
  1193 		}
       
  1194 	else
       
  1195 		{
       
  1196 		CleanupClosePushL(usb);
       
  1197 		}
       
  1198 
       
  1199 		User::Leave(-1);
       
  1200 	}
       
  1201 
       
  1202 	error = User::LoadLogicalDevice(KOtgdiLddFilename);
       
  1203 
       
  1204 	if (error != KErrNone)
       
  1205 		{
       
  1206 		LogPrint(_L("Error %d on loading OTG LDD"), error);
       
  1207 		User::Leave(-1);
       
  1208 		return;
       
  1209 		}
       
  1210 
       
  1211 	RUsbOtgDriver iOtgPort;
       
  1212 
       
  1213 	error = iOtgPort.Open();
       
  1214 
       
  1215 	if (error != KErrNone)
       
  1216 		{
       
  1217 		LogPrint(_L("Error %d on opening OTG port"), error);
       
  1218 		User::Leave(-1);
       
  1219 		return;
       
  1220 		}
       
  1221 	error = iOtgPort.StartStacks();
       
  1222 
       
  1223 	if (error != KErrNone)
       
  1224 		{
       
  1225 		LogPrint(_L("Error %d on starting USB stack"), error);
       
  1226 		User::Leave(-1);
       
  1227 		return;
       
  1228 		}
       
  1229 
       
  1230 #endif
       
  1231 
       
  1232 	if (gSharedChunkLdd)
       
  1233 		{
       
  1234 		CleanupClosePushL(usbsc);
       
  1235 		RChunk *tChunk = &gChunk;
       
  1236 		usbsc.FinalizeInterface(tChunk);
       
  1237 		}
       
  1238 	else
       
  1239 		{
       
  1240 		CleanupClosePushL(usb);
       
  1241 		}
       
  1242 
       
  1243 
       
  1244 //		RDebug::Print(_L("USBMSAPP: Create active objects\n"));
       
  1245 	CMessageKeyProcessor::NewLC(console);
       
  1246 	CPropertyWatch::NewLC(EUsbMsDriveState_KBytesRead, PropertyHandlers::Read);
       
  1247 	CPropertyWatch::NewLC(EUsbMsDriveState_KBytesWritten, PropertyHandlers::Written);
       
  1248 	CPropertyWatch::NewLC(EUsbMsDriveState_DriveStatus, PropertyHandlers::DriveStatus);
       
  1249 	CPropertyWatch::NewLC(EUsbMsDriveState_MediaError, PropertyHandlers::MediaError);
       
  1250 	if (gSharedChunkLdd)
       
  1251 		{
       
  1252 		CUsbWatch::NewLC(&usbsc);
       
  1253 		}
       
  1254 	else
       
  1255 		{
       
  1256 		CUsbWatch::NewLC(&usb);
       
  1257 		}
       
  1258 
       
  1259 	CPeriodUpdate::NewLC();
       
  1260 
       
  1261 	RUsbMassStorage UsbMs;
       
  1262 	TBuf<8>  t_vendorId(_L("vendor"));
       
  1263 	TBuf<16> t_productId(_L("product"));
       
  1264 	TBuf<4>  t_productRev(_L("1.00"));
       
  1265 
       
  1266 	TMassStorageConfig msConfig;
       
  1267 	msConfig.iVendorId.Copy(t_vendorId);
       
  1268 	msConfig.iProductId.Copy(t_productId);
       
  1269 	msConfig.iProductRev.Copy(t_productRev);
       
  1270 
       
  1271 //   	console->Printf(_L("Connect to Mass Storage"));
       
  1272 	error = UsbMs.Connect();
       
  1273 	User::LeaveIfError(error);
       
  1274 
       
  1275 //   	console->Printf(_L("Start Mass Storage"));
       
  1276 	error = UsbMs.Start(msConfig);
       
  1277 	User::LeaveIfError(error);
       
  1278 
       
  1279 	TBuf8<KUsbDescSize_Device> deviceDescriptor;
       
  1280 	if (gSharedChunkLdd)
       
  1281 		{
       
  1282 		error = usbsc.GetDeviceDescriptor(deviceDescriptor);
       
  1283 		}
       
  1284 	else
       
  1285 		{
       
  1286 		error = usb.GetDeviceDescriptor(deviceDescriptor);
       
  1287 		}
       
  1288 
       
  1289 	User::LeaveIfError(error);
       
  1290 
       
  1291 	const TInt KUsbSpecOffset = 2;
       
  1292 	const TInt KUsbDeviceClassOffset = 4;
       
  1293 	const TInt KUsbVendorIdOffset = 8;
       
  1294 	const TInt KUsbProductIdOffset = 10;
       
  1295 	const TInt KUsbDevReleaseOffset = 12;
       
  1296 	//Change the USB spec number to 2.00
       
  1297 	deviceDescriptor[KUsbSpecOffset]   = 0x00;
       
  1298 	deviceDescriptor[KUsbSpecOffset+1] = 0x02;
       
  1299 	//Change the Device Class, Device SubClass and Device Protocol 
       
  1300 	deviceDescriptor[KUsbDeviceClassOffset] = 0x00;
       
  1301 	deviceDescriptor[KUsbDeviceClassOffset+1] = 0x00;
       
  1302 	deviceDescriptor[KUsbDeviceClassOffset+2] = 0x00;
       
  1303 	//Change the device vendor ID (VID) to 0x0E22 (Symbian)
       
  1304 	deviceDescriptor[KUsbVendorIdOffset]   = 0x22;   // little endian
       
  1305 	deviceDescriptor[KUsbVendorIdOffset+1] = 0x0E;
       
  1306 	//Change the device product ID (PID) to 0x1111
       
  1307 	deviceDescriptor[KUsbProductIdOffset]   = 0x12;
       
  1308 	deviceDescriptor[KUsbProductIdOffset+1] = 0x11;
       
  1309 	//Change the device release number to 3.05
       
  1310 	deviceDescriptor[KUsbDevReleaseOffset]   = 0x05;
       
  1311 	deviceDescriptor[KUsbDevReleaseOffset+1] = 0x03;
       
  1312 	if (gSharedChunkLdd)
       
  1313 		{
       
  1314 		error = usbsc.SetDeviceDescriptor(deviceDescriptor);
       
  1315 		}
       
  1316 	else
       
  1317 		{
       
  1318 		error = usb.SetDeviceDescriptor(deviceDescriptor);
       
  1319 		}
       
  1320 
       
  1321 	User::LeaveIfError(error);
       
  1322 
       
  1323 	// Remove possible Remote-Wakup support in Configuration descriptor,
       
  1324 	// so that we can use the MSC device also easily for Chapter9 testing.
       
  1325 	TBuf8<KUsbDescSize_Config> configDescriptor;
       
  1326 	if (gSharedChunkLdd)
       
  1327 		{
       
  1328 		error = usbsc.GetConfigurationDescriptor(configDescriptor);
       
  1329 		}
       
  1330 	else
       
  1331 		{
       
  1332 		error = usb.GetConfigurationDescriptor(configDescriptor);
       
  1333 		}
       
  1334 
       
  1335 	User::LeaveIfError(error);
       
  1336 	const TInt KConfDesc_AttribOffset = 7;
       
  1337 	configDescriptor[KConfDesc_AttribOffset] &= ~KUsbDevAttr_RemoteWakeup;
       
  1338 	if (gSharedChunkLdd)
       
  1339 		{
       
  1340 		error = usbsc.SetConfigurationDescriptor(configDescriptor);
       
  1341 		}
       
  1342 	else
       
  1343 		{
       
  1344 		error = usb.SetConfigurationDescriptor(configDescriptor);
       
  1345 		}
       
  1346 
       
  1347 	User::LeaveIfError(error);
       
  1348 
       
  1349 	_LIT16(productID_L, "Symbian USB Mass Storage Device (Base)");
       
  1350 	TBuf16<KUsbStringDescStringMaxSize / 2> productID(productID_L);
       
  1351 		if (gSharedChunkLdd)
       
  1352 		{
       
  1353 		error = usbsc.SetProductStringDescriptor(productID);
       
  1354 		}
       
  1355 	else
       
  1356 		{
       
  1357 		error = usb.SetProductStringDescriptor(productID);
       
  1358 		}
       
  1359 
       
  1360 	User::LeaveIfError(error); 
       
  1361 
       
  1362 	TRequestStatus enum_status;
       
  1363 	console->SetPos(0,5);
       
  1364 	LogPrint(_L("Re-enumerating...\n"));
       
  1365 
       
  1366 #ifdef BUILD_OTG_USBMSAPP
       
  1367     // For OTG: The USB stack may not yet in the peripheral role. If it is not,
       
  1368     // then ReEnumerate() will not work here as the stack will ignore the call
       
  1369     // since the stack is not active. Therefore we simulate device connection to
       
  1370     // force the stack into peripheral role by calling DeviceConnectToHost().
       
  1371 	if (gSharedChunkLdd)
       
  1372 		{
       
  1373         usbsc.DeviceConnectToHost();
       
  1374         usbsc.ReEnumerate(enum_status);
       
  1375 		
       
  1376 		}
       
  1377 	else
       
  1378 		{
       
  1379         usb.DeviceConnectToHost();
       
  1380         usb.ReEnumerate(enum_status);		
       
  1381 		}    
       
  1382 #else
       
  1383 	if (gSharedChunkLdd)
       
  1384 		{
       
  1385 		usbsc.ReEnumerate(enum_status);
       
  1386 		}
       
  1387 	else
       
  1388 		{
       
  1389 		usb.ReEnumerate(enum_status);
       
  1390 		}
       
  1391 #endif
       
  1392 
       
  1393 	User::LeaveIfError(error);
       
  1394 	console->SetPos(0,5);
       
  1395 	User::WaitForRequest(enum_status);
       
  1396 	if(enum_status.Int() == KErrNone)
       
  1397 		LogPrint(_L("Re-enumeration Done\n"));
       
  1398 	else
       
  1399 		LogPrint(_L("Re-enumeration not successfully done\n"));
       
  1400 
       
  1401 #ifndef USB_BOOT_LOADER
       
  1402     console->SetPos(0,14);
       
  1403     TBuf<3>password(KDefPwd);
       
  1404     LogPrint(_L("Password: %S"), &password);
       
  1405 #endif
       
  1406 	ShowDriveSelection();
       
  1407 
       
  1408 	console->SetPos(0,17);
       
  1409 #ifdef USB_BOOT_LOADER
       
  1410 	_LIT(KMsgTitleB,"Menu:\n[Esc,Q]=RESET (boot image)\n");
       
  1411 #else
       
  1412 	_LIT(KMsgTitleB,"Menu: q=quit  d=chg drv\n      m=mount u=unmount\n       l=lock n=unlock\n      c=clr pwd");
       
  1413 #endif
       
  1414 
       
  1415 	//RDebug::Print(_L("USBMSAPP: Start CActiveScheduler\n"));
       
  1416 
       
  1417 	console->Printf(KMsgTitleB);
       
  1418 
       
  1419 #ifdef USB_BOOT_LOADER
       
  1420 	// Mount the mass storage on variant specific drive
       
  1421 	MountMsFs(KVariantUsbmsRemoveableDrive);
       
  1422 #endif
       
  1423 
       
  1424 	CActiveScheduler::Start();
       
  1425 
       
  1426 	error = UsbMs.Stop();
       
  1427 	User::LeaveIfError(error);
       
  1428 	UsbMs.Close();
       
  1429 	error = fs.RemoveFileSystem(KMsFs);
       
  1430 	User::LeaveIfError(error);
       
  1431 
       
  1432 	//The console object is left on the Cleanup Stack,
       
  1433 	//which is used in the delay processing logic of rebootit(). 
       
  1434 	CleanupStack::PopAndDestroy(10);
       
  1435 
       
  1436 #ifdef BUILD_OTG_USBMSAPP
       
  1437 	iOtgPort.StopStacks();
       
  1438 	iOtgPort.Close();
       
  1439 	error = User::FreeLogicalDevice(RUsbOtgDriver::Name());
       
  1440 	User::LeaveIfError(error);
       
  1441 #endif
       
  1442 
       
  1443 	// UnLoad the logical device
       
  1444 	TBuf<20> KDriverName;
       
  1445 	if (gSharedChunkLdd)
       
  1446 		{
       
  1447 		KDriverName = _L("USBCSC");
       
  1448 		gChunk.Close();
       
  1449 		usbsc.Close();
       
  1450 		User::After(100000);
       
  1451 		error = User::FreeLogicalDevice(KDriverName);
       
  1452 		}
       
  1453 	else
       
  1454 		{
       
  1455 		KDriverName = _L("USBC");
       
  1456 		error = User::FreeLogicalDevice(KDriverName);
       
  1457 		}
       
  1458 
       
  1459 	User::LeaveIfError(error); 
       
  1460 
       
  1461 #ifdef USB_BOOT_LOADER
       
  1462 	rebootit();
       
  1463 #endif
       
  1464 	CleanupStack::PopAndDestroy(1);
       
  1465 	}
       
  1466 
       
  1467 TInt ParseCommandLine()
       
  1468 	{
       
  1469 	TBuf<32> args;
       
  1470 	User::CommandLine(args);
       
  1471 	TLex lex(args);
       
  1472 	TInt err=KErrNone;
       
  1473 	FOREVER
       
  1474 		{
       
  1475 		TPtrC token=lex.NextToken();
       
  1476 
       
  1477 		if(token.Length()!=0)
       
  1478 			{
       
  1479 			if ((token.MatchF(_L("-sc")) == KErrNone))
       
  1480 				{
       
  1481 				gSharedChunkLdd = ETrue;
       
  1482 				err = KErrNone;
       
  1483 				}
       
  1484 			else
       
  1485 				{
       
  1486 				// Command line: list of drive letters to auto-mount (all if not specified)
       
  1487 				mountList.Append(token);
       
  1488 				mountList.UpperCase();
       
  1489 				err = KErrNone;
       
  1490 				} // endif token 
       
  1491 			}
       
  1492 		else
       
  1493 			break;
       
  1494 		}
       
  1495 	return err;
       
  1496 	}
       
  1497 
       
  1498 
       
  1499 
       
  1500 GLDEF_C TInt E32Main()
       
  1501 	{
       
  1502 	__UHEAP_MARK;
       
  1503 	CTrapCleanup* cleanup=CTrapCleanup::New();
       
  1504 
       
  1505 	if (ParseCommandLine())
       
  1506 		return KErrNone;
       
  1507 
       
  1508     msfsMountedList.Reset();  
       
  1509     unmountedFsList.Reset();  
       
  1510 
       
  1511 	
       
  1512     TRAPD(error,RunAppL());
       
  1513 #ifdef USB_BOOT_LOADER
       
  1514 	__ASSERT_ALWAYS(!error, User::Panic(KVariantUsbmsTitle, error));
       
  1515 #else
       
  1516 	__ASSERT_ALWAYS(!error, User::Panic(KTxtApp, error));
       
  1517 #endif
       
  1518 
       
  1519 	delete cleanup;
       
  1520 	__UHEAP_MARKEND;
       
  1521 	return 0;
       
  1522 	}
       
  1523 
       
  1524 
       
  1525 
       
  1526 
       
  1527 //-----------------------------------------------------------------------------
       
  1528 
       
  1529 CFileSystemDescriptor::~CFileSystemDescriptor()
       
  1530     {
       
  1531     iFsName.Close();
       
  1532     iPrimaryExtName.Close();
       
  1533     }
       
  1534 
       
  1535 //-----------------------------------------------------------------------------
       
  1536 CFileSystemDescriptor* CFileSystemDescriptor::NewL(const TDesC& aFsName, const TDesC& aPrimaryExtName, TBool aDrvSynch)
       
  1537     {
       
  1538     CFileSystemDescriptor* pSelf = new (ELeave) CFileSystemDescriptor;
       
  1539 
       
  1540     CleanupStack::PushL(pSelf);
       
  1541     
       
  1542     pSelf->iFsName.CreateMaxL(aFsName.Length());
       
  1543     pSelf->iFsName.Copy(aFsName);
       
  1544     
       
  1545     pSelf->iPrimaryExtName.CreateMaxL(aPrimaryExtName.Length());
       
  1546     pSelf->iPrimaryExtName.Copy(aPrimaryExtName);
       
  1547 
       
  1548     pSelf->iDriveSynch = aDrvSynch;
       
  1549 
       
  1550     CleanupStack::Pop();
       
  1551 
       
  1552     return pSelf;
       
  1553     }
       
  1554 
       
  1555 
       
  1556 
       
  1557 
       
  1558 
       
  1559 
       
  1560 
       
  1561 
       
  1562 
       
  1563 
       
  1564 
       
  1565 
       
  1566 
       
  1567 
       
  1568 
       
  1569 
       
  1570 
       
  1571 
       
  1572 
       
  1573