os/kernelhwsrv/kerneltest/e32utils/usbmsapp/usbmsapp.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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