sl@0: // Copyright (c) 2004-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: // CMassStorageFileSystem implementation. sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalTechnology sl@0: */ sl@0: sl@0: #include sl@0: #include "cmassstoragefilesystem.h" sl@0: #include "cmassstoragemountcb.h" sl@0: #include "massstoragedebug.h" sl@0: #include "massstorage.h" sl@0: sl@0: _LIT(KMsFsyName, "MassStorageFileSystem"); sl@0: _LIT(KMsThreadName, "MassStorageThread"); sl@0: _LIT(KMsDeadThreadName, "MassStorageDeadThread"); sl@0: _LIT(KMsFsysSemName, "MassStorageSemaphore"); sl@0: LOCAL_D const TInt KMsFsyMajorVersionNumber=1; sl@0: LOCAL_D const TInt KMsFsyMinorVersionNumber=0; sl@0: sl@0: CMassStorageFileSystem::CMassStorageFileSystem() sl@0: { sl@0: } sl@0: sl@0: CMassStorageFileSystem::~CMassStorageFileSystem() sl@0: { sl@0: //Kill the controller thread if it exists sl@0: delete iMassStorageController; sl@0: delete iMediaChanged; sl@0: RThread thread; sl@0: TInt err = thread.Open(KMsThreadName); sl@0: if (err == KErrNone) sl@0: { sl@0: thread.Kill(1); //Parameter is irrelevant sl@0: } sl@0: thread.Close(); sl@0: iMsDrives.Close(); sl@0: } sl@0: sl@0: CMassStorageFileSystem* CMassStorageFileSystem::NewL() sl@0: { sl@0: CMassStorageFileSystem* self = new (ELeave) CMassStorageFileSystem(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CMassStorageFileSystem::ConstructL() sl@0: { sl@0: iMediaChanged = new(ELeave) CArrayFixFlat(KMaxDrives); sl@0: } sl@0: sl@0: /** sl@0: Set the file system version and name sl@0: sl@0: @return Any of the standard Symbian error codes. sl@0: */ sl@0: TInt CMassStorageFileSystem::Install() sl@0: { sl@0: __PRINT(_L("CMassStorageFileSystem::Install In\n")); sl@0: iVersion=TVersion(KMsFsyMajorVersionNumber, KMsFsyMinorVersionNumber, KF32BuildVersionNumber); sl@0: TInt err = SetName(&KMsFsyName); sl@0: __PRINT(_L("CMassStorageFileSystem::Install Out\n")); sl@0: return err; sl@0: } sl@0: sl@0: TInt CMassStorageFileSystem::Remove() sl@0: { sl@0: __PRINT(_L("CMassStorageFileSystem::Remove In\n")); sl@0: TInt err = KErrNone; sl@0: if (iInstalled) sl@0: { sl@0: // Try connecting to the server to send a shutdown message. sl@0: // - If the class controller has a session in use, this will return KErrInUse sl@0: RUsbMassStorage usbMs; sl@0: err = usbMs.Connect(); sl@0: if(err == KErrNone) sl@0: { sl@0: err = usbMs.Shutdown(); sl@0: usbMs.Close(); sl@0: sl@0: if(err == KErrNone) sl@0: { sl@0: User::WaitForRequest(iThreadStat); sl@0: err = iThreadStat.Int(); sl@0: } sl@0: else sl@0: { sl@0: __PRINT1(_L("CMassStorageFileSystem::Remove Shutdown Error %d\n"),err); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: __PRINT1(_L("CMassStorageFileSystem::Remove Connect Error %d\n"),err); sl@0: } sl@0: } sl@0: __PRINT(_L("CMassStorageFileSystem::Remove Out\n")); sl@0: return(err); sl@0: } sl@0: sl@0: /** sl@0: Creates a new Mass Storage mount object. sl@0: sl@0: @return A new CMassStorageMountCB sl@0: @leave KErrNotReady if the Mass Storage controller is not running. sl@0: */ sl@0: CMountCB* CMassStorageFileSystem::NewMountL() const sl@0: { sl@0: if (!iRunning) sl@0: { sl@0: User::Leave(KErrNotReady); sl@0: } sl@0: return CMassStorageMountCB::NewL(iMsDrives); sl@0: } sl@0: sl@0: /** sl@0: Sets the media attributes and type in the aInfo parameter to those of the specified drive. sl@0: sl@0: @param anInfo TDriveInfo object to store the drive information. sl@0: @param aDriveNumber The number of the drive to get the information from. sl@0: */ sl@0: void CMassStorageFileSystem::DriveInfo(TDriveInfo& aInfo, TInt aDriveNumber) const sl@0: { sl@0: __PRINT(_L("CMassStorageFileSystem::DriveInfo In\n")); sl@0: TLocalDriveCapsV2Buf caps; sl@0: if (!IsValidLocalDriveMapping(aDriveNumber)) sl@0: { sl@0: return; sl@0: } sl@0: (void)GetLocalDrive(aDriveNumber).Caps(caps); sl@0: // error ignored as Caps always returns valid Media and Drive attributes sl@0: aInfo.iMediaAtt=caps().iMediaAtt; sl@0: aInfo.iType = ::EMediaNotPresent; // Media is not available to the file system sl@0: aInfo.iDriveAtt=caps().iDriveAtt; sl@0: __PRINT(_L("CMassStorageFileSystem::DriveInfo Out\n")); sl@0: } sl@0: sl@0: /** sl@0: Returns a reference to the Mass Storage controller. sl@0: sl@0: @return Reference to the Mass Storage controller. sl@0: */ sl@0: CUsbMassStorageController& CMassStorageFileSystem::Controller() sl@0: { sl@0: return *iMassStorageController; sl@0: } sl@0: sl@0: /** sl@0: Fill iMsDrives with a mapping of lun->drive number for supported mass storage drives sl@0: sl@0: */ sl@0: TInt CMassStorageFileSystem::EnumerateMsDrivesL() sl@0: { sl@0: __PRINT(_L("CMassStorageFileSystem::EnumerateMsDrives In\n")); sl@0: iMsDrives.Reset(); sl@0: TInt driveCount = 0; sl@0: sl@0: TLocalDriveCapsV2Buf caps; sl@0: for (TInt i = EDriveC; i < KMaxDrives; i++) sl@0: { sl@0: caps.FillZ(); sl@0: sl@0: if (IsValidLocalDriveMapping(i)) sl@0: { sl@0: TInt err = GetLocalDrive(i).Caps(caps); sl@0: TInt locDrvNum = DriveNumberToLocalDriveNumber(i); sl@0: __PRINT2(_L("Caps: err=%d, att=%d\n"), err, caps().iDriveAtt); sl@0: sl@0: TBool isRemovable = err==KErrNotReady || (caps().iDriveAtt & KDriveAttRemovable); sl@0: __PRINT2(_L("EnumerateMsDrives: Drive %c: is %sremovable\n"), sl@0: 'A'+i-EDriveA, sl@0: isRemovable?_S(""):_S("NOT ")); sl@0: sl@0: if (isRemovable) sl@0: { sl@0: // sl@0: // STF: Connect to the local drive here. This gives us the media changed flag, and sl@0: // our own TBusLocalDrive object for use by the proxy drive and controller. sl@0: // sl@0: TBool& mediaChanged = (*iMediaChanged).ExtendL(); sl@0: mediaChanged = EFalse; sl@0: TBusLocalDrive* localDrive = new(ELeave) TBusLocalDrive; sl@0: iLocalDriveForMediaFlag.Append(*localDrive); sl@0: sl@0: TInt err=iLocalDriveForMediaFlag[driveCount].Connect(locDrvNum, mediaChanged); sl@0: if(err == KErrNone) sl@0: { sl@0: iMsDrives.Append(i); sl@0: } sl@0: driveCount++; sl@0: } sl@0: } sl@0: } sl@0: sl@0: __PRINT1(_L("CMassStorageFileSystem::EnumerateMsDrives Out, %d MS drives found\n"), driveCount); sl@0: return driveCount; sl@0: } sl@0: sl@0: TBool CMassStorageFileSystem::IsExtensionSupported() const sl@0: { sl@0: return ETrue; sl@0: } sl@0: sl@0: /** sl@0: Creates a TrapCleanup and ActiveScheduler and initializes the Mass Storage controller. sl@0: Start the ActiveScheduler. sl@0: sl@0: @return Any of the standard Symbian error codes. sl@0: */ sl@0: TInt CMassStorageFileSystem::InitThread() sl@0: { sl@0: __PRINT(_L("CMassStorageFileSystem::InitThread In\n")); sl@0: sl@0: //Give the thread a name so we can kill it later sl@0: User::RenameThread(KMsThreadName); sl@0: sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); sl@0: if (cleanup == NULL) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: TRAPD(err, InitThreadL()); sl@0: sl@0: delete cleanup; sl@0: sl@0: __PRINT1(_L("CMassStorageFileSystem::InitThread Out, error=%d\n"), err); sl@0: return err; sl@0: } sl@0: sl@0: TInt CMassStorageFileSystem::InitThreadL() sl@0: { sl@0: __PRINT(_L("CMassStorageFileSystem::InitThreadL In\n")); sl@0: sl@0: RSemaphore gSemThreadReady; sl@0: sl@0: TInt ret = gSemThreadReady.OpenGlobal(KMsFsysSemName); sl@0: sl@0: if (ret != KErrNone && ret != KErrAlreadyExists) sl@0: { sl@0: User::Leave(ret); sl@0: } sl@0: sl@0: // Determine which drives are available for Mass Storage. sl@0: // (this also creates a local TBusLocalDrive for use by the drive controller) sl@0: EnumerateMsDrivesL(); sl@0: sl@0: CActiveScheduler* sched = new CActiveScheduler; sl@0: if (sched == NULL) sl@0: { sl@0: gSemThreadReady.Signal(); sl@0: User::Leave(KErrNoMemory); sl@0: } sl@0: CleanupStack::PushL(sched); sl@0: CActiveScheduler::Install(sched); sl@0: sl@0: iMassStorageController = new CUsbMassStorageController; sl@0: if (iMassStorageController == NULL) sl@0: { sl@0: gSemThreadReady.Signal(); sl@0: User::Leave(KErrNoMemory); sl@0: } sl@0: sl@0: __PRINT(_L("CMassStorageFileSystem::InitThread: Creating Mass Storage Controller\n")); sl@0: TRAPD(err, iMassStorageController->CreateL(iMsDrives)); sl@0: if (err != KErrNone) sl@0: { sl@0: gSemThreadReady.Signal(); sl@0: CActiveScheduler::Install(NULL); sl@0: User::Leave(err); sl@0: } sl@0: sl@0: CleanupStack::Pop(sched); sl@0: sl@0: iRunning = ETrue; sl@0: gSemThreadReady.Signal(); sl@0: gSemThreadReady.Close(); sl@0: CActiveScheduler::Start(); sl@0: sl@0: //========= stop thread ================ sl@0: delete iMassStorageController; sl@0: iMassStorageController = NULL; sl@0: TInt i=0; sl@0: for (;iInitThread(); sl@0: //Rename the thread so we can create a new one with the same original name later sl@0: User::RenameThread(KMsDeadThreadName); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Standard entry point for file systems. sl@0: Creates a new file system object and starts a new thread for the Mass Storage controller. sl@0: */ sl@0: extern "C" EXPORT_C CFileSystem* CreateFileSystem() sl@0: { sl@0: __PRINT(_L("CMassStorageFileSystem::CreateFileSystem In\n")); sl@0: RSemaphore gSemThreadReady; sl@0: TInt err = gSemThreadReady.CreateGlobal(KMsFsysSemName, 0); sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("CMassStorageFileSystem::CreateFileSystem Out Semaphore Error %d\n"),err); sl@0: return NULL; sl@0: } sl@0: sl@0: CFileSystem* msFsys = NULL; sl@0: TRAP(err, msFsys = CMassStorageFileSystem::NewL()); sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("CMassStorageFileSystem::CreateFileSystem Out MSFS Error %d\n"),err); sl@0: gSemThreadReady.Close(); sl@0: return NULL; sl@0: } sl@0: sl@0: RThread msThread; sl@0: __PRINT(_L("CMassStorageFileSystem::CreateFileSystem: Creating Mass Storage thread\n")); sl@0: err = msThread.Create(KMsThreadName, MsInitThreadFn, KDefaultStackSize, NULL, msFsys); sl@0: if (err != KErrNone) sl@0: { sl@0: __PRINT1(_L("CMassStorageFileSystem::CreateFileSystem Out Thread Error %d\n"),err); sl@0: gSemThreadReady.Close(); sl@0: return msFsys; sl@0: } sl@0: ((CMassStorageFileSystem*)msFsys)->iInstalled=ETrue; sl@0: sl@0: sl@0: msThread.Logon(((CMassStorageFileSystem*)msFsys)->iThreadStat); sl@0: msThread.Resume(); sl@0: gSemThreadReady.Wait(); sl@0: gSemThreadReady.Close(); sl@0: msThread.Close(); sl@0: sl@0: __PRINT(_L("CMassStorageFileSystem::CreateFileSystem Out Clean\n")); sl@0: sl@0: return msFsys; sl@0: } sl@0: