First public contribution.
1 // Copyright (c) 1996-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.
14 // f32\sfat32\sl_fatcache.cpp
15 // FAT12 and FAT16 cache implementation
24 #include "sl_fatcache.h"
27 //#################################################################################################################################
28 // CFatCacheBase implementation
29 // Base class for all types of FAT cache
30 //#################################################################################################################################
32 CFatCacheBase::~CFatCacheBase()
34 Close(ETrue); //-- deallocate cache's memory discarding any dirty data
37 CFatCacheBase::CFatCacheBase()
39 iCurrentFatNo = KInvalidFatNo;
45 FAT cache initialisation.
47 @param aOwner pointer to the owning FAT mount
49 void CFatCacheBase::InitialiseL(CFatMountCB* aOwner)
53 Close(ETrue); //-- deallocate cache's memory discarding any dirty data
55 //-- populate parameters from the owning mount
56 iFatType = aOwner->FatType();
57 __ASSERT_ALWAYS((iFatType == EFat12 || iFatType == EFat16 || iFatType == EFat32), User::Leave(KErrCorrupt));
59 ipDrive = &aOwner->DriveInterface();
60 iFatStartPos = aOwner->FirstFatSector() << aOwner->SectorSizeLog2();
61 iFatSize = aOwner->FatSizeInBytes();
62 iNumFATs = (TUint16)aOwner->NumberOfFats();
63 iFatSecSzLog2 = (TUint16)aOwner->SectorSizeLog2();
64 iFatClustSzLog2 = (TUint16)aOwner->ClusterSizeLog2();
66 __ASSERT_ALWAYS(iNumFATs >=1, User::Leave(KErrCorrupt));
68 __PRINT3(_L("#-CFatCacheBase::InitialiseL() FatStart:%u, FatSz:%d, drv:%d"),iFatStartPos, iFatSize, aOwner->DriveNumber());
71 //-----------------------------------------------------------------------------
73 This method shall be called to check if we are allowed to invalidate dirty cache, i.e. discard non-flushed data.
74 The behaviour is hardcoded (see KAllowInvalidateDirtyCache constant)
76 @return ETrue if invalidating dirty cache is allowed. Otherwise panics the current thread
78 TBool CFatCacheBase::CheckInvalidatingDirtyCache() const
81 //-- If not EFalse, invalidating dirty cache (pages) is allowed. This shall be OK, because
82 //-- invalidating the cache is required only after direct media writes to the FAT by RawWrite, which can corrupt it anyway.
83 TBool KAllowInvalidateDirtyCache = ETrue;
86 return KAllowInvalidateDirtyCache;
88 __PRINT(_L("#-CFatCacheBase::Invalidating dirty cache !"));
90 if(!KAllowInvalidateDirtyCache)
92 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
95 return KAllowInvalidateDirtyCache;
98 //-----------------------------------------------------------------------------
101 Read portion of raw data from 1st FAT copy.
103 @param aPos media position in the _FIRST_ FAT to start reading with
104 @param aLen number of bytes to read
105 @param aData data descriptor
107 @return standard error code.
109 TInt CFatCacheBase::ReadFatData(TUint32 aPos, TUint32 aLen, TDes8& aData) const
111 //__PRINT2(_L("#-CFatCacheNew::ReadFatData() pos:%u, Len:%d"), aPos, aLen);
113 //-- this method can pick up data corresponding to invalid FAT entries, like FAT[0], FAT[1] and
114 //-- the last portion beyond FAT because of read granularity. This isn't a problem, because the data there
115 //-- won't be written on disk.
116 ASSERT(aPos >= FatStartPos());
118 return ipDrive->ReadNonCritical(aPos, aLen, aData);
121 //-----------------------------------------------------------------------------
124 Writes data to the FAT table, which number is set in iCurrentFatNo member variable.
125 @param aPos data media position in the _FIRST_ FAT copy
126 @param aData data descriptor
127 @return standard error code.
129 TInt CFatCacheBase::WriteFatData(TUint32 aPos, const TDesC8& aData) const
131 //__PRINT3(_L("#-CFatCacheBase::WriteFatData() pos:%u, Len:%d, FAT:%d"), aPos, aData.Length(), iCurrentFatNo);
134 //-- FAT[0] and FAT[1] entries are reserved and we must not write data there. It's up to the caller of this method to
135 //-- calculate correct data position in FAT
136 TInt reserved_Entries_Offset=0;
139 case EFat32: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat32Entry); break; //-- FAT32
140 case EFat16: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat16Entry); break; //-- FAT16
141 case EFat12: reserved_Entries_Offset = 3; break; //-- FAT12
142 default: ASSERT(0); break;
144 ASSERT(aPos >= FatStartPos()+reserved_Entries_Offset);
145 ASSERT((aPos+aData.Length()) <= FatStartPos()+FatSize());
146 ASSERT(iCurrentFatNo < iNumFATs);
149 //-- goto the required FAT copy. iCurrentFatNo shall contain FAT number we are writing to.
150 aPos+=iCurrentFatNo*FatSize();
152 return ipDrive->WriteCritical(aPos, aData);
155 //-----------------------------------------------------------------------------
157 get a pointer to the CFatBitCache interface.
158 @return NULL because it is not present here
160 CFatBitCache* CFatCacheBase::BitCacheInterface()
166 //#################################################################################################################################
167 // CFatPagedCacheBase implementation
168 // Base class for all paged FAT caches
169 //#################################################################################################################################
171 CFatPagedCacheBase::CFatPagedCacheBase()
177 //#################################################################################################################################
178 // CFatCachePageBase implementation
179 // Base class for FAT cache pages (FAT16 fixed and FAT32 LRU)
180 //#################################################################################################################################
182 CFatCachePageBase::CFatCachePageBase(CFatPagedCacheBase& aCache)
185 ASSERT(IsPowerOf2(aCache.PageSize()));
186 iStartIndexInFAT = KMaxTUint;
188 //-- calculate number of FAT entries in the page, it depends on FAT type
189 switch(aCache.FatType())
192 iFatEntriesInPage = PageSize() >> KFat32EntrySzLog2;
196 iFatEntriesInPage = PageSize() >> KFat16EntrySzLog2;
201 Fault(EFatCache_BadFatType);
209 CFatCachePageBase::~CFatCachePageBase()
214 //-----------------------------------------------------------------------------
216 Mark the page as "invalid". I.e containing inalid data.
217 On the first read/write access to such page it will be re-read from the media
219 @param aIgnoreDirtyData if ETrue, it is allowed to ignore the fact that the page contains dirty (not flushed) data.
221 void CFatCachePageBase::Invalidate(TBool aIgnoreDirtyData /*= EFalse*/)
223 if(!aIgnoreDirtyData && IsDirty())
225 __PRINT1(_L("#-CFatCachePageBase::Invalidate() dirty page! FAT idx:%d"), iStartIndexInFAT);
226 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
229 iDirtySectors.Clear(); //-- clear dirty sectors bitmap
233 //-----------------------------------------------------------------------------
235 Flush all dirty page sectors to the media and mark the page as "clean" if required.
236 If the page is "clean" i.e doesn't contain changed data, does nothing.
238 @param aKeepDirty if ETrue, the "dirty" flag isn't reset after page flushing.
240 void CFatCachePageBase::FlushL(TBool aKeepDirty)
247 __PRINT1(_L("#-CFatCachePageBase::FlushL() Invalid page! FAT idx:%d"), iStartIndexInFAT);
249 User::Leave(KErrCorrupt);
253 //__PRINT1(_L("#-CFatCachePageBase::FlushL() FAT idx:%d"), iStartIndexInFAT);
255 //-- write dirty FAT sectors to the media one by one.
256 //-- merging adjacent dirty subsectors into larger clusters and writing them at once looks like a good idea, but
257 //-- in reality it showed FAT performance degradation, at least on MMC/SD media.
259 const TInt MaxSectors = iCache.SectorsInPage();
261 for(TInt i=0; i<MaxSectors; ++i)
269 //-- All data flushed; mark page as clean if it isn't required not to do.
276 //#################################################################################################################################
277 // CFat16FixedCache implementation
278 // Fixed cache (caches all FAT16) but organised as an array of pages
279 //#################################################################################################################################
281 CFat16FixedCache::CFat16FixedCache()
282 :CFatPagedCacheBase(),iPages(1) //-- array granularity is 1
286 //-----------------------------------------------------------------------------
288 FAT16 fixed cache factory function.
289 @param aOwner pointer to the owning FAT mount
290 @param aFatSize size of the FAT table in bytes
291 @param aRdGranularityLog2 Log2(read granularity)
292 @param aWrGranularityLog2 Log2(write granularity)
294 @return pointer to the constructed object.
296 CFat16FixedCache* CFat16FixedCache::NewL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
298 __PRINT(_L("#-CFat16FixedCache::NewL()"));
300 CFat16FixedCache* pSelf = NULL;
301 pSelf = new (ELeave) CFat16FixedCache;
303 CleanupStack::PushL(pSelf);
304 pSelf->InitialiseL(aOwner, aFatSize, aRdGranularityLog2, aWrGranularityLog2);
310 //-----------------------------------------------------------------------------
312 FAT16 fixed cache initialisation.
313 @param aOwner pointer to the owning FAT mount
314 @param aFatSize size of the FAT table in bytes
315 @param aRdGranularityLog2 Log2(read granularity)
316 @param aWrGranularityLog2 Log2(write granularity)
318 void CFat16FixedCache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
320 const TUint32 ReadGranularity = Pow2(aRdGranularityLog2);
321 const TUint32 WriteGranularity = Pow2(aWrGranularityLog2);
323 __PRINT3(_L("#-CFat16FixedCache::InitialiseL FatSz:%u, RdGr:%d, WrGr:%d"),aFatSize, ReadGranularity, WriteGranularity);
324 (void)ReadGranularity;
325 (void)WriteGranularity;
327 TBool bParamsValid = (aRdGranularityLog2 >= aWrGranularityLog2) && (aWrGranularityLog2 >= KDefSectorSzLog2);
328 __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity));
330 CFatPagedCacheBase::InitialiseL(aOwner);
332 ASSERT(FatType() == EFat16);
334 //-- See FAT specs, and round up the limit to the FAT sector boundary
335 const TUint32 KMaxFat16Size = ((65524*sizeof(TFat16Entry)+FAT_SectorSz()-1) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2();
336 const TUint32 KMinFat16Size = 4086*sizeof(TFat16Entry); //-- See FAT specs
338 bParamsValid = aFatSize >= KMinFat16Size && aFatSize <= KMaxFat16Size;
339 __ASSERT_ALWAYS(bParamsValid, User::Leave(KErrCorrupt));
341 //-- cache page size is (2^aRdGranularityLog2) bytes and consists of 2^(aRdGranularityLog2-aWrGranularity) sectors.
342 iPageSizeLog2 = aRdGranularityLog2;
343 iSectorSizeLog2 = aWrGranularityLog2; //-- Log2(number of sectors in cache page)
345 __ASSERT_ALWAYS(SectorsInPage() < KMaxSectorsInPage, Fault(EFatCache_BadGranularity));
347 const TUint numPages = (aFatSize+(PageSize()-1)) >> iPageSizeLog2;
348 __PRINT1(_L("#-CFat16FixedCache Num Pages:%d"), numPages);
350 //-- prepare pointer array for pages. NULL entry in the array means that the page at this index isn't allocated.
351 for(TUint i=0; i<numPages; ++i)
357 //-----------------------------------------------------------------------------
359 Close the cache and deallocate its memory.
360 @param aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.
362 void CFat16FixedCache::Close(TBool aDiscardDirtyData)
364 __PRINT1(_L("#-CFat16FixedCache::Close(%d)"), aDiscardDirtyData);
366 TInt cnt = iPages.Count();
369 CFat16FixedCachePage *pPage = iPages[cnt];
370 if(pPage && (pPage->IsDirty()))
371 {//-- trying to destroy the cache that has dirty pages
372 __PRINT1(_L("#-CFat16FixedCache::Close() The page is dirty! Start idx:%d"), pPage->StartFatIndex());
373 if(!aDiscardDirtyData)
375 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
377 //-- ignore this fact if requested.
387 //-----------------------------------------------------------------------------
389 Read FAT entry from the cache.
391 @param aIndex FAT entry index to read
392 @return FAT entry value at the index "aIndex"
394 TUint32 CFat16FixedCache::ReadEntryL(TUint32 aIndex)
396 //__PRINT1(_L("#-CFat16FixedCache::ReadEntryL() FAT idx:%d"), aIndex);
397 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() >> KFat16EntrySzLog2));
399 //-- calculate page index in the array
400 const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
401 CFat16FixedCachePage *pPage = iPages[pgIdx];
403 TUint32 entry = KMaxTUint;
406 {//-- page at this position isn't allocated yet
407 pPage = CFat16FixedCachePage::NewL(*this);
408 iPages[pgIdx] = pPage;
410 //-- read the page from media
411 entry = pPage->ReadFromMediaL(aIndex);
414 {//-- get cached entry from the page
415 TBool bRes = pPage->ReadCachedEntryL(aIndex, entry);
423 //-----------------------------------------------------------------------------
425 Write FAT entry to the cache.
426 Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
428 @param aIndex FAT entry index
429 @param aEntry FAT entry value
431 void CFat16FixedCache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
433 //__PRINT2(_L("#-CFat16FixedCache::WriteEntryL() FAT idx:%d, val:%d"), aIndex, aEntry);
435 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() >> KFat16EntrySzLog2));
439 //-- calculate page index in the array
440 const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
441 CFat16FixedCachePage *pPage = iPages[pgIdx];
444 {//-- page at this position isn't allocated yet
445 pPage = CFat16FixedCachePage::NewL(*this);
446 iPages[pgIdx] = pPage;
448 //-- read the page from media
449 pPage->ReadFromMediaL(aIndex);
452 //-- overwrite entry in cache
453 TBool bRes = pPage->WriteCachedEntryL(aIndex, aEntry);
459 A debug method that asserts that the cache is really clean
461 void CFat16FixedCache::AssertCacheReallyClean() const
464 for(TUint i=0; i<NumPages(); ++i)
466 CFat16FixedCachePage* pPage = iPages[i];
467 if(pPage && pPage->IsDirty())
469 __PRINT(_L("#-CFat16FixedCache::AssertCacheReallyClean()"));
477 //-----------------------------------------------------------------------------
479 Flushes all dirty data to the media.
481 void CFat16FixedCache::FlushL()
485 AssertCacheReallyClean();
490 //-- flush dirty data to all copies of FAT
491 for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
493 const TInt nPages = NumPages();
494 for(TInt i=0; i<nPages; ++i)
496 const TBool keepDirty = iCurrentFatNo < (NumFATs() - 1);
498 CFat16FixedCachePage* pPage = iPages[i];
500 pPage->FlushL(keepDirty);
505 iCurrentFatNo = KInvalidFatNo;
509 //-----------------------------------------------------------------------------
511 Invalidate whole cache. All pages will be marked as invalid and will be re-read from the media on first access to them.
512 @return always KErrNone
514 TInt CFat16FixedCache::Invalidate()
516 __PRINT(_L("#-CFat16FixedCache::Invalidate()"));
517 const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
519 //-- iterate through the array of pages marking invalidating every page
520 TInt cnt = iPages.Count();
523 CFat16FixedCachePage *pPage = iPages[cnt];
525 pPage->Invalidate(bIgnoreDirtyData);
534 //-----------------------------------------------------------------------------
536 Invalidate FAT cache pages that contain FAT entries from aStartIndex to (aStartIndex+aNumEntries)
537 These pages will be marked as invalid and will be re-read from the media on first access to them.
539 @param aStartIndex FAT start index of the region being invalidated
540 @param aNumEntries number of entries to invalidate
541 @return always KErrNone
543 TInt CFat16FixedCache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
545 __PRINT2(_L("#-CFat16FixedCache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
546 ASSERT(aStartIndex >= KFatFirstSearchCluster && aStartIndex < (FatSize() >> KFat16EntrySzLog2));
554 const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
555 const TUint startPgIdx = aStartIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
556 const TUint nPagesToInv = 1+(aNumEntries >> (PageSizeLog2()-KFat16EntrySzLog2));
559 //-- invalidate pages that contain [aStartIndex ... aStartIndex+aNumEntries] entries
560 for(i=0; i<nPagesToInv; ++i)
562 const TUint pageIdx = i+startPgIdx;
563 if(pageIdx >= NumPages())
566 CFat16FixedCachePage* pPage = iPages[pageIdx];
568 pPage->Invalidate(bIgnoreDirtyData);
573 //-- check if the cache still has dirty pages
574 for(i=0; i<NumPages(); ++i)
576 CFat16FixedCachePage* pPage = iPages[i];
577 if(pPage && pPage->IsDirty())
587 //#################################################################################################################################
588 // CFat16FixedCachePage implementation
589 // Page for the FAT16 fixed cache
590 //#################################################################################################################################
592 //-----------------------------------------------------------------------------
594 CFat16FixedCachePage::CFat16FixedCachePage(CFatPagedCacheBase& aCache)
595 :CFatCachePageBase(aCache)
597 ASSERT(IsPowerOf2(EntriesInPage()));
603 @param aCache reference to the owning cache.
604 @return pointer to the constructed object or NULL on error
606 CFat16FixedCachePage* CFat16FixedCachePage::NewL(CFatPagedCacheBase& aCache)
608 CFat16FixedCachePage* pSelf = NULL;
609 pSelf = new (ELeave) CFat16FixedCachePage(aCache);
611 CleanupStack::PushL(pSelf);
613 pSelf->iData.CreateMaxL(aCache.PageSize()); //-- allocate memory for the page
621 //-----------------------------------------------------------------------------
623 Read FAT16 entry from the cache.
625 1. If page's data are valid, just extracts data from the page buffer.
626 2. If page's data are invalid firstly reads data from the media and goto 1
628 @param aFatIndex entry's absolute FAT index (from the FAT start)
629 @param aResult on sucess there will be FAT16 entry value
630 @return ETrue, because FAT16 cache pages never get eviched.
632 TBool CFat16FixedCachePage::ReadCachedEntryL (TUint32 aFatIndex, TUint32& aResult)
635 {//-- read entry directly from page buffer, the cached data are valid
636 aResult = (*GetEntryPtr(aFatIndex)) & KFat16EntryMask;
639 {//-- aFatIndex belongs to this page, but the page is invalid and needs to be read from the media
640 //__PRINT(_L("#-CFat16FixedCachePage::ReadCachedEntry() The page is invalid, reading from the media"));
641 aResult = ReadFromMediaL(aFatIndex);
647 //-----------------------------------------------------------------------------
650 Writes FAT cache page sector to the media (to all copies of the FAT)
651 @param aSector sector number winthin this page
653 void CFat16FixedCachePage::DoWriteSectorL(TUint32 aSector)
655 //__PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorL() startSec:%d, cnt:%d"), aSector);
657 ASSERT(aSector < iCache.SectorsInPage());
661 if(iStartIndexInFAT == 0 && aSector == 0)
662 {//-- this is the very beginning of FAT16. We must skip FAT[0] & FAT[1] entries and do not write them to media.
663 offset = KFatFirstSearchCluster << KFat16EntrySzLog2;
666 const TUint8* pData = iData.Ptr()+offset+(aSector << iCache.SectorSizeLog2());
668 TUint32 dataLen = (1 << iCache.SectorSizeLog2()) - offset;
670 const TUint32 mediaPosStart = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2) + (aSector << iCache.SectorSizeLog2()) + offset;
671 const TUint32 mediaPosEnd = mediaPosStart + dataLen;
673 //-- check if we are going to write beyond FAT. It can happen if the write granularity is bigger that the sector size.
674 const TUint32 posFatEnd = iCache.FatStartPos() + iCache.FatSize();
675 if(mediaPosEnd > posFatEnd)
676 {//-- correct the leength of the data to write.
677 dataLen -= (mediaPosEnd-posFatEnd);
680 TPtrC8 ptrData(pData, dataLen); //-- source data descriptor
682 TInt nRes = iCache.WriteFatData(mediaPosStart, ptrData);
686 __PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorsL() failed! code:%d"), nRes);
692 //-----------------------------------------------------------------------------
694 Write FAT16 entry at aFatIndex to the cache. Note that the data are not written to the media, only to the cache page.
695 Corresponding page sector is marked as dirty and will be flushed on FlushL() call later.
697 1. If page's data are valid, copies data to the page buffer and marks sector as dirty.
698 2. If page's data are invalid, firstly reads data from the media and goto 1
700 @param aFatIndex entry's absolute FAT index (from the FAT start)
701 @param aFatEntry FAT16 entry value
702 @return ETrue because FAT16 cache pages never get eviched.
704 TBool CFat16FixedCachePage::WriteCachedEntryL(TUint32 aFatIndex, TUint32 aFatEntry)
707 ASSERT(IsEntryCached(aFatIndex));
710 {//-- we are trying to write data to the page that has invalid data. //-- read the data from the media first.
711 ReadFromMediaL(aFatIndex);
714 TFat16Entry* pEntry = GetEntryPtr(aFatIndex);
716 const TFat16Entry orgEntry = *pEntry;
717 *pEntry = (TFat16Entry)((orgEntry & ~KFat16EntryMask) | (aFatEntry & KFat16EntryMask));
719 //-- mark corresponding sector of the cache page as dirty
720 const TUint entryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
721 const TUint dirtySectorNum = entryIndexInPage >> (iCache.SectorSizeLog2() - KFat16EntrySzLog2);
723 ASSERT(dirtySectorNum < iCache.SectorsInPage());
725 iDirtySectors.SetBit(dirtySectorNum);
726 SetState(EDirty); //-- mark page as dirty.
731 //-----------------------------------------------------------------------------
734 Get a pointer to the FAT16 entry in the page buffer.
735 The page 's data shall be valid and the entry shall belong to this page.
737 @param aFatIndex absolute FAT index (from the FAT start) of the entry
738 @return pointer to the FAT16 entry in the page buffer.
740 TFat16Entry* CFat16FixedCachePage::GetEntryPtr(TUint32 aFatIndex) const
742 ASSERT(IsValid() && IsEntryCached(aFatIndex));
744 const TUint KEntryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
745 TFat16Entry* pEntry = ((TFat16Entry*)iData.Ptr()) + KEntryIndexInPage;
750 //-----------------------------------------------------------------------------
752 Read the FAT16 cache page from the media and returns required FAT16 entry.
754 @param aFatIndex entry's absolute FAT index (from the FAT start)
755 @return entry value at aFatIndex.
757 TUint32 CFat16FixedCachePage::ReadFromMediaL(TUint32 aFatIndex)
759 //__PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() FAT idx:%d"), aFatIndex);
760 const TUint KFat16EntriesInPageLog2 = iCache.PageSizeLog2()-KFat16EntrySzLog2; //-- number of FAT16 entries in page is always a power of 2
762 //-- find out index in FAT this page starts from
763 iStartIndexInFAT = (aFatIndex >> KFat16EntriesInPageLog2) << KFat16EntriesInPageLog2;
764 SetState(EInvalid); //-- mark the page as invalid just in case if the read fails.
766 //-- read page from the media
767 const TUint32 pageStartPos = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2);
769 TInt nRes = iCache.ReadFatData(pageStartPos, iCache.PageSize(), iData);
772 __PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() failed! code:%d"), nRes);
776 SetClean(); //-- mark this page as clean
778 const TFat16Entry entry = (TFat16Entry)((*GetEntryPtr(aFatIndex)) & KFat16EntryMask);
784 //-----------------------------------------------------------------------------
786 //#################################################################################################################################
787 // CFat12Cache implementation
788 // FAT12 non-paged fixed cache. This cache consists from only 1 page, logically divided up to 32 sectors (write granularity unit)
789 //#################################################################################################################################
791 CFat12Cache::CFat12Cache()
796 //-----------------------------------------------------------------------------
798 FAT12 fixed cache factory function.
799 @param aOwner pointer to the owning FAT mount
800 @param aFatSize size of the FAT table in bytes
802 @return pointer to the constructed object.
804 CFat12Cache* CFat12Cache::NewL(CFatMountCB* aOwner, TUint32 aFatSize)
806 __PRINT(_L("#-CFat12Cache::NewL()"));
807 CFat12Cache* pSelf = NULL;
808 pSelf = new (ELeave) CFat12Cache;
810 CleanupStack::PushL(pSelf);
811 pSelf->InitialiseL(aOwner, aFatSize);
817 //-----------------------------------------------------------------------------
819 FAT16 fixed cache initialisation.
820 @param aOwner pointer to the owning FAT mount
821 @param aFatSize size of the FAT table in bytes
823 void CFat12Cache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize)
825 __PRINT1(_L("#-CFat12Cache::InitialiseL FatSz:%u"),aFatSize);
827 CFatCacheBase::InitialiseL(aOwner);
828 ASSERT(FatType() == EFat12);
830 //-- see FAT specs; 4084 is a max. number of clusters, fat12 entry is 1.5 bytes; but we need to round up FAT12 size to the sector size
831 const TUint32 KMaxFat12Size = ( ((TUint32)(4084*1.5+FAT_SectorSz()-1)) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2();
832 const TUint32 KMinFat12Size = FAT_SectorSz(); //-- 1 FAT sector
833 __ASSERT_ALWAYS(aFatSize >= KMinFat12Size && aFatSize <= KMaxFat12Size, User::Leave(KErrCorrupt));
837 //-- as soon as FAT12 max size is 4084 entries or 6126 bytes, the cache is contiguous and divided
838 //-- to logical sectors (write granularity).
840 //-- calculate number write cache sector in the cache
841 iSectorsInCache = (aFatSize + (FAT_SectorSz()-1)) >> FAT_SectorSzLog2();
842 __ASSERT_ALWAYS(NumSectors() <= KMaxSectorsInCache, Fault(EFatCache_BadGranularity));
844 //-- round up cache size to write granularity (sector size)
845 const TUint32 cacheSize = NumSectors() << FAT_SectorSzLog2();
847 //-- create buffer for the whole FAT12
848 iData.CreateMaxL(cacheSize);
850 //-- this will read whole FAT into the cache
851 User::LeaveIfError(Invalidate());
854 //-----------------------------------------------------------------------------
856 Close the cache and deallocate its memory.
857 @param aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.
859 void CFat12Cache::Close(TBool aDiscardDirtyData)
861 __PRINT1(_L("#-CFat12Cache::Close(%d)"), aDiscardDirtyData);
863 for(TUint32 i=0; i<NumSectors(); ++i)
866 {//-- trying to destroy the cache that has dirty sectors
867 __PRINT1(_L("#-CFat12Cache::Close() The cache is dirty! cache sector:%d"), i);
868 if(!aDiscardDirtyData)
870 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
872 //-- ignore this fact if requested.
880 //-----------------------------------------------------------------------------
882 Read FAT entry from the cache.
884 @param aIndex FAT entry index to read
885 @return FAT entry value at the index "aIndex"
887 TUint32 CFat12Cache::ReadEntryL(TUint32 aIndex)
889 //__PRINT1(_L("#-CFat12Cache::ReadEntryL() FAT idx:%d"), aIndex);
890 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
897 const TUint32 byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
898 Mem::Copy(&entry, iData.Ptr()+byteIdx, 2);
903 const TUint32 byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
904 Mem::Copy(&entry, iData.Ptr()+byteIdx, 2);
907 entry &= KFat12EntryMask;
912 //-----------------------------------------------------------------------------
914 Write FAT entry to the cache.
915 Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
917 @param aIndex FAT entry index
918 @param aEntry FAT entry value
920 void CFat12Cache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
922 //__PRINT2(_L("#-CFat12Cache::WriteEntryL() FAT idx:%d, entry:%u"), aIndex, aEntry);
923 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
925 aEntry &= KFat12EntryMask;
933 byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
934 tmp = (TUint8)(iData[byteIdx] & 0x0F); //-- we modifying a higher nibble
935 tmp |= (TUint8) ((aEntry & 0x0F)<<4);
936 iData[byteIdx] = tmp;
938 iData[byteIdx+1] = (TUint8)(aEntry >> 4);
942 byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
943 iData[byteIdx] = (TUint8)aEntry;
945 const TUint32 nextIdx = byteIdx+1;
946 tmp = (TUint8)(iData[nextIdx] & 0xF0); //-- we modifying a lower nibble
947 tmp |= (TUint8)((aEntry >> 8) & 0x0F);
948 iData[nextIdx] = tmp;
952 //-- mark changed sectors dirty. We modified 2 bytes at [byteIdx] and [byteIdx+1]
953 iDirtySectors.SetBit(byteIdx >> FAT_SectorSzLog2());
954 iDirtySectors.SetBit((byteIdx+1) >> FAT_SectorSzLog2());
959 //-----------------------------------------------------------------------------
961 A debug method that asserts that the cache is really clean
963 void CFat12Cache::AssertCacheReallyClean() const
966 if(iDirtySectors.HasBitsSet())
968 __PRINT(_L("#-CFat12Cache::AssertCacheReallyClean()"));
975 //-----------------------------------------------------------------------------
977 Flushes all dirty data to the media.
978 Walks through all sectors in this cache and flushes dirty ones.
980 void CFat12Cache::FlushL()
984 AssertCacheReallyClean();
988 //-- write all dirty sectors to the media (into all copies of FAT)
989 for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
991 for(TUint secNo=0; secNo<NumSectors(); ++secNo)
993 if(iDirtySectors[secNo])
994 {//-- this sector is dirty, write it to the media
998 {//-- this is a first sector in FAT. We must skip FAT[0] & FAT[1] entries and do not write them to the media.
999 offset = 3; //-- 2 FAT12 entries
1002 const TUint32 secPos = secNo << FAT_SectorSzLog2(); //-- relative sector position in FAT
1003 const TUint8* pData = iData.Ptr()+offset+secPos; //-- pointer to the data in cache buffer
1004 const TUint32 len = FAT_SectorSz() - offset;
1005 TPtrC8 ptrData(pData, len); //-- source data descriptor
1006 const TUint32 mediaPos = FatStartPos() + secPos + offset;
1008 TInt nRes = WriteFatData(mediaPos, ptrData);
1010 if(nRes != KErrNone)
1012 __PRINT1(_L("#-CFat12Cache::FlushL() failed! code:%d"), nRes);
1016 }//if(iDirtySectors[secNo])
1021 iCurrentFatNo = KInvalidFatNo;
1023 //-- mark the cache as clean
1024 iDirtySectors.Clear();
1029 //-----------------------------------------------------------------------------
1031 Invalidates whole cache. Because FAT12 is tiny, just re-reads data from the media to the cache
1032 @return Media read result code.
1034 TInt CFat12Cache::Invalidate()
1036 __PRINT(_L("#-CFat12Cache::Invalidate()"));
1037 CheckInvalidatingDirtyCache();
1039 //-- read whole cache from the media
1040 const TUint32 posStart = FatStartPos();
1041 const TUint32 len = NumSectors() << FAT_SectorSzLog2();
1043 TInt nRes = ReadFatData(posStart, len, iData);
1044 if(nRes != KErrNone)
1047 //-- mark the cache as clean
1049 iDirtySectors.Clear();
1054 //-----------------------------------------------------------------------------
1056 Invalidate wholes cache. Because FAT12 is tiny, just re-reads data from the media to the cache
1057 @param aStartIndex ignored
1058 @param aNumEntries ignored
1059 @return Media read result code.
1061 TInt CFat12Cache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
1063 __PRINT2(_L("#-CFat12Cache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
1064 ASSERT(aStartIndex >= KFatFirstSearchCluster && aStartIndex < (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
1068 //-- just re-read all FAT12, it is just 6K max and isn't worth calculating invalid sectors
1069 return Invalidate();