sl@0: // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // USB Mass Storage Application - also used as an improvised boot loader mechanism sl@0: // sl@0: // sl@0: sl@0: sl@0: sl@0: /** sl@0: @file sl@0: */ sl@0: sl@0: #include "usbtestclient.h" sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #include "rusbmassstorage.h" sl@0: sl@0: enum sl@0: { sl@0: EUsbDeviceStateUndefined = EUsbcDeviceStateUndefined, sl@0: EUsbDeviceStateConfigured = EUsbcDeviceStateConfigured, sl@0: }; sl@0: sl@0: static CConsoleBase* console = NULL; sl@0: static RFs fs; sl@0: static TInt selectedDriveIndex = 0; sl@0: static TBuf<0x40> mountList; sl@0: sl@0: static TFixedArray msfsMountedList; ///< 'true' entry corresponds to the drive with mounted MSFS.FSY sl@0: static TFixedArray unmountedFsList; ///< every non-NULL entry corresponds to the unmounted original FS for the drive sl@0: sl@0: _LIT(KMsFsy, "USBTESTMSCLIENT.FSY"); sl@0: _LIT(KMsFs, "MassStorageFileSystem"); sl@0: _LIT(KOk,"OK"); sl@0: _LIT(KError,"Error"); sl@0: _LIT(KBytesTransferredFmt, "%c:%d/%d "); sl@0: _LIT(KErrFmt, "Error: %d\r"); sl@0: sl@0: _LIT(KTxtApp,"USB TEST CLIENT"); sl@0: _LIT(KDefPwd,"123"); sl@0: sl@0: //-- if defined, some useful information will be printed out via RDebug interface sl@0: //#define LOGGING_ENABLED sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: /** sl@0: prints a line to the console and copies it to the debug log if LOGGING_ENABLED sl@0: */ sl@0: void LogPrint(TRefByValue aFmt,...) sl@0: { sl@0: VA_LIST list; sl@0: VA_START(list, aFmt); sl@0: sl@0: TBuf<0x100> buf; sl@0: buf.FormatList(aFmt, list); //-- ignore overflows sl@0: sl@0: if(console) sl@0: console->Write(buf); sl@0: sl@0: #ifdef LOGGING_ENABLED sl@0: //-- print out the line via RDebug::Print sl@0: const TInt bufLen = buf.Length(); sl@0: if(bufLen >0 && buf[bufLen-1] == '\n') sl@0: { sl@0: buf.Insert(bufLen-1, _L("\r")); sl@0: } sl@0: else sl@0: { sl@0: buf.Append(_L("\r\n")); sl@0: } sl@0: sl@0: RDebug::RawPrint(buf); sl@0: #endif sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: /** sl@0: prints a line to the debug log if LOGGING_ENABLED sl@0: */ sl@0: void Log(TRefByValue aFmt,...) sl@0: { sl@0: #ifdef LOGGING_ENABLED sl@0: sl@0: VA_LIST list; sl@0: VA_START(list, aFmt); sl@0: sl@0: TBuf<0x100> buf; sl@0: buf.FormatList(aFmt, list); //-- ignore overflows sl@0: sl@0: //-- print out the line via RDebug::Print sl@0: const TInt bufLen = buf.Length(); sl@0: if(bufLen >0 && buf[bufLen-1] == '\n') sl@0: { sl@0: buf.Insert(bufLen-1, _L("\r")); sl@0: } sl@0: sl@0: RDebug::RawPrint(buf); sl@0: #else sl@0: (void)aFmt; sl@0: #endif sl@0: } sl@0: sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: sl@0: static void Clear(int row, int count=1) sl@0: { sl@0: _LIT(KBlank," "); sl@0: for(TInt i=0; iSetPos(0,row+i); sl@0: console->Printf(KBlank); sl@0: } sl@0: console->SetPos(0,row); sl@0: } sl@0: sl@0: sl@0: static void ShowDriveSelection() sl@0: { sl@0: console->SetPos(0,15); sl@0: if(PropertyHandlers::allDrivesStatus.Length()/2 > selectedDriveIndex) sl@0: { sl@0: LogPrint(_L("Selected Drive: %c"), 'A' + PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]); sl@0: } sl@0: else sl@0: { sl@0: LogPrint(_L("Selected Drive: (none)")); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: class CPeriodUpdate : public CActive sl@0: { sl@0: public: sl@0: static CPeriodUpdate* NewLC(); sl@0: private: sl@0: CPeriodUpdate(); sl@0: void ConstructL(); sl@0: ~CPeriodUpdate(); sl@0: void RunL(); sl@0: void DoCancel(); sl@0: sl@0: RTimer iTimer; sl@0: TUint iUpTime; sl@0: }; sl@0: sl@0: CPeriodUpdate* CPeriodUpdate::NewLC() sl@0: { sl@0: CPeriodUpdate* me=new(ELeave) CPeriodUpdate(); sl@0: CleanupStack::PushL(me); sl@0: me->ConstructL(); sl@0: return me; sl@0: } sl@0: sl@0: CPeriodUpdate::CPeriodUpdate() sl@0: : CActive(0), iUpTime(0) sl@0: {} sl@0: sl@0: void CPeriodUpdate::ConstructL() sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: iTimer.CreateLocal(); sl@0: RunL(); sl@0: } sl@0: sl@0: CPeriodUpdate::~CPeriodUpdate() sl@0: { sl@0: Cancel(); sl@0: } sl@0: sl@0: void CPeriodUpdate::DoCancel() sl@0: { sl@0: } sl@0: sl@0: void CPeriodUpdate::RunL() sl@0: { sl@0: SetActive(); sl@0: // Print RAM usage & up time sl@0: sl@0: iUpTime++; sl@0: TUint totmins=(iUpTime/60); sl@0: TUint tothrs=(totmins/60); sl@0: TInt mem=0; sl@0: if (HAL::Get(HALData::EMemoryRAMFree, mem)==KErrNone) sl@0: { sl@0: console->SetPos(0,22); sl@0: console->Printf(_L("mem (bytes) : %d\n"), mem); sl@0: console->Printf(_L("up time : %dh:%dm:%ds\n"), sl@0: tothrs, totmins%60, iUpTime%60); sl@0: } sl@0: iTimer.After(iStatus, 1000000); sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: /** sl@0: Dismounts the originally mounted FS and optional primary extension from the drive and stores sl@0: this information in the FS descriptor sl@0: sl@0: @return on success returns a pointer to the instantinated FS descriptor sl@0: */ sl@0: static CFileSystemDescriptor* DoDismountOrginalFS(RFs& aFs, TInt aDrive) sl@0: { sl@0: TInt nRes; sl@0: TBuf<128> fsName; sl@0: TBuf<128> primaryExtName; sl@0: TBool bDrvSync = EFalse; sl@0: sl@0: Log(_L("# DoDismountOrginalFS drv:%d\n"), aDrive); sl@0: sl@0: //-- 1. get file system name sl@0: nRes = aFs.FileSystemName(fsName, aDrive); sl@0: if(nRes != KErrNone) sl@0: {//-- probably no file system installed at all sl@0: return NULL; sl@0: } sl@0: sl@0: //-- 2. find out if the drive sync/async sl@0: TPckgBuf drvSyncBuf; sl@0: nRes = aFs.QueryVolumeInfoExt(aDrive, EIsDriveSync, drvSyncBuf); sl@0: if(nRes == KErrNone) sl@0: { sl@0: bDrvSync = drvSyncBuf(); sl@0: } sl@0: sl@0: //-- 3. find out primary extension name if it is present; we will need to add it againt when mounting the FS sl@0: //-- other extensions (non-primary) are not supported yet sl@0: nRes = aFs.ExtensionName(primaryExtName, aDrive, 0); sl@0: if(nRes != KErrNone) sl@0: { sl@0: primaryExtName.SetLength(0); sl@0: } sl@0: sl@0: //-- 3.1 check if the drive has non-primary extensions, fail in this case, because this FS can't be mounted back normally sl@0: nRes = aFs.ExtensionName(primaryExtName, aDrive, 1); sl@0: if(nRes == KErrNone) sl@0: { sl@0: LogPrint(_L("Non-primary extensions are not supported!\n")); sl@0: return NULL; sl@0: } sl@0: sl@0: Log(_L("# DoDismountOrginalFS FS:%S, Prim ext:%S, synch:%d\n"), &fsName, &primaryExtName, bDrvSync); sl@0: sl@0: //-- create FS descriptor and dismount the FS sl@0: CFileSystemDescriptor* pFsDesc = NULL; sl@0: sl@0: TRAP(nRes, pFsDesc = CFileSystemDescriptor::NewL(fsName, primaryExtName, bDrvSync)); sl@0: if(nRes != KErrNone) sl@0: return NULL; //-- OOM ? sl@0: sl@0: nRes = aFs.DismountFileSystem(fsName, aDrive); sl@0: if(nRes != KErrNone) sl@0: { sl@0: delete pFsDesc; sl@0: pFsDesc = NULL; sl@0: Log(_L("# DoDismountOrginalFS Dismounting Err:%d\n"), nRes); sl@0: } sl@0: sl@0: return pFsDesc; sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: /** sl@0: Tries to restore the original FS on the drive using the FS descriptor provided sl@0: @return standard error code. sl@0: */ sl@0: static TInt DoRestoreFS(RFs& aFs, TInt aDrive, CFileSystemDescriptor* apFsDesc) sl@0: { sl@0: TInt nRes; sl@0: sl@0: Log(_L("# DoRestoreFS drv:%d\n"), aDrive); sl@0: sl@0: //-- 1. check that there is no FS installed sl@0: { sl@0: TBuf<128> fsName; sl@0: nRes = aFs.FileSystemName(fsName, aDrive); sl@0: if(nRes == KErrNone) sl@0: {//-- probably no file system installed at all sl@0: Log(_L("# This drive already has FS intalled:%S \n"), &fsName); sl@0: return KErrAlreadyExists; sl@0: } sl@0: } sl@0: sl@0: TPtrC ptrN (apFsDesc->FsName()); sl@0: TPtrC ptrExt(apFsDesc->PrimaryExtName()); sl@0: Log(_L("# Mounting FS:%S, Prim ext:%S, synch:%d\n"), &ptrN, &ptrExt, apFsDesc->DriveIsSynch()); sl@0: sl@0: if(ptrExt.Length() >0) sl@0: {//-- there is a primary extension to be mounted sl@0: nRes = aFs.AddExtension(ptrExt); sl@0: if(nRes != KErrNone && nRes != KErrAlreadyExists) sl@0: { sl@0: return nRes; sl@0: } sl@0: sl@0: nRes = aFs.MountFileSystem(ptrN, ptrExt, aDrive, apFsDesc->DriveIsSynch()); sl@0: } sl@0: else sl@0: { sl@0: nRes = aFs.MountFileSystem(ptrN, aDrive, apFsDesc->DriveIsSynch()); sl@0: } sl@0: sl@0: if(nRes != KErrNone) sl@0: { sl@0: Log(_L("# Mount failed! code:%d\n"),nRes); sl@0: } sl@0: sl@0: return nRes; sl@0: } sl@0: sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: /** sl@0: Dismount the original FS from the drive and mount MsFS instead sl@0: */ sl@0: static void MountMsFs(TInt driveNumber) sl@0: { sl@0: TInt x = console->WhereX(); sl@0: TInt y = console->WhereY(); sl@0: sl@0: //-- 1. try dismounting the original FS sl@0: CFileSystemDescriptor* fsDesc = DoDismountOrginalFS(fs, driveNumber); sl@0: unmountedFsList[driveNumber] = fsDesc; sl@0: sl@0: console->SetPos(0, 10); sl@0: sl@0: if(fsDesc) sl@0: { sl@0: TPtrC ptrN(fsDesc->FsName()); sl@0: LogPrint(_L("drv:%d FS:%S Dismounted OK"),driveNumber, &ptrN); sl@0: } sl@0: else sl@0: { sl@0: LogPrint(_L("drv:%d Dismount FS Failed!"),driveNumber); sl@0: } sl@0: sl@0: console->ClearToEndOfLine(); sl@0: sl@0: //-- 2. try to mount the "MSFS" sl@0: TInt error; sl@0: error = fs.MountFileSystem(KMsFs, driveNumber); sl@0: console->SetPos(0, 11); sl@0: LogPrint(_L("MSFS Mount: %S (%d)"), (error?&KError:&KOk), error); sl@0: console->ClearToEndOfLine(); sl@0: sl@0: if (!error) sl@0: msfsMountedList[driveNumber] = ETrue; sl@0: sl@0: // restore console position sl@0: console->SetPos(x,y); sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: /** sl@0: Dismount MsFS and mount the original FS sl@0: */ sl@0: static TInt RestoreMount(TInt driveNumber) sl@0: { sl@0: TInt err = KErrNone; sl@0: sl@0: TInt x = console->WhereX(); sl@0: TInt y = console->WhereY(); sl@0: sl@0: //-- 1. try dismounting the "MSFS" sl@0: if (msfsMountedList[driveNumber]) sl@0: { sl@0: err = fs.DismountFileSystem(KMsFs, driveNumber); sl@0: console->SetPos(0, 11); sl@0: LogPrint(_L("MSFS Dismount:%S (%d)"), (err?&KError:&KOk), err); sl@0: console->ClearToEndOfLine(); sl@0: if (err) sl@0: return err; sl@0: sl@0: msfsMountedList[driveNumber] = EFalse; sl@0: } sl@0: sl@0: //-- 2. try to mount the original FS back sl@0: CFileSystemDescriptor* fsDesc = unmountedFsList[driveNumber]; sl@0: if(fsDesc) sl@0: { sl@0: err = DoRestoreFS(fs, driveNumber, fsDesc); sl@0: sl@0: TPtrC ptrN(fsDesc->FsName()); sl@0: console->SetPos(0, 10); sl@0: LogPrint(_L("%S Mount: %S (%d)"), &ptrN, (err?&KError:&KOk), err); sl@0: console->ClearToEndOfLine(); sl@0: sl@0: delete fsDesc; sl@0: unmountedFsList[driveNumber] = NULL; sl@0: } sl@0: sl@0: sl@0: // restore console position sl@0: console->SetPos(x,y); sl@0: return err; sl@0: } sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // CPropertyWatch sl@0: // An active object that tracks changes to the KUsbMsDriveState properties sl@0: // sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: CPropertyWatch* CPropertyWatch::NewLC(TUsbMsDriveState_Subkey aSubkey, PropertyHandlers::THandler aHandler) sl@0: { sl@0: CPropertyWatch* me=new(ELeave) CPropertyWatch(aHandler); sl@0: CleanupStack::PushL(me); sl@0: me->ConstructL(aSubkey); sl@0: return me; sl@0: } sl@0: sl@0: CPropertyWatch::CPropertyWatch(PropertyHandlers::THandler aHandler) sl@0: : CActive(0), iHandler(aHandler) sl@0: {} sl@0: sl@0: void CPropertyWatch::ConstructL(TUsbMsDriveState_Subkey aSubkey) sl@0: { sl@0: User::LeaveIfError(iProperty.Attach(KUsbMsDriveState_Category, aSubkey)); sl@0: CActiveScheduler::Add(this); sl@0: // initial subscription and process current property value sl@0: RunL(); sl@0: } sl@0: sl@0: CPropertyWatch::~CPropertyWatch() sl@0: { sl@0: Cancel(); sl@0: iProperty.Close(); sl@0: } sl@0: sl@0: void CPropertyWatch::DoCancel() sl@0: { sl@0: iProperty.Cancel(); sl@0: } sl@0: sl@0: void CPropertyWatch::RunL() sl@0: { sl@0: // resubscribe before processing new value to prevent missing updates sl@0: iProperty.Subscribe(iStatus); sl@0: SetActive(); sl@0: sl@0: iHandler(iProperty); sl@0: } sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // CUsbWatch sl@0: // sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: CUsbWatch* CUsbWatch::NewLC(RUsb& aUsb) sl@0: { sl@0: CUsbWatch* me=new(ELeave) CUsbWatch(aUsb); sl@0: CleanupStack::PushL(me); sl@0: me->ConstructL(); sl@0: return me; sl@0: } sl@0: sl@0: CUsbWatch::CUsbWatch(RUsb& aUsb) sl@0: : sl@0: CActive(0), sl@0: iUsb(aUsb), sl@0: iUsbDeviceState(EUsbDeviceStateUndefined), sl@0: iWasConfigured(EFalse) sl@0: {} sl@0: sl@0: void CUsbWatch::ConstructL() sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: RunL(); sl@0: } sl@0: sl@0: CUsbWatch::~CUsbWatch() sl@0: { sl@0: Cancel(); sl@0: // iUsb.DeviceStateNotificationCancel(); sl@0: iUsb.AlternateDeviceStatusNotifyCancel(); sl@0: } sl@0: sl@0: void CUsbWatch::DoCancel() sl@0: { sl@0: // iUsb.DeviceStateNotificationCancel(); sl@0: iUsb.AlternateDeviceStatusNotifyCancel(); sl@0: } sl@0: sl@0: static TBool IsDriveConnected(TInt driveStatusIndex) sl@0: { sl@0: TInt driveStatus = PropertyHandlers::allDrivesStatus[2*driveStatusIndex+1]; sl@0: return driveStatus >= EUsbMsDriveState_Connected ? ETrue : EFalse; sl@0: } sl@0: sl@0: static TChar DriveNumberToLetter(TInt driveNumber) sl@0: { sl@0: TChar driveLetter = '?'; sl@0: fs.DriveToChar(driveNumber, driveLetter); sl@0: return driveLetter; sl@0: } sl@0: sl@0: static TBool IsDriveInMountList(TUint driveLetter) sl@0: { sl@0: TUint16 driveLetter16 = static_cast(driveLetter); sl@0: return(!mountList.Length() || KErrNotFound != mountList.Find(&driveLetter16, 1)); sl@0: } sl@0: sl@0: void CUsbWatch::RunL() sl@0: { sl@0: // RDebug::Print(_L(">> CUsbWatch[%d] %d"), iUsbDeviceState, iWasConfigured); sl@0: sl@0: // const TUint stateMask = 0xFF; sl@0: // iUsb.DeviceStateNotification(stateMask, iUsbDeviceState, iStatus); sl@0: iUsb.AlternateDeviceStatusNotify(iStatus, iUsbDeviceState); sl@0: SetActive(); sl@0: sl@0: //RDebug::Print(_L("CUsbWatch DeviceStateNotification: iUsbDeviceState=%d"), iUsbDeviceState); sl@0: sl@0: // If the cable is disconnected, unmount all the connected drives. sl@0: if(iWasConfigured && iUsbDeviceState == EUsbDeviceStateUndefined) sl@0: { sl@0: for(TInt i=0; i PropertyHandlers::allDrivesStatus; sl@0: TUsbMsBytesTransferred PropertyHandlers::iKBytesRead; sl@0: TUsbMsBytesTransferred PropertyHandlers::iKBytesWritten; sl@0: TInt PropertyHandlers::iMediaError; sl@0: sl@0: void PropertyHandlers::Read(RProperty& aProperty) sl@0: { sl@0: Transferred(aProperty, iKBytesRead); sl@0: } sl@0: sl@0: void PropertyHandlers::Written(RProperty& aProperty) sl@0: { sl@0: Transferred(aProperty, iKBytesWritten); sl@0: } sl@0: sl@0: void PropertyHandlers::Transferred(RProperty& aProperty, TUsbMsBytesTransferred& aReadOrWritten) sl@0: { sl@0: console->SetPos(0,1); sl@0: console->Printf(_L("KB R/W: ")); sl@0: TInt err = aProperty.Get(aReadOrWritten); sl@0: if(err == KErrNone) sl@0: { sl@0: for(TInt i = 0; i < allDrivesStatus.Length()/2; i++) sl@0: { sl@0: console->Printf(KBytesTransferredFmt, sl@0: (char)DriveNumberToLetter(allDrivesStatus[2*i]), iKBytesRead[i], iKBytesWritten[i]); sl@0: } sl@0: console->ClearToEndOfLine(); sl@0: } sl@0: else sl@0: { sl@0: console->Printf(KErrFmt, err); sl@0: } sl@0: } sl@0: sl@0: void PropertyHandlers::DriveStatus(RProperty& aProperty) sl@0: { sl@0: // RDebug::Print(_L(">> PropertyHandlers::DriveStatus")); sl@0: TInt err = aProperty.Get(allDrivesStatus); sl@0: console->SetPos(0,0); sl@0: if(err == KErrNone) sl@0: { sl@0: console->Printf(_L("Status: ")); sl@0: for(TInt i = 0; i < allDrivesStatus.Length()/2; i++) sl@0: { sl@0: TInt driveNumber = allDrivesStatus[2*i]; sl@0: TInt driveStatus = allDrivesStatus[2*i+1]; sl@0: TChar driveLetter = DriveNumberToLetter(driveNumber); sl@0: sl@0: // RDebug::Print(_L("%c:%d "), (char)driveLetter, driveStatus); sl@0: sl@0: switch(driveStatus) sl@0: { sl@0: case EUsbMsDriveState_Disconnected: sl@0: { sl@0: LogPrint(_L("%c:%d:Disconnected "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_Connecting: sl@0: { sl@0: LogPrint(_L("%c:%d:Connecting "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_Connected: sl@0: { sl@0: LogPrint(_L("%c:%d:Connected "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_Disconnecting: sl@0: { sl@0: LogPrint(_L("%c:%d:Disconnecting"), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_Active: sl@0: { sl@0: LogPrint(_L("%c:%d:Active "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_Locked: sl@0: { sl@0: LogPrint(_L("%c:%d:Locked "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_MediaNotPresent: sl@0: { sl@0: LogPrint(_L("%c:%d:Not Present "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_Removed: sl@0: { sl@0: LogPrint(_L("%c:%d:Removed "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: case EUsbMsDriveState_Error: sl@0: { sl@0: LogPrint(_L("%c:%d:Error "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: default : sl@0: { sl@0: LogPrint(_L("%c:%d:Unknown "), (char)driveLetter, driveStatus); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: if(IsDriveInMountList(driveLetter)) sl@0: { sl@0: if (driveStatus == EUsbMsDriveState_Connecting) sl@0: { sl@0: MountMsFs(driveNumber); sl@0: } sl@0: else if (driveStatus == EUsbMsDriveState_Disconnected) sl@0: { sl@0: RestoreMount(driveNumber); sl@0: } sl@0: else sl@0: { sl@0: //RDebug::Print(_L("PropertyHandlers::DriveStatus: nothing to do")); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: //RDebug::Print(_L("PropertyHandlers::DriveStatus: %c: is not in mountList\n"), driveLetter); sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: LogPrint(KErrFmt, err); sl@0: } sl@0: sl@0: //RDebug::Print(_L("<< PropertyHandlers::DriveStatus")); sl@0: } sl@0: sl@0: void PropertyHandlers::MediaError(RProperty& aProperty) sl@0: { sl@0: TInt err = aProperty.Get(iMediaError); sl@0: if (err != KErrNone) sl@0: { sl@0: // RDebug::Printf("RProperty::Get returned %d", err); sl@0: return; sl@0: } sl@0: sl@0: //RDebug::Printf("PropertyHandlers::MediaError %x", iMediaError); sl@0: sl@0: TInt x = console->WhereX(); sl@0: TInt y = console->WhereY(); sl@0: Clear(27,1); sl@0: LogPrint(_L("Media Error %x"), iMediaError); sl@0: // restore console position sl@0: console->SetPos(x,y); sl@0: } sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // CMessageKeyProcessor sl@0: // sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: CMessageKeyProcessor::CMessageKeyProcessor(CConsoleBase* aConsole) sl@0: : CActive(CActive::EPriorityUserInput), iConsole(aConsole) sl@0: { sl@0: } sl@0: sl@0: CMessageKeyProcessor* CMessageKeyProcessor::NewLC(CConsoleBase* aConsole) sl@0: { sl@0: CMessageKeyProcessor* self=new (ELeave) CMessageKeyProcessor(aConsole); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: CMessageKeyProcessor* CMessageKeyProcessor::NewL(CConsoleBase* aConsole) sl@0: { sl@0: CMessageKeyProcessor* self = NewLC(aConsole); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: void CMessageKeyProcessor::ConstructL() sl@0: { sl@0: // Add to active scheduler sl@0: CActiveScheduler::Add(this); sl@0: RequestCharacter(); sl@0: } sl@0: sl@0: void CMessageKeyProcessor::MakePassword(TMediaPassword &aPassword) sl@0: { sl@0: // Create password with same format as eshell and S60 sl@0: TBuf<3> password(KDefPwd); sl@0: sl@0: // fill aPassword with contents of password, not converting to ASCII sl@0: const TInt byteLen = password.Length() * 2; sl@0: aPassword.Copy(reinterpret_cast(password.Ptr()), byteLen); sl@0: } sl@0: sl@0: CMessageKeyProcessor::~CMessageKeyProcessor() sl@0: { sl@0: // Make sure we're cancelled sl@0: Cancel(); sl@0: } sl@0: sl@0: void CMessageKeyProcessor::DoCancel() sl@0: { sl@0: iConsole->ReadCancel(); sl@0: } sl@0: sl@0: void CMessageKeyProcessor::RunL() sl@0: { sl@0: // Handle completed request sl@0: ProcessKeyPress(TChar(iConsole->KeyCode())); sl@0: } sl@0: sl@0: void CMessageKeyProcessor::RequestCharacter() sl@0: { sl@0: // A request is issued to the CConsoleBase to accept a sl@0: // character from the keyboard. sl@0: iConsole->Read(iStatus); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CMessageKeyProcessor::ProcessKeyPress(TChar aChar) sl@0: { sl@0: sl@0: TInt error = KErrNone; sl@0: sl@0: aChar.UpperCase(); sl@0: switch(aChar) sl@0: { sl@0: case 'Q': sl@0: case EKeyEscape: sl@0: { sl@0: TInt err = KErrNone; sl@0: for(TInt j=0; j= PropertyHandlers::allDrivesStatus.Length()/2) sl@0: { sl@0: selectedDriveIndex = 0; sl@0: } sl@0: ShowDriveSelection(); sl@0: break; sl@0: sl@0: case 'M': sl@0: if(PropertyHandlers::allDrivesStatus.Length()) sl@0: { sl@0: MountMsFs(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]); sl@0: } sl@0: break; sl@0: sl@0: case 'U': sl@0: if(PropertyHandlers::allDrivesStatus.Length()) sl@0: { sl@0: RestoreMount(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2]); sl@0: } sl@0: break; sl@0: sl@0: case 'L': sl@0: { sl@0: // lock unprotected drive sl@0: TMediaPassword password; sl@0: MakePassword(password); sl@0: sl@0: _LIT(KEmpty, ""); sl@0: TMediaPassword nul; sl@0: nul.Copy(KEmpty); sl@0: error = fs.LockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2], sl@0: nul, password, ETrue); sl@0: console->SetPos(0,9); sl@0: LogPrint(_L("LockDrive %S (%d)"), (error?&KError:&KOk), error); sl@0: break; sl@0: } sl@0: sl@0: case 'I': sl@0: { sl@0: // lock password protected drive sl@0: TMediaPassword password; sl@0: MakePassword(password); sl@0: error = fs.LockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2], sl@0: password, password, ETrue); sl@0: console->SetPos(0,9); sl@0: LogPrint(_L("LockDrive %S (%d)"), (error?&KError:&KOk), error); sl@0: break; sl@0: } sl@0: sl@0: case 'N': sl@0: { sl@0: TMediaPassword password; sl@0: MakePassword(password); sl@0: error = fs.UnlockDrive(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2], sl@0: password, ETrue); sl@0: Clear(9); sl@0: LogPrint(_L("UnlockDrive %S (%d)"), (error?&KError:&KOk), error); sl@0: } sl@0: break; sl@0: sl@0: case 'C': sl@0: { sl@0: TMediaPassword password; sl@0: MakePassword(password); sl@0: error = fs.ClearPassword(PropertyHandlers::allDrivesStatus[selectedDriveIndex*2], sl@0: password); sl@0: Clear(9); sl@0: LogPrint(_L("ClearPassword %S (%d)"), (error?&KError:&KOk), error); sl@0: } sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: RequestCharacter(); sl@0: } sl@0: sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: // sl@0: // Application entry point sl@0: // sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: static void RunAppL() sl@0: { sl@0: sl@0: TInt error = KErrUnknown; sl@0: sl@0: //RDebug::Print(_L("USBMSAPP: Creating console\n")); sl@0: console = Console::NewL(KTxtApp,TSize(KConsFullScreen,KConsFullScreen)); sl@0: CleanupStack::PushL(console); sl@0: sl@0: console->SetPos(0,2); sl@0: console->Printf(_L("========================================")); sl@0: sl@0: // Command line: list of drive letters to auto-mount (all if not specified) sl@0: User::CommandLine(mountList); sl@0: mountList.UpperCase(); sl@0: sl@0: CActiveScheduler* sched = new(ELeave) CActiveScheduler; sl@0: CleanupStack::PushL(sched); sl@0: CActiveScheduler::Install(sched); sl@0: sl@0: fs.Connect(); sl@0: CleanupClosePushL(fs); sl@0: sl@0: _LIT(KMountAllDefault,"(all)"); sl@0: console->SetPos(0,3); sl@0: LogPrint(_L("Drives to auto-mount: %S"), (mountList.Length() ? &mountList : &KMountAllDefault)); sl@0: sl@0: // Add MS file system sl@0: error = fs.AddFileSystem(KMsFsy); sl@0: if(error != KErrNone && error != KErrAlreadyExists) sl@0: { sl@0: //RDebug::Print(_L("AddFileSystem failed, err=%d\n"), error); sl@0: User::Leave(error); sl@0: } sl@0: console->SetPos(0,4); sl@0: LogPrint(_L("MSFS file system:\tAdded OK\n")); sl@0: sl@0: RUsb usb; sl@0: sl@0: // Load the logical device sl@0: _LIT(KDriverFileName,"EUSBC.LDD"); sl@0: error = User::LoadLogicalDevice(KDriverFileName); sl@0: if (error != KErrAlreadyExists) sl@0: User::LeaveIfError(error); sl@0: sl@0: error = usb.Open(0); sl@0: User::LeaveIfError(error); sl@0: sl@0: _LIT(KOtgdiLddFilename, "otgdi"); sl@0: // Check for OTG support sl@0: TBuf8 otg_desc; sl@0: error = usb.GetOtgDescriptor(otg_desc); sl@0: if (!(error == KErrNotSupported || error == KErrNone)) sl@0: { sl@0: LogPrint(_L("Error %d while fetching OTG descriptor"), error); sl@0: User::Leave(-1); sl@0: return; sl@0: } sl@0: sl@0: // On an OTG device we have to start the OTG driver, otherwise the Client sl@0: // stack will remain disabled forever. sl@0: if (error == KErrNotSupported) sl@0: { sl@0: CleanupClosePushL(usb); sl@0: User::Leave(-1); sl@0: } sl@0: sl@0: error = User::LoadLogicalDevice(KOtgdiLddFilename); sl@0: if (error != KErrNone) sl@0: { sl@0: LogPrint(_L("Error %d on loading OTG LDD"), error); sl@0: User::Leave(-1); sl@0: return; sl@0: } sl@0: sl@0: RUsbOtgDriver iOtgPort; sl@0: sl@0: error = iOtgPort.Open(); sl@0: if (error != KErrNone) sl@0: { sl@0: LogPrint(_L("Error %d on opening OTG port"), error); sl@0: User::Leave(-1); sl@0: return; sl@0: } sl@0: error = iOtgPort.StartStacks(); sl@0: if (error != KErrNone) sl@0: { sl@0: LogPrint(_L("Error %d on starting USB stack"), error); sl@0: User::Leave(-1); sl@0: return; sl@0: } sl@0: sl@0: CleanupClosePushL(usb); sl@0: sl@0: // RDebug::Print(_L("USBMSAPP: Create active objects\n")); sl@0: CMessageKeyProcessor::NewLC(console); sl@0: CPropertyWatch::NewLC(EUsbMsDriveState_KBytesRead, PropertyHandlers::Read); sl@0: CPropertyWatch::NewLC(EUsbMsDriveState_KBytesWritten, PropertyHandlers::Written); sl@0: CPropertyWatch::NewLC(EUsbMsDriveState_DriveStatus, PropertyHandlers::DriveStatus); sl@0: CPropertyWatch::NewLC(EUsbMsDriveState_MediaError, PropertyHandlers::MediaError); sl@0: CUsbWatch::NewLC(usb); sl@0: CPeriodUpdate::NewLC(); sl@0: sl@0: RUsbMassStorage UsbMs; sl@0: TBuf<8> t_vendorId(_L("vendor")); sl@0: TBuf<16> t_productId(_L("product")); sl@0: TBuf<4> t_productRev(_L("1.00")); sl@0: sl@0: TMassStorageConfig msConfig; sl@0: msConfig.iVendorId.Copy(t_vendorId); sl@0: msConfig.iProductId.Copy(t_productId); sl@0: msConfig.iProductRev.Copy(t_productRev); sl@0: sl@0: // console->Printf(_L("Connect to Mass Storage")); sl@0: error = UsbMs.Connect(); sl@0: User::LeaveIfError(error); sl@0: sl@0: // console->Printf(_L("Start Mass Storage")); sl@0: error = UsbMs.Start(msConfig); sl@0: User::LeaveIfError(error); sl@0: sl@0: TBuf8 deviceDescriptor; sl@0: error = usb.GetDeviceDescriptor(deviceDescriptor); sl@0: User::LeaveIfError(error); sl@0: sl@0: const TInt KUsbSpecOffset = 2; sl@0: const TInt KUsbDeviceClassOffset = 4; sl@0: const TInt KUsbVendorIdOffset = 8; sl@0: const TInt KUsbProductIdOffset = 10; sl@0: const TInt KUsbDevReleaseOffset = 12; sl@0: //Change the USB spec number to 2.00 sl@0: deviceDescriptor[KUsbSpecOffset] = 0x00; sl@0: deviceDescriptor[KUsbSpecOffset+1] = 0x02; sl@0: //Change the Device Class, Device SubClass and Device Protocol sl@0: deviceDescriptor[KUsbDeviceClassOffset] = 0x00; sl@0: deviceDescriptor[KUsbDeviceClassOffset+1] = 0x00; sl@0: deviceDescriptor[KUsbDeviceClassOffset+2] = 0x00; sl@0: //Change the device vendor ID (VID) to 0x0E22 (Symbian) sl@0: deviceDescriptor[KUsbVendorIdOffset] = 0x22; // little endian sl@0: deviceDescriptor[KUsbVendorIdOffset+1] = 0x0E; sl@0: //Change the device product ID (PID) to 0x1111 sl@0: deviceDescriptor[KUsbProductIdOffset] = 0x12; sl@0: deviceDescriptor[KUsbProductIdOffset+1] = 0x11; sl@0: //Change the device release number to 3.05 sl@0: deviceDescriptor[KUsbDevReleaseOffset] = 0x05; sl@0: deviceDescriptor[KUsbDevReleaseOffset+1] = 0x03; sl@0: error = usb.SetDeviceDescriptor(deviceDescriptor); sl@0: User::LeaveIfError(error); sl@0: sl@0: // Remove possible Remote-Wakup support in Configuration descriptor, sl@0: // so that we can use the MSC device also easily for Chapter9 testing. sl@0: TBuf8 configDescriptor; sl@0: error = usb.GetConfigurationDescriptor(configDescriptor); sl@0: User::LeaveIfError(error); sl@0: const TInt KConfDesc_AttribOffset = 7; sl@0: configDescriptor[KConfDesc_AttribOffset] &= ~KUsbDevAttr_RemoteWakeup; sl@0: error = usb.SetConfigurationDescriptor(configDescriptor); sl@0: User::LeaveIfError(error); sl@0: sl@0: _LIT16(productID_L, "Symbian USB Mass Storage Device (Base)"); sl@0: TBuf16 productID(productID_L); sl@0: error = usb.SetProductStringDescriptor(productID); sl@0: User::LeaveIfError(error); sl@0: sl@0: TRequestStatus enum_status; sl@0: console->SetPos(0,5); sl@0: LogPrint(_L("Re-enumerating...\n")); sl@0: usb.ReEnumerate(enum_status); sl@0: User::LeaveIfError(error); sl@0: console->SetPos(0,5); sl@0: User::WaitForRequest(enum_status); sl@0: if(enum_status.Int() == KErrNone) sl@0: LogPrint(_L("Re-enumeration Done\n")); sl@0: else sl@0: LogPrint(_L("Re-enumeration not successfully done\n")); sl@0: sl@0: sl@0: console->SetPos(0,14); sl@0: TBuf<3>password(KDefPwd); sl@0: LogPrint(_L("Password: %S"), &password); sl@0: sl@0: ShowDriveSelection(); sl@0: sl@0: console->SetPos(0,17); sl@0: sl@0: _LIT(KMsgTitleB,"Menu: q=quit d=chg drv\n m=mount u=unmount\n l=lock i=lock n=unlock\n c=clr pwd"); sl@0: sl@0: sl@0: //RDebug::Print(_L("USBMSAPP: Start CActiveScheduler\n")); sl@0: sl@0: console->Printf(KMsgTitleB); sl@0: sl@0: CActiveScheduler::Start(); sl@0: sl@0: error = UsbMs.Stop(); sl@0: User::LeaveIfError(error); sl@0: UsbMs.Close(); sl@0: error = fs.RemoveFileSystem(KMsFs); sl@0: User::LeaveIfError(error); sl@0: sl@0: CleanupStack::PopAndDestroy(11); sl@0: sl@0: iOtgPort.StopStacks(); sl@0: iOtgPort.Close(); sl@0: error = User::FreeLogicalDevice(RUsbOtgDriver::Name()); sl@0: User::LeaveIfError(error); sl@0: sl@0: error = User::FreeLogicalDevice(_L("USBC")); sl@0: User::LeaveIfError(error); sl@0: sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: __UHEAP_MARK; sl@0: CTrapCleanup* cleanup=CTrapCleanup::New(); sl@0: sl@0: msfsMountedList.Reset(); sl@0: unmountedFsList.Reset(); sl@0: sl@0: sl@0: TRAPD(error,RunAppL()); sl@0: __ASSERT_ALWAYS(!error, User::Panic(KTxtApp, error)); sl@0: sl@0: delete cleanup; sl@0: __UHEAP_MARKEND; sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: sl@0: CFileSystemDescriptor::~CFileSystemDescriptor() sl@0: { sl@0: iFsName.Close(); sl@0: iPrimaryExtName.Close(); sl@0: } sl@0: sl@0: //----------------------------------------------------------------------------- sl@0: CFileSystemDescriptor* CFileSystemDescriptor::NewL(const TDesC& aFsName, const TDesC& aPrimaryExtName, TBool aDrvSynch) sl@0: { sl@0: CFileSystemDescriptor* pSelf = new (ELeave) CFileSystemDescriptor; sl@0: sl@0: CleanupStack::PushL(pSelf); sl@0: sl@0: pSelf->iFsName.CreateMaxL(aFsName.Length()); sl@0: pSelf->iFsName.Copy(aFsName); sl@0: sl@0: pSelf->iPrimaryExtName.CreateMaxL(aPrimaryExtName.Length()); sl@0: pSelf->iPrimaryExtName.Copy(aPrimaryExtName); sl@0: sl@0: pSelf->iDriveSynch = aDrvSynch; sl@0: sl@0: CleanupStack::Pop(); sl@0: sl@0: return pSelf; sl@0: }