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
00020 #if 1
00021 #define PAGES_PER_BLOCK 32
00022 #define PAGE_DATA_SIZE 512
00023 #define PAGE_SPARE_SIZE 16
00024
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];
00046 static u8 em_monitor_spare[TOTAL_BLOCKS * PAGES_PER_BLOCK];
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
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
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
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
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
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;
00456 dev->attr.maker = 0xec;
00457 dev->attr.id = 0xe3;
00458 dev->attr.total_blocks = TOTAL_BLOCKS;
00459 dev->attr.block_data_size = BLOCK_DATA_SIZE;
00460 dev->attr.page_data_size = PAGE_DATA_SIZE;
00461 dev->attr.spare_size = PAGE_SPARE_SIZE;
00462 dev->attr.pages_per_block = PAGES_PER_BLOCK;
00463 dev->ops = &emu_DevOps;
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