os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_fatcache.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// f32\sfat32\sl_fatcache.cpp
sl@0
    15
// FAT12 and FAT16 cache implementation
sl@0
    16
// 
sl@0
    17
//
sl@0
    18
sl@0
    19
/**
sl@0
    20
 @file
sl@0
    21
*/
sl@0
    22
sl@0
    23
#include "sl_std.h"
sl@0
    24
#include "sl_fatcache.h"
sl@0
    25
sl@0
    26
sl@0
    27
//#################################################################################################################################
sl@0
    28
//  CFatCacheBase implementation
sl@0
    29
//  Base class for all types of FAT cache
sl@0
    30
//#################################################################################################################################
sl@0
    31
sl@0
    32
CFatCacheBase::~CFatCacheBase()
sl@0
    33
    {
sl@0
    34
    Close(ETrue); //-- deallocate cache's memory discarding any dirty data
sl@0
    35
    }
sl@0
    36
sl@0
    37
CFatCacheBase::CFatCacheBase()
sl@0
    38
    {
sl@0
    39
    iCurrentFatNo = KInvalidFatNo;
sl@0
    40
    SetDirty(EFalse);
sl@0
    41
    }
sl@0
    42
sl@0
    43
sl@0
    44
/**
sl@0
    45
    FAT cache initialisation.
sl@0
    46
sl@0
    47
    @param  aOwner pointer to the owning FAT mount
sl@0
    48
*/
sl@0
    49
void CFatCacheBase::InitialiseL(CFatMountCB* aOwner)
sl@0
    50
    {
sl@0
    51
    ASSERT(aOwner);
sl@0
    52
    
sl@0
    53
    Close(ETrue); //-- deallocate cache's memory discarding any dirty data
sl@0
    54
    
sl@0
    55
    //-- populate parameters from the owning mount
sl@0
    56
    iFatType = aOwner->FatType();
sl@0
    57
    __ASSERT_ALWAYS((iFatType == EFat12 || iFatType == EFat16 || iFatType == EFat32), User::Leave(KErrCorrupt));  
sl@0
    58
    
sl@0
    59
    ipDrive = &aOwner->DriveInterface();
sl@0
    60
    iFatStartPos = aOwner->FirstFatSector() << aOwner->SectorSizeLog2(); 
sl@0
    61
    iFatSize = aOwner->FatSizeInBytes();
sl@0
    62
    iNumFATs = (TUint16)aOwner->NumberOfFats();
sl@0
    63
    iFatSecSzLog2   = (TUint16)aOwner->SectorSizeLog2(); 
sl@0
    64
    iFatClustSzLog2 = (TUint16)aOwner->ClusterSizeLog2();
sl@0
    65
sl@0
    66
    __ASSERT_ALWAYS(iNumFATs >=1, User::Leave(KErrCorrupt));
sl@0
    67
sl@0
    68
    __PRINT3(_L("#-CFatCacheBase::InitialiseL() FatStart:%u, FatSz:%d, drv:%d"),iFatStartPos, iFatSize, aOwner->DriveNumber());
sl@0
    69
    }
sl@0
    70
sl@0
    71
//-----------------------------------------------------------------------------
sl@0
    72
/**
sl@0
    73
    This method shall be called to check if we are allowed to invalidate dirty cache, i.e. discard non-flushed data.
sl@0
    74
    The behaviour is hardcoded (see KAllowInvalidateDirtyCache constant)
sl@0
    75
sl@0
    76
    @return ETrue if invalidating dirty cache is allowed. Otherwise panics the current thread
sl@0
    77
*/
sl@0
    78
TBool CFatCacheBase::CheckInvalidatingDirtyCache() const
sl@0
    79
    {
sl@0
    80
    
sl@0
    81
    //-- If not EFalse, invalidating dirty cache (pages) is allowed. This shall be OK, because
sl@0
    82
    //-- invalidating the cache is required only after direct media writes to the FAT by RawWrite, which can corrupt it anyway. 
sl@0
    83
    TBool KAllowInvalidateDirtyCache = ETrue;
sl@0
    84
    
sl@0
    85
    if(!IsDirty())
sl@0
    86
        return KAllowInvalidateDirtyCache;        
sl@0
    87
sl@0
    88
    __PRINT(_L("#-CFatCacheBase::Invalidating dirty cache !"));
sl@0
    89
    
sl@0
    90
    if(!KAllowInvalidateDirtyCache)
sl@0
    91
        {
sl@0
    92
        __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
sl@0
    93
        }
sl@0
    94
sl@0
    95
    return KAllowInvalidateDirtyCache;        
sl@0
    96
    }
sl@0
    97
sl@0
    98
//-----------------------------------------------------------------------------
sl@0
    99
sl@0
   100
/**
sl@0
   101
    Read portion of raw data from 1st FAT copy.
sl@0
   102
    
sl@0
   103
    @param  aPos   media position in the _FIRST_ FAT to start reading with
sl@0
   104
    @param  aLen   number of bytes to read
sl@0
   105
    @param  aData  data descriptor
sl@0
   106
sl@0
   107
    @return standard error code.
sl@0
   108
*/
sl@0
   109
TInt CFatCacheBase::ReadFatData(TUint32 aPos, TUint32 aLen, TDes8& aData) const
sl@0
   110
    {
sl@0
   111
    //__PRINT2(_L("#-CFatCacheNew::ReadFatData() pos:%u, Len:%d"), aPos, aLen);
sl@0
   112
sl@0
   113
    //-- this method can pick up data corresponding to invalid FAT entries, like FAT[0], FAT[1] and
sl@0
   114
    //-- the last portion beyond FAT because of read granularity. This isn't a problem, because the data there
sl@0
   115
    //-- won't be written on disk.
sl@0
   116
    ASSERT(aPos >= FatStartPos()); 
sl@0
   117
sl@0
   118
    return ipDrive->ReadNonCritical(aPos, aLen, aData);
sl@0
   119
    }
sl@0
   120
sl@0
   121
//-----------------------------------------------------------------------------
sl@0
   122
sl@0
   123
/** 
sl@0
   124
    Writes data to the FAT table, which number is set in iCurrentFatNo member variable. 
sl@0
   125
    @param  aPos   data media position in the _FIRST_ FAT copy
sl@0
   126
    @param  aData  data descriptor
sl@0
   127
    @return standard error code.
sl@0
   128
*/
sl@0
   129
TInt CFatCacheBase::WriteFatData(TUint32 aPos, const TDesC8& aData) const
sl@0
   130
    {
sl@0
   131
    //__PRINT3(_L("#-CFatCacheBase::WriteFatData() pos:%u, Len:%d, FAT:%d"), aPos, aData.Length(), iCurrentFatNo);
sl@0
   132
sl@0
   133
#ifdef _DEBUG    
sl@0
   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
sl@0
   135
    //-- calculate correct data position in FAT
sl@0
   136
    TInt reserved_Entries_Offset=0;
sl@0
   137
    switch(iFatType)
sl@0
   138
        {
sl@0
   139
        case EFat32: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat32Entry); break;  //-- FAT32  
sl@0
   140
        case EFat16: reserved_Entries_Offset = KFatFirstSearchCluster*sizeof(TFat16Entry); break;  //-- FAT16  
sl@0
   141
        case EFat12: reserved_Entries_Offset = 3;   break;                                         //-- FAT12
sl@0
   142
        default: ASSERT(0); break;
sl@0
   143
        }
sl@0
   144
    ASSERT(aPos >= FatStartPos()+reserved_Entries_Offset);
sl@0
   145
    ASSERT((aPos+aData.Length()) <= FatStartPos()+FatSize());
sl@0
   146
    ASSERT(iCurrentFatNo < iNumFATs);
sl@0
   147
#endif    
sl@0
   148
sl@0
   149
    //-- goto the required FAT copy. iCurrentFatNo shall contain FAT number we are writing to.
sl@0
   150
    aPos+=iCurrentFatNo*FatSize(); 
sl@0
   151
sl@0
   152
    return ipDrive->WriteCritical(aPos, aData);
sl@0
   153
    }
sl@0
   154
sl@0
   155
//-----------------------------------------------------------------------------
sl@0
   156
/** 
sl@0
   157
    get a pointer to the CFatBitCache interface. 
sl@0
   158
    @return NULL because it is not present here 
sl@0
   159
*/
sl@0
   160
CFatBitCache* CFatCacheBase::BitCacheInterface() 
sl@0
   161
    {
sl@0
   162
    return NULL;
sl@0
   163
    }
sl@0
   164
    
sl@0
   165
sl@0
   166
//#################################################################################################################################
sl@0
   167
//  CFatPagedCacheBase implementation
sl@0
   168
//  Base class for all paged FAT caches
sl@0
   169
//#################################################################################################################################
sl@0
   170
sl@0
   171
CFatPagedCacheBase::CFatPagedCacheBase()
sl@0
   172
               :CFatCacheBase() 
sl@0
   173
    {
sl@0
   174
    }
sl@0
   175
sl@0
   176
sl@0
   177
//#################################################################################################################################
sl@0
   178
//  CFatCachePageBase implementation
sl@0
   179
//  Base class for FAT cache pages (FAT16 fixed and FAT32 LRU)
sl@0
   180
//#################################################################################################################################
sl@0
   181
sl@0
   182
CFatCachePageBase::CFatCachePageBase(CFatPagedCacheBase& aCache)
sl@0
   183
                  :iCache(aCache)
sl@0
   184
    {
sl@0
   185
    ASSERT(IsPowerOf2(aCache.PageSize()));
sl@0
   186
    iStartIndexInFAT = KMaxTUint;
sl@0
   187
sl@0
   188
    //-- calculate number of FAT entries in the page, it depends on FAT type
sl@0
   189
    switch(aCache.FatType())
sl@0
   190
        {
sl@0
   191
        case EFat32:
sl@0
   192
            iFatEntriesInPage = PageSize() >> KFat32EntrySzLog2;
sl@0
   193
        break;
sl@0
   194
    
sl@0
   195
        case EFat16:
sl@0
   196
            iFatEntriesInPage = PageSize() >> KFat16EntrySzLog2;
sl@0
   197
        break;
sl@0
   198
    
sl@0
   199
        default:
sl@0
   200
            ASSERT(0);
sl@0
   201
            Fault(EFatCache_BadFatType);
sl@0
   202
        break;
sl@0
   203
sl@0
   204
        };
sl@0
   205
sl@0
   206
    SetState(EInvalid); 
sl@0
   207
    }
sl@0
   208
sl@0
   209
CFatCachePageBase::~CFatCachePageBase()
sl@0
   210
    {
sl@0
   211
    iData.Close();
sl@0
   212
    }
sl@0
   213
sl@0
   214
//-----------------------------------------------------------------------------
sl@0
   215
/**
sl@0
   216
    Mark the page as "invalid". I.e containing inalid data.
sl@0
   217
    On the first read/write access to such page it will be re-read from the media
sl@0
   218
sl@0
   219
    @param aIgnoreDirtyData if ETrue, it is allowed to ignore the fact that the page contains dirty (not flushed) data.
sl@0
   220
*/
sl@0
   221
void CFatCachePageBase::Invalidate(TBool aIgnoreDirtyData /*= EFalse*/)
sl@0
   222
    {
sl@0
   223
    if(!aIgnoreDirtyData && IsDirty())
sl@0
   224
        {
sl@0
   225
        __PRINT1(_L("#-CFatCachePageBase::Invalidate() dirty page! FAT idx:%d"), iStartIndexInFAT);
sl@0
   226
        __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
sl@0
   227
        }
sl@0
   228
sl@0
   229
    iDirtySectors.Clear(); //-- clear dirty sectors bitmap
sl@0
   230
    SetState(EInvalid);
sl@0
   231
    }
sl@0
   232
sl@0
   233
//-----------------------------------------------------------------------------
sl@0
   234
/**
sl@0
   235
    Flush all dirty page sectors to the media and mark the page as "clean" if required.
sl@0
   236
    If the page is "clean" i.e doesn't contain changed data, does nothing.
sl@0
   237
sl@0
   238
    @param  aKeepDirty  if ETrue, the "dirty" flag isn't reset after page flushing.
sl@0
   239
*/
sl@0
   240
void CFatCachePageBase::FlushL(TBool aKeepDirty)
sl@0
   241
    {
sl@0
   242
    if(!IsDirty())
sl@0
   243
        return;
sl@0
   244
sl@0
   245
    if(!IsValid())
sl@0
   246
        {
sl@0
   247
        __PRINT1(_L("#-CFatCachePageBase::FlushL() Invalid page! FAT idx:%d"), iStartIndexInFAT);
sl@0
   248
        ASSERT(0);
sl@0
   249
        User::Leave(KErrCorrupt);
sl@0
   250
        return;
sl@0
   251
        }
sl@0
   252
sl@0
   253
    //__PRINT1(_L("#-CFatCachePageBase::FlushL() FAT idx:%d"), iStartIndexInFAT);
sl@0
   254
sl@0
   255
    //-- write dirty FAT sectors  to the media one by one. 
sl@0
   256
    //-- merging adjacent dirty subsectors into larger clusters and writing them at once looks like a good idea, but
sl@0
   257
    //-- in reality it showed FAT performance degradation, at least on MMC/SD media.
sl@0
   258
    
sl@0
   259
    const TInt MaxSectors = iCache.SectorsInPage();
sl@0
   260
    
sl@0
   261
    for(TInt i=0; i<MaxSectors; ++i)
sl@0
   262
        {
sl@0
   263
        if(iDirtySectors[i])
sl@0
   264
            {
sl@0
   265
            DoWriteSectorL(i);
sl@0
   266
            }
sl@0
   267
        }
sl@0
   268
sl@0
   269
    //-- All data flushed; mark page as clean if it isn't required not to do.
sl@0
   270
    if(!aKeepDirty)
sl@0
   271
        SetClean(); 
sl@0
   272
sl@0
   273
    }
sl@0
   274
sl@0
   275
sl@0
   276
//#################################################################################################################################
sl@0
   277
//  CFat16FixedCache implementation
sl@0
   278
//  Fixed cache (caches all FAT16) but organised as an array of pages
sl@0
   279
//#################################################################################################################################
sl@0
   280
sl@0
   281
CFat16FixedCache::CFat16FixedCache()
sl@0
   282
                 :CFatPagedCacheBase(),iPages(1) //-- array granularity is 1
sl@0
   283
    {
sl@0
   284
    }
sl@0
   285
sl@0
   286
//-----------------------------------------------------------------------------
sl@0
   287
/**
sl@0
   288
    FAT16 fixed cache factory function.
sl@0
   289
    @param  aOwner              pointer to the owning FAT mount
sl@0
   290
    @param  aFatSize            size of the FAT table in bytes
sl@0
   291
    @param  aRdGranularityLog2  Log2(read granularity)
sl@0
   292
    @param  aWrGranularityLog2  Log2(write granularity)
sl@0
   293
sl@0
   294
    @return pointer to the constructed object.
sl@0
   295
*/
sl@0
   296
CFat16FixedCache* CFat16FixedCache::NewL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
sl@0
   297
    {
sl@0
   298
    __PRINT(_L("#-CFat16FixedCache::NewL()"));
sl@0
   299
sl@0
   300
    CFat16FixedCache* pSelf = NULL;
sl@0
   301
    pSelf = new (ELeave) CFat16FixedCache;
sl@0
   302
sl@0
   303
    CleanupStack::PushL(pSelf);
sl@0
   304
    pSelf->InitialiseL(aOwner, aFatSize, aRdGranularityLog2, aWrGranularityLog2);
sl@0
   305
    CleanupStack::Pop();
sl@0
   306
    
sl@0
   307
    return pSelf;
sl@0
   308
    }
sl@0
   309
sl@0
   310
//-----------------------------------------------------------------------------
sl@0
   311
/**
sl@0
   312
    FAT16 fixed cache initialisation.
sl@0
   313
    @param  aOwner              pointer to the owning FAT mount
sl@0
   314
    @param  aFatSize            size of the FAT table in bytes
sl@0
   315
    @param  aRdGranularityLog2  Log2(read granularity)
sl@0
   316
    @param  aWrGranularityLog2  Log2(write granularity)
sl@0
   317
*/
sl@0
   318
void CFat16FixedCache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
sl@0
   319
    {
sl@0
   320
    const TUint32 ReadGranularity = Pow2(aRdGranularityLog2);
sl@0
   321
    const TUint32 WriteGranularity = Pow2(aWrGranularityLog2);
sl@0
   322
sl@0
   323
    __PRINT3(_L("#-CFat16FixedCache::InitialiseL FatSz:%u, RdGr:%d, WrGr:%d"),aFatSize, ReadGranularity, WriteGranularity);
sl@0
   324
    (void)ReadGranularity;
sl@0
   325
    (void)WriteGranularity;
sl@0
   326
sl@0
   327
    TBool bParamsValid = (aRdGranularityLog2 >= aWrGranularityLog2) && (aWrGranularityLog2 >= KDefSectorSzLog2);
sl@0
   328
    __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity));
sl@0
   329
sl@0
   330
    CFatPagedCacheBase::InitialiseL(aOwner);
sl@0
   331
    
sl@0
   332
    ASSERT(FatType() == EFat16);
sl@0
   333
sl@0
   334
    //-- See FAT specs, and round up the limit to the FAT sector boundary
sl@0
   335
    const TUint32 KMaxFat16Size = ((65524*sizeof(TFat16Entry)+FAT_SectorSz()-1) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2(); 
sl@0
   336
    const TUint32 KMinFat16Size = 4086*sizeof(TFat16Entry);  //-- See FAT specs
sl@0
   337
    
sl@0
   338
    bParamsValid = aFatSize >= KMinFat16Size && aFatSize <= KMaxFat16Size;
sl@0
   339
	__ASSERT_ALWAYS(bParamsValid, User::Leave(KErrCorrupt));
sl@0
   340
sl@0
   341
    //-- cache page size is (2^aRdGranularityLog2) bytes and consists of 2^(aRdGranularityLog2-aWrGranularity) sectors.
sl@0
   342
    iPageSizeLog2 = aRdGranularityLog2;
sl@0
   343
    iSectorSizeLog2 = aWrGranularityLog2; //-- Log2(number of sectors in cache page)
sl@0
   344
    
sl@0
   345
    __ASSERT_ALWAYS(SectorsInPage() < KMaxSectorsInPage, Fault(EFatCache_BadGranularity));
sl@0
   346
sl@0
   347
    const TUint numPages = (aFatSize+(PageSize()-1)) >> iPageSizeLog2;
sl@0
   348
    __PRINT1(_L("#-CFat16FixedCache Num Pages:%d"), numPages);
sl@0
   349
sl@0
   350
    //-- prepare pointer array for pages. NULL entry in the array means that the page at this index isn't allocated.
sl@0
   351
    for(TUint i=0; i<numPages; ++i)
sl@0
   352
        iPages.Append(NULL);
sl@0
   353
    
sl@0
   354
    }
sl@0
   355
sl@0
   356
sl@0
   357
//-----------------------------------------------------------------------------
sl@0
   358
/**
sl@0
   359
    Close the cache and deallocate its memory.
sl@0
   360
    @param  aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.  
sl@0
   361
*/
sl@0
   362
void CFat16FixedCache::Close(TBool aDiscardDirtyData)
sl@0
   363
    {
sl@0
   364
    __PRINT1(_L("#-CFat16FixedCache::Close(%d)"), aDiscardDirtyData);
sl@0
   365
sl@0
   366
    TInt cnt = iPages.Count();
sl@0
   367
    while(cnt--)
sl@0
   368
        {//-- delete pages
sl@0
   369
        CFat16FixedCachePage *pPage = iPages[cnt];
sl@0
   370
        if(pPage && (pPage->IsDirty()))
sl@0
   371
            {//-- trying to destroy the cache that has dirty pages
sl@0
   372
            __PRINT1(_L("#-CFat16FixedCache::Close() The page is dirty! Start idx:%d"), pPage->StartFatIndex());
sl@0
   373
            if(!aDiscardDirtyData)
sl@0
   374
                {
sl@0
   375
                __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
sl@0
   376
                }
sl@0
   377
            //-- ignore this fact if requested.
sl@0
   378
            }
sl@0
   379
        
sl@0
   380
        delete pPage;
sl@0
   381
        }
sl@0
   382
sl@0
   383
    iPages.Close();
sl@0
   384
    SetDirty(EFalse);
sl@0
   385
    }
sl@0
   386
sl@0
   387
//-----------------------------------------------------------------------------
sl@0
   388
/**
sl@0
   389
    Read FAT entry from the cache. 
sl@0
   390
sl@0
   391
    @param  aIndex FAT entry index to read
sl@0
   392
    @return FAT entry value at the index "aIndex" 
sl@0
   393
*/
sl@0
   394
TUint32 CFat16FixedCache::ReadEntryL(TUint32 aIndex)
sl@0
   395
    {
sl@0
   396
    //__PRINT1(_L("#-CFat16FixedCache::ReadEntryL() FAT idx:%d"), aIndex);
sl@0
   397
    ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex < (FatSize() >> KFat16EntrySzLog2));
sl@0
   398
sl@0
   399
    //-- calculate page index in the array
sl@0
   400
    const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
sl@0
   401
    CFat16FixedCachePage *pPage = iPages[pgIdx];
sl@0
   402
    
sl@0
   403
    TUint32 entry = KMaxTUint;
sl@0
   404
sl@0
   405
    if(!pPage)
sl@0
   406
        {//-- page at this position isn't allocated yet
sl@0
   407
        pPage = CFat16FixedCachePage::NewL(*this);
sl@0
   408
        iPages[pgIdx] = pPage;
sl@0
   409
        
sl@0
   410
        //-- read the page from media
sl@0
   411
        entry = pPage->ReadFromMediaL(aIndex);
sl@0
   412
        }
sl@0
   413
    else
sl@0
   414
        {//-- get cached entry from the page
sl@0
   415
        TBool bRes = pPage->ReadCachedEntryL(aIndex, entry);
sl@0
   416
        ASSERT(bRes);
sl@0
   417
        (void)bRes;
sl@0
   418
        }
sl@0
   419
sl@0
   420
    return entry;
sl@0
   421
    }
sl@0
   422
sl@0
   423
//-----------------------------------------------------------------------------
sl@0
   424
/**
sl@0
   425
    Write FAT entry to the cache. 
sl@0
   426
    Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
sl@0
   427
sl@0
   428
    @param  aIndex FAT entry index
sl@0
   429
    @param  aEntry FAT entry value
sl@0
   430
*/
sl@0
   431
void CFat16FixedCache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
sl@0
   432
    {
sl@0
   433
    //__PRINT2(_L("#-CFat16FixedCache::WriteEntryL() FAT idx:%d, val:%d"), aIndex, aEntry);
sl@0
   434
sl@0
   435
    ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex < (FatSize() >> KFat16EntrySzLog2));
sl@0
   436
sl@0
   437
    SetDirty(ETrue);
sl@0
   438
sl@0
   439
    //-- calculate page index in the array
sl@0
   440
    const TInt pgIdx = aIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
sl@0
   441
    CFat16FixedCachePage *pPage = iPages[pgIdx];
sl@0
   442
sl@0
   443
    if(!pPage)
sl@0
   444
        {//-- page at this position isn't allocated yet
sl@0
   445
        pPage = CFat16FixedCachePage::NewL(*this);
sl@0
   446
        iPages[pgIdx] = pPage;
sl@0
   447
        
sl@0
   448
        //-- read the page from media
sl@0
   449
        pPage->ReadFromMediaL(aIndex);
sl@0
   450
        }
sl@0
   451
sl@0
   452
    //-- overwrite entry in cache
sl@0
   453
    TBool bRes = pPage->WriteCachedEntryL(aIndex, aEntry);
sl@0
   454
    ASSERT(bRes);
sl@0
   455
    (void)bRes;
sl@0
   456
    }
sl@0
   457
sl@0
   458
/**
sl@0
   459
    A debug method that asserts that the cache is really clean
sl@0
   460
*/
sl@0
   461
void CFat16FixedCache::AssertCacheReallyClean() const
sl@0
   462
    {
sl@0
   463
#ifdef _DEBUG 
sl@0
   464
        for(TUint i=0; i<NumPages(); ++i)
sl@0
   465
        {
sl@0
   466
            CFat16FixedCachePage* pPage = iPages[i];
sl@0
   467
            if(pPage && pPage->IsDirty())
sl@0
   468
                {
sl@0
   469
                __PRINT(_L("#-CFat16FixedCache::AssertCacheReallyClean()"));
sl@0
   470
                ASSERT(0);
sl@0
   471
                }
sl@0
   472
        }
sl@0
   473
#endif   
sl@0
   474
    }
sl@0
   475
sl@0
   476
sl@0
   477
//-----------------------------------------------------------------------------
sl@0
   478
/**
sl@0
   479
    Flushes all dirty data to the media.
sl@0
   480
*/
sl@0
   481
void CFat16FixedCache::FlushL()
sl@0
   482
    {
sl@0
   483
    if(!IsDirty())
sl@0
   484
        {
sl@0
   485
        AssertCacheReallyClean();
sl@0
   486
        return;
sl@0
   487
        }
sl@0
   488
sl@0
   489
sl@0
   490
    //-- flush dirty data to all copies of FAT
sl@0
   491
    for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
sl@0
   492
        {
sl@0
   493
        const TInt nPages = NumPages();
sl@0
   494
        for(TInt i=0; i<nPages; ++i)
sl@0
   495
            {
sl@0
   496
            const TBool keepDirty = iCurrentFatNo < (NumFATs() - 1);
sl@0
   497
sl@0
   498
            CFat16FixedCachePage* pPage = iPages[i];
sl@0
   499
            if(pPage)
sl@0
   500
                pPage->FlushL(keepDirty);
sl@0
   501
            }
sl@0
   502
       
sl@0
   503
        }
sl@0
   504
   
sl@0
   505
    iCurrentFatNo = KInvalidFatNo;
sl@0
   506
    SetDirty(EFalse);
sl@0
   507
    }
sl@0
   508
sl@0
   509
//-----------------------------------------------------------------------------
sl@0
   510
/**
sl@0
   511
    Invalidate whole cache. All pages will be marked as invalid and will be re-read from the media on first access to them.
sl@0
   512
    @return always KErrNone
sl@0
   513
*/
sl@0
   514
TInt CFat16FixedCache::Invalidate()
sl@0
   515
    {
sl@0
   516
    __PRINT(_L("#-CFat16FixedCache::Invalidate()"));
sl@0
   517
    const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
sl@0
   518
sl@0
   519
    //-- iterate through the array of pages marking invalidating every page
sl@0
   520
    TInt cnt = iPages.Count();
sl@0
   521
    while(cnt--)
sl@0
   522
        {//-- delete pages
sl@0
   523
        CFat16FixedCachePage *pPage = iPages[cnt];
sl@0
   524
        if(pPage)
sl@0
   525
            pPage->Invalidate(bIgnoreDirtyData);
sl@0
   526
        }
sl@0
   527
sl@0
   528
sl@0
   529
    SetDirty(EFalse);
sl@0
   530
sl@0
   531
    return KErrNone;
sl@0
   532
    }
sl@0
   533
sl@0
   534
//-----------------------------------------------------------------------------
sl@0
   535
/**
sl@0
   536
    Invalidate FAT cache pages that contain FAT entries from aStartIndex to (aStartIndex+aNumEntries)
sl@0
   537
    These pages will be marked as invalid and will be re-read from the media on first access to them.
sl@0
   538
    
sl@0
   539
    @param  aStartIndex FAT start index of the region being invalidated
sl@0
   540
    @param  aNumEntries number of entries to invalidate
sl@0
   541
    @return always KErrNone
sl@0
   542
*/
sl@0
   543
TInt CFat16FixedCache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
sl@0
   544
    {
sl@0
   545
    __PRINT2(_L("#-CFat16FixedCache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
sl@0
   546
    ASSERT(aStartIndex >= KFatFirstSearchCluster &&  aStartIndex < (FatSize() >> KFat16EntrySzLog2));
sl@0
   547
sl@0
   548
    if(!aNumEntries)
sl@0
   549
        {
sl@0
   550
        ASSERT(0);
sl@0
   551
        return KErrNone;
sl@0
   552
        }
sl@0
   553
sl@0
   554
    const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
sl@0
   555
    const TUint startPgIdx  = aStartIndex >> (PageSizeLog2()-KFat16EntrySzLog2);
sl@0
   556
    const TUint nPagesToInv = 1+(aNumEntries >> (PageSizeLog2()-KFat16EntrySzLog2));
sl@0
   557
sl@0
   558
    TUint i;
sl@0
   559
    //-- invalidate pages that contain [aStartIndex ... aStartIndex+aNumEntries] entries
sl@0
   560
    for(i=0; i<nPagesToInv; ++i)
sl@0
   561
        {
sl@0
   562
        const TUint pageIdx = i+startPgIdx;
sl@0
   563
        if(pageIdx >= NumPages())
sl@0
   564
            break;
sl@0
   565
        
sl@0
   566
        CFat16FixedCachePage* pPage = iPages[pageIdx];
sl@0
   567
        if(pPage)
sl@0
   568
            pPage->Invalidate(bIgnoreDirtyData);
sl@0
   569
        } 
sl@0
   570
sl@0
   571
    SetDirty(EFalse);
sl@0
   572
   
sl@0
   573
    //-- check if the cache still has dirty pages
sl@0
   574
    for(i=0; i<NumPages(); ++i)
sl@0
   575
        {
sl@0
   576
        CFat16FixedCachePage* pPage = iPages[i];
sl@0
   577
        if(pPage && pPage->IsDirty()) 
sl@0
   578
            {
sl@0
   579
            SetDirty(ETrue);
sl@0
   580
            break;
sl@0
   581
            }      
sl@0
   582
        }
sl@0
   583
sl@0
   584
    return KErrNone;
sl@0
   585
    }
sl@0
   586
sl@0
   587
//#################################################################################################################################
sl@0
   588
//  CFat16FixedCachePage implementation
sl@0
   589
//  Page for the FAT16 fixed cache
sl@0
   590
//#################################################################################################################################
sl@0
   591
sl@0
   592
//-----------------------------------------------------------------------------
sl@0
   593
sl@0
   594
CFat16FixedCachePage::CFat16FixedCachePage(CFatPagedCacheBase& aCache)
sl@0
   595
                     :CFatCachePageBase(aCache)
sl@0
   596
    {
sl@0
   597
    ASSERT(IsPowerOf2(EntriesInPage()));
sl@0
   598
    }
sl@0
   599
sl@0
   600
sl@0
   601
/**
sl@0
   602
    Factory function.
sl@0
   603
    @param aCache reference to the owning cache.
sl@0
   604
    @return pointer to the constructed object or NULL on error
sl@0
   605
*/
sl@0
   606
CFat16FixedCachePage* CFat16FixedCachePage::NewL(CFatPagedCacheBase& aCache)
sl@0
   607
    {
sl@0
   608
    CFat16FixedCachePage* pSelf = NULL;
sl@0
   609
    pSelf = new (ELeave) CFat16FixedCachePage(aCache);
sl@0
   610
sl@0
   611
    CleanupStack::PushL(pSelf);
sl@0
   612
    
sl@0
   613
    pSelf->iData.CreateMaxL(aCache.PageSize()); //-- allocate memory for the page
sl@0
   614
   
sl@0
   615
    CleanupStack::Pop();
sl@0
   616
sl@0
   617
    return pSelf;
sl@0
   618
    }
sl@0
   619
sl@0
   620
sl@0
   621
//-----------------------------------------------------------------------------
sl@0
   622
/**
sl@0
   623
    Read FAT16 entry from the cache. 
sl@0
   624
    
sl@0
   625
    1. If page's data are valid, just extracts data from the page buffer.
sl@0
   626
    2. If page's data are invalid firstly reads data from the media and goto 1
sl@0
   627
    
sl@0
   628
    @param  aFatIndex entry's absolute FAT index (from the FAT start)
sl@0
   629
    @param  aResult on sucess there will be FAT16 entry value
sl@0
   630
    @return ETrue, because FAT16 cache pages never get eviched.
sl@0
   631
*/
sl@0
   632
TBool CFat16FixedCachePage::ReadCachedEntryL (TUint32 aFatIndex, TUint32& aResult)
sl@0
   633
    {
sl@0
   634
    if(IsValid())
sl@0
   635
        {//-- read entry directly from page buffer, the cached data are valid
sl@0
   636
        aResult = (*GetEntryPtr(aFatIndex)) & KFat16EntryMask;
sl@0
   637
        }
sl@0
   638
    else
sl@0
   639
        {//-- aFatIndex belongs to this page, but the page is invalid and needs to be read from the media
sl@0
   640
        //__PRINT(_L("#-CFat16FixedCachePage::ReadCachedEntry() The page is invalid, reading from the media"));
sl@0
   641
        aResult = ReadFromMediaL(aFatIndex);
sl@0
   642
        }
sl@0
   643
sl@0
   644
    return ETrue;
sl@0
   645
    }
sl@0
   646
sl@0
   647
//-----------------------------------------------------------------------------
sl@0
   648
sl@0
   649
/**
sl@0
   650
    Writes FAT cache page sector to the media (to all copies of the FAT)
sl@0
   651
    @param  aSector sector number winthin this page
sl@0
   652
*/
sl@0
   653
void CFat16FixedCachePage::DoWriteSectorL(TUint32 aSector)
sl@0
   654
    {
sl@0
   655
    //__PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorL() startSec:%d, cnt:%d"), aSector);
sl@0
   656
sl@0
   657
    ASSERT(aSector < iCache.SectorsInPage());
sl@0
   658
sl@0
   659
    TInt offset = 0;
sl@0
   660
sl@0
   661
    if(iStartIndexInFAT == 0 && aSector == 0)
sl@0
   662
        {//-- this is the very beginning of FAT16. We must skip FAT[0] & FAT[1] entries and do not write them to media.    
sl@0
   663
        offset = KFatFirstSearchCluster << KFat16EntrySzLog2; 
sl@0
   664
        }    
sl@0
   665
    
sl@0
   666
    const TUint8* pData = iData.Ptr()+offset+(aSector << iCache.SectorSizeLog2());
sl@0
   667
    
sl@0
   668
    TUint32 dataLen = (1 << iCache.SectorSizeLog2()) - offset;
sl@0
   669
sl@0
   670
    const TUint32 mediaPosStart = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2) + (aSector << iCache.SectorSizeLog2()) + offset; 
sl@0
   671
    const TUint32 mediaPosEnd = mediaPosStart + dataLen; 
sl@0
   672
sl@0
   673
    //-- check if we are going to write beyond FAT. It can happen if the write granularity is bigger that the sector size.
sl@0
   674
    const TUint32 posFatEnd = iCache.FatStartPos() + iCache.FatSize();
sl@0
   675
    if(mediaPosEnd > posFatEnd)
sl@0
   676
        {//-- correct the leength of the data to write.
sl@0
   677
        dataLen -= (mediaPosEnd-posFatEnd);
sl@0
   678
        }
sl@0
   679
sl@0
   680
    TPtrC8 ptrData(pData, dataLen); //-- source data descriptor 
sl@0
   681
sl@0
   682
    TInt nRes = iCache.WriteFatData(mediaPosStart, ptrData);
sl@0
   683
    
sl@0
   684
    if(nRes != KErrNone)
sl@0
   685
        {
sl@0
   686
        __PRINT1(_L("#-CFat16FixedCachePage::DoWriteSectorsL() failed! code:%d"), nRes);
sl@0
   687
        User::Leave(nRes);
sl@0
   688
        }
sl@0
   689
sl@0
   690
    }
sl@0
   691
sl@0
   692
//-----------------------------------------------------------------------------
sl@0
   693
/**
sl@0
   694
    Write FAT16 entry at aFatIndex to the cache. Note that the data are not written to the media, only to the cache page.
sl@0
   695
    Corresponding page sector is marked as dirty and will be flushed on FlushL() call later.
sl@0
   696
sl@0
   697
    1. If page's data are valid, copies data to the page buffer and marks sector as dirty.
sl@0
   698
    2. If page's data are invalid, firstly reads data from the media and goto 1
sl@0
   699
sl@0
   700
    @param  aFatIndex entry's absolute FAT index (from the FAT start)
sl@0
   701
    @param  aFatEntry FAT16 entry value
sl@0
   702
    @return ETrue because FAT16 cache pages never get eviched.
sl@0
   703
*/
sl@0
   704
TBool CFat16FixedCachePage::WriteCachedEntryL(TUint32 aFatIndex, TUint32 aFatEntry)
sl@0
   705
    {
sl@0
   706
    
sl@0
   707
    ASSERT(IsEntryCached(aFatIndex));
sl@0
   708
sl@0
   709
    if(!IsValid())
sl@0
   710
        {//-- we are trying to write data to the page that has invalid data. //-- read the data from the media first.
sl@0
   711
        ReadFromMediaL(aFatIndex);
sl@0
   712
        }
sl@0
   713
sl@0
   714
    TFat16Entry* pEntry = GetEntryPtr(aFatIndex);
sl@0
   715
    
sl@0
   716
    const TFat16Entry orgEntry = *pEntry;
sl@0
   717
    *pEntry = (TFat16Entry)((orgEntry & ~KFat16EntryMask) | (aFatEntry & KFat16EntryMask));
sl@0
   718
    
sl@0
   719
    //-- mark corresponding sector of the cache page as dirty
sl@0
   720
    const TUint entryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
sl@0
   721
    const TUint dirtySectorNum   = entryIndexInPage >> (iCache.SectorSizeLog2() - KFat16EntrySzLog2);
sl@0
   722
sl@0
   723
    ASSERT(dirtySectorNum < iCache.SectorsInPage());
sl@0
   724
sl@0
   725
    iDirtySectors.SetBit(dirtySectorNum);
sl@0
   726
    SetState(EDirty); //-- mark page as dirty.
sl@0
   727
sl@0
   728
    return ETrue;
sl@0
   729
    }
sl@0
   730
sl@0
   731
//-----------------------------------------------------------------------------
sl@0
   732
sl@0
   733
/**
sl@0
   734
    Get a pointer to the FAT16 entry in the page buffer.
sl@0
   735
    The page 's data shall be valid and the entry shall belong to this page.
sl@0
   736
    
sl@0
   737
    @param aFatIndex absolute FAT index (from the FAT start) of the entry
sl@0
   738
    @return pointer to the FAT16 entry in the page buffer.
sl@0
   739
*/
sl@0
   740
TFat16Entry* CFat16FixedCachePage::GetEntryPtr(TUint32 aFatIndex) const
sl@0
   741
    {
sl@0
   742
    ASSERT(IsValid() && IsEntryCached(aFatIndex));
sl@0
   743
sl@0
   744
    const TUint KEntryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
sl@0
   745
    TFat16Entry* pEntry = ((TFat16Entry*)iData.Ptr()) + KEntryIndexInPage;
sl@0
   746
sl@0
   747
    return  pEntry;
sl@0
   748
    }
sl@0
   749
sl@0
   750
//-----------------------------------------------------------------------------
sl@0
   751
/**
sl@0
   752
    Read the FAT16 cache page from the media and returns required FAT16 entry.    
sl@0
   753
sl@0
   754
    @param  aFatIndex entry's absolute FAT index (from the FAT start)
sl@0
   755
    @return entry value at aFatIndex.
sl@0
   756
*/
sl@0
   757
TUint32 CFat16FixedCachePage::ReadFromMediaL(TUint32 aFatIndex)
sl@0
   758
    {
sl@0
   759
    //__PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() FAT idx:%d"), aFatIndex);
sl@0
   760
    const TUint KFat16EntriesInPageLog2 = iCache.PageSizeLog2()-KFat16EntrySzLog2; //-- number of FAT16 entries in page is always a power of 2
sl@0
   761
sl@0
   762
    //-- find out index in FAT this page starts from
sl@0
   763
    iStartIndexInFAT = (aFatIndex >> KFat16EntriesInPageLog2) << KFat16EntriesInPageLog2;
sl@0
   764
    SetState(EInvalid); //-- mark the page as invalid just in case if the read fails.
sl@0
   765
sl@0
   766
    //-- read page from the media
sl@0
   767
    const TUint32 pageStartPos = iCache.FatStartPos() + (iStartIndexInFAT << KFat16EntrySzLog2);
sl@0
   768
    
sl@0
   769
    TInt nRes = iCache.ReadFatData(pageStartPos, iCache.PageSize(), iData);
sl@0
   770
    if(nRes != KErrNone)
sl@0
   771
        {
sl@0
   772
        __PRINT1(_L("#-CFat16FixedCachePage::ReadFromMediaL() failed! code:%d"), nRes);
sl@0
   773
        User::Leave(nRes);
sl@0
   774
        }
sl@0
   775
sl@0
   776
    SetClean(); //-- mark this page as clean
sl@0
   777
sl@0
   778
    const TFat16Entry entry = (TFat16Entry)((*GetEntryPtr(aFatIndex)) & KFat16EntryMask);
sl@0
   779
sl@0
   780
    return entry;
sl@0
   781
    }
sl@0
   782
sl@0
   783
sl@0
   784
//-----------------------------------------------------------------------------
sl@0
   785
sl@0
   786
//#################################################################################################################################
sl@0
   787
//  CFat12Cache implementation
sl@0
   788
//  FAT12 non-paged fixed cache. This cache consists from only 1 page, logically divided up to 32 sectors (write granularity unit)
sl@0
   789
//#################################################################################################################################
sl@0
   790
sl@0
   791
CFat12Cache::CFat12Cache()
sl@0
   792
            :CFatCacheBase()
sl@0
   793
    {
sl@0
   794
    }
sl@0
   795
sl@0
   796
//-----------------------------------------------------------------------------
sl@0
   797
/**
sl@0
   798
    FAT12 fixed cache factory function.
sl@0
   799
    @param  aOwner              pointer to the owning FAT mount
sl@0
   800
    @param  aFatSize            size of the FAT table in bytes
sl@0
   801
sl@0
   802
    @return pointer to the constructed object.
sl@0
   803
*/
sl@0
   804
CFat12Cache* CFat12Cache::NewL(CFatMountCB* aOwner, TUint32 aFatSize)
sl@0
   805
    {
sl@0
   806
    __PRINT(_L("#-CFat12Cache::NewL()"));
sl@0
   807
    CFat12Cache* pSelf = NULL;
sl@0
   808
    pSelf = new (ELeave) CFat12Cache;
sl@0
   809
sl@0
   810
    CleanupStack::PushL(pSelf);
sl@0
   811
    pSelf->InitialiseL(aOwner, aFatSize);
sl@0
   812
    CleanupStack::Pop();
sl@0
   813
    
sl@0
   814
    return pSelf;
sl@0
   815
    }
sl@0
   816
sl@0
   817
//-----------------------------------------------------------------------------
sl@0
   818
/**
sl@0
   819
    FAT16 fixed cache initialisation.
sl@0
   820
    @param  aOwner              pointer to the owning FAT mount
sl@0
   821
    @param  aFatSize            size of the FAT table in bytes
sl@0
   822
*/
sl@0
   823
void CFat12Cache::InitialiseL(CFatMountCB* aOwner, TUint32 aFatSize)
sl@0
   824
    {
sl@0
   825
    __PRINT1(_L("#-CFat12Cache::InitialiseL FatSz:%u"),aFatSize);
sl@0
   826
sl@0
   827
    CFatCacheBase::InitialiseL(aOwner);
sl@0
   828
    ASSERT(FatType() == EFat12);
sl@0
   829
sl@0
   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
sl@0
   831
    const TUint32 KMaxFat12Size = ( ((TUint32)(4084*1.5+FAT_SectorSz()-1)) >> FAT_SectorSzLog2()) << FAT_SectorSzLog2();
sl@0
   832
    const TUint32 KMinFat12Size = FAT_SectorSz();  //-- 1 FAT sector
sl@0
   833
	__ASSERT_ALWAYS(aFatSize >= KMinFat12Size && aFatSize <= KMaxFat12Size, User::Leave(KErrCorrupt));
sl@0
   834
    (void)KMaxFat12Size;
sl@0
   835
    (void)KMinFat12Size;
sl@0
   836
sl@0
   837
    //-- as soon as FAT12 max size is 4084 entries or 6126 bytes, the cache is contiguous and divided 
sl@0
   838
    //-- to logical sectors (write granularity). 
sl@0
   839
sl@0
   840
    //-- calculate number write cache sector in the cache
sl@0
   841
    iSectorsInCache = (aFatSize + (FAT_SectorSz()-1)) >> FAT_SectorSzLog2();
sl@0
   842
    __ASSERT_ALWAYS(NumSectors() <= KMaxSectorsInCache, Fault(EFatCache_BadGranularity));
sl@0
   843
sl@0
   844
    //-- round up cache size to write granularity (sector size)
sl@0
   845
    const TUint32 cacheSize = NumSectors() << FAT_SectorSzLog2();
sl@0
   846
    
sl@0
   847
    //-- create buffer for the whole FAT12
sl@0
   848
    iData.CreateMaxL(cacheSize);
sl@0
   849
sl@0
   850
    //-- this will read whole FAT into the cache 
sl@0
   851
    User::LeaveIfError(Invalidate()); 
sl@0
   852
    }
sl@0
   853
sl@0
   854
//-----------------------------------------------------------------------------
sl@0
   855
/**
sl@0
   856
    Close the cache and deallocate its memory.
sl@0
   857
    @param  aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.  
sl@0
   858
*/
sl@0
   859
void CFat12Cache::Close(TBool aDiscardDirtyData)
sl@0
   860
    {
sl@0
   861
    __PRINT1(_L("#-CFat12Cache::Close(%d)"), aDiscardDirtyData);    
sl@0
   862
    
sl@0
   863
    for(TUint32 i=0; i<NumSectors(); ++i)
sl@0
   864
        {
sl@0
   865
        if(iDirtySectors[i])
sl@0
   866
            {//-- trying to destroy the cache that has dirty sectors
sl@0
   867
            __PRINT1(_L("#-CFat12Cache::Close() The cache is dirty! cache sector:%d"), i);
sl@0
   868
            if(!aDiscardDirtyData)
sl@0
   869
                {
sl@0
   870
                __ASSERT_ALWAYS(0, Fault(EFatCache_DiscardingDirtyData));
sl@0
   871
                }
sl@0
   872
            //-- ignore this fact if requested.
sl@0
   873
            }
sl@0
   874
        }
sl@0
   875
sl@0
   876
    iData.Close();
sl@0
   877
    SetDirty(EFalse);
sl@0
   878
    }
sl@0
   879
sl@0
   880
//-----------------------------------------------------------------------------
sl@0
   881
/**
sl@0
   882
    Read FAT entry from the cache. 
sl@0
   883
sl@0
   884
    @param  aIndex FAT entry index to read
sl@0
   885
    @return FAT entry value at the index "aIndex" 
sl@0
   886
*/
sl@0
   887
TUint32 CFat12Cache::ReadEntryL(TUint32 aIndex)
sl@0
   888
    {
sl@0
   889
    //__PRINT1(_L("#-CFat12Cache::ReadEntryL() FAT idx:%d"), aIndex);
sl@0
   890
    ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex <  (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
sl@0
   891
sl@0
   892
    TUint32 entry;
sl@0
   893
sl@0
   894
    if(aIndex & 0x01)
sl@0
   895
        {//-- odd index
sl@0
   896
        --aIndex;
sl@0
   897
        const TUint32 byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
sl@0
   898
        Mem::Copy(&entry, iData.Ptr()+byteIdx, 2); 
sl@0
   899
        entry >>= 4;   
sl@0
   900
        }
sl@0
   901
    else
sl@0
   902
        {//-- even index
sl@0
   903
        const TUint32 byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
sl@0
   904
        Mem::Copy(&entry, iData.Ptr()+byteIdx, 2);
sl@0
   905
        }
sl@0
   906
sl@0
   907
    entry &= KFat12EntryMask; 
sl@0
   908
sl@0
   909
    return entry;
sl@0
   910
    }
sl@0
   911
sl@0
   912
//-----------------------------------------------------------------------------
sl@0
   913
/**
sl@0
   914
    Write FAT entry to the cache. 
sl@0
   915
    Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
sl@0
   916
sl@0
   917
    @param  aIndex FAT entry index
sl@0
   918
    @param  aEntry FAT entry value
sl@0
   919
*/
sl@0
   920
void CFat12Cache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
sl@0
   921
    {
sl@0
   922
    //__PRINT2(_L("#-CFat12Cache::WriteEntryL() FAT idx:%d, entry:%u"), aIndex, aEntry);
sl@0
   923
    ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex <  (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
sl@0
   924
sl@0
   925
    aEntry &= KFat12EntryMask; 
sl@0
   926
 
sl@0
   927
    TUint32 byteIdx = 0;
sl@0
   928
    TUint8 tmp;
sl@0
   929
sl@0
   930
    if(aIndex & 0x01)
sl@0
   931
        {//-- odd index
sl@0
   932
        --aIndex;
sl@0
   933
        byteIdx = 1 + aIndex + (aIndex >> 1); //-- byteIdx = 1+(aIndex-1)*1.5
sl@0
   934
        tmp = (TUint8)(iData[byteIdx] & 0x0F); //-- we modifying a higher nibble 
sl@0
   935
        tmp |= (TUint8) ((aEntry & 0x0F)<<4);
sl@0
   936
        iData[byteIdx] = tmp;
sl@0
   937
sl@0
   938
        iData[byteIdx+1] = (TUint8)(aEntry >> 4);  
sl@0
   939
        }
sl@0
   940
    else
sl@0
   941
        {//-- even index
sl@0
   942
        byteIdx = aIndex + (aIndex >> 1); //-- byteIdx = aIndex*1.5
sl@0
   943
        iData[byteIdx] = (TUint8)aEntry;  
sl@0
   944
sl@0
   945
        const TUint32 nextIdx = byteIdx+1;
sl@0
   946
        tmp = (TUint8)(iData[nextIdx] & 0xF0); //-- we modifying a lower nibble 
sl@0
   947
        tmp |= (TUint8)((aEntry >> 8) & 0x0F);
sl@0
   948
        iData[nextIdx] = tmp;
sl@0
   949
sl@0
   950
        }
sl@0
   951
sl@0
   952
    //-- mark changed sectors dirty. We modified 2 bytes at [byteIdx] and [byteIdx+1]
sl@0
   953
    iDirtySectors.SetBit(byteIdx >> FAT_SectorSzLog2());
sl@0
   954
    iDirtySectors.SetBit((byteIdx+1) >> FAT_SectorSzLog2());
sl@0
   955
sl@0
   956
    SetDirty(ETrue);
sl@0
   957
    }
sl@0
   958
sl@0
   959
//-----------------------------------------------------------------------------
sl@0
   960
/**
sl@0
   961
    A debug method that asserts that the cache is really clean
sl@0
   962
*/
sl@0
   963
void CFat12Cache::AssertCacheReallyClean() const
sl@0
   964
    {
sl@0
   965
#ifdef _DEBUG 
sl@0
   966
    if(iDirtySectors.HasBitsSet())
sl@0
   967
        {
sl@0
   968
        __PRINT(_L("#-CFat12Cache::AssertCacheReallyClean()"));
sl@0
   969
        ASSERT(0);
sl@0
   970
        }
sl@0
   971
sl@0
   972
#endif   
sl@0
   973
    }
sl@0
   974
sl@0
   975
//-----------------------------------------------------------------------------
sl@0
   976
/**
sl@0
   977
    Flushes all dirty data to the media.
sl@0
   978
    Walks through all sectors in this cache and flushes dirty ones.
sl@0
   979
*/
sl@0
   980
void CFat12Cache::FlushL()
sl@0
   981
    {
sl@0
   982
    if(!IsDirty())
sl@0
   983
        {
sl@0
   984
        AssertCacheReallyClean();
sl@0
   985
        return;
sl@0
   986
        }
sl@0
   987
sl@0
   988
    //-- write all dirty sectors to the media (into all copies of FAT)
sl@0
   989
    for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
sl@0
   990
        {
sl@0
   991
        for(TUint secNo=0; secNo<NumSectors(); ++secNo)
sl@0
   992
            {
sl@0
   993
            if(iDirtySectors[secNo])
sl@0
   994
                {//-- this sector is dirty, write it to the media
sl@0
   995
sl@0
   996
                TInt offset = 0;
sl@0
   997
                if(secNo == 0)
sl@0
   998
                    {//-- this is a first sector in FAT. We must skip FAT[0] & FAT[1] entries and do not write them to the media.    
sl@0
   999
                    offset = 3; //-- 2 FAT12 entries
sl@0
  1000
                    }
sl@0
  1001
sl@0
  1002
                const TUint32 secPos = secNo << FAT_SectorSzLog2(); //-- relative sector position in FAT
sl@0
  1003
                const TUint8* pData = iData.Ptr()+offset+secPos;    //-- pointer to the data in cache buffer
sl@0
  1004
                const TUint32 len = FAT_SectorSz() - offset;          
sl@0
  1005
                TPtrC8 ptrData(pData, len);                         //-- source data descriptor 
sl@0
  1006
                const TUint32 mediaPos = FatStartPos() + secPos + offset;
sl@0
  1007
                
sl@0
  1008
                TInt nRes = WriteFatData(mediaPos, ptrData);
sl@0
  1009
sl@0
  1010
                if(nRes != KErrNone)
sl@0
  1011
                    {
sl@0
  1012
                    __PRINT1(_L("#-CFat12Cache::FlushL() failed! code:%d"), nRes);
sl@0
  1013
                    User::Leave(nRes);
sl@0
  1014
                    }
sl@0
  1015
sl@0
  1016
                }//if(iDirtySectors[secNo])
sl@0
  1017
            }
sl@0
  1018
sl@0
  1019
        }
sl@0
  1020
sl@0
  1021
    iCurrentFatNo = KInvalidFatNo;
sl@0
  1022
sl@0
  1023
    //-- mark the cache as clean
sl@0
  1024
    iDirtySectors.Clear();
sl@0
  1025
    SetDirty(EFalse);
sl@0
  1026
    
sl@0
  1027
    }
sl@0
  1028
sl@0
  1029
//-----------------------------------------------------------------------------
sl@0
  1030
/**
sl@0
  1031
    Invalidates whole cache. Because FAT12 is tiny, just re-reads data from the media to the cache
sl@0
  1032
    @return Media read result code.
sl@0
  1033
*/
sl@0
  1034
TInt CFat12Cache::Invalidate()
sl@0
  1035
    {
sl@0
  1036
    __PRINT(_L("#-CFat12Cache::Invalidate()"));
sl@0
  1037
    CheckInvalidatingDirtyCache();
sl@0
  1038
    
sl@0
  1039
    //-- read whole cache from the media
sl@0
  1040
    const TUint32 posStart = FatStartPos();
sl@0
  1041
    const TUint32 len      = NumSectors() << FAT_SectorSzLog2();
sl@0
  1042
     
sl@0
  1043
    TInt nRes = ReadFatData(posStart, len, iData);
sl@0
  1044
    if(nRes != KErrNone)
sl@0
  1045
        return nRes;
sl@0
  1046
sl@0
  1047
    //-- mark the cache as clean
sl@0
  1048
    SetDirty(EFalse);
sl@0
  1049
    iDirtySectors.Clear();
sl@0
  1050
sl@0
  1051
    return KErrNone;
sl@0
  1052
    }
sl@0
  1053
sl@0
  1054
//-----------------------------------------------------------------------------
sl@0
  1055
/**
sl@0
  1056
    Invalidate wholes cache. Because FAT12 is tiny, just re-reads data from the media to the cache
sl@0
  1057
    @param  aStartIndex ignored
sl@0
  1058
    @param  aNumEntries ignored
sl@0
  1059
    @return Media read result code.
sl@0
  1060
*/
sl@0
  1061
TInt CFat12Cache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
sl@0
  1062
    {
sl@0
  1063
    __PRINT2(_L("#-CFat12Cache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
sl@0
  1064
    ASSERT(aStartIndex >= KFatFirstSearchCluster &&  aStartIndex <  (FatSize() + FatSize()/2)); //-- FAT12 entry is 1.5 bytes long
sl@0
  1065
    (void)aStartIndex;
sl@0
  1066
    (void)aNumEntries;
sl@0
  1067
sl@0
  1068
    //-- just re-read all FAT12, it is just 6K max and isn't worth calculating invalid sectors
sl@0
  1069
    return Invalidate();
sl@0
  1070
    }
sl@0
  1071
sl@0
  1072
sl@0
  1073
sl@0
  1074
sl@0
  1075
sl@0
  1076
sl@0
  1077
sl@0
  1078
sl@0
  1079
sl@0
  1080
sl@0
  1081
sl@0
  1082
sl@0
  1083
sl@0
  1084
sl@0
  1085
sl@0
  1086
sl@0
  1087
sl@0
  1088
sl@0
  1089
sl@0
  1090
sl@0
  1091
sl@0
  1092
sl@0
  1093
sl@0
  1094
sl@0
  1095
sl@0
  1096
sl@0
  1097
sl@0
  1098
sl@0
  1099
sl@0
  1100
sl@0
  1101
sl@0
  1102
sl@0
  1103
sl@0
  1104
sl@0
  1105
sl@0
  1106
sl@0
  1107
sl@0
  1108
sl@0
  1109
sl@0
  1110
sl@0
  1111
sl@0
  1112
sl@0
  1113