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