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 \
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)
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
+
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+
+
+}
+
--- /dev/null
+/*
+ * 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
#!/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
+
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 "#########"
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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
#include "yaffs_flashif2.h"
#include "yaffs_m18_drv.h"
#include "yaffs_nor_drv.h"
+#include "yaffs_nand_drv.h"
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;
}