uffs_fileem.c

Go to the documentation of this file.
00001 
00008 #include <sys/types.h>
00009 #include <string.h>
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 
00013 
00014 #include "uffs/uffs_device.h"
00015 
00016 #define PFX "femu:"
00017 
00018 
00019 /* to define basic parameters of the NAND device */
00020 #if 1
00021     #define PAGES_PER_BLOCK 32
00022     #define PAGE_DATA_SIZE  512
00023     #define PAGE_SPARE_SIZE 16
00024     //#define TOTAL_BLOCKS  8192    //128M
00025     #define TOTAL_BLOCKS    128     //2M
00026 #else
00027     #define PAGES_PER_BLOCK 4
00028     #define PAGE_DATA_SIZE  512
00029     #define PAGE_SPARE_SIZE 16
00030     #define TOTAL_BLOCKS    5
00031 #endif
00032 
00033 #define PAGE_SIZE                   (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
00034 #define BLOCK_DATA_SIZE             (PAGES_PER_BLOCK * PAGE_DATA_SIZE)
00035 #define TOTAL_DATA_SIZE             (TOTAL_BLOCKS * BLOCK_DATA_SIZE)
00036 #define BLOCK_SIZE                  (PAGES_PER_BLOCK * PAGE_SIZE)
00037 #define TOTAL_SIZE                  (BLOCK_SIZE * TOTAL_BLOCKS)
00038 
00039 
00040 #define EMUFILE "uffsemfile.bin"
00041 
00042 #define MAXWRITETIME_PAGE 2
00043 #define MAXWRITETIME_SPARE 2
00044 
00045 static u8 em_monitor_page[TOTAL_BLOCKS * PAGES_PER_BLOCK];      //page write count
00046 static u8 em_monitor_spare[TOTAL_BLOCKS * PAGES_PER_BLOCK];     //page spare write count
00047 
00048 static u8 em_page_buf[PAGE_SIZE];
00049 
00050 
00051 static URET CheckInit(uffs_Device *dev);
00052 static URET femu_WritePage(uffs_Device *dev, u32 block, u32 pageNum, const u8 *data, const u8 *spare);
00053 static URET femu_WritePageData(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int ofs, int len);
00054 static URET femu_WritePageSpare(uffs_Device *dev, u32 block, u32 pageNum, const u8 *spare, int ofs, int len);
00055 static URET femu_ReadPage(uffs_Device *dev, u32 block, u32 pageNum, u8 *data, u8 *spare);
00056 static URET femu_ReadPageData(uffs_Device *dev, u32 block, u32 pageNum, u8 *page, int ofs, int len);
00057 static URET femu_ReadPageSpare(uffs_Device *dev, u32 block, u32 pageNum, u8 *spare, int ofs, int len);
00058 static URET femu_EraseBlock(uffs_Device *dev, u32 blockNumber);
00059 static URET femu_ResetFlash(uffs_Device *dev);
00060 static UBOOL femu_IsBlockBad(uffs_Device *dev, u32 block);
00061 static URET emu_initDevice(uffs_Device *dev);
00062 
00063 
00064 typedef struct femu_privateSt {
00065     int initCount;
00066     FILE *fp;
00067 } femu_private;
00068 
00069 static femu_private g_femu_priv = {0};
00070 
00071 static URET CheckInit(uffs_Device *dev)
00072 {
00073     int i;
00074     int fSize;
00075     int written;
00076     u8 * p = em_page_buf;
00077     femu_private *emu;
00078     
00079     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00080     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00081     pgdSize = dev->attr.page_data_size;
00082     spSize = dev->attr.spare_size;
00083     blkPgs = dev->attr.pages_per_block;
00084     blks = dev->attr.total_blocks;
00085     blkSize = dev->attr.block_data_size;
00086     
00087     emu = (femu_private *)(dev->private);
00088 
00089     if(emu->initCount > 0) {
00090         emu->initCount++;
00091         return U_SUCC;
00092     }
00093 
00094     //clear monitor
00095     memset(em_monitor_page, 0, blks * blkPgs);
00096     memset(em_monitor_spare, 0, blks * blkPgs);
00097 
00098     emu->fp = fopen(EMUFILE, "rb");
00099     if (emu->fp == NULL) {
00100         emu->fp = fopen(EMUFILE, "ab+");
00101         if (emu->fp == NULL) {
00102             printf(PFX"Failed to create uffs emulation file.");
00103             return U_FAIL;
00104         }
00105 
00106         fseek(emu->fp, 0, SEEK_END);
00107         fSize = ftell(emu->fp);
00108         
00109         if(fSize < blkSize * blks)  {
00110             printf("Creating uffs emulation file\n");
00111             fseek(emu->fp, 0, SEEK_SET);
00112             memset(p, 0xff, pgdSize + spSize);
00113             for(i = 0; i < blkPgs * blks; i++)  {
00114                 written = fwrite(p, 1, pgdSize + spSize, emu->fp);
00115                 if(written != pgdSize + spSize) {
00116                     printf("Write failed\n");
00117                     fclose(emu->fp);
00118                     emu->fp = NULL;
00119                     return U_FAIL;
00120                 }
00121             }       
00122         }
00123     }
00124     fflush(emu->fp);    
00125     fclose(emu->fp);
00126 
00127     emu->fp = fopen(EMUFILE, "rb+");
00128     if (emu->fp == NULL) {
00129         printf(PFX"Can't open emulation file.\n");
00130         return U_FAIL;
00131     }
00132 
00133     emu->initCount++;
00134 
00135     return U_SUCC;
00136 }
00137 
00138 static URET femu_WritePage(uffs_Device *dev, u32 block, u32 pageNum, const u8 *data, const u8 *spare)
00139 {
00140     int ret;
00141     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00142 
00143     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00144     pgdSize = dev->attr.page_data_size;
00145     spSize = dev->attr.spare_size;
00146     blkPgs = dev->attr.pages_per_block;
00147     blks = dev->attr.total_blocks;
00148     blkSize = dev->attr.block_data_size;
00149 
00150     if(data) {
00151         ret = femu_WritePageData(dev, block, pageNum, data, 0, pgdSize);
00152         if(ret == U_FAIL) return ret;
00153     }
00154     
00155     if(spare) {
00156         ret = femu_WritePageSpare(dev, block, pageNum, spare, 0, spSize);
00157         if(ret == U_FAIL) return ret;
00158     }
00159 
00160     return U_SUCC;  
00161 
00162 }
00163 
00164 static URET femu_WritePageData(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int ofs, int len)
00165 {
00166     int written;
00167     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00168     femu_private *emu;
00169     emu = (femu_private *)(dev->private);
00170 
00171     if (!emu || !(emu->fp)) return U_FAIL;
00172 
00173     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00174     pgdSize = dev->attr.page_data_size;
00175     spSize = dev->attr.spare_size;
00176     blkPgs = dev->attr.pages_per_block;
00177     blks = dev->attr.total_blocks;
00178     blkSize = dev->attr.block_data_size;
00179 
00180     if(ofs + len > pgdSize) {
00181         printf("femu: write page data out of range!\n");
00182         return U_FAIL;
00183     }
00184 
00185     em_monitor_page[block * blkPgs + pageNum]++;
00186     if(em_monitor_page[block * blkPgs + pageNum] > MAXWRITETIME_PAGE) {
00187         printf("Warrning: block %d page %d exceed it's maximum write time!\r\n", block, pageNum);
00188         return U_FAIL;
00189     }
00190     
00191     if(page)
00192     {
00193         fseek(emu->fp, 
00194             (block * blkPgs + pageNum) * 
00195             (pgdSize + spSize) 
00196             + ofs, SEEK_SET);
00197         written = fwrite(page, 1, len, emu->fp);
00198         
00199         if(written != len) {
00200             printf("femu: write page I/O error ?\n");
00201             return U_FAIL;
00202         }
00203     }
00204 
00205     dev->st.pageWriteCount++;
00206     fflush(emu->fp);
00207     
00208     return U_SUCC;
00209 }
00210 
00211 static URET femu_WritePageSpare(uffs_Device *dev, u32 block, u32 pageNum, const u8 *spare, int ofs, int len)
00212 {
00213     int written;
00214     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00215     femu_private *emu;
00216     emu = (femu_private *)(dev->private);
00217     if (!emu || !(emu->fp)) return U_FAIL;
00218 
00219     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00220     pgdSize = dev->attr.page_data_size;
00221     spSize = dev->attr.spare_size;
00222     blkPgs = dev->attr.pages_per_block;
00223     blks = dev->attr.total_blocks;
00224     blkSize = dev->attr.block_data_size;
00225 
00226 //  printf("WS: %d/%d, size %d\n", block, pageNum, len);
00227     
00228     if(ofs + len > spSize) {
00229         printf("femu: write page data out of range!\n");
00230         return U_FAIL;
00231     }
00232 
00233     em_monitor_spare[block*blkPgs + pageNum]++;
00234     if(em_monitor_spare[block*blkPgs + pageNum] > MAXWRITETIME_SPARE) {
00235         printf("Warrning: block %d page %d (spare) exceed it's maximum write time!\r\n", block, pageNum);
00236         return U_FAIL;
00237     }
00238     
00239     if(spare) {
00240         fseek(emu->fp, (block*blkPgs + pageNum) * (pgdSize + spSize) + PAGE_DATA_SIZE + ofs, SEEK_SET);
00241         written = fwrite(spare, 1, len, emu->fp);
00242         if(written != len) {
00243             printf("femu: write spare I/O error ?\n");
00244             return U_FAIL;
00245         }
00246     }
00247 
00248     fflush(emu->fp);
00249     dev->st.spareWriteCount++;
00250 
00251     return U_SUCC;
00252 }
00253 
00254 
00255 static URET femu_ReadPage(uffs_Device *dev, u32 block, u32 pageNum, u8 *data, u8 *spare)
00256 {
00257     int ret;
00258     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00259     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00260     pgdSize = dev->attr.page_data_size;
00261     spSize = dev->attr.spare_size;
00262     blkPgs = dev->attr.pages_per_block;
00263     blks = dev->attr.total_blocks;
00264     blkSize = dev->attr.block_data_size;
00265 
00266     if(data)
00267     {
00268         ret = femu_ReadPageData(dev, block, pageNum, data, 0, pgdSize);
00269         if(ret == U_FAIL) return U_FAIL;
00270     }
00271     
00272     if(spare)
00273     {
00274         ret = femu_ReadPageSpare(dev, block, pageNum, spare, 0, spSize);
00275         if(ret == U_FAIL) return U_FAIL;
00276     }
00277 
00278     return U_SUCC;  
00279 }
00280 
00281 static URET femu_ReadPageData(uffs_Device *dev, u32 block, u32 pageNum, u8 *page, int ofs, int len)
00282 {
00283     int nread;
00284     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00285     femu_private *emu;
00286     emu = (femu_private *)(dev->private);
00287     if (!emu || !(emu->fp)) return U_FAIL;
00288 
00289     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00290     pgdSize = dev->attr.page_data_size;
00291     spSize = dev->attr.spare_size;
00292     blkPgs = dev->attr.pages_per_block;
00293     blks = dev->attr.total_blocks;
00294     blkSize = dev->attr.block_data_size;
00295 
00296     if(ofs + len > pgdSize) {
00297         printf("femu: read page data out of range!\n");
00298         return U_FAIL;
00299     }
00300     
00301     if(page) {
00302         fseek(emu->fp, (block*blkPgs + pageNum) * (pgdSize + spSize) + ofs, SEEK_SET);
00303         nread = fread(page, 1, len, emu->fp);
00304         
00305         if(nread != len) {
00306             printf("femu: read page I/O error ?\n");
00307             return U_FAIL;
00308         }
00309     }
00310 
00311     dev->st.pageReadCount++;
00312 
00313     return U_SUCC;
00314 }
00315 
00316 static URET femu_ReadPageSpare(uffs_Device *dev, u32 block, u32 pageNum, u8 *spare, int ofs, int len)
00317 {
00318     int nread;
00319     int pos;
00320     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00321     femu_private *emu;
00322     emu = (femu_private *)(dev->private);
00323     if (!emu || !(emu->fp)) return U_FAIL;
00324 
00325     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00326     pgdSize = dev->attr.page_data_size;
00327     spSize = dev->attr.spare_size;
00328     blkPgs = dev->attr.pages_per_block;
00329     blks = dev->attr.total_blocks;
00330     blkSize = dev->attr.block_data_size;
00331     
00332 //  printf("RS: %d/%d, size %d\n", block, pageNum, len);
00333 
00334     if(ofs + len > spSize) {
00335         printf("femu: read page spare out of range!\n");
00336         return U_FAIL;
00337     }
00338 
00339     if(spare) {
00340         pos = (block*blkPgs + pageNum) * (pgdSize + spSize) + PAGE_DATA_SIZE + ofs;
00341         if(fseek(emu->fp, pos, SEEK_SET) != 0) {
00342             printf("femu: seek to %d fail!\n", pos);
00343             return U_FAIL;
00344         }
00345         nread= fread(spare, 1, len, emu->fp);
00346         
00347         if(nread != len) {
00348             printf("femu: read spare I/O error ?\n");
00349             return U_FAIL;
00350         }
00351     }   
00352 
00353     dev->st.spareReadCount++;
00354         
00355     return U_SUCC;
00356 }
00357 
00358 
00359 
00360 static URET femu_EraseBlock(uffs_Device *dev, u32 blockNumber)
00361 {
00362 
00363     int i;
00364     u8 * pg = em_page_buf;
00365     int pgSize, pgdSize, spSize, blks, blkPgs, blkSize;
00366     femu_private *emu;
00367     emu = (femu_private *)(dev->private);
00368     if (!emu || !(emu->fp)) return U_FAIL;
00369 
00370     pgSize = dev->attr.page_data_size + dev->attr.spare_size;
00371     pgdSize = dev->attr.page_data_size;
00372     spSize = dev->attr.spare_size;
00373     blkPgs = dev->attr.pages_per_block;
00374     blks = dev->attr.total_blocks;
00375     blkSize = dev->attr.block_data_size;
00376     
00377     printf("femu: erase block %d\n", blockNumber);
00378 
00379     if((int)blockNumber >= blks) {
00380         printf("Attempt to erase non-existant block %d\n",blockNumber);
00381         return U_FAIL;
00382     }
00383     else {
00384         //clear this block monitors
00385         memset(em_monitor_page + (blockNumber * blkPgs), 
00386             0, 
00387             blkPgs * sizeof(u8));
00388         memset(em_monitor_spare + (blockNumber * blkPgs),
00389             0,
00390             blkPgs * sizeof(u8));
00391         
00392         memset(pg, 0xff, (pgdSize + spSize));
00393         
00394         fseek(emu->fp, blockNumber * blkPgs * (pgdSize + spSize), SEEK_SET);
00395         
00396         for(i = 0; i < blkPgs; i++) {
00397             fwrite(pg, 1, (pgdSize + spSize), emu->fp);
00398         }
00399 
00400         fflush(emu->fp);
00401         dev->st.blockEraseCount++;
00402 
00403         return U_SUCC;
00404     }
00405     
00406 }
00407 
00408 static URET femu_ResetFlash(uffs_Device *dev)
00409 {
00410     return U_SUCC;
00411 }
00412 
00413 static UBOOL femu_IsBlockBad(uffs_Device *dev, u32 block)
00414 {
00415     //this function is called when formating flash device
00416 
00417     char mark;
00418     mark = 0;
00419     femu_ReadPageSpare(dev, block, 0, &mark, 5, 1);
00420     if (mark == 0xff) {
00421         femu_ReadPageSpare(dev, block, 1, &mark, 5, 1);
00422         if (mark == 0xff) {
00423             return U_FALSE;
00424         }
00425     }
00426 
00427     return U_TRUE;
00428 }
00429 
00431 
00432 static uffs_DevOps emu_DevOps = {
00433     femu_ResetFlash,
00434     femu_IsBlockBad, 
00435     femu_EraseBlock,
00436     femu_WritePage,
00437     femu_WritePageData,
00438     femu_WritePageSpare,
00439     femu_ReadPage,
00440     femu_ReadPageData,
00441     femu_ReadPageSpare,
00442 };
00443 
00444 
00445 static URET femu_initDevice(uffs_Device *dev)
00446 {
00447     uffs_Perror(UFFS_ERR_NORMAL, PFX "femu device init.\n");
00448 
00449 #ifdef USE_NATIVE_MEMORY_ALLOCATOR
00450     if (uffs_initNativeMemAllocator(dev) != U_SUCC) {
00451         uffs_Perror(UFFS_ERR_SERIOUS, PFX"Init native memory allocator fail!\n");
00452         return U_FAIL;
00453     }
00454 #endif
00455     dev->attr.dev_type =    UFFS_DEV_EMU;           /* dev_type */
00456     dev->attr.maker = 0xec;                         /* simulate Samsung: 0xEC */
00457     dev->attr.id = 0xe3;                            /* chip id */
00458     dev->attr.total_blocks = TOTAL_BLOCKS;          /* total blocks */
00459     dev->attr.block_data_size = BLOCK_DATA_SIZE;    /* block data size */
00460     dev->attr.page_data_size = PAGE_DATA_SIZE;      /* page data size */
00461     dev->attr.spare_size = PAGE_SPARE_SIZE;         /* page spare size */
00462     dev->attr.pages_per_block = PAGES_PER_BLOCK;    /* pages per block */
00463     dev->ops = &emu_DevOps;                         /* EMU device operations */
00464 
00465     CheckInit(dev);
00466 
00467     return U_SUCC;
00468 }
00469 
00470 static void femu_printStatistic(uffs_Device *dev)
00471 {
00472     uffs_stat *s;
00473     s = &(dev->st);
00474     
00475     printf("-----------statistics-----------\n");
00476     printf("Block Erased: %d\n", s->blockEraseCount);
00477     printf("Write Page:   %d\n", s->pageWriteCount);
00478     printf("Write Spare:  %d\n", s->spareWriteCount);
00479     printf("Read Page:    %d\n", s->pageReadCount);
00480     printf("Read Spare:   %d\n", s->spareReadCount);
00481     printf("Disk total:   %d\n", uffs_GetDeviceTotal(dev));
00482     printf("Disk Used:    %d\n", uffs_GetDeviceUsed(dev));
00483     printf("Disk Free:    %d\n", uffs_GetDeviceFree(dev));
00484 }
00485 
00486 static URET femu_releaseDevice(uffs_Device *dev)
00487 {
00488     femu_private *emu;
00489 #ifdef USE_NATIVE_MEMORY_ALLOCATOR
00490     int count;  
00491 #endif
00492 
00493     uffs_Perror(UFFS_ERR_NORMAL, PFX "femu device release.\n");
00494 
00495     emu = (femu_private *)(dev->private);
00496 
00497     emu->initCount--;
00498     if(emu->initCount == 0) {
00499         if (emu->fp) {
00500             fclose(emu->fp);
00501             emu->fp = NULL;
00502         }
00503         femu_printStatistic(dev);
00504         memset(emu, 0, sizeof(femu_private));
00505 
00506 #ifdef USE_NATIVE_MEMORY_ALLOCATOR
00507         count = uffs_releaseNativeMemAllocator(dev);
00508         if (count < 0) {
00509             uffs_Perror(UFFS_ERR_SERIOUS, PFX"Release native memory allocator fail!\n");
00510         }
00511         else if (count > 0) {
00512             uffs_Perror(UFFS_ERR_NORMAL, PFX"Find %d block memory leak!\n", count);
00513         }
00514 #endif
00515 
00516     }
00517     return U_SUCC;
00518 }
00519 
00520 uffs_Device uffs_femuDev = {
00521     femu_initDevice,
00522     femu_releaseDevice,
00523     (void *)(&g_femu_priv),
00524 };
00525 
00526 

Generated on Sat Mar 17 15:45:44 2007 for uffs-doc by  doxygen 1.5.0