From: Charles Manning Date: Tue, 7 May 2013 04:04:57 +0000 (+1200) Subject: Add nand driver that works with a nand simulator X-Git-Tag: aleph1-release~64 X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=commitdiff_plain;h=fd65eb6c02fba80b81f6e6f327ebb73250cbd9f5 Add nand driver that works with a nand simulator Signed-off-by: Charles Manning --- diff --git a/direct/test-framework/FrameworkRules.mk b/direct/test-framework/FrameworkRules.mk index 52cd4da..29eb44d 100644 --- a/direct/test-framework/FrameworkRules.mk +++ b/direct/test-framework/FrameworkRules.mk @@ -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 index 0000000..c0c8f1d --- /dev/null +++ b/direct/test-framework/nand_chip.h @@ -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 + * + * 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 + +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 index 0000000..431ec1a --- /dev/null +++ b/direct/test-framework/nand_store.h @@ -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 + * + * 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 index 0000000..5fb05c0 --- /dev/null +++ b/direct/test-framework/nanddrv.c @@ -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 + * + * 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 index 0000000..5b8e8e7 --- /dev/null +++ b/direct/test-framework/nanddrv.h @@ -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 + * + * 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 index 0000000..9c8a6fe --- /dev/null +++ b/direct/test-framework/nandsim.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include + +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 index 0000000..77d256d --- /dev/null +++ b/direct/test-framework/nandsim.h @@ -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 + * + * 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 index 0000000..f5940a2 --- /dev/null +++ b/direct/test-framework/nandsim_file.c @@ -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 + * + * 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 + + +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 index 0000000..2db2b92 --- /dev/null +++ b/direct/test-framework/nandsim_file.h @@ -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 + * + * 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 index 0000000..1b9b70b --- /dev/null +++ b/direct/test-framework/nandstore_file.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include + +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 index 0000000..4f2c136 --- /dev/null +++ b/direct/test-framework/nandstore_file.h @@ -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 + * + * 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 diff --git a/direct/test-framework/tests/init_fw_update_test_nand.sh b/direct/test-framework/tests/init_fw_update_test_nand.sh index 648313a..7575e76 100755 --- a/direct/test-framework/tests/init_fw_update_test_nand.sh +++ b/direct/test-framework/tests/init_fw_update_test_nand.sh @@ -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 + diff --git a/direct/test-framework/tests/run_fw_update_test_nand.sh b/direct/test-framework/tests/run_fw_update_test_nand.sh index 70747a1..cd2c0fc 100755 --- a/direct/test-framework/tests/run_fw_update_test_nand.sh +++ b/direct/test-framework/tests/run_fw_update_test_nand.sh @@ -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 index 0000000..6b3a91e --- /dev/null +++ b/direct/test-framework/yaffs_nand_drv.c @@ -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 + * + * 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 index 0000000..3e93644 --- /dev/null +++ b/direct/test-framework/yaffs_nand_drv.h @@ -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 + * + * 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 diff --git a/direct/test-framework/yaffscfg2k.c b/direct/test-framework/yaffscfg2k.c index 9e24866..005a02d 100644 --- a/direct/test-framework/yaffscfg2k.c +++ b/direct/test-framework/yaffscfg2k.c @@ -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; }