-// NAND Simulator for testing YAFFS\r
-\r
-#include <string.h>\r
-\r
-#include "yramsim.h"\r
-\r
-#include "yaffs_nandif.h"\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
- return 0;\r
- }\r
-\r
- if(!sym->blockList[blockId]){\r
- return 0;\r
- }\r
-\r
- if(!force && !sym->blockList[blockId]->blockOk){\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
- 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
- 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
- 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
- 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
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2010 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * NAND Simulator for testing YAFFS
+ */
+
+#include <string.h>
+
+#include "yramsim.h"
+
+#include "yaffs_nandif.h"
+
+
+#define DATA_SIZE 2048
+#define SPARE_SIZE 64
+#define PAGE_SIZE (DATA_SIZE + SPARE_SIZE)
+#define PAGES_PER_BLOCK 64
+
+
+typedef struct {
+ unsigned char page[PAGES_PER_BLOCK][PAGE_SIZE];
+ unsigned blockOk;
+} Block;
+
+typedef struct {
+ Block **blockList;
+ int nBlocks;
+} SimData;
+
+
+SimData *simDevs[N_RAM_SIM_DEVS];
+
+static SimData *DevToSim(struct yaffs_dev *dev)
+{
+ ynandif_Geometry *geom = (ynandif_Geometry *)(dev->driver_context);
+ SimData * sim = (SimData*)(geom->privateData);
+ return sim;
+}
+
+
+static void CheckInitialised(void)
+{
+
+}
+
+static int yramsim_erase_internal(SimData *sim, unsigned blockId,int force)
+{
+ if(blockId < 0 || blockId >= sim->nBlocks){
+ return 0;
+ }
+
+ if(!sim->blockList[blockId]){
+ return 0;
+ }
+
+ if(!force && !sim->blockList[blockId]->blockOk){
+ return 0;
+ }
+
+ memset(sim->blockList[blockId],0xff,sizeof(Block));
+ sim->blockList[blockId]->blockOk = 1;
+
+ return 1;
+}
+
+
+
+
+static int yramsim_initialise(struct yaffs_dev *dev)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+ return blockList != NULL;
+}
+
+
+static int yramsim_deinitialise(struct yaffs_dev *dev)
+{
+ return 1;
+}
+
+static int yramsim_rd_chunk (struct yaffs_dev *dev, unsigned pageId,
+ unsigned char *data, unsigned dataLength,
+ unsigned char *spare, unsigned spareLength,
+ int *eccStatus)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+
+ unsigned blockId = pageId / PAGES_PER_BLOCK;
+ unsigned pageOffset = pageId % PAGES_PER_BLOCK;
+ unsigned char * d;
+ unsigned char *s;
+ if(blockId >= sim->nBlocks ||
+ pageOffset >= PAGES_PER_BLOCK ||
+ dataLength >DATA_SIZE ||
+ spareLength > SPARE_SIZE ||
+ !eccStatus ||
+ !blockList[blockId]->blockOk){
+ return 0;
+ }
+
+ d = blockList[blockId]->page[pageOffset];
+ s = d + DATA_SIZE;
+
+ if(data)
+ memcpy(data,d,dataLength);
+
+ if(spare)
+ memcpy(spare,s,spareLength);
+
+ *eccStatus = 0; // 0 = no error, -1 = unfixable error, 1 = fixable
+
+ return 1;
+}
+
+static int yramsim_wr_chunk (struct yaffs_dev *dev,unsigned pageId,
+ const unsigned char *data, unsigned dataLength,
+ const unsigned char *spare, unsigned spareLength)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+
+ unsigned blockId = pageId / PAGES_PER_BLOCK;
+ unsigned pageOffset = pageId % PAGES_PER_BLOCK;
+ unsigned char * d;
+ unsigned char *s;
+ if(blockId >= sim->nBlocks ||
+ pageOffset >= PAGES_PER_BLOCK ||
+ dataLength >DATA_SIZE ||
+ spareLength > SPARE_SIZE ||
+ !blockList[blockId]->blockOk){
+ return 0;
+ }
+
+ d = blockList[blockId]->page[pageOffset];
+ s = d + DATA_SIZE;
+
+ if(data)
+ memcpy(d,data,dataLength);
+
+ if(spare)
+ memcpy(s,spare,spareLength);
+
+ return 1;
+}
+
+
+static int yramsim_erase(struct yaffs_dev *dev,unsigned blockId)
+{
+ SimData *sim = DevToSim(dev);
+
+ CheckInitialised();
+ return yramsim_erase_internal(sim,blockId,0);
+}
+
+static int yramsim_check_block_ok(struct yaffs_dev *dev,unsigned blockId)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+ if(blockId >= sim->nBlocks){
+ return 0;
+ }
+
+ return blockList[blockId]->blockOk ? 1 : 0;
+}
+
+static int yramsim_mark_block_bad(struct yaffs_dev *dev,unsigned blockId)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+ if(blockId >= sim->nBlocks){
+ return 0;
+ }
+
+ blockList[blockId]->blockOk = 0;
+
+ return 1;
+}
+
+
+static SimData *yramsim_alloc_sim_data(u32 devId, u32 nBlocks)
+{
+ int ok = 1;
+
+ Block **blockList;
+ SimData *sim;
+ Block *b;
+ u32 i;
+
+ if(devId >= N_RAM_SIM_DEVS)
+ return NULL;
+
+ sim = simDevs[devId];
+
+ if(sim)
+ return sim;
+
+ sim = malloc(sizeof (SimData));
+ if(!sim)
+ return NULL;
+
+ simDevs[devId] = sim;
+
+ blockList = malloc(nBlocks * sizeof(Block *));
+
+ sim->blockList = blockList;
+ sim->nBlocks = nBlocks;
+ if(!blockList){
+ free(sim);
+ return NULL;
+ }
+
+ for(i = 0; i < nBlocks; i++)
+ blockList[i] = NULL;
+
+ for(i = 0; i < nBlocks && ok; i++){
+ b= malloc(sizeof(Block));
+ if(b){
+ blockList[i] = b;
+ yramsim_erase_internal(sim,i,1);
+ }
+ else
+ ok = 0;
+ }
+
+ if(!ok){
+ for(i = 0; i < nBlocks; i++)
+ if(blockList[i]){
+ free(blockList[i]);
+ blockList[i] = NULL;
+ }
+ free(blockList);
+ blockList = NULL;
+ free(sim);
+ sim = NULL;
+ }
+
+ return sim;
+}
+
+
+struct yaffs_dev *yramsim_CreateRamSim(const YCHAR *name,
+ u32 devId, u32 nBlocks,
+ u32 start_block, u32 end_block)
+{
+ SimData *sim;
+ ynandif_Geometry *g;
+
+ sim = yramsim_alloc_sim_data(devId, nBlocks);
+
+ g = YMALLOC(sizeof(ynandif_Geometry));
+
+ if(!sim || !g){
+ if(g)
+ YFREE(g);
+ return NULL;
+ }
+
+ if(start_block >= sim->nBlocks)
+ start_block = 0;
+ if(end_block == 0 || end_block >= sim->nBlocks)
+ end_block = sim->nBlocks - 1;
+
+ memset(g,0,sizeof(ynandif_Geometry));
+ g->start_block = start_block;
+ g->end_block = end_block;
+ g->dataSize = DATA_SIZE;
+ g->spareSize= SPARE_SIZE;
+ g->pagesPerBlock = PAGES_PER_BLOCK;
+ g->hasECC = 1;
+ g->inband_tags = 0;
+ g->useYaffs2 = 1;
+ g->initialise = yramsim_initialise;
+ g->deinitialise = yramsim_deinitialise;
+ g->readChunk = yramsim_rd_chunk,
+ g->writeChunk = yramsim_wr_chunk,
+ g->eraseBlock = yramsim_erase,
+ g->checkBlockOk = yramsim_check_block_ok,
+ g->markBlockBad = yramsim_mark_block_bad,
+ g->privateData = (void *)sim;
+
+ return yaffs_add_dev_from_geometry(name,g);
}