Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//
#include "sf_std.h"
#include "e32cmn.h"
#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
#include "sf_notifier.h"
#endif
GLREF_C CProxyDriveFactory* GetExtension(const TDesC& aName);
GLREF_C CExtProxyDriveFactory* GetProxyDriveFactory(const TDesC& aName);
TBusLocalDrive LocalDrives::iLocalDrives[KMaxLocalDrives];
TInt LocalDrives::iMapping[KMaxDrives];
TInt LocalDrives::iReverseMapping[KMaxLocalDrives];
TBool LocalDrives::iMappingSet;
LocalDrives::TSocketDesc LocalDrives::iSocketDescs[KMaxPBusSockets];
CExtProxyDrive* LocalDrives::iProxyDriveMapping[KMaxProxyDrives];
TBool LocalDrives::iIsMultiSlotDrive[KMaxDrives];
const TInt KInvalidSocketNumber = -1;
void LocalDrives::Initialise()
//
//
//
{
iMappingSet = EFalse;
TInt i;
Mem::FillZ((TAny*)iProxyDriveMapping,sizeof(CExtProxyDriveFactory*)*KMaxProxyDrives);
// initialise mapping from drive number to local drive
for(i=0;i<KMaxDrives;i++)
{
iMapping[i] = KDriveInvalid;
iIsMultiSlotDrive[i] = EFalse;
}
// initialise reverse mapping from local drive to drive.
for(i=0;i<KMaxLocalDrives;i++)
{
iReverseMapping[i] = KDriveInvalid;
}
// initialise mapping from socket number to drive numbers
for(i=0;i<KMaxPBusSockets;++i)
{
TSocketDesc& socketDesc = iSocketDescs[i];
socketDesc.iMediaType = EInvalidMedia;
socketDesc.iControllerRelativeSocket = KInvalidSocketNumber;
for(TInt j=0;j<KMaxDrivesPerSocket;++j)
socketDesc.iDriveNumbers[j]=KDriveInvalid;
}
}
// Searches for a local socket which matches the media type and
// controller relative socket number.
// If none is found then this function returns a new socket number.
// If no more free sockets available, returns KErrNoMemory
TInt LocalDrives::GetLocalSocket(TInt aControllerRelativeSocket, TMediaDevice aMediaType)
{
TInt i;
TSocketDesc* socketDesc = NULL;
for (i=0; i<KMaxPBusSockets; i++)
{
socketDesc = &iSocketDescs[i];
TMediaDevice mediaType = socketDesc->iMediaType;
if (mediaType == aMediaType && socketDesc->iControllerRelativeSocket == aControllerRelativeSocket)
return i;
if (mediaType == EInvalidMedia) // socket unassigned ?
break;
}
if (i == KMaxPBusSockets)
return KErrNoMemory;
// assign a new local socket for this controller relative socket number & media type
socketDesc->iMediaType = aMediaType;
socketDesc->iControllerRelativeSocket = aControllerRelativeSocket;
return i;
}
TBusLocalDrive& LocalDrives::GetLocalDrive(TInt aDrive)
//
// Export localdrives
//
{
__ASSERT_DEBUG(aDrive>=0 && aDrive<KMaxDrives,Fault(EGetLocalDrive1));
__ASSERT_DEBUG(iMapping[aDrive]!=KDriveInvalid && iMapping[aDrive]<KMaxLocalDrives,Fault(EGetLocalDrive2));
return(iLocalDrives[iMapping[aDrive]]);
}
TInt LocalDrives::GetLocalDriveNumber(TBusLocalDrive* aLocDrv)
//
// Get the local drive number for the local drive object passed in
//
{
for(TInt i=0;i<KMaxLocalDrives;++i)
if(&iLocalDrives[i]==aLocDrv)
return(i);
return(KDriveInvalid);
}
CExtProxyDrive* LocalDrives::GetProxyDrive(TInt aDrive)
{
__ASSERT_DEBUG(aDrive>=0 && aDrive<KMaxDrives,Fault(EGetProxyDriveMapping1));
__ASSERT_DEBUG(iMapping[aDrive]!=KDriveInvalid && iMapping[aDrive]>=KMaxLocalDrives && iMapping[aDrive]<KMaxDrives,Fault(EGetProxyDriveMapping1));
return iProxyDriveMapping[iMapping[aDrive]-KMaxLocalDrives];
}
LOCAL_C TBool DriveNumberIsInRange(TInt aDrive)
{
return((aDrive>=0) && (aDrive<KMaxDrives));
}
TBool LocalDrives::IsValidDriveMapping(TInt aDrive)
//
// Is the drive number to local drive mapping valid?
//
{
__ASSERT_DEBUG(DriveNumberIsInRange(aDrive),Fault(EIsValidDriveMapping));
return(iMapping[aDrive]!=KDriveInvalid);
}
TInt LocalDrives::DriveNumberToLocalDriveNumber(TInt aDrive)
//
// Get the mapping from drive number to local drive
//
{
return(iMapping[aDrive]);
}
TInt LocalDrives::SetDriveMappingL(CFsRequest* aRequest)
//
//
//
{
__PRINT(_L("LocalDrives::SetDriveMappingL()"));
if (iMappingSet)
return(KErrAccessDenied);
TLocalDriveMappingInfoBuf mBuf;
mBuf.FillZ();
aRequest->ReadL(KMsgPtr0,mBuf);
TLocalDriveMappingInfo& ldmi=mBuf();
if (ldmi.iOperation==TLocalDriveMappingInfo::ESwapIntMappingAndSet)
{
// Only the 1st two entries of the mapping table are valid - holding the drive numbers to be swapped
TInt r=KErrNone;
if (DriveNumberIsInRange(ldmi.iDriveMapping[0]) && DriveNumberIsInRange(ldmi.iDriveMapping[1]))
r=SwapDriveMapping(ldmi.iDriveMapping[0],ldmi.iDriveMapping[1]);
iMappingSet=ETrue;
return(r);
}
// That just leaves EWriteMappingsAndSet and EWriteMappingsNoSet
for (TInt i=0;i<KMaxLocalDrives;++i)
{
TInt driveLetter=ldmi.iDriveMapping[i];
if(driveLetter==KDriveInvalid)
continue;
if ( !DriveNumberIsInRange(driveLetter))
{
// invalid mapping list passed in, clear all mappings set up
for(TInt j=0;j<KMaxDrives;j++)
iMapping[j] = KDriveInvalid;
return(KErrArgument);
}
__PRINT2(_L("drive letter %d -> local drive %d"),driveLetter,i);
// If this mapping (letter -> localdrive) is already set then
// this must be a multislot device. Save this mapping as an
// alternative mapping (by storing it in iReverseMapping)
if(iMapping[driveLetter] != KDriveInvalid)
{
iIsMultiSlotDrive[driveLetter] = ETrue;
}
// first time we've seen this drive letter
iMapping[driveLetter]=i;
// following mapping is used when we want to swap back again.
iReverseMapping[i]=driveLetter;
}
InitDriveMapping();
if (ldmi.iOperation==TLocalDriveMappingInfo::EWriteMappingsAndSet)
iMappingSet=ETrue;
return(KErrNone);
}
// Changes here must be reflected in SwapDriveMapping()
void LocalDrives::InitDriveMapping()
{
__PRINT(_L("InitDriveMapping()"));
TDriveInfoV1Buf driveInfo;
TInt r=UserHal::DriveInfo(driveInfo);
__ASSERT_ALWAYS(r==KErrNone,Fault(EInitDriveMappingDriveInfo));
// initialise the local drives
TInt i;
for(i=0;i<KMaxLocalDrives;++i)
{
TInt driveNo = iReverseMapping[i];
if(driveNo!=KDriveInvalid)
{
r=iLocalDrives[i].Connect(i,TheDrives[driveNo].iChanged);
__ASSERT_ALWAYS(r==KErrNone,Fault(EInitConnectLocalDrive));
__PRINT2(_L("connect to locdrv %d using drive %d"),i,driveNo);
//If this is a multislot then we need to set the iChanged to True
//So that we are mapped to the correct drive when we're booted.
if(iIsMultiSlotDrive[driveNo])
{
TheDrives[driveNo].iChanged = ETrue;
}
if (driveInfo().iDriveName[i].Length()==0)
continue;
TheDriveNames[driveNo]=driveInfo().iDriveName[i].Alloc();
__ASSERT_ALWAYS(TheDriveNames[driveNo],Fault(EInitCreateDriveName));
}
}
TInt drivesPerSocket[KMaxPBusSockets];
Mem::FillZ(&drivesPerSocket,KMaxPBusSockets*sizeof(TInt));
TInt nSockets=driveInfo().iTotalSockets;
for(i=0;i<KMaxLocalDrives;++i)
{
TInt socket;
if(iLocalDrives[i].Handle()==0 || !iLocalDrives[i].IsRemovable(socket))
{
TInt driveNo = iReverseMapping[i];
// Non-removable drive so shouldn't be listed as a Multislot drive
// Drives such as composite drives may have been
// set to true as the drive letter had been encountered before.
// make sure those drives are set to false here.
iIsMultiSlotDrive[driveNo]=EFalse;
continue;
}
__ASSERT_ALWAYS(socket>=0 && socket<nSockets,Fault(EInitDriveMappingSocketNo));
TInt drv=GetDriveFromLocalDrive(i);
// get local socket number
TMediaDevice mediaDevice = iLocalDrives[i].MediaDevice();
TInt localSocket = LocalDrives::GetLocalSocket(socket, mediaDevice);
__ASSERT_ALWAYS(localSocket>=0 && localSocket<KMaxPBusSockets,Fault(EInitDriveMappingSocketNo));
__PRINT4(_L("InitDriveMapping(), i = %d, , mediaDevice = %d, socket = %d, localSocket = %d"),
i, mediaDevice, socket, localSocket);
__PRINT2(_L("drv = %d (%C:)"), drv, 'A' + drv);
TSocketDesc& socketDesc = iSocketDescs[localSocket];
if(drv!=KDriveInvalid)
{
TInt& count = drivesPerSocket[localSocket];
// setup up socket to drive mapping
__ASSERT_ALWAYS(count < KMaxDrivesPerSocket,Fault(ETooManyDrivesPerSocket));
socketDesc.iDriveNumbers[count]=drv;
if(count==0)
{
// setup media change notifier if this is first local drive found on socket
CNotifyMediaChange* pN=new CNotifyMediaChange(&iLocalDrives[i],localSocket);
__ASSERT_ALWAYS(pN!=NULL,Fault(EInitCreateMediaChangeNotifier));
__PRINT2(_L("created CNotifyMediaChange media 0x%x using local drive %d"), localSocket,i);
socketDesc.iMediaChanges = pN;
CActiveSchedulerFs::Add(pN);
pN->RunL();
}
++count;
}
}
}
TInt LocalDrives::InitProxyDrive(CFsRequest* aRequest)
{
__PRINT(_L("LocalDrives::InitProxyDrive"));
TInt drive = aRequest->Message().Int0() ;
if (drive < 0 || drive >= KMaxDrives)
return KErrArgument;
if (drive!=EDriveZ && iMapping[drive]!=KDriveInvalid)
return KErrInUse; // Z is special case for composite
TFullName extname;
aRequest->ReadL(KMsgPtr1,extname);
// leave info thing for now
CExtProxyDriveFactory* pF = GetProxyDriveFactory(extname);
if (!pF)
return KErrArgument; // that extension has not been added
FsThreadManager::LockDrive(drive);
// find a free mapping to place this drive into
TInt i;
for (i=0; i <KMaxProxyDrives; i++)
{
if (!iProxyDriveMapping[i])
break;
}
FsThreadManager::UnlockDrive(drive);
if (i==KMaxProxyDrives)
return KErrInUse; // there are no free proxy drives left
// Create the actual proxy drive...
CProxyDrive* pD = NULL;
TInt r = pF->CreateProxyDrive(pD, NULL);
__ASSERT_ALWAYS(r == KErrNone, User::Panic(_L("CreateProxyDrive Error"), r));
__ASSERT_ALWAYS(pD != NULL, User::Panic(_L("CreateProxyDrive returned NULL"), -999));
iMapping[drive] = i+KMaxLocalDrives;
aRequest->SetDrive(&TheDrives[drive]);
aRequest->SetScratchValue((TUint)pD);
return KErrNone;
}
TInt LocalDrives::MountProxyDrive(CFsRequest* aRequest)
{
CExtProxyDrive* pProxyDrive = (CExtProxyDrive*)aRequest->ScratchValue();
__ASSERT_ALWAYS(pProxyDrive != NULL, User::Panic(_L("MountProxyDrive has NULL proxy extension class"), -999));
TInt driveNumber = aRequest->Drive()->DriveNumber();
TInt proxyDriveNo = iMapping[driveNumber] - KMaxLocalDrives;
FsThreadManager::LockDrive(driveNumber);
iProxyDriveMapping[proxyDriveNo] = pProxyDrive;
pProxyDrive->SetDriveNumber(driveNumber);
FsThreadManager::UnlockDrive(driveNumber);
//
// Pass initialisation information onto the extension to allow it to initialise
//
TInt err = pProxyDrive->SetInfo(aRequest->Message(),
(TAny*)aRequest->Message().Ptr2(),
(TAny*)aRequest->Message().Ptr3());
if (err != KErrNone)
{
//
// If we fail to initialise the extension, then close the drive (destroying the thread)
// and remove the mapping so we can attempt to mount again in the future.
//
FsThreadManager::LockDrive(driveNumber);
FsThreadManager::CloseDrive(driveNumber);
ClearProxyDriveMapping(driveNumber);
FsThreadManager::UnlockDrive(driveNumber);
return err;
}
return(iMapping[driveNumber]);
}
TBool LocalDrives::IsProxyDrive(TInt aDrive)
{
__ASSERT_ALWAYS(aDrive>=0 && aDrive<KMaxDrives,Fault(EIsProxyDrive));
return (iMapping[aDrive] >= KMaxLocalDrives);
}
TBool LocalDrives::IsProxyDriveInUse(CExtProxyDriveFactory* aDevice)
{
for (TInt i=0; i < KMaxProxyDrives; i++)
if (iProxyDriveMapping[i] && (iProxyDriveMapping[i]->FactoryP() == aDevice))
return(ETrue);
return(EFalse);
}
void LocalDrives::ClearProxyDriveMapping(TInt aDrive)
{
__ASSERT_ALWAYS(aDrive>=0 && aDrive<KMaxDrives,Fault(EClearProxyDriveMapping1));
__ASSERT_DEBUG(iMapping[aDrive]>= KMaxLocalDrives && iProxyDriveMapping[iMapping[aDrive]-KMaxLocalDrives],Fault(EClearProxyDriveMapping2));
TInt idx = iMapping[aDrive]-KMaxLocalDrives;
delete iProxyDriveMapping[idx];
iProxyDriveMapping[idx] = NULL;
iMapping[aDrive] = KDriveInvalid;
}
TInt LocalDrives::SetupMediaChange(TInt aDrive)
{
CExtProxyDrive* pProxyDrive = LocalDrives::GetProxyDrive(aDrive);
__ASSERT_ALWAYS(pProxyDrive != NULL,User::Panic(_L("SetupMediaChange - pProxyDrive == NULL"), ESetupMediaChange));
return pProxyDrive->SetupMediaChange();
}
void LocalDrives::NotifyChangeCancel(TInt aDrive)
{
CExtProxyDrive* pProxyDrive = LocalDrives::GetProxyDrive(aDrive);
__ASSERT_ALWAYS(pProxyDrive != NULL,User::Panic(_L("NotifyChangeCancel - pProxyDrive == NULL"), ECancelNotifyChange));
pProxyDrive->NotifyChangeCancel();
}
TInt LocalDrives::SwapDriveMapping(TInt aFirstDrive,TInt aSecondDrive)
{
__PRINT(_L("SwapDriveMapping()"));
TInt firstLocalDrv=iMapping[aFirstDrive];
TInt secondLocalDrv=iMapping[aSecondDrive];
// First, check this swap doesn't affect removable drives
TInt socket;
if (iLocalDrives[firstLocalDrv].Handle()!=0 && iLocalDrives[firstLocalDrv].IsRemovable(socket))
return(KErrAccessDenied);
if (iLocalDrives[secondLocalDrv].Handle()!=0 && iLocalDrives[secondLocalDrv].IsRemovable(socket))
return(KErrAccessDenied);
// Now swap the mappings over
iMapping[aFirstDrive]=secondLocalDrv;
iMapping[aSecondDrive]=firstLocalDrv;
iReverseMapping[firstLocalDrv]=aSecondDrive;
iReverseMapping[secondLocalDrv]=aFirstDrive;
// Finally, swap the drive names over
HBufC* drvName=TheDriveNames[aSecondDrive];
TheDriveNames[aSecondDrive]=TheDriveNames[aFirstDrive];
TheDriveNames[aFirstDrive]=drvName;
return(KErrNone);
}
void LocalDrives::CompleteNotifications(TInt aSocket)
//
//
//
{
__ASSERT_DEBUG(aSocket>=0 && aSocket<KMaxPBusSockets && iSocketDescs[aSocket].iDriveNumbers[0]!=KDriveInvalid,Fault(ECompleteNotifSocketNo));
TInt i=0;
// In a data-paging environment, the local media subsytem will only update the TDrive::iChanged flag
// for drives which have a CNotifyMediaChange object, i.e. for drives which call TBusLocalDrive::NotifyChange().
// Since we only create ONE CNotifyMediaChange object for each socket (no matter how many partitions/local drives
// are associated with that socket), we need to propagate the TDrive::iChanged flag to all drives on the socket.
TBool changedFlag = TheDrives[iSocketDescs[aSocket].iDriveNumbers[0]].IsChanged();
while(i<KMaxDrivesPerSocket && iSocketDescs[aSocket].iDriveNumbers[i]!=KDriveInvalid)
{
TheDrives[iSocketDescs[aSocket].iDriveNumbers[i]].SetChanged(changedFlag);
CompleteDriveNotifications(iSocketDescs[aSocket].iDriveNumbers[i++]);
}
}
void LocalDrives::CompleteDriveNotifications(TInt aDrive)
//
//
//
{
// If the drive is hung, then don't complete any disk change
// notifications until the request causing the hang completes
if(FsThreadManager::IsDriveHung(aDrive))
FsThreadManager::SetMediaChangePending(aDrive);
else
{
FsNotify::DiskChange(aDrive);
#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
if(FsNotificationManager::IsInitialised())
{
__PRINT3(_L("LocalDrives::CompleteDriveNotifications() Initialised=%d, Count=%d, Drive=%d"),FsNotificationManager::IsInitialised(),FsNotificationManager::Count(), aDrive);
TBuf<2> driveDes;
driveDes.Append((TChar)aDrive+(TChar)'A');
driveDes.Append((TChar)':');
FsNotificationManager::HandleChange(NULL,driveDes,TFsNotification::EMediaChange);
}
#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
//If this is a multislot device we should update mappings here.
TheDrives[aDrive].MultiSlotDriveCheck();
}
}
TInt LocalDrives::GetDriveFromLocalDrive(TInt aLocDrv)
//
//
//
{
return iReverseMapping[aLocDrv];
}
CNotifyMediaChange::CNotifyMediaChange(RLocalDrive* aDrive,TInt aSocketNo)
//
// Constructor
//
: CActive(EPriorityHigh), iDrive(aDrive), iSocket(aSocketNo)
{}
void CNotifyMediaChange::RunL()
//
// Notification that a card has been mounted/removed
//
{
LocalDrives::CompleteNotifications(iSocket);
iDrive->NotifyChange(&iStatus);
SetActive();
}
CExtNotifyMediaChange::CExtNotifyMediaChange(CExtProxyDrive* aDrive)
//
// Constructor
//
: CActive(EPriorityHigh),
iDrive(aDrive),
iPtr((TUint8*)&TheDrives[aDrive->DriveNumber()].iChanged,sizeof(TBool))
{
}
CExtNotifyMediaChange* CExtNotifyMediaChange::NewL(CExtProxyDrive* aDrive)
{
CExtNotifyMediaChange* pSelf = new(ELeave) CExtNotifyMediaChange(aDrive);
CleanupStack::PushL(pSelf);
pSelf->ConstructL();
CleanupStack::Pop();
return pSelf;
}
void CExtNotifyMediaChange::ConstructL()
{
CActiveSchedulerFs::Add(this);
TRAPD(err, RunL());
if(err != KErrNone)
Deque();
User::LeaveIfError(err);
}
CExtNotifyMediaChange::~CExtNotifyMediaChange()
{
Cancel();
}
void CExtNotifyMediaChange::RequestL()
{
if (!IsActive())
{
User::LeaveIfError(iDrive->NotifyChange(iPtr, &iStatus));
SetActive();
}
}
void CExtNotifyMediaChange::DoCancel()
{
iDrive->NotifyChangeCancel();
}
void CExtNotifyMediaChange::RunL()
{
if(iStatus==KErrDisconnected || iStatus==KErrCancel)
return;
TInt driveNum = iDrive->DriveNumber();
LocalDrives::CompleteDriveNotifications(driveNum);
/* NOTE: We need SetChanged here though the iChanged variable is set in the MSC, since the cache is not getting cleared
(inside the CompleteDriveNotifications call) during the initial first notification */
TheDrives[driveNum].SetChanged(ETrue);
if(iStatus != KErrNotSupported)
{
RequestL();
}
}