userlibandfileserver/fileserver/sfile/sf_local.cpp
changeset 0 a41df078684a
child 36 bbf8bed59bcb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfile/sf_local.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,586 @@
+// 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();
+        }
+	}
+
+
+