--- /dev/null
+// NAND Simulator for testing YAFFS\r
+\r
+#include <string.h>\r
+\r
+#include "yramsim.h"\r
+\r
+#include "yaffs_nandif.h"\r
+\r
+\r
+#ifdef __WINCE__\r
+#include <windows.h>\r
+#else\r
+#define DebugBreak() do { } while(0)\r
+#endif\r
+\r
+\r
+#define DATA_SIZE 2048\r
+#define SPARE_SIZE 64\r
+#define PAGE_SIZE (DATA_SIZE + SPARE_SIZE)\r
+#define PAGES_PER_BLOCK 64\r
+\r
+\r
+typedef struct {\r
+ unsigned char page[PAGES_PER_BLOCK][PAGE_SIZE];\r
+ unsigned blockOk;\r
+} Block;\r
+\r
+typedef struct {\r
+ Block **blockList;\r
+ int nBlocks;\r
+} SymData;\r
+\r
+\r
+static SymData *DevToSym(yaffs_Device *dev)\r
+{\r
+ ynandif_Geometry *geom = (ynandif_Geometry *)(dev->driverContext);\r
+ SymData * sym = (SymData*)(geom->privateData);\r
+ return sym;\r
+} \r
+\r
+\r
+static void CheckInitialised(void)\r
+{\r
+\r
+}\r
+\r
+static int yramsim_EraseBlockInternal(SymData *sym, unsigned blockId,int force)\r
+{\r
+ if(blockId < 0 || blockId >= sym->nBlocks){\r
+ DebugBreak();\r
+ return 0;\r
+ }\r
+\r
+ if(!sym->blockList[blockId]){\r
+ DebugBreak();\r
+ return 0;\r
+ }\r
+\r
+ if(!force && !sym->blockList[blockId]->blockOk){\r
+ DebugBreak();\r
+ return 0;\r
+ }\r
+\r
+ memset(sym->blockList[blockId],0xff,sizeof(Block));\r
+ sym->blockList[blockId]->blockOk = 1;\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+\r
+\r
+static int yramsim_Initialise(yaffs_Device *dev)\r
+{\r
+ SymData *sym = DevToSym(dev);\r
+ Block **blockList = sym->blockList;\r
+ return blockList != NULL;\r
+}\r
+\r
+\r
+static int yramsim_Deinitialise(yaffs_Device *dev)\r
+{\r
+ return 1;\r
+}\r
+\r
+static int yramsim_ReadChunk (yaffs_Device *dev, unsigned pageId, \r
+ unsigned char *data, unsigned dataLength,\r
+ unsigned char *spare, unsigned spareLength,\r
+ int *eccStatus)\r
+{\r
+ SymData *sym = DevToSym(dev);\r
+ Block **blockList = sym->blockList;\r
+\r
+ unsigned blockId = pageId / PAGES_PER_BLOCK;\r
+ unsigned pageOffset = pageId % PAGES_PER_BLOCK;\r
+ unsigned char * d;\r
+ unsigned char *s;\r
+ if(blockId >= sym->nBlocks ||\r
+ pageOffset >= PAGES_PER_BLOCK ||\r
+ dataLength >DATA_SIZE ||\r
+ spareLength > SPARE_SIZE ||\r
+ !eccStatus ||\r
+ !blockList[blockId]->blockOk){\r
+ DebugBreak();\r
+ return 0;\r
+ }\r
+\r
+ d = blockList[blockId]->page[pageOffset];\r
+ s = d + DATA_SIZE;\r
+\r
+ if(data)\r
+ memcpy(data,d,dataLength);\r
+\r
+ if(spare)\r
+ memcpy(spare,s,spareLength);\r
+\r
+ *eccStatus = 0; // 0 = no error, -1 = unfixable error, 1 = fixable\r
+\r
+ return 1;\r
+ \r
+}\r
+\r
+static int yramsim_WriteChunk (yaffs_Device *dev,unsigned pageId, \r
+ const unsigned char *data, unsigned dataLength,\r
+ const unsigned char *spare, unsigned spareLength)\r
+{\r
+ SymData *sym = DevToSym(dev);\r
+ Block **blockList = sym->blockList;\r
+\r
+ unsigned blockId = pageId / PAGES_PER_BLOCK;\r
+ unsigned pageOffset = pageId % PAGES_PER_BLOCK;\r
+ unsigned char * d;\r
+ unsigned char *s;\r
+ if(blockId >= sym->nBlocks ||\r
+ pageOffset >= PAGES_PER_BLOCK ||\r
+ dataLength >DATA_SIZE ||\r
+ spareLength > SPARE_SIZE ||\r
+ !blockList[blockId]->blockOk){\r
+ DebugBreak();\r
+ return 0;\r
+ }\r
+\r
+ d = blockList[blockId]->page[pageOffset];\r
+ s = d + DATA_SIZE;\r
+\r
+ if(data)\r
+ memcpy(d,data,dataLength);\r
+\r
+ if(spare)\r
+ memcpy(s,spare,spareLength);\r
+\r
+ return 1;\r
+ \r
+}\r
+\r
+\r
+static int yramsim_EraseBlock(yaffs_Device *dev,unsigned blockId)\r
+{\r
+ SymData *sym = DevToSym(dev);\r
+\r
+ CheckInitialised();\r
+ return yramsim_EraseBlockInternal(sym,blockId,0);\r
+}\r
+\r
+static int yramsim_CheckBlockOk(yaffs_Device *dev,unsigned blockId)\r
+{\r
+ SymData *sym = DevToSym(dev);\r
+ Block **blockList = sym->blockList;\r
+ if(blockId >= sym->nBlocks){\r
+ DebugBreak();\r
+ return 0;\r
+ }\r
+\r
+ return blockList[blockId]->blockOk ? 1 : 0;\r
+}\r
+\r
+static int yramsim_MarkBlockBad(yaffs_Device *dev,unsigned blockId)\r
+{\r
+ SymData *sym = DevToSym(dev);\r
+ Block **blockList = sym->blockList;\r
+ if(blockId >= sym->nBlocks){\r
+ DebugBreak();\r
+ return 0;\r
+ }\r
+\r
+ blockList[blockId]->blockOk = 0;\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+static SymData *yramsim_AllocSymData(int nBlocks)\r
+{\r
+ int ok = 1;\r
+\r
+ Block **blockList;\r
+ SymData *sym;\r
+ Block *b;\r
+ int i;\r
+\r
+ sym = malloc(sizeof (SymData));\r
+ if(!sym)\r
+ return NULL;\r
+\r
+ blockList = malloc(nBlocks * sizeof(Block *));\r
+ \r
+ sym->blockList = blockList;\r
+ sym->nBlocks = nBlocks;\r
+ if(!blockList){\r
+ free(sym);\r
+ return NULL;\r
+ }\r
+\r
+ for(i = 0; i < nBlocks; i++)\r
+ blockList[i] = NULL;\r
+\r
+ for(i = 0; i < nBlocks && ok; i++){\r
+ b= malloc(sizeof(Block));\r
+ if(b){\r
+ blockList[i] = b;\r
+ yramsim_EraseBlockInternal(sym,i,1);\r
+ }\r
+ else\r
+ ok = 0;\r
+ }\r
+\r
+ if(!ok){\r
+ for(i = 0; i < nBlocks; i++)\r
+ if(blockList[i]){\r
+ free(blockList[i]);\r
+ blockList[i] = NULL;\r
+ }\r
+ free(blockList);\r
+ blockList = NULL;\r
+ free(sym);\r
+ sym = NULL;\r
+ }\r
+\r
+ return sym;\r
+}\r
+\r
+\r
+struct yaffs_DeviceStruct *yramsim_CreateSim(const YCHAR *name,int nBlocks)\r
+{\r
+ void *sym = (void *)yramsim_AllocSymData(nBlocks);\r
+ ynandif_Geometry *g;\r
+\r
+ g = YMALLOC(sizeof(ynandif_Geometry));\r
+ \r
+ if(!sym || !g){\r
+ if(sym)\r
+ YFREE(sym);\r
+ if(g)\r
+ YFREE(g);\r
+ return NULL;\r
+ }\r
+\r
+ memset(g,0,sizeof(ynandif_Geometry));\r
+ g->startBlock = 0;\r
+ g->endBlock = nBlocks - 1;\r
+ g->dataSize = DATA_SIZE;\r
+ g->spareSize= SPARE_SIZE;\r
+ g->pagesPerBlock = PAGES_PER_BLOCK;\r
+ g->hasECC = 1;\r
+ g->inbandTags = 0;\r
+ g->useYaffs2 = 1;\r
+ g->initialise = yramsim_Initialise;\r
+ g->deinitialise = yramsim_Deinitialise; \r
+ g->readChunk = yramsim_ReadChunk, \r
+ g->writeChunk = yramsim_WriteChunk,\r
+ g->eraseBlock = yramsim_EraseBlock,\r
+ g->checkBlockOk = yramsim_CheckBlockOk,\r
+ g->markBlockBad = yramsim_MarkBlockBad,\r
+ g->privateData = sym;\r
+\r
+ return yaffs_AddDeviceFromGeometry(name,g);\r
+}