Update contrib.
1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
19 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
20 #include "sf_notifier.h"
23 GLREF_C CProxyDriveFactory* GetExtension(const TDesC& aName);
24 GLREF_C CExtProxyDriveFactory* GetProxyDriveFactory(const TDesC& aName);
26 TBusLocalDrive LocalDrives::iLocalDrives[KMaxLocalDrives];
27 TInt LocalDrives::iMapping[KMaxDrives];
28 TInt LocalDrives::iReverseMapping[KMaxLocalDrives];
29 TBool LocalDrives::iMappingSet;
30 LocalDrives::TSocketDesc LocalDrives::iSocketDescs[KMaxPBusSockets];
31 CExtProxyDrive* LocalDrives::iProxyDriveMapping[KMaxProxyDrives];
32 TBool LocalDrives::iIsMultiSlotDrive[KMaxDrives];
33 const TInt KInvalidSocketNumber = -1;
35 void LocalDrives::Initialise()
42 Mem::FillZ((TAny*)iProxyDriveMapping,sizeof(CExtProxyDriveFactory*)*KMaxProxyDrives);
43 // initialise mapping from drive number to local drive
44 for(i=0;i<KMaxDrives;i++)
46 iMapping[i] = KDriveInvalid;
47 iIsMultiSlotDrive[i] = EFalse;
49 // initialise reverse mapping from local drive to drive.
50 for(i=0;i<KMaxLocalDrives;i++)
52 iReverseMapping[i] = KDriveInvalid;
54 // initialise mapping from socket number to drive numbers
55 for(i=0;i<KMaxPBusSockets;++i)
57 TSocketDesc& socketDesc = iSocketDescs[i];
58 socketDesc.iMediaType = EInvalidMedia;
59 socketDesc.iControllerRelativeSocket = KInvalidSocketNumber;
60 for(TInt j=0;j<KMaxDrivesPerSocket;++j)
61 socketDesc.iDriveNumbers[j]=KDriveInvalid;
65 // Searches for a local socket which matches the media type and
66 // controller relative socket number.
67 // If none is found then this function returns a new socket number.
68 // If no more free sockets available, returns KErrNoMemory
69 TInt LocalDrives::GetLocalSocket(TInt aControllerRelativeSocket, TMediaDevice aMediaType)
72 TSocketDesc* socketDesc = NULL;
73 for (i=0; i<KMaxPBusSockets; i++)
75 socketDesc = &iSocketDescs[i];
76 TMediaDevice mediaType = socketDesc->iMediaType;
77 if (mediaType == aMediaType && socketDesc->iControllerRelativeSocket == aControllerRelativeSocket)
79 if (mediaType == EInvalidMedia) // socket unassigned ?
82 if (i == KMaxPBusSockets)
85 // assign a new local socket for this controller relative socket number & media type
86 socketDesc->iMediaType = aMediaType;
87 socketDesc->iControllerRelativeSocket = aControllerRelativeSocket;
92 TBusLocalDrive& LocalDrives::GetLocalDrive(TInt aDrive)
97 __ASSERT_DEBUG(aDrive>=0 && aDrive<KMaxDrives,Fault(EGetLocalDrive1));
98 __ASSERT_DEBUG(iMapping[aDrive]!=KDriveInvalid && iMapping[aDrive]<KMaxLocalDrives,Fault(EGetLocalDrive2));
99 return(iLocalDrives[iMapping[aDrive]]);
103 TInt LocalDrives::GetLocalDriveNumber(TBusLocalDrive* aLocDrv)
105 // Get the local drive number for the local drive object passed in
108 for(TInt i=0;i<KMaxLocalDrives;++i)
109 if(&iLocalDrives[i]==aLocDrv)
111 return(KDriveInvalid);
116 CExtProxyDrive* LocalDrives::GetProxyDrive(TInt aDrive)
118 __ASSERT_DEBUG(aDrive>=0 && aDrive<KMaxDrives,Fault(EGetProxyDriveMapping1));
119 __ASSERT_DEBUG(iMapping[aDrive]!=KDriveInvalid && iMapping[aDrive]>=KMaxLocalDrives && iMapping[aDrive]<KMaxDrives,Fault(EGetProxyDriveMapping1));
120 return iProxyDriveMapping[iMapping[aDrive]-KMaxLocalDrives];
124 LOCAL_C TBool DriveNumberIsInRange(TInt aDrive)
127 return((aDrive>=0) && (aDrive<KMaxDrives));
131 TBool LocalDrives::IsValidDriveMapping(TInt aDrive)
133 // Is the drive number to local drive mapping valid?
137 __ASSERT_DEBUG(DriveNumberIsInRange(aDrive),Fault(EIsValidDriveMapping));
138 return(iMapping[aDrive]!=KDriveInvalid);
142 TInt LocalDrives::DriveNumberToLocalDriveNumber(TInt aDrive)
144 // Get the mapping from drive number to local drive
147 return(iMapping[aDrive]);
151 TInt LocalDrives::SetDriveMappingL(CFsRequest* aRequest)
157 __PRINT(_L("LocalDrives::SetDriveMappingL()"));
159 return(KErrAccessDenied);
161 TLocalDriveMappingInfoBuf mBuf;
163 aRequest->ReadL(KMsgPtr0,mBuf);
164 TLocalDriveMappingInfo& ldmi=mBuf();
166 if (ldmi.iOperation==TLocalDriveMappingInfo::ESwapIntMappingAndSet)
168 // Only the 1st two entries of the mapping table are valid - holding the drive numbers to be swapped
170 if (DriveNumberIsInRange(ldmi.iDriveMapping[0]) && DriveNumberIsInRange(ldmi.iDriveMapping[1]))
171 r=SwapDriveMapping(ldmi.iDriveMapping[0],ldmi.iDriveMapping[1]);
176 // That just leaves EWriteMappingsAndSet and EWriteMappingsNoSet
177 for (TInt i=0;i<KMaxLocalDrives;++i)
179 TInt driveLetter=ldmi.iDriveMapping[i];
180 if(driveLetter==KDriveInvalid)
182 if ( !DriveNumberIsInRange(driveLetter))
184 // invalid mapping list passed in, clear all mappings set up
185 for(TInt j=0;j<KMaxDrives;j++)
186 iMapping[j] = KDriveInvalid;
187 return(KErrArgument);
189 __PRINT2(_L("drive letter %d -> local drive %d"),driveLetter,i);
191 // If this mapping (letter -> localdrive) is already set then
192 // this must be a multislot device. Save this mapping as an
193 // alternative mapping (by storing it in iReverseMapping)
194 if(iMapping[driveLetter] != KDriveInvalid)
196 iIsMultiSlotDrive[driveLetter] = ETrue;
198 // first time we've seen this drive letter
199 iMapping[driveLetter]=i;
200 // following mapping is used when we want to swap back again.
201 iReverseMapping[i]=driveLetter;
205 if (ldmi.iOperation==TLocalDriveMappingInfo::EWriteMappingsAndSet)
210 // Changes here must be reflected in SwapDriveMapping()
211 void LocalDrives::InitDriveMapping()
213 __PRINT(_L("InitDriveMapping()"));
214 TDriveInfoV1Buf driveInfo;
215 TInt r=UserHal::DriveInfo(driveInfo);
216 __ASSERT_ALWAYS(r==KErrNone,Fault(EInitDriveMappingDriveInfo));
218 // initialise the local drives
220 for(i=0;i<KMaxLocalDrives;++i)
222 TInt driveNo = iReverseMapping[i];
223 if(driveNo!=KDriveInvalid)
225 r=iLocalDrives[i].Connect(i,TheDrives[driveNo].iChanged);
226 __ASSERT_ALWAYS(r==KErrNone,Fault(EInitConnectLocalDrive));
227 __PRINT2(_L("connect to locdrv %d using drive %d"),i,driveNo);
228 //If this is a multislot then we need to set the iChanged to True
229 //So that we are mapped to the correct drive when we're booted.
230 if(iIsMultiSlotDrive[driveNo])
232 TheDrives[driveNo].iChanged = ETrue;
234 if (driveInfo().iDriveName[i].Length()==0)
236 TheDriveNames[driveNo]=driveInfo().iDriveName[i].Alloc();
237 __ASSERT_ALWAYS(TheDriveNames[driveNo],Fault(EInitCreateDriveName));
241 TInt drivesPerSocket[KMaxPBusSockets];
242 Mem::FillZ(&drivesPerSocket,KMaxPBusSockets*sizeof(TInt));
243 TInt nSockets=driveInfo().iTotalSockets;
244 for(i=0;i<KMaxLocalDrives;++i)
247 if(iLocalDrives[i].Handle()==0 || !iLocalDrives[i].IsRemovable(socket))
249 TInt driveNo = iReverseMapping[i];
250 // Non-removable drive so shouldn't be listed as a Multislot drive
251 // Drives such as composite drives may have been
252 // set to true as the drive letter had been encountered before.
253 // make sure those drives are set to false here.
254 iIsMultiSlotDrive[driveNo]=EFalse;
257 __ASSERT_ALWAYS(socket>=0 && socket<nSockets,Fault(EInitDriveMappingSocketNo));
258 TInt drv=GetDriveFromLocalDrive(i);
259 // get local socket number
260 TMediaDevice mediaDevice = iLocalDrives[i].MediaDevice();
261 TInt localSocket = LocalDrives::GetLocalSocket(socket, mediaDevice);
262 __ASSERT_ALWAYS(localSocket>=0 && localSocket<KMaxPBusSockets,Fault(EInitDriveMappingSocketNo));
263 __PRINT4(_L("InitDriveMapping(), i = %d, , mediaDevice = %d, socket = %d, localSocket = %d"),
264 i, mediaDevice, socket, localSocket);
265 __PRINT2(_L("drv = %d (%C:)"), drv, 'A' + drv);
267 TSocketDesc& socketDesc = iSocketDescs[localSocket];
268 if(drv!=KDriveInvalid)
270 TInt& count = drivesPerSocket[localSocket];
271 // setup up socket to drive mapping
272 __ASSERT_ALWAYS(count < KMaxDrivesPerSocket,Fault(ETooManyDrivesPerSocket));
273 socketDesc.iDriveNumbers[count]=drv;
276 // setup media change notifier if this is first local drive found on socket
277 CNotifyMediaChange* pN=new CNotifyMediaChange(&iLocalDrives[i],localSocket);
278 __ASSERT_ALWAYS(pN!=NULL,Fault(EInitCreateMediaChangeNotifier));
279 __PRINT2(_L("created CNotifyMediaChange media 0x%x using local drive %d"), localSocket,i);
280 socketDesc.iMediaChanges = pN;
281 CActiveSchedulerFs::Add(pN);
289 TInt LocalDrives::InitProxyDrive(CFsRequest* aRequest)
291 __PRINT(_L("LocalDrives::InitProxyDrive"));
293 TInt drive = aRequest->Message().Int0() ;
295 if (drive < 0 || drive >= KMaxDrives)
298 if (drive!=EDriveZ && iMapping[drive]!=KDriveInvalid)
299 return KErrInUse; // Z is special case for composite
302 aRequest->ReadL(KMsgPtr1,extname);
304 // leave info thing for now
305 CExtProxyDriveFactory* pF = GetProxyDriveFactory(extname);
307 return KErrArgument; // that extension has not been added
308 FsThreadManager::LockDrive(drive);
309 // find a free mapping to place this drive into
311 for (i=0; i <KMaxProxyDrives; i++)
313 if (!iProxyDriveMapping[i])
316 FsThreadManager::UnlockDrive(drive);
317 if (i==KMaxProxyDrives)
318 return KErrInUse; // there are no free proxy drives left
320 // Create the actual proxy drive...
321 CProxyDrive* pD = NULL;
322 TInt r = pF->CreateProxyDrive(pD, NULL);
323 __ASSERT_ALWAYS(r == KErrNone, User::Panic(_L("CreateProxyDrive Error"), r));
324 __ASSERT_ALWAYS(pD != NULL, User::Panic(_L("CreateProxyDrive returned NULL"), -999));
326 iMapping[drive] = i+KMaxLocalDrives;
328 aRequest->SetDrive(&TheDrives[drive]);
329 aRequest->SetScratchValue((TUint)pD);
334 TInt LocalDrives::MountProxyDrive(CFsRequest* aRequest)
336 CExtProxyDrive* pProxyDrive = (CExtProxyDrive*)aRequest->ScratchValue();
337 __ASSERT_ALWAYS(pProxyDrive != NULL, User::Panic(_L("MountProxyDrive has NULL proxy extension class"), -999));
339 TInt driveNumber = aRequest->Drive()->DriveNumber();
342 TInt proxyDriveNo = iMapping[driveNumber] - KMaxLocalDrives;
343 FsThreadManager::LockDrive(driveNumber);
344 iProxyDriveMapping[proxyDriveNo] = pProxyDrive;
345 pProxyDrive->SetDriveNumber(driveNumber);
346 FsThreadManager::UnlockDrive(driveNumber);
348 // Pass initialisation information onto the extension to allow it to initialise
350 TInt err = pProxyDrive->SetInfo(aRequest->Message(),
351 (TAny*)aRequest->Message().Ptr2(),
352 (TAny*)aRequest->Message().Ptr3());
356 // If we fail to initialise the extension, then close the drive (destroying the thread)
357 // and remove the mapping so we can attempt to mount again in the future.
359 FsThreadManager::LockDrive(driveNumber);
360 FsThreadManager::CloseDrive(driveNumber);
361 ClearProxyDriveMapping(driveNumber);
362 FsThreadManager::UnlockDrive(driveNumber);
366 return(iMapping[driveNumber]);
369 TBool LocalDrives::IsProxyDrive(TInt aDrive)
371 __ASSERT_ALWAYS(aDrive>=0 && aDrive<KMaxDrives,Fault(EIsProxyDrive));
372 return (iMapping[aDrive] >= KMaxLocalDrives);
375 TBool LocalDrives::IsProxyDriveInUse(CExtProxyDriveFactory* aDevice)
377 for (TInt i=0; i < KMaxProxyDrives; i++)
378 if (iProxyDriveMapping[i] && (iProxyDriveMapping[i]->FactoryP() == aDevice))
384 void LocalDrives::ClearProxyDriveMapping(TInt aDrive)
386 __ASSERT_ALWAYS(aDrive>=0 && aDrive<KMaxDrives,Fault(EClearProxyDriveMapping1));
387 __ASSERT_DEBUG(iMapping[aDrive]>= KMaxLocalDrives && iProxyDriveMapping[iMapping[aDrive]-KMaxLocalDrives],Fault(EClearProxyDriveMapping2));
388 TInt idx = iMapping[aDrive]-KMaxLocalDrives;
389 delete iProxyDriveMapping[idx];
390 iProxyDriveMapping[idx] = NULL;
391 iMapping[aDrive] = KDriveInvalid;
394 TInt LocalDrives::SetupMediaChange(TInt aDrive)
396 CExtProxyDrive* pProxyDrive = LocalDrives::GetProxyDrive(aDrive);
397 __ASSERT_ALWAYS(pProxyDrive != NULL,User::Panic(_L("SetupMediaChange - pProxyDrive == NULL"), ESetupMediaChange));
399 return pProxyDrive->SetupMediaChange();
402 void LocalDrives::NotifyChangeCancel(TInt aDrive)
404 CExtProxyDrive* pProxyDrive = LocalDrives::GetProxyDrive(aDrive);
405 __ASSERT_ALWAYS(pProxyDrive != NULL,User::Panic(_L("NotifyChangeCancel - pProxyDrive == NULL"), ECancelNotifyChange));
407 pProxyDrive->NotifyChangeCancel();
410 TInt LocalDrives::SwapDriveMapping(TInt aFirstDrive,TInt aSecondDrive)
413 __PRINT(_L("SwapDriveMapping()"));
414 TInt firstLocalDrv=iMapping[aFirstDrive];
415 TInt secondLocalDrv=iMapping[aSecondDrive];
417 // First, check this swap doesn't affect removable drives
419 if (iLocalDrives[firstLocalDrv].Handle()!=0 && iLocalDrives[firstLocalDrv].IsRemovable(socket))
420 return(KErrAccessDenied);
421 if (iLocalDrives[secondLocalDrv].Handle()!=0 && iLocalDrives[secondLocalDrv].IsRemovable(socket))
422 return(KErrAccessDenied);
424 // Now swap the mappings over
425 iMapping[aFirstDrive]=secondLocalDrv;
426 iMapping[aSecondDrive]=firstLocalDrv;
428 iReverseMapping[firstLocalDrv]=aSecondDrive;
429 iReverseMapping[secondLocalDrv]=aFirstDrive;
431 // Finally, swap the drive names over
432 HBufC* drvName=TheDriveNames[aSecondDrive];
433 TheDriveNames[aSecondDrive]=TheDriveNames[aFirstDrive];
434 TheDriveNames[aFirstDrive]=drvName;
438 void LocalDrives::CompleteNotifications(TInt aSocket)
443 __ASSERT_DEBUG(aSocket>=0 && aSocket<KMaxPBusSockets && iSocketDescs[aSocket].iDriveNumbers[0]!=KDriveInvalid,Fault(ECompleteNotifSocketNo));
446 // In a data-paging environment, the local media subsytem will only update the TDrive::iChanged flag
447 // for drives which have a CNotifyMediaChange object, i.e. for drives which call TBusLocalDrive::NotifyChange().
448 // Since we only create ONE CNotifyMediaChange object for each socket (no matter how many partitions/local drives
449 // are associated with that socket), we need to propagate the TDrive::iChanged flag to all drives on the socket.
450 TBool changedFlag = TheDrives[iSocketDescs[aSocket].iDriveNumbers[0]].IsChanged();
452 while(i<KMaxDrivesPerSocket && iSocketDescs[aSocket].iDriveNumbers[i]!=KDriveInvalid)
454 TheDrives[iSocketDescs[aSocket].iDriveNumbers[i]].SetChanged(changedFlag);
455 CompleteDriveNotifications(iSocketDescs[aSocket].iDriveNumbers[i++]);
459 void LocalDrives::CompleteDriveNotifications(TInt aDrive)
464 // If the drive is hung, then don't complete any disk change
465 // notifications until the request causing the hang completes
466 if(FsThreadManager::IsDriveHung(aDrive))
467 FsThreadManager::SetMediaChangePending(aDrive);
470 FsNotify::DiskChange(aDrive);
472 #ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
473 if(FsNotificationManager::IsInitialised())
475 __PRINT3(_L("LocalDrives::CompleteDriveNotifications() Initialised=%d, Count=%d, Drive=%d"),FsNotificationManager::IsInitialised(),FsNotificationManager::Count(), aDrive);
477 driveDes.Append((TChar)aDrive+(TChar)'A');
478 driveDes.Append((TChar)':');
479 FsNotificationManager::HandleChange(NULL,driveDes,TFsNotification::EMediaChange);
481 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
483 //If this is a multislot device we should update mappings here.
484 TheDrives[aDrive].MultiSlotDriveCheck();
488 TInt LocalDrives::GetDriveFromLocalDrive(TInt aLocDrv)
493 return iReverseMapping[aLocDrv];
497 CNotifyMediaChange::CNotifyMediaChange(RLocalDrive* aDrive,TInt aSocketNo)
501 : CActive(EPriorityHigh), iDrive(aDrive), iSocket(aSocketNo)
504 void CNotifyMediaChange::RunL()
506 // Notification that a card has been mounted/removed
509 LocalDrives::CompleteNotifications(iSocket);
510 iDrive->NotifyChange(&iStatus);
515 CExtNotifyMediaChange::CExtNotifyMediaChange(CExtProxyDrive* aDrive)
519 : CActive(EPriorityHigh),
521 iPtr((TUint8*)&TheDrives[aDrive->DriveNumber()].iChanged,sizeof(TBool))
526 CExtNotifyMediaChange* CExtNotifyMediaChange::NewL(CExtProxyDrive* aDrive)
528 CExtNotifyMediaChange* pSelf = new(ELeave) CExtNotifyMediaChange(aDrive);
530 CleanupStack::PushL(pSelf);
537 void CExtNotifyMediaChange::ConstructL()
539 CActiveSchedulerFs::Add(this);
545 User::LeaveIfError(err);
548 CExtNotifyMediaChange::~CExtNotifyMediaChange()
553 void CExtNotifyMediaChange::RequestL()
557 User::LeaveIfError(iDrive->NotifyChange(iPtr, &iStatus));
562 void CExtNotifyMediaChange::DoCancel()
564 iDrive->NotifyChangeCancel();
567 void CExtNotifyMediaChange::RunL()
569 if(iStatus==KErrDisconnected || iStatus==KErrCancel)
572 TInt driveNum = iDrive->DriveNumber();
573 LocalDrives::CompleteDriveNotifications(driveNum);
575 /* NOTE: We need SetChanged here though the iChanged variable is set in the MSC, since the cache is not getting cleared
576 (inside the CompleteDriveNotifications call) during the initial first notification */
577 TheDrives[driveNum].SetChanged(ETrue);
579 if(iStatus != KErrNotSupported)