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