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 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
25 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
29 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
30 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
33 #include "sl_fatcache.h"
36 //#################################################################################################################################
37 // CFatCacheBase implementation
38 // Base class for all types of FAT cache
39 //#################################################################################################################################
41 CFatCacheBase::~CFatCacheBase()
43 Close(ETrue); //-- deallocate cache's memory discarding any dirty data
46 CFatCacheBase::CFatCacheBase()
48 iCurrentFatNo = KInvalidFatNo;
54 FAT cache initialisation.
56 @param aOwner pointer to the owning FAT mount
58 void CFatCacheBase::InitialiseL(CFatMountCB* aOwner)
62 Close(ETrue); //-- deallocate cache's memory discarding any dirty data
64 //-- populate parameters from the owning mount
65 iFatType = aOwner->FatType();
66 __ASSERT_ALWAYS((iFatType == EFat12 || iFatType == EFat16 || iFatType == EFat32), User::Leave(KErrCorrupt));
68 ipDrive = &aOwner->DriveInterface();
69 iFatStartPos = aOwner->FirstFatSector() << aOwner->SectorSizeLog2();
70 iFatSize = aOwner->FatSizeInBytes();
71 iNumFATs = (TUint16)aOwner->NumberOfFats();
72 iFatSecSzLog2 = (TUint16)aOwner->SectorSizeLog2();
73 iFatClustSzLog2 = (TUint16)aOwner->ClusterSizeLog2();
75 __ASSERT_ALWAYS(iNumFATs >=1, User::Leave(KErrCorrupt));
77 __PRINT3(_L("#-CFatCacheBase::InitialiseL() FatStart:%u, FatSz:%d, drv:%d"),iFatStartPos, iFatSize, aOwner->DriveNumber());
80 //-----------------------------------------------------------------------------
82 This method shall be called to check if we are allowed to invalidate dirty cache, i.e. discard non-flushed data.
83 The behaviour is hardcoded (see KAllowInvalidateDirtyCache constant)
85 @return ETrue if invalidating dirty cache is allowed. Otherwise panics the current thread
87 TBool CFatCacheBase::CheckInvalidatingDirtyCache() const
90 //-- If not EFalse, invalidating dirty cache (pages) is allowed. This shall be OK, because
91 //-- invalidating the cache is required only after direct media writes to the FAT by RawWrite, which can corrupt it anyway.
92 TBool KAllowInvalidateDirtyCache = ETrue;
95 return KAllowInvalidateDirtyCache;
97 __PRINT(_L("#-CFatCacheBase::Invalidating dirty cache !"));
99 if(!KAllowInvalidateDirtyCache)
101 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
104 return KAllowInvalidateDirtyCache;
107 //-----------------------------------------------------------------------------
110 Read portion of raw data from 1st FAT copy.
112 @param aPos media position in the _FIRST_ FAT to start reading with
113 @param aLen number of bytes to read
114 @param aData data descriptor
116 @return standard error code.
118 TInt CFatCacheBase::ReadFatData(TUint32 aPos, TUint32 aLen, TDes8& aData) const
120 //__PRINT2(_L("#-CFatCacheNew::ReadFatData() pos:%u, Len:%d"), aPos, aLen);
122 //-- this method can pick up data corresponding to invalid FAT entries, like FAT[0], FAT[1] and
123 //-- the last portion beyond FAT because of read granularity. This isn't a problem, because the data there
124 //-- won't be written on disk.
125 ASSERT(aPos >= FatStartPos());
127 return ipDrive->ReadNonCritical(aPos, aLen, aData);
130 //-----------------------------------------------------------------------------
133 Writes data to the FAT table, which number is set in iCurrentFatNo member variable.
134 @param aPos data media position in the _FIRST_ FAT copy
135 @param aData data descriptor
136 @return standard error code.
138 TInt CFatCacheBase::WriteFatData(TUint32 aPos, const TDesC8& aData) const
140 //__PRINT3(_L("#-CFatCacheBase::WriteFatData() pos:%u, Len:%d, FAT:%d"), aPos, aData.Length(), iCurrentFatNo);
143 //-- 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
144 //-- calculate correct data position in FAT
145 TInt reserved_Entries_Offset=0;
148 case EFat32: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat32Entry); break; //-- FAT32
149 case EFat16: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat16Entry); break; //-- FAT16
150 case EFat12: reserved_Entries_Offset = 3; break; //-- FAT12
151 default: ASSERT(0); break;
153 ASSERT(aPos >= FatStartPos()+reserved_Entries_Offset);
154 ASSERT((aPos+aData.Length()) <= FatStartPos()+FatSize());
155 ASSERT(iCurrentFatNo < iNumFATs);
158 //-- goto the required FAT copy. iCurrentFatNo shall contain FAT number we are writing to.
159 aPos+=iCurrentFatNo*FatSize();
161 return ipDrive->WriteCritical(aPos, aData);
164 //-----------------------------------------------------------------------------
166 get a pointer to the CFatBitCache interface.
167 @return NULL because it is not present here
169 CFatBitCache* CFatCacheBase::BitCacheInterface()
175 //#################################################################################################################################
176 // CFatPagedCacheBase implementation
177 // Base class for all paged FAT caches
178 //#################################################################################################################################
180 CFatPagedCacheBase::CFatPagedCacheBase()
186 //#################################################################################################################################
187 // CFatCachePageBase implementation
188 // Base class for FAT cache pages (FAT16 fixed and FAT32 LRU)
189 //#################################################################################################################################
191 CFatCachePageBase::CFatCachePageBase(CFatPagedCacheBase& aCache)
194 ASSERT(IsPowerOf2(aCache.PageSize()));
195 iStartIndexInFAT = KMaxTUint;
197 //-- calculate number of FAT entries in the page, it depends on FAT type
198 switch(aCache.FatType())
201 iFatEntriesInPage = PageSize() >> KFat32EntrySzLog2;
205 iFatEntriesInPage = PageSize() >> KFat16EntrySzLog2;
210 Fault(EFatCache_BadFatType);
218 CFatCachePageBase::~CFatCachePageBase()
223 //-----------------------------------------------------------------------------
225 Mark the page as "invalid". I.e containing inalid data.
226 On the first read/write access to such page it will be re-read from the media
228 @param aIgnoreDirtyData if ETrue, it is allowed to ignore the fact that the page contains dirty (not flushed) data.
230 void CFatCachePageBase::Invalidate(TBool aIgnoreDirtyData /*= EFalse*/)
232 if(!aIgnoreDirtyData && IsDirty())
234 __PRINT1(_L("#-CFatCachePageBase::Invalidate() dirty page! FAT idx:%d"), iStartIndexInFAT);
235 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
238 iDirtySectors.Clear(); //-- clear dirty sectors bitmap
242 //-----------------------------------------------------------------------------
244 Flush all dirty page sectors to the media and mark the page as "clean" if required.
245 If the page is "clean" i.e doesn't contain changed data, does nothing.
247 @param aKeepDirty if ETrue, the "dirty" flag isn't reset after page flushing.
249 void CFatCachePageBase::FlushL(TBool aKeepDirty)
256 __PRINT1(_L("#-CFatCachePageBase::FlushL() Invalid page! FAT idx:%d"), iStartIndexInFAT);
258 User::Leave(KErrCorrupt);
262 //__PRINT1(_L("#-CFatCachePageBase::FlushL() FAT idx:%d"), iStartIndexInFAT);
264 //-- write dirty FAT sectors to the media one by one.
265 //-- merging adjacent dirty subsectors into larger clusters and writing them at once looks like a good idea, but
266 //-- in reality it showed FAT performance degradation, at least on MMC/SD media.
268 const TInt MaxSectors = iCache.SectorsInPage();
270 for(TInt i=0; i<MaxSectors; ++i)
278 //-- All data flushed; mark page as clean if it isn't required not to do.
285 //#################################################################################################################################
286 // CFat16FixedCache implementation
287 // Fixed cache (caches all FAT16) but organised as an array of pages
288 //#################################################################################################################################
290 CFat16FixedCache::CFat16FixedCache()
291 :CFatPagedCacheBase(),iPages(1) //-- array granularity is 1
295 //-----------------------------------------------------------------------------
297 FAT16 fixed cache factory function.
298 @param aOwner pointer to the owning FAT mount
299 @param aFatSize size of the FAT table in bytes
300 @param aRdGranularityLog2 Log2(read granularity)
301 @param aWrGranularityLog2 Log2(write granularity)
303 @return pointer to the constructed object.
305 CFat16FixedCache* CFat16FixedCache::NewL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
307 __PRINT(_L("#-CFat16FixedCache::NewL()"));
309 CFat16FixedCache* pSelf = NULL;
310 pSelf = new (ELeave) CFat16FixedCache;
312 CleanupStack::PushL(pSelf);
313 pSelf->InitialiseL(aOwner, aFatSize, aRdGranularityLog2, aWrGranularityLog2);
319 //-----------------------------------------------------------------------------
321 FAT16 fixed cache initialisation.
322 @param aOwner pointer to the owning FAT mount
323 @param aFatSize size of the FAT table in bytes
324 @param aRdGranularityLog2 Log2(read granularity)
325 @param aWrGranularityLog2 Log2(write granularity)
327 void CFat16FixedCache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
329 const TUint32 ReadGranularity = Pow2(aRdGranularityLog2);
330 const TUint32 WriteGranularity = Pow2(aWrGranularityLog2);
332 __PRINT3(_L("#-CFat16FixedCache::InitialiseL FatSz:%u, RdGr:%d, WrGr:%d"),aFatSize, ReadGranularity, WriteGranularity);
333 (void)ReadGranularity;
334 (void)WriteGranularity;
336 TBool bParamsValid = (aRdGranularityLog2 >= aWrGranularityLog2) && (aWrGranularityLog2 >= KDefSectorSzLog2);
337 __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity));
339 CFatPagedCacheBase::InitialiseL(aOwner);
341 ASSERT(FatType() == EFat16);
343 //-- See FAT specs, and round up the limit to the FAT sector boundary
344 const TUint32 KMaxFat16Size = ((65524*sizeof(TFat16Entry)+FAT_SectorSz()-1) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2();
345 const TUint32 KMinFat16Size = 4086*sizeof(TFat16Entry); //-- See FAT specs
347 bParamsValid = aFatSize >= KMinFat16Size && aFatSize <= KMaxFat16Size;
348 __ASSERT_ALWAYS(bParamsValid, User::Leave(KErrCorrupt));
350 //-- cache page size is (2^aRdGranularityLog2) bytes and consists of 2^(aRdGranularityLog2-aWrGranularity) sectors.
351 iPageSizeLog2 = aRdGranularityLog2;
352 iSectorSizeLog2 = aWrGranularityLog2; //-- Log2(number of sectors in cache page)
354 __ASSERT_ALWAYS(SectorsInPage() < KMaxSectorsInPage, Fault(EFatCache_BadGranularity));
356 const TUint numPages = (aFatSize+(PageSize()-1)) >> iPageSizeLog2;
357 __PRINT1(_L("#-CFat16FixedCache Num Pages:%d"), numPages);
359 //-- prepare pointer array for pages. NULL entry in the array means that the page at this index isn't allocated.
360 for(TUint i=0; i<numPages; ++i)
366 //-----------------------------------------------------------------------------
368 Close the cache and deallocate its memory.
369 @param aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.
371 void CFat16FixedCache::Close(TBool aDiscardDirtyData)
373 __PRINT1(_L("#-CFat16FixedCache::Close(%d)"), aDiscardDirtyData);
375 TInt cnt = iPages.Count();
378 CFat16FixedCachePage *pPage = iPages[cnt];
379 if(pPage && (pPage->IsDirty()))
380 {//-- trying to destroy the cache that has dirty pages
381 __PRINT1(_L("#-CFat16FixedCache::Close() The page is dirty! Start idx:%d"), pPage->StartFatIndex());
382 if(!aDiscardDirtyData)
384 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
386 //-- ignore this fact if requested.
396 //-----------------------------------------------------------------------------
398 Read FAT entry from the cache.
400 @param aIndex FAT entry index to read
401 @return FAT entry value at the index "aIndex"
403 TUint32 CFat16FixedCache::ReadEntryL(TUint32 aIndex)
405 //__PRINT1(_L("#-CFat16FixedCache::ReadEntryL() FAT idx:%d"), aIndex);
406 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() >> KFat16EntrySzLog2));
408 //-- calculate page index in the array
409 const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
410 CFat16FixedCachePage *pPage = iPages[pgIdx];
412 TUint32 entry = KMaxTUint;
415 {//-- page at this position isn't allocated yet
416 pPage = CFat16FixedCachePage::NewL(*this);
417 iPages[pgIdx] = pPage;
419 //-- read the page from media
420 entry = pPage->ReadFromMediaL(aIndex);
423 {//-- get cached entry from the page
424 TBool bRes = pPage->ReadCachedEntryL(aIndex, entry);
432 //-----------------------------------------------------------------------------
434 Write FAT entry to the cache.
435 Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
437 @param aIndex FAT entry index
438 @param aEntry FAT entry value
440 void CFat16FixedCache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
442 //__PRINT2(_L("#-CFat16FixedCache::WriteEntryL() FAT idx:%d, val:%d"), aIndex, aEntry);
444 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() >> KFat16EntrySzLog2));
448 //-- calculate page index in the array
449 const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
450 CFat16FixedCachePage *pPage = iPages[pgIdx];
453 {//-- page at this position isn't allocated yet
454 pPage = CFat16FixedCachePage::NewL(*this);
455 iPages[pgIdx] = pPage;
457 //-- read the page from media
458 pPage->ReadFromMediaL(aIndex);
461 //-- overwrite entry in cache
462 TBool bRes = pPage->WriteCachedEntryL(aIndex, aEntry);
468 A debug method that asserts that the cache is really clean
470 void CFat16FixedCache::AssertCacheReallyClean() const
473 for(TUint i=0; i<NumPages(); ++i)
475 CFat16FixedCachePage* pPage = iPages[i];
476 if(pPage && pPage->IsDirty())
478 __PRINT(_L("#-CFat16FixedCache::AssertCacheReallyClean()"));
486 //-----------------------------------------------------------------------------
488 Flushes all dirty data to the media.
490 void CFat16FixedCache::FlushL()
494 AssertCacheReallyClean();
499 //-- flush dirty data to all copies of FAT
500 for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
502 const TInt nPages = NumPages();
503 for(TInt i=0; i<nPages; ++i)
505 const TBool keepDirty = iCurrentFatNo < (NumFATs() - 1);
507 CFat16FixedCachePage* pPage = iPages[i];
509 pPage->FlushL(keepDirty);
514 iCurrentFatNo = KInvalidFatNo;
518 //-----------------------------------------------------------------------------
520 Invalidate whole cache. All pages will be marked as invalid and will be re-read from the media on first access to them.
521 @return always KErrNone
523 TInt CFat16FixedCache::Invalidate()
525 __PRINT(_L("#-CFat16FixedCache::Invalidate()"));
526 const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
528 //-- iterate through the array of pages marking invalidating every page
529 TInt cnt = iPages.Count();
532 CFat16FixedCachePage *pPage = iPages[cnt];
534 pPage->Invalidate(bIgnoreDirtyData);
543 //-----------------------------------------------------------------------------
545 Invalidate FAT cache pages that contain FAT entries from aStartIndex to (aStartIndex+aNumEntries)
546 These pages will be marked as invalid and will be re-read from the media on first access to them.
548 @param aStartIndex FAT start index of the region being invalidated
549 @param aNumEntries number of entries to invalidate
550 @return always KErrNone
552 TInt CFat16FixedCache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
554 __PRINT2(_L("#-CFat16FixedCache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
555 ASSERT(aStartIndex >= KFatFirstSearchCluster && aStartIndex < (FatSize() >> KFat16EntrySzLog2));
563 const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
564 const TUint startPgIdx = aStartIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
565 const TUint nPagesToInv = 1+(aNumEntries >> (PageSizeLog2()-KFat16EntrySzLog2));
568 //-- invalidate pages that contain [aStartIndex ... aStartIndex+aNumEntries] entries
569 for(i=0; i<nPagesToInv; ++i)
571 const TUint pageIdx = i+startPgIdx;
572 if(pageIdx >= NumPages())
575 CFat16FixedCachePage* pPage = iPages[pageIdx];
577 pPage->Invalidate(bIgnoreDirtyData);
582 //-- check if the cache still has dirty pages
583 for(i=0; i<NumPages(); ++i)
585 CFat16FixedCachePage* pPage = iPages[i];
586 if(pPage && pPage->IsDirty())
596 //#################################################################################################################################
597 // CFat16FixedCachePage implementation
598 // Page for the FAT16 fixed cache
599 //#################################################################################################################################
601 //-----------------------------------------------------------------------------
603 CFat16FixedCachePage::CFat16FixedCachePage(CFatPagedCacheBase& aCache)
604 :CFatCachePageBase(aCache)
606 ASSERT(IsPowerOf2(EntriesInPage()));
612 @param aCache reference to the owning cache.
613 @return pointer to the constructed object or NULL on error
615 CFat16FixedCachePage* CFat16FixedCachePage::NewL(CFatPagedCacheBase& aCache)
617 CFat16FixedCachePage* pSelf = NULL;
618 pSelf = new (ELeave) CFat16FixedCachePage(aCache);
620 CleanupStack::PushL(pSelf);
622 pSelf->iData.CreateMaxL(aCache.PageSize()); //-- allocate memory for the page
630 //-----------------------------------------------------------------------------
632 Read FAT16 entry from the cache.
634 1. If page's data are valid, just extracts data from the page buffer.
635 2. If page's data are invalid firstly reads data from the media and goto 1
637 @param aFatIndex entry's absolute FAT index (from the FAT start)
638 @param aResult on sucess there will be FAT16 entry value
639 @return ETrue, because FAT16 cache pages never get eviched.
641 TBool CFat16FixedCachePage::ReadCachedEntryL (TUint32 aFatIndex, TUint32& aResult)
644 {//-- read entry directly from page buffer, the cached data are valid
645 aResult = (*GetEntryPtr(aFatIndex)) & KFat16EntryMask;
648 {//-- aFatIndex belongs to this page, but the page is invalid and needs to be read from the media
649 //__PRINT(_L("#-CFat16FixedCachePage::ReadCachedEntry() The page is invalid, reading from the media"));
650 aResult = ReadFromMediaL(aFatIndex);
656 //-----------------------------------------------------------------------------
659 Writes FAT cache page sector to the media (to all copies of the FAT)
660 @param aSector sector number winthin this page
662 void CFat16FixedCachePage::DoWriteSectorL(TUint32 aSector)
664 //__PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorL() startSec:%d, cnt:%d"), aSector);
666 ASSERT(aSector < iCache.SectorsInPage());
670 if(iStartIndexInFAT == 0 && aSector == 0)
671 {//-- this is the very beginning of FAT16. We must skip FAT[0] & FAT[1] entries and do not write them to media.
672 offset = KFatFirstSearchCluster << KFat16EntrySzLog2;
675 const TUint8* pData = iData.Ptr()+offset+(aSector << iCache.SectorSizeLog2());
677 TUint32 dataLen = (1 << iCache.SectorSizeLog2()) - offset;
679 const TUint32 mediaPosStart = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2) + (aSector << iCache.SectorSizeLog2()) + offset;
680 const TUint32 mediaPosEnd = mediaPosStart + dataLen;
682 //-- check if we are going to write beyond FAT. It can happen if the write granularity is bigger that the sector size.
683 const TUint32 posFatEnd = iCache.FatStartPos() + iCache.FatSize();
684 if(mediaPosEnd > posFatEnd)
685 {//-- correct the leength of the data to write.
686 dataLen -= (mediaPosEnd-posFatEnd);
689 TPtrC8 ptrData(pData, dataLen); //-- source data descriptor
691 TInt nRes = iCache.WriteFatData(mediaPosStart, ptrData);
695 __PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorsL() failed! code:%d"), nRes);
701 //-----------------------------------------------------------------------------
703 Write FAT16 entry at aFatIndex to the cache. Note that the data are not written to the media, only to the cache page.
704 Corresponding page sector is marked as dirty and will be flushed on FlushL() call later.
706 1. If page's data are valid, copies data to the page buffer and marks sector as dirty.
707 2. If page's data are invalid, firstly reads data from the media and goto 1
709 @param aFatIndex entry's absolute FAT index (from the FAT start)
710 @param aFatEntry FAT16 entry value
711 @return ETrue because FAT16 cache pages never get eviched.
713 TBool CFat16FixedCachePage::WriteCachedEntryL(TUint32 aFatIndex, TUint32 aFatEntry)
716 ASSERT(IsEntryCached(aFatIndex));
719 {//-- we are trying to write data to the page that has invalid data. //-- read the data from the media first.
720 ReadFromMediaL(aFatIndex);
723 TFat16Entry* pEntry = GetEntryPtr(aFatIndex);
725 const TFat16Entry orgEntry = *pEntry;
726 *pEntry = (TFat16Entry)((orgEntry & ~KFat16EntryMask) | (aFatEntry & KFat16EntryMask));
728 //-- mark corresponding sector of the cache page as dirty
729 const TUint entryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
730 const TUint dirtySectorNum = entryIndexInPage >> (iCache.SectorSizeLog2() - KFat16EntrySzLog2);
732 ASSERT(dirtySectorNum < iCache.SectorsInPage());
734 iDirtySectors.SetBit(dirtySectorNum);
735 SetState(EDirty); //-- mark page as dirty.
740 //-----------------------------------------------------------------------------
743 Get a pointer to the FAT16 entry in the page buffer.
744 The page 's data shall be valid and the entry shall belong to this page.
746 @param aFatIndex absolute FAT index (from the FAT start) of the entry
747 @return pointer to the FAT16 entry in the page buffer.
749 TFat16Entry* CFat16FixedCachePage::GetEntryPtr(TUint32 aFatIndex) const
751 ASSERT(IsValid() && IsEntryCached(aFatIndex));
753 const TUint KEntryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
754 TFat16Entry* pEntry = ((TFat16Entry*)iData.Ptr()) + KEntryIndexInPage;
759 //-----------------------------------------------------------------------------
761 Read the FAT16 cache page from the media and returns required FAT16 entry.
763 @param aFatIndex entry's absolute FAT index (from the FAT start)
764 @return entry value at aFatIndex.
766 TUint32 CFat16FixedCachePage::ReadFromMediaL(TUint32 aFatIndex)
768 //__PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() FAT idx:%d"), aFatIndex);
769 const TUint KFat16EntriesInPageLog2 = iCache.PageSizeLog2()-KFat16EntrySzLog2; //-- number of FAT16 entries in page is always a power of 2
771 //-- find out index in FAT this page starts from
772 iStartIndexInFAT = (aFatIndex >> KFat16EntriesInPageLog2) << KFat16EntriesInPageLog2;
773 SetState(EInvalid); //-- mark the page as invalid just in case if the read fails.
775 //-- read page from the media
776 const TUint32 pageStartPos = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2);
778 TInt nRes = iCache.ReadFatData(pageStartPos, iCache.PageSize(), iData);
781 __PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() failed! code:%d"), nRes);
785 SetClean(); //-- mark this page as clean
787 const TFat16Entry entry = (TFat16Entry)((*GetEntryPtr(aFatIndex)) & KFat16EntryMask);
793 //-----------------------------------------------------------------------------
795 //#################################################################################################################################
796 // CFat12Cache implementation
797 // FAT12 non-paged fixed cache. This cache consists from only 1 page, logically divided up to 32 sectors (write granularity unit)
798 //#################################################################################################################################
800 CFat12Cache::CFat12Cache()
805 //-----------------------------------------------------------------------------
807 FAT12 fixed cache factory function.
808 @param aOwner pointer to the owning FAT mount
809 @param aFatSize size of the FAT table in bytes
811 @return pointer to the constructed object.
813 CFat12Cache* CFat12Cache::NewL(CFatMountCB* aOwner, TUint32 aFatSize)
815 __PRINT(_L("#-CFat12Cache::NewL()"));
816 CFat12Cache* pSelf = NULL;
817 pSelf = new (ELeave) CFat12Cache;
819 CleanupStack::PushL(pSelf);
820 pSelf->InitialiseL(aOwner, aFatSize);
826 //-----------------------------------------------------------------------------
828 FAT16 fixed cache initialisation.
829 @param aOwner pointer to the owning FAT mount
830 @param aFatSize size of the FAT table in bytes
832 void CFat12Cache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize)
834 __PRINT1(_L("#-CFat12Cache::InitialiseL FatSz:%u"),aFatSize);
836 CFatCacheBase::InitialiseL(aOwner);
837 ASSERT(FatType() == EFat12);
839 //-- 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
840 const TUint32 KMaxFat12Size = ( ((TUint32)(4084*1.5+FAT_SectorSz()-1)) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2();
841 const TUint32 KMinFat12Size = FAT_SectorSz(); //-- 1 FAT sector
842 __ASSERT_ALWAYS(aFatSize >= KMinFat12Size && aFatSize <= KMaxFat12Size, User::Leave(KErrCorrupt));
846 //-- as soon as FAT12 max size is 4084 entries or 6126 bytes, the cache is contiguous and divided
847 //-- to logical sectors (write granularity).
849 //-- calculate number write cache sector in the cache
850 iSectorsInCache = (aFatSize + (FAT_SectorSz()-1)) >> FAT_SectorSzLog2();
851 __ASSERT_ALWAYS(NumSectors() <= KMaxSectorsInCache, Fault(EFatCache_BadGranularity));
853 //-- round up cache size to write granularity (sector size)
854 const TUint32 cacheSize = NumSectors() << FAT_SectorSzLog2();
856 //-- create buffer for the whole FAT12
857 iData.CreateMaxL(cacheSize);
859 //-- this will read whole FAT into the cache
860 User::LeaveIfError(Invalidate());
863 //-----------------------------------------------------------------------------
865 Close the cache and deallocate its memory.
866 @param aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.
868 void CFat12Cache::Close(TBool aDiscardDirtyData)
870 __PRINT1(_L("#-CFat12Cache::Close(%d)"), aDiscardDirtyData);
872 for(TUint32 i=0; i<NumSectors(); ++i)
875 {//-- trying to destroy the cache that has dirty sectors
876 __PRINT1(_L("#-CFat12Cache::Close() The cache is dirty! cache sector:%d"), i);
877 if(!aDiscardDirtyData)
879 __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
881 //-- ignore this fact if requested.
889 //-----------------------------------------------------------------------------
891 Read FAT entry from the cache.
893 @param aIndex FAT entry index to read
894 @return FAT entry value at the index "aIndex"
896 TUint32 CFat12Cache::ReadEntryL(TUint32 aIndex)
898 //__PRINT1(_L("#-CFat12Cache::ReadEntryL() FAT idx:%d"), aIndex);
899 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
906 const TUint32 byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
907 Mem::Copy(&entry, iData.Ptr()+byteIdx, 2);
912 const TUint32 byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
913 Mem::Copy(&entry, iData.Ptr()+byteIdx, 2);
916 entry &= KFat12EntryMask;
921 //-----------------------------------------------------------------------------
923 Write FAT entry to the cache.
924 Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
926 @param aIndex FAT entry index
927 @param aEntry FAT entry value
929 void CFat12Cache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
931 //__PRINT2(_L("#-CFat12Cache::WriteEntryL() FAT idx:%d, entry:%u"), aIndex, aEntry);
932 ASSERT(aIndex >= KFatFirstSearchCluster && aIndex < (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
934 aEntry &= KFat12EntryMask;
942 byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
943 tmp = (TUint8)(iData[byteIdx] & 0x0F); //-- we modifying a higher nibble
944 tmp |= (TUint8) ((aEntry & 0x0F)<<4);
945 iData[byteIdx] = tmp;
947 iData[byteIdx+1] = (TUint8)(aEntry >> 4);
951 byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
952 iData[byteIdx] = (TUint8)aEntry;
954 const TUint32 nextIdx = byteIdx+1;
955 tmp = (TUint8)(iData[nextIdx] & 0xF0); //-- we modifying a lower nibble
956 tmp |= (TUint8)((aEntry >> 8) & 0x0F);
957 iData[nextIdx] = tmp;
961 //-- mark changed sectors dirty. We modified 2 bytes at [byteIdx] and [byteIdx+1]
962 iDirtySectors.SetBit(byteIdx >> FAT_SectorSzLog2());
963 iDirtySectors.SetBit((byteIdx+1) >> FAT_SectorSzLog2());
968 //-----------------------------------------------------------------------------
970 A debug method that asserts that the cache is really clean
972 void CFat12Cache::AssertCacheReallyClean() const
975 if(iDirtySectors.HasBitsSet())
977 __PRINT(_L("#-CFat12Cache::AssertCacheReallyClean()"));
984 //-----------------------------------------------------------------------------
986 Flushes all dirty data to the media.
987 Walks through all sectors in this cache and flushes dirty ones.
989 void CFat12Cache::FlushL()
993 AssertCacheReallyClean();
997 //-- write all dirty sectors to the media (into all copies of FAT)
998 for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
1000 for(TUint secNo=0; secNo<NumSectors(); ++secNo)
1002 if(iDirtySectors[secNo])
1003 {//-- this sector is dirty, write it to the media
1007 {//-- this is a first sector in FAT. We must skip FAT[0] & FAT[1] entries and do not write them to the media.
1008 offset = 3; //-- 2 FAT12 entries
1011 const TUint32 secPos = secNo << FAT_SectorSzLog2(); //-- relative sector position in FAT
1012 const TUint8* pData = iData.Ptr()+offset+secPos; //-- pointer to the data in cache buffer
1013 const TUint32 len = FAT_SectorSz() - offset;
1014 TPtrC8 ptrData(pData, len); //-- source data descriptor
1015 const TUint32 mediaPos = FatStartPos() + secPos + offset;
1017 TInt nRes = WriteFatData(mediaPos, ptrData);
1019 if(nRes != KErrNone)
1021 __PRINT1(_L("#-CFat12Cache::FlushL() failed! code:%d"), nRes);
1025 }//if(iDirtySectors[secNo])
1030 iCurrentFatNo = KInvalidFatNo;
1032 //-- mark the cache as clean
1033 iDirtySectors.Clear();
1038 //-----------------------------------------------------------------------------
1040 Invalidates whole cache. Because FAT12 is tiny, just re-reads data from the media to the cache
1041 @return Media read result code.
1043 TInt CFat12Cache::Invalidate()
1045 __PRINT(_L("#-CFat12Cache::Invalidate()"));
1046 CheckInvalidatingDirtyCache();
1048 //-- read whole cache from the media
1049 const TUint32 posStart = FatStartPos();
1050 const TUint32 len = NumSectors() << FAT_SectorSzLog2();
1052 TInt nRes = ReadFatData(posStart, len, iData);
1053 if(nRes != KErrNone)
1056 //-- mark the cache as clean
1058 iDirtySectors.Clear();
1063 //-----------------------------------------------------------------------------
1065 Invalidate wholes cache. Because FAT12 is tiny, just re-reads data from the media to the cache
1066 @param aStartIndex ignored
1067 @param aNumEntries ignored
1068 @return Media read result code.
1070 TInt CFat12Cache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
1072 __PRINT2(_L("#-CFat12Cache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
1073 ASSERT(aStartIndex >= KFatFirstSearchCluster && aStartIndex < (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
1077 //-- just re-read all FAT12, it is just 6K max and isn't worth calculating invalid sectors
1078 return Invalidate();