Add nand driver that works with a nand simulator
authorCharles Manning <cdhmanning@gmail.com>
Tue, 7 May 2013 04:04:57 +0000 (16:04 +1200)
committerCharles Manning <cdhmanning@gmail.com>
Tue, 7 May 2013 04:04:57 +0000 (16:04 +1200)
Signed-off-by: Charles Manning <cdhmanning@gmail.com>
16 files changed:
direct/test-framework/FrameworkRules.mk
direct/test-framework/nand_chip.h [new file with mode: 0644]
direct/test-framework/nand_store.h [new file with mode: 0644]
direct/test-framework/nanddrv.c [new file with mode: 0644]
direct/test-framework/nanddrv.h [new file with mode: 0644]
direct/test-framework/nandsim.c [new file with mode: 0644]
direct/test-framework/nandsim.h [new file with mode: 0644]
direct/test-framework/nandsim_file.c [new file with mode: 0644]
direct/test-framework/nandsim_file.h [new file with mode: 0644]
direct/test-framework/nandstore_file.c [new file with mode: 0644]
direct/test-framework/nandstore_file.h [new file with mode: 0644]
direct/test-framework/tests/init_fw_update_test_nand.sh
direct/test-framework/tests/run_fw_update_test_nand.sh
direct/test-framework/yaffs_nand_drv.c [new file with mode: 0644]
direct/test-framework/yaffs_nand_drv.h [new file with mode: 0644]
direct/test-framework/yaffscfg2k.c

index 52cd4da..29eb44d 100644 (file)
@@ -37,6 +37,9 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o\
                 yaffs_checkptrw.o  yaffs_qsort.o\
                 yaffs_nameval.o yaffs_attribs.o \
                 yaffs_m18_drv.o  yaffs_nor_drv.o ynorsim.o \
+                yaffs_nand_drv.o \
+                nanddrv.o nandsim.o \
+                nandsim_file.o nandstore_file.o \
                 yaffs_allocator.o \
                 yaffs_bitmap.o \
                 yaffs_yaffs1.o \
@@ -77,7 +80,10 @@ FRAMEWORKEXTRASYMLINKS = \
                yaffscfg2k.c yaffs_fileem2k.c yaffs_fileem2k.h\
                yaffs_fileem.c yaffs_m18_drv.c yaffs_m18_drv.h \
                yaffs_nor_drv.c yaffs_nor_drv.h \
+               yaffs_nand_drv.c yaffs_nand_drv.h \
                yaffs_ramdisk.c yaffs_ramdisk.h yaffs_ramem2k.c \
+               nand_chip.h nanddrv.c nanddrv.h nandsim.c nandsim.h nand_store.h \
+               nandsim_file.c nandsim_file.h nandstore_file.c nandstore_file.h \
                ynorsim.h ynorsim.c yaffs_osglue.c
 
 FRAMEWORK_SOURCES = $(YAFFSDIRECTSYMLINKS) $(FRAMEWORKEXTRASYMLINKS)
diff --git a/direct/test-framework/nand_chip.h b/direct/test-framework/nand_chip.h
new file mode 100644 (file)
index 0000000..c0c8f1d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *
+ * 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 Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAND_CHIP_H__
+#define __NAND_CHIP_H__
+
+#include <stdint.h>
+
+struct nand_chip {
+       void *private_data;
+
+       void (*set_ale)(struct nand_chip * this, int high);
+       void (*set_cle)(struct nand_chip * this, int high);
+
+       unsigned (*read_cycle)(struct nand_chip * this);
+       void (*write_cycle)(struct nand_chip * this, unsigned b);
+
+       int (*check_busy)(struct nand_chip * this);
+       void (*idle_fn) (struct nand_chip *this);
+       int (*power_check) (struct nand_chip *this);
+
+       int blocks;
+       int pages_per_block;
+       int data_bytes_per_page;
+       int spare_bytes_per_page;
+       int bus_width_shift;
+};
+#endif
diff --git a/direct/test-framework/nand_store.h b/direct/test-framework/nand_store.h
new file mode 100644 (file)
index 0000000..431ec1a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *
+ * 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 Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAND_STORE_H__
+#define __NAND_STORE_H__
+
+struct nand_store {
+       void *private_data;
+
+       int (*store)(struct nand_store *this, int page,
+                       const unsigned char * buffer);
+       int (*retrieve)(struct nand_store *this, int page,
+                       unsigned char * buffer);
+       int (*erase)(struct nand_store *this, int block);
+       int (*shutdown)(struct nand_store *this);
+
+       int blocks;
+       int pages_per_block;
+       int data_bytes_per_page;
+       int spare_bytes_per_page;
+};
+#endif
diff --git a/direct/test-framework/nanddrv.c b/direct/test-framework/nanddrv.c
new file mode 100644 (file)
index 0000000..5fb05c0
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2010-2011 Aleph One Ltd.
+ *
+ * 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.
+ */
+
+
+#include "nanddrv.h"
+#include "nand_chip.h"
+
+int nanddrv_initialise(void)
+{
+       return 0;
+}
+
+static void nanddrv_send_addr(struct nand_chip *this, int page, int offset)
+{
+       this->set_ale(this,1);
+       if(offset >= 0){
+           this->write_cycle(this, offset & 0xff);
+           this->write_cycle(this, (offset>>8) & 0x0f);
+       }
+
+       if(page >= 0){
+           this->write_cycle(this, page & 0xff);
+           this->write_cycle(this, (page>>8) & 0xff);
+           this->write_cycle(this, (page>>16) & 0xff);
+       }
+       this->set_ale(this,0);
+}
+
+static void nanddrv_send_cmd(struct nand_chip *this, unsigned char cmd)
+{
+       this->set_cle(this, 1);
+       this->write_cycle(this, cmd);
+       this->set_cle(this, 0);
+}
+
+
+static inline int nanddrv_status_pass(unsigned char status)
+{
+       /* If bit 0 is zero then pass, if 1 then fail */
+       return (status & (1 << 0)) == 0;
+}
+
+static inline int nanddrv_status_busy(unsigned char status)
+{
+       /* If bit 6 is zero then busy, if 1 then ready */
+       return (status & (1 << 6)) == 0;
+}
+
+static unsigned char nanddrv_get_status(struct nand_chip *this,
+                                       int wait_not_busy)
+{
+       unsigned char status;
+
+       nanddrv_send_cmd(this, 0x70);
+       status = this->read_cycle(this) & 0xff;
+       if(!wait_not_busy)
+               return status;
+       while (nanddrv_status_busy(status)) {
+               status = this->read_cycle(this) & 0xff;
+       }
+       return status;
+}
+
+int nanddrv_read_tr(struct nand_chip *this, int page,
+               struct nanddrv_transfer *tr, int n_tr)
+{
+       unsigned char status;
+       int ncycles;
+       unsigned char *buffer;
+
+       if(n_tr < 1)
+               return 0;
+
+       nanddrv_send_cmd(this, 0x00);
+       nanddrv_send_addr(this, page, tr->offset);
+       nanddrv_send_cmd(this, 0x30);
+       status = nanddrv_get_status(this, 1);
+       if(!nanddrv_status_pass(status))
+               return -1;
+       nanddrv_send_cmd(this, 0x30);
+       while (1) {
+               if(this->bus_width_shift == 0) {
+                       unsigned char *buffer = tr->buffer;
+
+                       ncycles = tr->nbytes;
+                       while (ncycles> 0) {
+                               *buffer = this->read_cycle(this);
+                               ncycles--;
+                               buffer++;
+                       }
+               } else {
+                       unsigned short *buffer = tr->buffer;
+
+                       ncycles = tr->nbytes >> 1;
+                       while (ncycles> 0) {
+                               *buffer = this->read_cycle(this);
+                               ncycles--;
+                               buffer++;
+                       }
+               }
+               n_tr--;
+               tr++;
+               if(n_tr < 1)
+                       break;
+               nanddrv_send_cmd(this, 0x05);
+               nanddrv_send_addr(this, -1, tr->offset);
+               nanddrv_send_cmd(this, 0xE0);
+       }
+       return 0;
+}
+
+
+/*
+ * Program page
+ * Cmd: 0x80, 5-byte address, data bytes,  Cmd: 0x10, wait not busy
+ */
+int nanddrv_write_tr(struct nand_chip *this, int page,
+               struct nanddrv_transfer *tr, int n_tr)
+{
+       unsigned char status;
+       int ncycles;
+
+       if (n_tr < 1)
+               return 0;
+
+       nanddrv_send_cmd(this, 0x80);
+       nanddrv_send_addr(this, page, tr->offset);
+       while (1) {
+               if(this->bus_width_shift == 0) {
+                       unsigned char *buffer = tr->buffer;
+
+                       ncycles = tr->nbytes;
+                       while (ncycles> 0) {
+                               this->write_cycle(this, *buffer);
+                               ncycles--;
+                               buffer++;
+                       }
+               } else {
+                       unsigned short *buffer = tr->buffer;
+
+                       ncycles = tr->nbytes >> 1;
+                       while (ncycles> 0) {
+                               this->write_cycle(this, *buffer);
+                               ncycles--;
+                               buffer++;
+                       }
+               }
+               n_tr--;
+               tr++;
+               if (n_tr < 1)
+                       break;
+               nanddrv_send_cmd(this, 0x85);
+               nanddrv_send_addr(this, -1, tr->offset);
+       }
+
+       if(this->power_check && this->power_check(this) < 0)
+               return -1;
+
+       nanddrv_send_cmd(this, 0x10);
+       status = nanddrv_get_status(this, 1);
+       if(nanddrv_status_pass(status))
+               return 0;
+       return -1;
+}
+
+/*
+ * Block erase
+ * Cmd: 0x60, 3-byte address, cmd: 0xD0. Wait not busy.
+ */
+int nanddrv_erase(struct nand_chip *this, int block)
+{
+       unsigned char status;
+
+       nanddrv_send_cmd(this, 0x60);
+       nanddrv_send_addr(this, block * this->pages_per_block, -1);
+
+       if(this->power_check && this->power_check(this) < 0)
+               return -1;
+
+       nanddrv_send_cmd(this, 0xD0);
+       status = nanddrv_get_status(this, 1);
+       if(nanddrv_status_pass(status))
+               return 0;
+       return -1;
+}
+
+
+
diff --git a/direct/test-framework/nanddrv.h b/direct/test-framework/nanddrv.h
new file mode 100644 (file)
index 0000000..5b8e8e7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *
+ * 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 Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAND_DRIVER_H__
+#define __NAND_DRIVER_H__
+#include "nand_chip.h"
+
+struct nanddrv_transfer {
+       unsigned char *buffer;
+       int offset;
+       int nbytes;
+};
+
+int nanddrv_read_tr(struct nand_chip *this, int page,
+               struct nanddrv_transfer *tr, int n_tr);
+int nanddrv_write_tr(struct nand_chip *this, int page,
+               struct nanddrv_transfer *tr, int n_tr);
+int nanddrv_erase(struct nand_chip *this, int block);
+
+#endif
+
diff --git a/direct/test-framework/nandsim.c b/direct/test-framework/nandsim.c
new file mode 100644 (file)
index 0000000..9c8a6fe
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2010-2011 Aleph One Ltd.
+ *
+ * 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 modelled on a Samsung K9K2G08U0A 8-bit, but capable of
+ * simulating x16 access too.
+ *
+ * Page size 2k + 64
+ * Block size 64 pages
+ * Dev size 256 Mbytes
+ */
+
+#include "nandsim.h"
+#include "nand_chip.h"
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int nandsim_debug = 0;
+
+#define debug(n, fmt, ...) \
+       do { \
+       if (n <= nandsim_debug) \
+               printf(fmt, ## __VA_ARGS__); \
+       } while (0)
+
+
+
+struct nandsim_private {
+
+       struct nand_store *store;
+       /*
+       * Access buffers.
+       * Address buffer has two parts to it:
+       * 2 byte column (byte) offset
+       * 3 byte row (page) offset
+       */
+
+       unsigned char *buffer;
+       int buff_size;
+
+       unsigned char addr_buffer[5];
+
+       /*
+       * Offsets used to access address, read or write buffer.
+       * If the offset is negative then accessing is illegal.
+       */
+
+       int addr_offset;
+       int addr_expected;
+       int addr_received;
+
+       int read_offset;
+       int write_offset;
+       int read_started;
+
+       /*
+       * busy_count: If greater than zero then the device is busy.
+       * Busy count is decremented by check_busy() and by read_status()
+       */
+       int busy_count;
+       int write_prog_error;
+       int reading_status;
+       unsigned char last_cmd_byte;
+
+       int ale;
+       int cle;
+};
+
+static void last_cmd(struct nandsim_private *ns, unsigned char val)
+{
+       ns->last_cmd_byte = val;
+}
+
+static void check_last(struct nandsim_private *ns,
+                       unsigned char should_be, int line)
+{
+       if(ns->last_cmd_byte != should_be)
+               debug(1, "At line %d:, last_cmd should be %02x, but is %02x\n",
+                       line, should_be, ns->last_cmd_byte);
+}
+
+static void idle(struct nandsim_private *ns, int line)
+{
+       ns->read_offset = -1;
+       ns->write_offset = -1;
+       ns->addr_offset = -1;
+       ns->addr_expected = -1;
+       ns->addr_received = -1;
+       last_cmd(ns, 0xff);
+       ns->busy_count = 0;
+       ns->reading_status = 0;
+       ns->read_started = 0;
+}
+
+
+static void expect_address(struct nandsim_private *ns,
+                       int nbytes, int line)
+{
+       int from;
+       switch (nbytes) {
+       case 2:
+       case 5: /* contains an offset */
+               from = 0;
+               break;
+       case 3: /* no offset */
+               from = 2;
+               break;
+       default:
+               debug(1, "expect_address illegal nbytes %d called at line %d\n",
+                               nbytes, line);
+               return;
+       }
+
+       ns->addr_offset = from;
+       ns->addr_expected = nbytes;
+       ns->addr_received = 0;
+       debug(1, "Expect %d address bytes\n",nbytes);
+}
+
+static int get_page_address(struct nandsim_private *ns)
+{
+       int addr;
+
+       addr = (ns->addr_buffer[2]) |
+               (ns->addr_buffer[3] << 8) |
+               (ns->addr_buffer[4] << 16);
+       return addr;
+}
+
+static int get_page_offset(struct nandsim_private *ns)
+{
+       int offs;
+
+       offs = (ns->addr_buffer[0]) |
+               (ns->addr_buffer[1] << 8);
+       return offs;
+}
+
+static void check_address(struct nandsim_private *ns, int nbytes, int line)
+{
+       if(ns->addr_expected != 0)
+               debug(1, "Still expecting %d address bytes at line: %d\n",
+                                       ns->addr_expected, line);
+       if(ns->addr_received != nbytes)
+               debug(1, "Only received %d address bytes instead of %d at line %d\n",
+                                       ns->addr_received, nbytes, line);
+}
+
+static void set_offset(struct nandsim_private *ns)
+{
+       ns->read_offset = -1;
+       ns->write_offset = -1;
+
+       if(ns->last_cmd_byte == 0x80 )
+               ns->write_offset = get_page_offset(ns);
+       else if(ns->last_cmd_byte == 0x00 || ns->last_cmd_byte == 0x05)
+               ns->read_offset = get_page_offset(ns);
+       debug(2, "Last command was %02X offsets set to read %d write %d\n",
+                       ns->last_cmd_byte, ns->read_offset, ns->write_offset);
+}
+
+static void load_read_buffer(struct nandsim_private *ns)
+{
+       int addr = get_page_address(ns);
+       debug(1, "Store read at address %d\n", addr);
+       ns->store->retrieve(ns->store, addr,ns->buffer);
+}
+static void save_write_buffer(struct nandsim_private *ns)
+{
+       int addr = get_page_address(ns);
+       debug(1, "Store write at address %d\n", addr);
+       ns->store->store(ns->store, addr, ns->buffer);
+}
+
+static void check_read_buffer(struct nandsim_private *ns, int line)
+{
+}
+
+static void end_cmd(struct nandsim_private *ns, int line)
+{
+       ns->last_cmd_byte = 0xff;
+}
+
+static void set_busy(struct nandsim_private *ns, int cycles, int line)
+{
+       ns->busy_count = cycles;
+}
+
+static int check_not_busy(struct nandsim_private *ns, int line)
+{
+       if(ns->busy_count > 0)
+               debug(1, "Busy check failed at line %d\n",line);
+       return (ns->busy_count < 1);
+}
+
+/*
+ * Reset
+ * Cmd: 0xff
+ */
+static void reset_0(struct nandsim_private *ns)
+{
+       debug(2, "Reset\n");
+       last_cmd(ns, 0xff);
+       idle(ns, __LINE__);
+       end_cmd(ns, __LINE__);
+}
+
+/*
+ * Read
+ * cmd: 0x00, 5 address bytes, cmd: 0x30, wait not busy, read out data
+ *
+ * Note that 0x30 can also be used to exit the status reading state
+ * and return to data reading state.
+ *
+ * The following sequence uses the busy pin to wait:
+ *
+ *  Write cmd 0x00
+ *  Write 5 address bytes
+ *  Write cmd 0x30. Device now goes busy
+ *  Wait for busy pin to go idle
+ *  Read data bytes.
+ *
+ * The following sequence uses the status read to wait:
+ *  Write cmd 0x00
+ *  Write 5 address bytes
+ *  Write cmd 0x30. Device now goes busy
+ *  Write 0x70: (status)
+ *  Read status until device no longer busy
+ *  Write command byte 0x30 to exit status read. Can now read data
+ *  Read data bytes.
+
+ */
+
+
+static void read_0(struct nandsim_private *ns)
+{
+       debug(2, "Read 0\n");
+       check_last(ns, 0xff, __LINE__);
+       if(check_not_busy(ns, __LINE__))
+               ns->reading_status = 0;
+       expect_address(ns, 5, __LINE__);
+       last_cmd(ns, 0x00);
+       ns->read_started = 1;
+}
+
+static void read_1(struct nandsim_private *ns)
+{
+       debug(2, "Read 1\n");
+       if(check_not_busy(ns, __LINE__))
+               ns->reading_status = 0;
+       if(ns->read_started){
+               /* Doing a read */
+               ns->read_started = 0;
+               check_address(ns, 5, __LINE__);
+               load_read_buffer(ns);
+               set_busy(ns, 2, __LINE__);
+               end_cmd(ns, __LINE__);
+       } else {
+               /* reenter read mode after a status check */
+               end_cmd(ns, __LINE__);
+       }
+}
+
+/*
+ * Random Data Output (sets read position in current page)
+ * Cmd: 0x05, 2-byte address, cmd: 0xE0. No busy
+ */
+
+static void random_data_output_0(struct nandsim_private *ns)
+{
+       debug(2, "Random data out 0\n");
+       check_last(ns, 0xff, __LINE__);
+       if(check_not_busy(ns, __LINE__))
+               ns->reading_status = 0;
+       check_read_buffer(ns, __LINE__);
+       expect_address(ns, 2, __LINE__);
+       last_cmd(ns, 0x05);
+}
+
+static void random_data_output_1(struct nandsim_private *ns)
+{
+       debug(2, "Random data out 1\n");
+       check_last(ns, 0x05, __LINE__);
+       check_address(ns, 2, __LINE__);
+}
+
+
+/*
+ * Program page
+ * Cmd: 0x80, 5-byte address, data bytes,  Cmd: 0x10, wait not busy
+ * That can be extended with random data input by inserting
+ * any number of random data input cycles before the 0x10 command
+ * Each random data input cycle is
+ *  Cmd 0x85 , 2 byte offset, data bytes
+ */
+
+static void program_0(struct nandsim_private *ns)
+{
+       debug(2, "Program 0\n");
+       check_last(ns, 0xff, __LINE__);
+       if(check_not_busy(ns, __LINE__))
+               ns->reading_status = 0;
+       expect_address(ns, 5, __LINE__);
+       memset(ns->buffer, 0xff, ns->buff_size);
+       last_cmd(ns, 0x80);
+}
+static void random_data_input(struct nandsim_private *ns)
+{
+       debug(2, "Random data input\n");
+       check_last(ns, 0x80, __LINE__);
+       expect_address(ns, 2, __LINE__);
+       last_cmd(ns, 0x80);
+}
+
+static void program_1(struct nandsim_private *ns)
+{
+       debug(2, "Program 1\n");
+       if(check_not_busy(ns, __LINE__))
+               ns->reading_status = 0;
+       check_last(ns, 0x80, __LINE__);
+       check_address(ns, 5, __LINE__);
+       save_write_buffer(ns);
+       set_busy(ns, 2, __LINE__);
+       end_cmd(ns, __LINE__);
+}
+
+
+
+/*
+ * Block erase
+ * Cmd: 0x60, 3-byte address, cmd: 0xD0. Wait not busy.
+ */
+static void block_erase_0(struct nandsim_private *ns)
+{
+       debug(2, "Block Erase 0\n");
+       check_last(ns, 0xff, __LINE__);
+       if(check_not_busy(ns, __LINE__))
+               ns->reading_status = 0;
+       expect_address(ns, 3, __LINE__);
+       last_cmd(ns, 0x60);
+}
+
+static void block_erase_1(struct nandsim_private *ns)
+{
+       int addr;
+
+       debug(2, "Block Erase 1\n");
+       check_last(ns, 0x60, __LINE__);
+       if(check_not_busy(ns, __LINE__))
+               ns->reading_status = 0;
+       check_address(ns, 3, __LINE__);
+       set_busy(ns, 5, __LINE__);
+       addr = get_page_address(ns);
+       debug(1, "Erasing block at address %d\n", addr);
+       ns->store->erase(ns->store, addr);
+       end_cmd(ns, __LINE__);
+}
+/*
+ * Read stuatus
+ * Cmd 0x70
+ */
+static void read_status(struct nandsim_private *ns)
+{
+       debug(2, "Read status\n");
+       ns->reading_status = 1;
+}
+
+static void read_id(struct nandsim_private *ns)
+{
+}
+
+
+static void unsupported(struct nandsim_private *ns)
+{
+}
+
+static void nandsim_cl_write(struct nandsim_private *ns, unsigned char val)
+{
+       debug(2, "CLE write %02X\n",val);
+       switch(val){
+               case 0x00:
+                       read_0(ns);
+                       break;
+               case 0x05:
+                       random_data_output_0(ns);
+                       break;
+               case 0x10:
+                       program_1(ns);
+                       break;
+               case 0x15:
+                       unsupported(ns);
+                       break;
+               case 0x30:
+                       read_1(ns);
+                       break;
+               case 0x35:
+                       unsupported(ns);
+                       break;
+               case 0x60:
+                       block_erase_0(ns);
+                       break;
+               case 0x70:
+                       read_status(ns);
+                       break;
+               case 0x80:
+                       program_0(ns);
+                       break;
+               case 0x85:
+                       random_data_input(ns);
+                       break;
+               case 0x90:
+                       read_id(ns);
+                       break;
+               case 0xD0:
+                       block_erase_1(ns);
+                       break;
+               case 0xE0:
+                       random_data_output_1(ns);
+                       break;
+               case 0xFF:
+                       reset_0(ns);
+                       break;
+               default:
+                       debug(1, "CLE written with invalid value %02X.\n",val);
+                       break;
+                       /* Valid codes that we don't handle */
+                       debug(1, "CLE written with invalid value %02X.\n",val);
+       }
+}
+
+
+static void nandsim_al_write(struct nandsim_private *ns, unsigned char val)
+{
+       check_not_busy(ns, __LINE__);
+       if(ns->addr_expected < 1 ||
+               ns->addr_offset < 0 ||
+               ns->addr_offset >= sizeof(ns->addr_buffer)){
+               debug(1, "Address write when not expected\n");
+       } else {
+               debug(1, "Address write when expecting %d bytes\n",
+                       ns->addr_expected);
+               ns->addr_buffer[ns->addr_offset] = val;
+               ns->addr_offset++;
+               ns->addr_received++;
+               ns->addr_expected--;
+               if(ns->addr_expected == 0)
+                       set_offset(ns);
+       }
+}
+
+static void nandsim_dl_write(struct nandsim_private *ns, 
+                               unsigned val,
+                               int bus_width_shift)
+{
+       check_not_busy(ns, __LINE__);
+       if( ns->write_offset < 0 || ns->write_offset >= ns->buff_size){
+               debug(1, "Write at illegal buffer offset %d\n",
+                               ns->write_offset);
+       } else if(bus_width_shift == 0) {
+               ns->buffer[ns->write_offset] = val & 0xff;
+               ns->write_offset++;
+       } else if(bus_width_shift == 1) {
+               ns->buffer[ns->write_offset] = val & 0xff;
+               ns->write_offset++;
+               ns->buffer[ns->write_offset] = (val>>8) & 0xff;
+               ns->write_offset++;
+       }
+}
+
+static unsigned nandsim_dl_read(struct nandsim_private *ns,
+                               int bus_width_shift)
+{
+       unsigned retval;
+       if(ns->reading_status){
+               /*
+                * bit 0 == 0 pass, == 1 fail.
+                * bit 6 == 0 busy, == 1 ready
+                */
+               retval = 0xfe;
+               if(ns->busy_count > 0){
+                       ns->busy_count--;
+                       retval&= ~(1<<6);
+               }
+               if(ns->write_prog_error)
+                       retval |= ~(1<<-0);
+               debug(2, "Read status returning %02X\n",retval);
+       } else if(ns->busy_count > 0){
+               debug(1, "Read while still busy\n");
+               retval = 0;
+       } else if(ns->read_offset < 0 || ns->read_offset >= ns->buff_size){
+               debug(1, "Read with no data available\n");
+               retval = 0;
+       } else if(bus_width_shift == 0){
+               retval = ns->buffer[ns->read_offset];
+               ns->read_offset++;
+       } else if(bus_width_shift == 1){
+               retval = ns->buffer[ns->read_offset];
+               ns->read_offset++;
+               retval |= (((unsigned)ns->buffer[ns->read_offset]) << 8);
+               ns->read_offset++;
+       }
+
+       return retval;
+}
+
+
+static struct nandsim_private *
+nandsim_init_private(struct nand_store *store)
+{
+       struct nandsim_private *ns;
+       unsigned char *buffer;
+       int buff_size;
+
+       buff_size = (store->data_bytes_per_page + store->spare_bytes_per_page);
+
+       ns = malloc(sizeof(struct nandsim_private));
+       buffer = malloc(buff_size);
+       if(!ns || !buffer){
+               free(ns);
+               free(buffer);
+               return NULL;
+       }
+
+       memset(ns, 0, sizeof(struct nandsim_private));
+       ns->buffer = buffer;
+       ns->buff_size = buff_size;
+       ns->store = store;
+       idle(ns, __LINE__);
+       return ns;
+}
+
+
+static void nandsim_set_ale(struct nand_chip * this, int ale)
+{
+       struct nandsim_private *ns =
+               (struct nandsim_private *)this->private_data;
+       ns->ale = ale;
+}
+
+static void nandsim_set_cle(struct nand_chip * this, int cle)
+{
+       struct nandsim_private *ns =
+               (struct nandsim_private *)this->private_data;
+       ns->cle = cle;
+}
+
+static unsigned nandsim_read_cycle(struct nand_chip * this)
+{
+       unsigned retval;
+       struct nandsim_private *ns =
+               (struct nandsim_private *)this->private_data;
+
+       if (ns->cle || ns->ale){
+               debug(1, "Read cycle with CLE %s and ALE %s\n",
+                       ns->cle ? "high" : "low",
+                       ns->ale ? "high" : "low");
+               retval = 0;
+       } else {
+               retval =nandsim_dl_read(ns, this->bus_width_shift);
+       }
+       debug(5, "Read cycle returning %02X\n",retval);
+       return retval;
+}
+
+static void nandsim_write_cycle(struct nand_chip * this, unsigned b)
+{
+       struct nandsim_private *ns =
+               (struct nandsim_private *)this->private_data;
+       const char *x;
+
+       if(ns->ale && ns->cle)
+               x = "ALE AND CLE";
+       else if (ns->ale)
+               x = "ALE";
+       else if (ns->cle)
+               x = "CLE";
+       else
+               x = "data";
+
+       debug(5, "Write %02x to %s\n",
+                       b, x);
+       if (ns->cle && ns->ale)
+               debug(1, "Write cycle with both ALE and CLE high\n");
+       else if (ns->cle)
+               nandsim_cl_write(ns, b);
+       else if (ns->ale)
+               nandsim_al_write(ns, b);
+       else
+               nandsim_dl_write(ns, b, this->bus_width_shift);
+}
+
+static int nandsim_check_busy(struct nand_chip * this)
+{
+       struct nandsim_private *ns =
+               (struct nandsim_private *)this->private_data;
+
+
+       if (ns->busy_count> 0){
+               ns->busy_count--;
+               debug(2, "Still busy\n");
+               return 1;
+       } else {
+               debug(2, "Not busy\n");
+               return 0;
+       }
+}
+
+static void nandsim_idle_fn(struct nand_chip *this)
+{
+       struct nandsim_private *ns =
+               (struct nandsim_private *)this->private_data;
+       ns = ns;
+}
+
+struct nand_chip *nandsim_init(struct nand_store *store, int bus_width_shift)
+{
+       struct nand_chip *chip = NULL;
+       struct nandsim_private *ns = NULL;
+
+       chip = malloc(sizeof(struct nand_chip));
+       ns = nandsim_init_private(store);
+
+       if(chip && ns){
+               memset(chip, 0, sizeof(struct nand_chip));;
+
+               chip->private_data = ns;
+               chip->set_ale = nandsim_set_ale;
+               chip->set_cle = nandsim_set_cle;
+               chip->read_cycle = nandsim_read_cycle;
+               chip->write_cycle = nandsim_write_cycle;
+               chip->check_busy = nandsim_check_busy;
+               chip->idle_fn = nandsim_idle_fn;
+
+               chip->bus_width_shift = bus_width_shift;
+
+               chip->blocks = ns->store->blocks;
+               chip->pages_per_block = ns->store->pages_per_block;
+               chip->data_bytes_per_page = ns->store->data_bytes_per_page;
+               chip->spare_bytes_per_page = ns->store->spare_bytes_per_page;
+
+               return chip;
+       } else {
+               free(chip);
+               free(ns);
+               return NULL;
+       }
+}
+
+void nandsim_set_debug(int d)
+{
+       nandsim_debug = d;
+}
diff --git a/direct/test-framework/nandsim.h b/direct/test-framework/nandsim.h
new file mode 100644 (file)
index 0000000..77d256d
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *
+ * 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 Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAND_SIM_H__
+#define __NAND_SIM_H__
+#include "nand_store.h"
+#include "nand_chip.h"
+struct nand_chip *nandsim_init(struct nand_store *store, int bus_width_shift);
+void nandsim_set_debug(int d);
+#endif
diff --git a/direct/test-framework/nandsim_file.c b/direct/test-framework/nandsim_file.c
new file mode 100644 (file)
index 0000000..f5940a2
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2010-2011 Aleph One Ltd.
+ *
+ * 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.
+ */
+
+#include "nandsim_file.h"
+#include "nandstore_file.h"
+#include "nandsim.h"
+#include <unistd.h>
+
+
+struct nand_chip *nandsim_file_init(const char *fname,
+                               int blocks,
+                               int pages_per_block,
+                               int data_bytes_per_page,
+                               int spare_bytes_per_page,
+                               int bus_width_shift)
+{
+       struct nand_store *store = NULL;
+       struct nand_chip *chip = NULL;
+
+       store = nandstore_file_init(fname, blocks, pages_per_block,
+                                       data_bytes_per_page,
+                                       spare_bytes_per_page);
+       if(store)
+               chip = nandsim_init(store, bus_width_shift);
+
+       if(chip)
+               return chip;
+
+       if(store){
+               /* tear down */
+       }
+       return NULL;
+}
diff --git a/direct/test-framework/nandsim_file.h b/direct/test-framework/nandsim_file.h
new file mode 100644 (file)
index 0000000..2db2b92
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *
+ * 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 Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAND_SIM_FILE_H__
+#define __NAND_SIM_FILE_H__
+#include "nand_chip.h"
+struct nand_chip *nandsim_file_init(const char *fname,
+                               int blocks,
+                               int pages_per_block,
+                               int data_bytes_per_page,
+                               int spare_bytes_per_page,
+                               int bus_width_shift);
+#endif
diff --git a/direct/test-framework/nandstore_file.c b/direct/test-framework/nandstore_file.c
new file mode 100644 (file)
index 0000000..1b9b70b
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2010-2011 Aleph One Ltd.
+ *
+ * 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 modelled on a Samsung K9K2G08U0A 8-bit
+ *
+ *  Need to implement basic commands first:
+ *  Status
+ *  Reset
+ *  Read
+ *  Random read (ie set read position within current page)
+ *  Write
+ *  Erase
+ */
+
+#include "nandstore_file.h"
+#include "nand_store.h"
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int random_seed;
+extern int simulate_power_failure;
+static int remaining_ops;
+static int nops_so_far;
+
+struct nandstore_file_private {
+       char backing_file[500];
+       int handle;
+       unsigned char * buffer;
+       int buff_size;
+};
+
+static void maybe_power_fail(unsigned int nand_chunk, int fail_point)
+{
+
+   nops_so_far++;
+
+   remaining_ops--;
+   if(simulate_power_failure &&
+      remaining_ops < 1){
+       printf("Simulated power failure after %d operations\n",nops_so_far);
+       printf("  power failed on nand_chunk %d, at fail point %d\n",
+                               nand_chunk, fail_point);
+       exit(0);
+  }
+}
+
+static void power_fail_init(void)
+{
+       remaining_ops = (rand() % 1000) * 5;
+}
+
+static int nandstore_file_store(struct nand_store *this, int page,
+                               const unsigned char * buffer)
+{
+       struct nandstore_file_private *nsfp =
+               (struct nandstore_file_private *)this->private_data;
+       int pos = nsfp->buff_size * page;
+       int i;
+
+       maybe_power_fail(page, __LINE__);
+
+       lseek(nsfp->handle, pos, SEEK_SET);
+       read(nsfp->handle, nsfp->buffer, nsfp->buff_size);
+       for(i = 0; i < nsfp->buff_size; i++)
+               nsfp->buffer[i] &= buffer[i];
+       lseek(nsfp->handle, pos, SEEK_SET);
+       write(nsfp->handle, nsfp->buffer, nsfp->buff_size);
+
+       maybe_power_fail(page, __LINE__);
+
+       return 0;
+}
+
+static int nandstore_file_retrieve(struct nand_store *this, int page,
+                               unsigned char * buffer)
+{
+       struct nandstore_file_private *nsfp =
+               (struct nandstore_file_private *)this->private_data;
+
+       lseek(nsfp->handle, nsfp->buff_size * page, SEEK_SET);
+       read(nsfp->handle, buffer, nsfp->buff_size);
+       return 0;
+}
+static int nandstore_file_erase(struct nand_store *this, int page)
+{
+       int block = page / this->pages_per_block;
+       struct nandstore_file_private *nsfp =
+               (struct nandstore_file_private *)this->private_data;
+       int i;
+
+       maybe_power_fail(page, __LINE__);
+
+       lseek(nsfp->handle,
+               block * nsfp->buff_size * this->pages_per_block, SEEK_SET);
+       memset(nsfp->buffer, 0xff, nsfp->buff_size);
+       for(i = 0; i < this->pages_per_block; i++)
+               write(nsfp->handle, nsfp->buffer, nsfp->buff_size);
+       return 0;
+}
+
+static int nandstore_file_shutdown(struct nand_store *this)
+{
+       struct nandstore_file_private *nsfp =
+               (struct nandstore_file_private *)this->private_data;
+       close(nsfp->handle);
+       nsfp->handle = -1;
+       return 0;
+}
+
+struct nand_store *
+nandstore_file_init(const char *fname,
+                               int blocks,
+                               int pages_per_block,
+                               int data_bytes_per_page,
+                               int spare_bytes_per_page)
+{
+       int fsize;
+       int nbytes;
+       int i;
+       struct nand_store *ns;
+       struct nandstore_file_private *nsfp;
+       unsigned char *buffer;
+       int buff_size = data_bytes_per_page + spare_bytes_per_page;
+
+       ns = malloc(sizeof(struct nand_store));
+       nsfp = malloc(sizeof(struct nandstore_file_private));
+       buffer = malloc(buff_size);
+
+
+       if (!ns || !nsfp || !buffer) {
+               free(ns);
+               free(nsfp);
+               free(buffer);
+               return NULL;
+       }
+
+       memset(ns, 0, sizeof(*ns));
+       memset(nsfp, 0, sizeof(*nsfp));
+       nsfp->buffer = buffer;
+       nsfp->buff_size = buff_size;
+       ns->private_data = nsfp;
+
+       ns->store = nandstore_file_store;
+       ns->retrieve = nandstore_file_retrieve;
+       ns->erase = nandstore_file_erase;
+       ns->shutdown = nandstore_file_shutdown;
+
+       ns->blocks = blocks;
+       ns->pages_per_block = pages_per_block;
+       ns->data_bytes_per_page = data_bytes_per_page;
+       ns->spare_bytes_per_page = spare_bytes_per_page;
+
+       strncpy(nsfp->backing_file, fname, sizeof(nsfp->backing_file));
+
+       nsfp->handle = open(nsfp->backing_file, O_RDWR | O_CREAT);
+       if(nsfp->handle >=0){
+               fsize = lseek(nsfp->handle,0,SEEK_END);
+               nbytes = ns->blocks * ns->pages_per_block *
+                       (ns->data_bytes_per_page + ns->spare_bytes_per_page);
+               if (fsize != nbytes) {
+                       printf("Initialising backing file.\n");
+                       ftruncate(nsfp->handle,0);
+                       for(i = 0; i < ns->blocks; i++)
+                               nandstore_file_erase(ns,
+                                       i * ns->pages_per_block);
+               }
+       }
+
+       power_fail_init();
+
+       return ns;
+
+
+}
+
diff --git a/direct/test-framework/nandstore_file.h b/direct/test-framework/nandstore_file.h
new file mode 100644 (file)
index 0000000..4f2c136
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *
+ * 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 Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __NAND_STORE_FILE_H__
+#define __NAND_STORE_FILE_H__
+
+#include "nand_store.h"
+
+struct nand_store *
+nandstore_file_init(const char *fname,
+                               int blocks,
+                               int pages_per_block,
+                               int data_bytes_per_page,
+                               int spare_bytes_per_page);
+
+#endif
index 648313a..7575e76 100755 (executable)
@@ -1,6 +1,7 @@
 #!/bin/bash
 # Run this to initialise the file system for the test runs.
    rm seed-nand-*
-   rm emfile-2k-*
-   ./yaffs_test  -u -i yaffs2
+   rm emfile-nand-*
+   ./yaffs_test  -u -i nand
+  
 
index 70747a1..cd2c0fc 100755 (executable)
@@ -21,15 +21,9 @@ do
    rm -f seed-nand-*$j
    echo $seed>seed-nand-for-run-$i
 
-   rm -f emfile-2k-0-*$j
-   rm -f emfile-2k-1-*$j
-   rm -f emfile-2k-2-*$j
-   rm -f emfile-2k-3-*$j
+   rm -f emfile-nand-*$j
 
-   cp emfile-2k-0 emfile-2k-0-$i
-   cp emfile-2k-1 emfile-2k-1-$i
-   cp emfile-2k-2 emfile-2k-2-$i
-   cp emfile-2k-3 emfile-2k-3-$i
+   cp emfile-nand emfile-nand-$j
 
    echo "#########"
    echo "#########"
@@ -38,5 +32,5 @@ do
    echo "#########"
    echo "#########"
    echo "#########"
-   ./yaffs_test -u -f -p -s$seed -t 0 yaffs2 >log-nand-$i
+   ./yaffs_test -u -f -p -s$seed -t 0 nand >log-nand-$i
 done
diff --git a/direct/test-framework/yaffs_nand_drv.c b/direct/test-framework/yaffs_nand_drv.c
new file mode 100644 (file)
index 0000000..6b3a91e
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ */
+
+/*
+ * This is an interface module for handling NAND in yaffs2 mode.
+ */
+
+/* This code calls a driver that accesses "generic" NAND. In the simulator
+ * this is direceted at a file-backed NAND simulator. The NAND access functions
+ * should also work with real NAND.
+ *
+ * This driver is designed for use in yaffs2 mode with a 2k page size and
+ * 64 bytes of spare.
+ *
+ * The spare ares is used as follows:
+ * offset 0: 2 bytes bad block marker.
+ * offset 2: 8x3 bytes of ECC over the data.
+ * offset 26: rest available to store Yaffs tags etc.
+ */
+
+#include "yaffs_nand_drv.h"
+#include "yportenv.h"
+#include "yaffs_trace.h"
+
+#include "nand_store.h"
+#include "yaffs_flashif.h"
+#include "yaffs_guts.h"
+#include "nanddrv.h"
+#include "yaffs_ecc.h"
+
+struct nand_context {
+       struct nand_chip *chip;
+       u8 *buffer;
+};
+
+
+static inline struct nand_chip *dev_to_chip(struct yaffs_dev *dev)
+{
+       struct nand_context *ctxt =
+               (struct nand_context *)(dev->driver_context);
+       return ctxt->chip;
+}
+
+static inline u8 *dev_to_buffer(struct yaffs_dev *dev)
+{
+       struct nand_context *ctxt =
+               (struct nand_context *)(dev->driver_context);
+       return ctxt->buffer;
+}
+
+static int yaffs_nand_drv_WriteChunk(struct yaffs_dev *dev, int nand_chunk,
+                                  const u8 *data, int data_len,
+                                  const u8 *oob, int oob_len)
+{
+       struct nand_chip *chip = dev_to_chip(dev);
+       u8 *buffer = dev_to_buffer(dev);
+       u8 *e;
+       struct nanddrv_transfer tr[2];
+       int i;
+
+       if(!data || !oob)
+               return YAFFS_FAIL;
+
+
+       /* Calc ECC and marshall the oob bytes into the buffer */
+
+       memset(buffer, 0xff, chip->spare_bytes_per_page);
+
+       for(i = 0, e = buffer + 2; i < chip->data_bytes_per_page; i+=256, e+=3)
+               yaffs_ecc_calc(data + i, e);
+
+       memcpy(buffer + 26, oob, oob_len);
+
+       /* Set up and execute transfer */
+
+       tr[0].buffer = data;
+       tr[0].offset = 0;
+       tr[0].nbytes = data_len;
+
+       tr[1].buffer = buffer;
+       tr[1].offset = chip->data_bytes_per_page;
+       tr[1].nbytes = chip->spare_bytes_per_page;
+
+       if(nanddrv_write_tr(chip, nand_chunk, tr, 2) == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+static int yaffs_nand_drv_ReadChunk(struct yaffs_dev *dev, int nand_chunk,
+                                  u8 *data, int data_len,
+                                  u8 *oob, int oob_len,
+                                  enum yaffs_ecc_result *ecc_result_out)
+{
+       struct nand_chip *chip = dev_to_chip(dev);
+       u8 *buffer = dev_to_buffer(dev);
+       struct nanddrv_transfer tr[2];
+       struct nanddrv_transfer *trp = tr;
+       int n_tr = 0;
+       int ret;
+       enum yaffs_ecc_result ecc_result;
+       int i;
+       u8 *e;
+       u8 read_ecc[3];
+
+       if(data) {
+               trp->buffer = data;
+               trp->offset = 0;
+               trp->nbytes = data_len;
+               n_tr++;
+               trp++;
+       }
+
+
+       trp->buffer = buffer;
+       trp->offset = chip->data_bytes_per_page;
+       trp->nbytes = chip->spare_bytes_per_page;
+       n_tr++;
+       trp++;
+
+
+       ret = nanddrv_read_tr(chip, nand_chunk, tr, n_tr);
+
+       if(ret < 0) {
+               if (ecc_result_out)
+                       *ecc_result_out = YAFFS_ECC_RESULT_UNKNOWN;
+               return YAFFS_FAIL;
+       }
+
+       /* Do ECC and marshalling */
+       if(oob)
+               memcpy(oob, buffer + 26, oob_len);
+
+       ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+#if 0
+       if(data) {
+               for(i = 0, e = buffer + 2; i < chip->data_bytes_per_page; i+=256, e+=3) {
+                       yaffs_ecc_calc(data + i, read_ecc);
+                       ret = yaffs_ecc_correct(data + i, e, read_ecc);
+                       if (ret < 0)
+                               ecc_result = YAFFS_ECC_RESULT_UNFIXED;
+                       else if( ret > 0 && ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
+                               ecc_result = YAFFS_ECC_RESULT_FIXED;
+               }
+       }
+#endif
+
+       if (ecc_result_out)
+               *ecc_result_out = ecc_result;
+
+       return YAFFS_OK;
+}
+
+static int yaffs_nand_drv_EraseBlock(struct yaffs_dev *dev, int block_no)
+{
+       struct nand_chip *chip = dev_to_chip(dev);
+
+       if(nanddrv_erase(chip, block_no) == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+static int yaffs_nand_drv_MarkBad(struct yaffs_dev *dev, int block_no)
+{
+       struct nand_chip *chip = dev_to_chip(dev);
+       u8 *buffer = dev_to_buffer(dev);
+       int nand_chunk = block_no * chip->pages_per_block;
+       struct nanddrv_transfer tr[1];
+
+       memset(buffer, 0xff, chip->spare_bytes_per_page);
+       buffer[0] = 'Y';
+       buffer[1] = 'Y';
+
+       tr[0].buffer = buffer;
+       tr[0].offset = chip->data_bytes_per_page;
+       tr[0].nbytes = chip->spare_bytes_per_page;
+
+       if(nanddrv_write_tr(chip, nand_chunk, tr, 1) == 0)
+               return YAFFS_OK;
+       else
+               return YAFFS_FAIL;
+}
+
+static int yaffs_nand_drv_CheckBad(struct yaffs_dev *dev, int block_no)
+{
+       struct nand_chip *chip = dev_to_chip(dev);
+       u8 *buffer = dev_to_buffer(dev);
+       int nand_chunk = block_no * chip->pages_per_block;
+       int ret;
+
+       struct nanddrv_transfer tr[1];
+
+       memset(buffer, 0, chip->spare_bytes_per_page);
+
+       tr[0].buffer = buffer;
+       tr[0].offset = chip->data_bytes_per_page;
+       tr[0].nbytes = chip->spare_bytes_per_page;
+
+       ret = nanddrv_read_tr(chip, nand_chunk, tr, 1);
+
+       /* Check that bad block marker is not set */
+       if(yaffs_hweight8(buffer[0]) + yaffs_hweight8(buffer[1]) < 14)
+               return YAFFS_FAIL;
+       else
+               return YAFFS_OK;
+
+}
+
+static int yaffs_nand_drv_Initialise(struct yaffs_dev *dev)
+{
+       struct nand_chip *chip = dev_to_chip(dev);
+
+       return YAFFS_OK;
+}
+
+static int yaffs_nand_drv_Deinitialise(struct yaffs_dev *dev)
+{
+       struct nand_chip *chip = dev_to_chip(dev);
+
+       return YAFFS_OK;
+}
+
+#include "nandsim_file.h"
+
+struct yaffs_dev *yaffs_nandsim_install_drv(const char *name,
+                                       const char *file_name,
+                                       int n_blocks)
+{
+       struct yaffs_dev *dev;
+       char *name_copy = NULL;
+       struct yaffs_param *param;
+       struct yaffs_driver *drv;
+       struct nand_chip *chip = NULL;
+       struct nand_context *ctxt = NULL;
+       u8 *buffer = NULL;
+
+       dev = malloc(sizeof(struct yaffs_dev));
+       ctxt = malloc(sizeof(struct nand_context));
+       name_copy = strdup(name);
+
+       if(!dev || !ctxt || !name_copy)
+               goto fail;
+
+       chip = nandsim_file_init(file_name, n_blocks, 64, 2048, 64, 0);
+       if(!chip)
+               goto fail;
+
+       buffer = malloc(chip->spare_bytes_per_page);
+
+       if(!buffer)
+               goto fail;
+
+       param = &dev->param;
+       drv = &dev->drv;
+
+       memset(dev, 0, sizeof(*dev));
+       memset(ctxt, 0, sizeof(*ctxt));
+
+       param->name = name_copy;
+
+       param->total_bytes_per_chunk = chip->data_bytes_per_page;
+       param->chunks_per_block = chip->pages_per_block;
+       param->n_reserved_blocks = 5;
+       param->start_block = 0; // Can use block 0
+       param->end_block = chip->blocks - 1; // Last block
+       param->is_yaffs2 = 1;
+       param->use_nand_ecc = 1;
+       param->n_caches = 10;
+
+       drv->drv_write_chunk_fn = yaffs_nand_drv_WriteChunk;
+       drv->drv_read_chunk_fn = yaffs_nand_drv_ReadChunk;
+       drv->drv_erase_fn = yaffs_nand_drv_EraseBlock;
+       drv->drv_mark_bad_fn = yaffs_nand_drv_MarkBad;
+       drv->drv_check_bad_fn = yaffs_nand_drv_CheckBad;
+       drv->drv_initialise_fn = yaffs_nand_drv_Initialise;
+       drv->drv_deinitialise_fn = yaffs_nand_drv_Deinitialise;
+
+       ctxt->chip = chip;
+       ctxt->buffer = buffer;
+       dev->driver_context = (void *) ctxt;
+
+       yaffs_add_device(dev);
+
+       return dev;
+
+fail:
+       free(dev);
+       free(ctxt);
+       free(name_copy);
+       free(buffer);
+       return NULL;
+}
diff --git a/direct/test-framework/yaffs_nand_drv.h b/direct/test-framework/yaffs_nand_drv.h
new file mode 100644 (file)
index 0000000..3e93644
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_NAND_DRV_H__
+#define __YAFFS_NAND_DRV_H__
+
+struct nand_store;
+
+struct yaffs_dev *
+       yaffs_nand_install_drv(const char *name,
+                               struct nand_store *ns);
+
+struct yaffs_dev *yaffs_nandsim_install_drv(const char *name,
+                                       const char *file_name,
+                                       int n_blocks);
+
+#endif
index 9e24866..005a02d 100644 (file)
@@ -49,6 +49,7 @@ unsigned yaffs_trace_mask =
 #include "yaffs_flashif2.h"
 #include "yaffs_m18_drv.h"
 #include "yaffs_nor_drv.h"
+#include "yaffs_nand_drv.h"
 
 int yaffs_start_up(void)
 {
@@ -62,12 +63,11 @@ int yaffs_start_up(void)
        // Stuff to initialise anything special (eg lock semaphore).
        yaffsfs_OSInitialisation();
 
+       yflash2_install_drv("yflash2");
 
        yaffs_m18_install_drv("M18-1");
        yaffs_nor_install_drv("nor");
-
-       // /yaffs2  yaffs2 file emulation
-       yflash2_install_drv("yaffs2");
+       yaffs_nandsim_install_drv("nand", "emfile-nand", 256);
 
        return 0;
 }