Set up a test framework.
[yaffs2.git] / direct / test-framework / yramsim.c
diff --git a/direct/test-framework/yramsim.c b/direct/test-framework/yramsim.c
new file mode 100644 (file)
index 0000000..10c9c07
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 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)
+{
+       struct ynandif_Geometry *geom = 
+               (struct 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;
+       struct ynandif_Geometry *g;
+
+       sim = yramsim_alloc_sim_data(devId, nBlocks);
+
+       g = malloc(sizeof(*g));
+
+       if(!sim || !g){
+               if(g)
+                       free(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(*g));
+       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);
+}