sl@0: // Copyright (c) 2002-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: // sl@0: sl@0: #include "sf_std.h" sl@0: #include "e32cmn.h" sl@0: sl@0: #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION sl@0: #include "sf_notifier.h" sl@0: #endif sl@0: sl@0: GLREF_C CProxyDriveFactory* GetExtension(const TDesC& aName); sl@0: GLREF_C CExtProxyDriveFactory* GetProxyDriveFactory(const TDesC& aName); sl@0: sl@0: TBusLocalDrive LocalDrives::iLocalDrives[KMaxLocalDrives]; sl@0: TInt LocalDrives::iMapping[KMaxDrives]; sl@0: TInt LocalDrives::iReverseMapping[KMaxLocalDrives]; sl@0: TBool LocalDrives::iMappingSet; sl@0: LocalDrives::TSocketDesc LocalDrives::iSocketDescs[KMaxPBusSockets]; sl@0: CExtProxyDrive* LocalDrives::iProxyDriveMapping[KMaxProxyDrives]; sl@0: TBool LocalDrives::iIsMultiSlotDrive[KMaxDrives]; sl@0: const TInt KInvalidSocketNumber = -1; sl@0: sl@0: void LocalDrives::Initialise() sl@0: // sl@0: // sl@0: // sl@0: { sl@0: iMappingSet = EFalse; sl@0: TInt i; sl@0: Mem::FillZ((TAny*)iProxyDriveMapping,sizeof(CExtProxyDriveFactory*)*KMaxProxyDrives); sl@0: // initialise mapping from drive number to local drive sl@0: for(i=0;iiMediaType; sl@0: if (mediaType == aMediaType && socketDesc->iControllerRelativeSocket == aControllerRelativeSocket) sl@0: return i; sl@0: if (mediaType == EInvalidMedia) // socket unassigned ? sl@0: break; sl@0: } sl@0: if (i == KMaxPBusSockets) sl@0: return KErrNoMemory; sl@0: sl@0: // assign a new local socket for this controller relative socket number & media type sl@0: socketDesc->iMediaType = aMediaType; sl@0: socketDesc->iControllerRelativeSocket = aControllerRelativeSocket; sl@0: sl@0: return i; sl@0: } sl@0: sl@0: TBusLocalDrive& LocalDrives::GetLocalDrive(TInt aDrive) sl@0: // sl@0: // Export localdrives sl@0: // sl@0: { sl@0: __ASSERT_DEBUG(aDrive>=0 && aDrive=0 && aDrive=KMaxLocalDrives && iMapping[aDrive]=0) && (aDriveReadL(KMsgPtr0,mBuf); sl@0: TLocalDriveMappingInfo& ldmi=mBuf(); sl@0: sl@0: if (ldmi.iOperation==TLocalDriveMappingInfo::ESwapIntMappingAndSet) sl@0: { sl@0: // Only the 1st two entries of the mapping table are valid - holding the drive numbers to be swapped sl@0: TInt r=KErrNone; sl@0: if (DriveNumberIsInRange(ldmi.iDriveMapping[0]) && DriveNumberIsInRange(ldmi.iDriveMapping[1])) sl@0: r=SwapDriveMapping(ldmi.iDriveMapping[0],ldmi.iDriveMapping[1]); sl@0: iMappingSet=ETrue; sl@0: return(r); sl@0: } sl@0: sl@0: // That just leaves EWriteMappingsAndSet and EWriteMappingsNoSet sl@0: for (TInt i=0;i local drive %d"),driveLetter,i); sl@0: sl@0: // If this mapping (letter -> localdrive) is already set then sl@0: // this must be a multislot device. Save this mapping as an sl@0: // alternative mapping (by storing it in iReverseMapping) sl@0: if(iMapping[driveLetter] != KDriveInvalid) sl@0: { sl@0: iIsMultiSlotDrive[driveLetter] = ETrue; sl@0: } sl@0: // first time we've seen this drive letter sl@0: iMapping[driveLetter]=i; sl@0: // following mapping is used when we want to swap back again. sl@0: iReverseMapping[i]=driveLetter; sl@0: } sl@0: sl@0: InitDriveMapping(); sl@0: if (ldmi.iOperation==TLocalDriveMappingInfo::EWriteMappingsAndSet) sl@0: iMappingSet=ETrue; sl@0: return(KErrNone); sl@0: } sl@0: sl@0: // Changes here must be reflected in SwapDriveMapping() sl@0: void LocalDrives::InitDriveMapping() sl@0: { sl@0: __PRINT(_L("InitDriveMapping()")); sl@0: TDriveInfoV1Buf driveInfo; sl@0: TInt r=UserHal::DriveInfo(driveInfo); sl@0: __ASSERT_ALWAYS(r==KErrNone,Fault(EInitDriveMappingDriveInfo)); sl@0: sl@0: // initialise the local drives sl@0: TInt i; sl@0: for(i=0;i=0 && socket=0 && localSocketRunL(); sl@0: } sl@0: ++count; sl@0: } sl@0: } sl@0: } sl@0: sl@0: TInt LocalDrives::InitProxyDrive(CFsRequest* aRequest) sl@0: { sl@0: __PRINT(_L("LocalDrives::InitProxyDrive")); sl@0: sl@0: TInt drive = aRequest->Message().Int0() ; sl@0: sl@0: if (drive < 0 || drive >= KMaxDrives) sl@0: return KErrArgument; sl@0: sl@0: if (drive!=EDriveZ && iMapping[drive]!=KDriveInvalid) sl@0: return KErrInUse; // Z is special case for composite sl@0: sl@0: TFullName extname; sl@0: aRequest->ReadL(KMsgPtr1,extname); sl@0: sl@0: // leave info thing for now sl@0: CExtProxyDriveFactory* pF = GetProxyDriveFactory(extname); sl@0: if (!pF) sl@0: return KErrArgument; // that extension has not been added sl@0: FsThreadManager::LockDrive(drive); sl@0: // find a free mapping to place this drive into sl@0: TInt i; sl@0: for (i=0; i CreateProxyDrive(pD, NULL); sl@0: __ASSERT_ALWAYS(r == KErrNone, User::Panic(_L("CreateProxyDrive Error"), r)); sl@0: __ASSERT_ALWAYS(pD != NULL, User::Panic(_L("CreateProxyDrive returned NULL"), -999)); sl@0: sl@0: iMapping[drive] = i+KMaxLocalDrives; sl@0: sl@0: aRequest->SetDrive(&TheDrives[drive]); sl@0: aRequest->SetScratchValue((TUint)pD); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt LocalDrives::MountProxyDrive(CFsRequest* aRequest) sl@0: { sl@0: CExtProxyDrive* pProxyDrive = (CExtProxyDrive*)aRequest->ScratchValue(); sl@0: __ASSERT_ALWAYS(pProxyDrive != NULL, User::Panic(_L("MountProxyDrive has NULL proxy extension class"), -999)); sl@0: sl@0: TInt driveNumber = aRequest->Drive()->DriveNumber(); sl@0: sl@0: sl@0: TInt proxyDriveNo = iMapping[driveNumber] - KMaxLocalDrives; sl@0: FsThreadManager::LockDrive(driveNumber); sl@0: iProxyDriveMapping[proxyDriveNo] = pProxyDrive; sl@0: pProxyDrive->SetDriveNumber(driveNumber); sl@0: FsThreadManager::UnlockDrive(driveNumber); sl@0: // sl@0: // Pass initialisation information onto the extension to allow it to initialise sl@0: // sl@0: TInt err = pProxyDrive->SetInfo(aRequest->Message(), sl@0: (TAny*)aRequest->Message().Ptr2(), sl@0: (TAny*)aRequest->Message().Ptr3()); sl@0: if (err != KErrNone) sl@0: { sl@0: // sl@0: // If we fail to initialise the extension, then close the drive (destroying the thread) sl@0: // and remove the mapping so we can attempt to mount again in the future. sl@0: // sl@0: FsThreadManager::LockDrive(driveNumber); sl@0: FsThreadManager::CloseDrive(driveNumber); sl@0: ClearProxyDriveMapping(driveNumber); sl@0: FsThreadManager::UnlockDrive(driveNumber); sl@0: return err; sl@0: } sl@0: sl@0: return(iMapping[driveNumber]); sl@0: } sl@0: sl@0: TBool LocalDrives::IsProxyDrive(TInt aDrive) sl@0: { sl@0: __ASSERT_ALWAYS(aDrive>=0 && aDrive= KMaxLocalDrives); sl@0: } sl@0: sl@0: TBool LocalDrives::IsProxyDriveInUse(CExtProxyDriveFactory* aDevice) sl@0: { sl@0: for (TInt i=0; i < KMaxProxyDrives; i++) sl@0: if (iProxyDriveMapping[i] && (iProxyDriveMapping[i]->FactoryP() == aDevice)) sl@0: return(ETrue); sl@0: sl@0: return(EFalse); sl@0: } sl@0: sl@0: void LocalDrives::ClearProxyDriveMapping(TInt aDrive) sl@0: { sl@0: __ASSERT_ALWAYS(aDrive>=0 && aDrive= KMaxLocalDrives && iProxyDriveMapping[iMapping[aDrive]-KMaxLocalDrives],Fault(EClearProxyDriveMapping2)); sl@0: TInt idx = iMapping[aDrive]-KMaxLocalDrives; sl@0: delete iProxyDriveMapping[idx]; sl@0: iProxyDriveMapping[idx] = NULL; sl@0: iMapping[aDrive] = KDriveInvalid; sl@0: } sl@0: sl@0: TInt LocalDrives::SetupMediaChange(TInt aDrive) sl@0: { sl@0: CExtProxyDrive* pProxyDrive = LocalDrives::GetProxyDrive(aDrive); sl@0: __ASSERT_ALWAYS(pProxyDrive != NULL,User::Panic(_L("SetupMediaChange - pProxyDrive == NULL"), ESetupMediaChange)); sl@0: sl@0: return pProxyDrive->SetupMediaChange(); sl@0: } sl@0: sl@0: void LocalDrives::NotifyChangeCancel(TInt aDrive) sl@0: { sl@0: CExtProxyDrive* pProxyDrive = LocalDrives::GetProxyDrive(aDrive); sl@0: __ASSERT_ALWAYS(pProxyDrive != NULL,User::Panic(_L("NotifyChangeCancel - pProxyDrive == NULL"), ECancelNotifyChange)); sl@0: sl@0: pProxyDrive->NotifyChangeCancel(); sl@0: } sl@0: sl@0: TInt LocalDrives::SwapDriveMapping(TInt aFirstDrive,TInt aSecondDrive) sl@0: { sl@0: sl@0: __PRINT(_L("SwapDriveMapping()")); sl@0: TInt firstLocalDrv=iMapping[aFirstDrive]; sl@0: TInt secondLocalDrv=iMapping[aSecondDrive]; sl@0: sl@0: // First, check this swap doesn't affect removable drives sl@0: TInt socket; sl@0: if (iLocalDrives[firstLocalDrv].Handle()!=0 && iLocalDrives[firstLocalDrv].IsRemovable(socket)) sl@0: return(KErrAccessDenied); sl@0: if (iLocalDrives[secondLocalDrv].Handle()!=0 && iLocalDrives[secondLocalDrv].IsRemovable(socket)) sl@0: return(KErrAccessDenied); sl@0: sl@0: // Now swap the mappings over sl@0: iMapping[aFirstDrive]=secondLocalDrv; sl@0: iMapping[aSecondDrive]=firstLocalDrv; sl@0: sl@0: iReverseMapping[firstLocalDrv]=aSecondDrive; sl@0: iReverseMapping[secondLocalDrv]=aFirstDrive; sl@0: sl@0: // Finally, swap the drive names over sl@0: HBufC* drvName=TheDriveNames[aSecondDrive]; sl@0: TheDriveNames[aSecondDrive]=TheDriveNames[aFirstDrive]; sl@0: TheDriveNames[aFirstDrive]=drvName; sl@0: return(KErrNone); sl@0: } sl@0: sl@0: void LocalDrives::CompleteNotifications(TInt aSocket) sl@0: // sl@0: // sl@0: // sl@0: { sl@0: __ASSERT_DEBUG(aSocket>=0 && aSocket driveDes; sl@0: driveDes.Append((TChar)aDrive+(TChar)'A'); sl@0: driveDes.Append((TChar)':'); sl@0: FsNotificationManager::HandleChange(NULL,driveDes,TFsNotification::EMediaChange); sl@0: } sl@0: #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION sl@0: sl@0: //If this is a multislot device we should update mappings here. sl@0: TheDrives[aDrive].MultiSlotDriveCheck(); sl@0: } sl@0: } sl@0: sl@0: TInt LocalDrives::GetDriveFromLocalDrive(TInt aLocDrv) sl@0: // sl@0: // sl@0: // sl@0: { sl@0: return iReverseMapping[aLocDrv]; sl@0: } sl@0: sl@0: sl@0: CNotifyMediaChange::CNotifyMediaChange(RLocalDrive* aDrive,TInt aSocketNo) sl@0: // sl@0: // Constructor sl@0: // sl@0: : CActive(EPriorityHigh), iDrive(aDrive), iSocket(aSocketNo) sl@0: {} sl@0: sl@0: void CNotifyMediaChange::RunL() sl@0: // sl@0: // Notification that a card has been mounted/removed sl@0: // sl@0: { sl@0: LocalDrives::CompleteNotifications(iSocket); sl@0: iDrive->NotifyChange(&iStatus); sl@0: SetActive(); sl@0: } sl@0: sl@0: sl@0: CExtNotifyMediaChange::CExtNotifyMediaChange(CExtProxyDrive* aDrive) sl@0: // sl@0: // Constructor sl@0: // sl@0: : CActive(EPriorityHigh), sl@0: iDrive(aDrive), sl@0: iPtr((TUint8*)&TheDrives[aDrive->DriveNumber()].iChanged,sizeof(TBool)) sl@0: { sl@0: } sl@0: sl@0: sl@0: CExtNotifyMediaChange* CExtNotifyMediaChange::NewL(CExtProxyDrive* aDrive) sl@0: { sl@0: CExtNotifyMediaChange* pSelf = new(ELeave) CExtNotifyMediaChange(aDrive); sl@0: sl@0: CleanupStack::PushL(pSelf); sl@0: pSelf->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: sl@0: return pSelf; sl@0: } sl@0: sl@0: void CExtNotifyMediaChange::ConstructL() sl@0: { sl@0: CActiveSchedulerFs::Add(this); sl@0: sl@0: TRAPD(err, RunL()); sl@0: if(err != KErrNone) sl@0: Deque(); sl@0: sl@0: User::LeaveIfError(err); sl@0: } sl@0: sl@0: CExtNotifyMediaChange::~CExtNotifyMediaChange() sl@0: { sl@0: Cancel(); sl@0: } sl@0: sl@0: void CExtNotifyMediaChange::RequestL() sl@0: { sl@0: if (!IsActive()) sl@0: { sl@0: User::LeaveIfError(iDrive->NotifyChange(iPtr, &iStatus)); sl@0: SetActive(); sl@0: } sl@0: } sl@0: sl@0: void CExtNotifyMediaChange::DoCancel() sl@0: { sl@0: iDrive->NotifyChangeCancel(); sl@0: } sl@0: sl@0: void CExtNotifyMediaChange::RunL() sl@0: { sl@0: if(iStatus==KErrDisconnected || iStatus==KErrCancel) sl@0: return; sl@0: sl@0: TInt driveNum = iDrive->DriveNumber(); sl@0: LocalDrives::CompleteDriveNotifications(driveNum); sl@0: sl@0: /* NOTE: We need SetChanged here though the iChanged variable is set in the MSC, since the cache is not getting cleared sl@0: (inside the CompleteDriveNotifications call) during the initial first notification */ sl@0: TheDrives[driveNum].SetChanged(ETrue); sl@0: sl@0: if(iStatus != KErrNotSupported) sl@0: { sl@0: RequestL(); sl@0: } sl@0: } sl@0: sl@0: sl@0: