summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
author[email protected] <[email protected]>2011-01-16 14:15:31 +0000
committer[email protected] <[email protected]>2011-01-16 14:15:31 +0000
commitac07efd463bc0d6b5b3318095acf59e8bd674b6e (patch)
tree5db9cd8ae3c67def6c619cab245dcf1f0ef0cebd /components
parentef0d03aaff0cd9f956d6f4374787ab9a9f557708 (diff)
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1245 bbd45198-f89e-11dd-88c7-29a3b14d5316
Diffstat (limited to 'components')
-rw-r--r--components/dfs/filesystems/uffs/SConscript126
-rw-r--r--components/dfs/filesystems/uffs/dfs_nand_if.c293
-rw-r--r--components/dfs/filesystems/uffs/flash/K9F2G08.h27
-rw-r--r--components/dfs/filesystems/uffs/flash/k9f2g08.c366
-rw-r--r--components/dfs/filesystems/uffs/flash/nand.h77
-rw-r--r--components/dfs/filesystems/uffs/flash/nand_ids.c135
-rw-r--r--components/dfs/filesystems/uffs/flash/uffs_nand_samsung.c0
-rw-r--r--components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw.c234
-rw-r--r--components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw_auto.c350
-rw-r--r--components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_soft.c212
-rw-r--r--components/dfs/filesystems/uffs/src/emu/uffs_fileem_share.c224
-rw-r--r--components/dfs/filesystems/uffs/src/emu/uffs_fileem_wrap.c260
-rw-r--r--components/dfs/filesystems/uffs/src/inc/uffs/uffs_fileem.h55
-rw-r--r--components/dfs/filesystems/uffs/uffs_ext.c320
-rw-r--r--components/dfs/filesystems/uffs/uffs_ext.h11
15 files changed, 2690 insertions, 0 deletions
diff --git a/components/dfs/filesystems/uffs/SConscript b/components/dfs/filesystems/uffs/SConscript
new file mode 100644
index 0000000000..2914dbaf74
--- /dev/null
+++ b/components/dfs/filesystems/uffs/SConscript
@@ -0,0 +1,126 @@
+Import('RTT_ROOT')
+Import('rtconfig')
+from building import *
+
+# The set of source files associated with this SConscript file.
+dfs = Split("""
+src/dfs.c
+src/dfs_fs.c
+src/dfs_file.c
+src/dfs_posix.c
+""")
+
+# DFS-ELMFAT options
+elmfat = Split("""
+filesystems/elmfat/dfs_elm.c
+filesystems/elmfat/ff.c
+""")
+
+# DFS-ROMFS options
+romfs = Split("""
+filesystems/romfs/dfs_romfs.c
+filesystems/romfs/romfs.c
+""")
+
+# DFS-DeviceFS options
+devfs = Split("""
+filesystems/devfs/devfs.c
+filesystems/devfs/console.c
+""")
+
+# DFS-YAFFS2 options
+yaffs2_main = Split("""
+filesystems/yaffs2/direct/yaffscfg.c
+filesystems/yaffs2/direct/yaffs_fileem.c
+filesystems/yaffs2/direct/yaffsfs.c
+filesystems/yaffs2/direct/dfs_yaffs2.c
+""")
+
+yaffs2_comm = Split("""
+filesystems/yaffs2/yaffs_ecc.c
+filesystems/yaffs2/yaffs_guts.c
+filesystems/yaffs2/yaffs_packedtags1.c
+filesystems/yaffs2/yaffs_tagscompat.c
+filesystems/yaffs2/yaffs_packedtags2.c
+filesystems/yaffs2/yaffs_tagsvalidity.c
+filesystems/yaffs2/yaffs_nand.c
+filesystems/yaffs2/yaffs_checkptrw.c
+filesystems/yaffs2/yaffs_qsort.c
+""")
+
+nfs = Split('''
+filesystems/nfs/mount_clnt.c
+filesystems/nfs/mount_xdr.c
+filesystems/nfs/nfs_clnt.c
+filesystems/nfs/nfs_xdr.c
+filesystems/nfs/dfs_nfs.c
+filesystems/nfs/rpc/auth_none.c
+filesystems/nfs/rpc/clnt_generic.c
+filesystems/nfs/rpc/clnt_udp.c
+filesystems/nfs/rpc/rpc_prot.c
+filesystems/nfs/rpc/pmap.c
+filesystems/nfs/rpc/xdr.c
+filesystems/nfs/rpc/xdr_mem.c
+''')
+
+uffs = Split('''
+filesystems/uffs/src/uffs/uffs_badblock.c
+filesystems/uffs/src/uffs/uffs_blockinfo.c
+filesystems/uffs/src/uffs/uffs_buf.c
+filesystems/uffs/src/uffs/uffs_debug.c
+filesystems/uffs/src/uffs/uffs_device.c
+filesystems/uffs/src/uffs/uffs_ecc.c
+filesystems/uffs/src/uffs/uffs_fd.c
+filesystems/uffs/src/uffs/uffs_find.c
+filesystems/uffs/src/uffs/uffs_flash.c
+filesystems/uffs/src/uffs/uffs_fs.c
+filesystems/uffs/src/uffs/uffs_init.c
+filesystems/uffs/src/uffs/uffs_mem.c
+filesystems/uffs/src/uffs/uffs_mtb.c
+filesystems/uffs/src/uffs/uffs_pool.c
+filesystems/uffs/src/uffs/uffs_public.c
+filesystems/uffs/src/uffs/uffs_tree.c
+filesystems/uffs/src/uffs/uffs_utils.c
+filesystems/uffs/src/uffs/uffs_version.c
+filesystems/uffs/dfs_uffs.c
+''')
+
+others = '''
+filesystems/uffs/dfs_nand_if.c
+filesystems/uffs/uffs_ext.c
+filesystems/uffs/flash/k9f2g08.c
+filesystems/uffs/flash/nand_ids.c
+'''
+
+src_local = dfs
+# The set of source files associated with this SConscript file.
+path = [RTT_ROOT + '/components/dfs', RTT_ROOT + '/components/dfs/include']
+
+if GetDepend('RT_USING_DFS_YAFFS2'):
+ src_local = src_local + yaffs2_main + yaffs2_comm
+ path = path + [RTT_ROOT + '/components/dfs/filesystems/yaffs2', RTT_ROOT + '/components/dfs/filesystems/yaffs2/direct']
+
+if GetDepend('RT_USING_DFS_ELMFAT'):
+ if GetDepend('RT_DFS_ELM_USE_LFN'):
+ elmfat += ['filesystems/elmfat/option/cc936.c']
+ src_local = src_local + elmfat
+
+if GetDepend(['RT_USING_DFS_NFS', 'RT_USING_LWIP']):
+ src_local = src_local + nfs
+ path = path + [RTT_ROOT + '/components/dfs/filesystems/nfs']
+
+if GetDepend('RT_USING_DFS_ROMFS'):
+ src_local = src_local + romfs
+ path = path + [RTT_ROOT + '/components/dfs/filesystems/romfs']
+
+if GetDepend('RT_USING_DFS_DEVFS'):
+ src_local = src_local + devfs
+ path = path + [RTT_ROOT + '/components/dfs/filesystems/devfs']
+
+if GetDepend('RT_USING_DFS_DEVFS'):
+ src_local = src_local + uffs
+ path = path + [RTT_ROOT + '/components/dfs/filesystems/uffs/src/inc', RTT_ROOT + '/components/dfs/filesystems/uffs', RTT_ROOT + '/components/dfs/filesystems/uffs/flash']
+
+group = DefineGroup('Filesystem', src_local, depend = ['RT_USING_DFS'], CPPPATH = path)
+
+Return('group')
diff --git a/components/dfs/filesystems/uffs/dfs_nand_if.c b/components/dfs/filesystems/uffs/dfs_nand_if.c
new file mode 100644
index 0000000000..0e57c9c556
--- /dev/null
+++ b/components/dfs/filesystems/uffs/dfs_nand_if.c
@@ -0,0 +1,293 @@
+ /*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+*/
+/**
+ * \file nand flash interface example
+ * \brief example for using nand flash driver and multiple partitions, with system memory allocator.
+ * \author Ricky Zheng, created at 27 Nov, 2007
+ */
+
+#include <rtthread.h>
+#include <stdio.h>
+#include <dfs_fs.h>
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_flash.h"
+#include "uffs/uffs_mtb.h"
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_utils.h"
+#include "uffs/uffs_find.h"
+#include "uffs/uffs_fd.h"
+#include "uffs_ext.h"
+
+#include "k9f2g08.h"
+
+#define PFX "nand-drv:"
+
+/*
+ * Note: all=0,read manufacturer id and device id only.
+ * all=1,read all bytes,comprise additional ids.
+ */
+static void nand_read_chip_ids(u8* buf, UBOOL all)
+{
+ K9F2G08_ReadChipID(buf, all);
+}
+
+static int nand_write_page_data(uffs_Device *dev, u32 block, u32 page, const u8 *buffer, int len, u8 *ecc)
+{
+ K9F2G08_WritePage(block,page,buffer,len,ecc);
+
+ dev->st.page_write_count++;
+ return UFFS_FLASH_NO_ERR;
+}
+
+
+static int nand_write_page_spare(uffs_Device *dev, u32 block, u32 page, const u8 *spare, int ofs, int len, UBOOL eod)
+{
+ K9F2G08_WriteTags(block,page,spare,ofs,len);
+
+ dev->st.spare_write_count++;
+ return UFFS_FLASH_NO_ERR;
+}
+
+static int nand_read_page_data(uffs_Device *dev, u32 block, u32 page, u8 *buffer, int len, u8 *ecc)
+{
+ K9F2G08_ReadPage(block,page,buffer,len,ecc);
+
+ dev->st.page_read_count++;
+ return UFFS_FLASH_NO_ERR;
+}
+
+static int nand_read_page_spare(uffs_Device *dev, u32 block, u32 page, u8 *spare, int ofs, int len)
+{
+ K9F2G08_ReadTags(block,page,spare,ofs,len);
+
+ dev->st.spare_read_count++;
+ return UFFS_FLASH_NO_ERR;
+}
+
+static int nand_erase_block(uffs_Device *dev, u32 block)
+{
+ K9F2G08_EraseBlock(block);
+
+ dev->st.block_erase_count++;
+ return UFFS_FLASH_NO_ERR;
+}
+
+static int nand_mark_badblock(uffs_Device *dev,u32 block)
+{
+ return K9F2G08_Mark_badblk(block);
+}
+
+static int nand_is_badblock(uffs_Device *dev,u32 block)
+{
+ return K9F2G08_Check_badblk(block);
+}
+
+static uffs_FlashOps nand_driver_ops =
+{
+ nand_read_page_data, //ReadPageData
+ nand_read_page_spare, //ReadPageSpare
+ NULL, //ReadPageSpareWithLayout
+ nand_write_page_data, //WritePageData
+ nand_write_page_spare, //WritePageSpare
+ NULL, //WriteFullPage
+ nand_is_badblock, //IsBadBlock
+ nand_mark_badblock, //MarkBadBlock
+ nand_erase_block, //EraseBlock
+};
+
+//change these parameters to fit your nand flash specification
+//#define MAN_ID MAN_ID_SAMSUNG // simulate Samsung's NAND flash
+
+static struct uffs_StorageAttrSt flash_storage = {0};
+
+static int initDevice(uffs_Device *dev)
+{
+ dev->ops = &nand_driver_ops;
+ return RT_EOK;
+}
+
+static int releaseDevice(uffs_Device *dev)
+{
+ return RT_EOK;
+}
+
+#include <dfs_uffs.h>
+
+static uffs_Device uffs_device = {0};
+/* define mount table,UFFS FS private data */
+/* it is absolute accessing for uffs.*/
+static uffs_MountTable uffs_mount_table =
+{
+ &uffs_device,
+ 0,
+ TOTAL_BLOCKS-1,
+ "/" ,
+ NULL,
+};
+
+#include "nand.h"
+extern struct nand_flash_dev nand_flash_ids[];
+extern struct nand_manufacturers nand_manuf_ids[];
+
+struct nand_flash_dev* nand_init(u8* buf)
+{
+ struct nand_flash_dev* type=RT_NULL;
+ int i, dev_id,maf_id;
+
+ K9F2G08_Reset();
+ rt_kprintf("nand: ");
+
+ nand_read_chip_ids(buf,0);
+ maf_id= buf[0];
+ /* Try to identify manufacturer */
+ for (i = 0; nand_manuf_ids[i].id != 0x0; i++)
+ {
+ if (nand_manuf_ids[i].id == maf_id)
+ {
+ rt_kprintf("%s ",nand_manuf_ids[i].name);
+ break;
+ }
+ }
+ if(nand_manuf_ids[i].id == 0x0)
+ {
+ rt_kprintf("%s\n",nand_manuf_ids[i].name);
+ return RT_NULL;
+ }
+
+ dev_id = buf[1];
+ /* Lookup the flash id */
+ for(i = 0; nand_flash_ids[i].name != RT_NULL; i++)
+ {
+ if(dev_id == nand_flash_ids[i].id)
+ {
+ type = &nand_flash_ids[i];
+ rt_kprintf("%s\n",nand_flash_ids[i].name);
+ return type;
+ }
+ }
+
+ return RT_NULL;
+}
+
+/* RT-Thread Device Driver Interface */
+/* UFFS FileSystem NandFlash InterFace */
+/* we don't use entity, let uffs autarky */
+
+struct rt_device nand_device;
+
+static rt_err_t rt_nand_init(rt_device_t dev)
+{
+ return 0;
+}
+
+static rt_err_t rt_nand_open(rt_device_t dev, u16 oflag)
+{
+ return 0;
+}
+
+static rt_err_t rt_nand_close(rt_device_t dev)
+{
+ return 0;
+}
+
+static rt_err_t rt_nand_control(rt_device_t dev, u8 cmd, void *args)
+{
+ return 0;
+}
+
+static rt_size_t rt_nand_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+ return 0;
+}
+
+static rt_size_t rt_nand_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+ return 0;
+}
+
+void rt_hw_nand_init(void)
+{
+ struct nand_flash_dev *type = RT_NULL;
+ u8 buf[5];
+ if((type = nand_init(buf)) != RT_NULL)
+ {
+ uffs_MountTable *entry;
+ struct uffs_StorageAttrSt *chip = &flash_storage;
+
+ rt_device_t dev = &nand_device;
+ /* fill in NandFlash device struct */
+ dev->type = RT_Device_Class_Block;
+ dev->init = rt_nand_init;
+ dev->open = rt_nand_open;
+ dev->close = rt_nand_close;
+ dev->read = rt_nand_read;
+ dev->write = rt_nand_write;
+ dev->control = rt_nand_control;
+ dev->user_data = &uffs_mount_table;
+ /* register nandfalsh device */
+ rt_device_register(&nand_device, "nand0",
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
+
+ /* about uffs codes */
+ entry = &uffs_mount_table;
+ //entry->lock = rt_sem_create("sem_nand0", 1, RT_IPC_FLAG_FIFO);//??it's lonely!how to do?
+
+ uffs_MemSetupSystemAllocator(&(entry->dev->mem));
+ entry->dev->Init = initDevice;
+ entry->dev->Release = releaseDevice;
+ entry->dev->attr = chip;
+ uffs_RegisterMountTable(entry);
+
+ /* Newer devices have all the information in additional id bytes */
+ if(!type->pagesize)
+ {
+ int extid;
+ nand_read_chip_ids(buf,1);//reread chip ids,the all and the one.
+
+ /* The 3rd id byte holds MLC / multichip data,untapped */
+ /* The 4th id byte is the important one */
+ extid = buf[3];
+ /* Calc pagesize */
+ chip->page_data_size = 1024 << (extid & 0x3);
+ extid >>= 2;
+ /* Calc oobsize */
+ chip->spare_size = (8<<(extid & 0x01))*(chip->page_data_size>>9);
+ extid >>= 2;
+ /* Calc blocksize. Blocksize is multiples of 64KiB */
+ chip->pages_per_block = ((64*1024)<<(extid & 0x03))/(chip->page_data_size);
+ /* The 5th id byte */
+ chip->total_blocks = (type->chipsize*1024*1024) /
+ chip->page_data_size / chip->pages_per_block;
+
+ }
+ else
+ { /* Old devices have chip data hardcoded in the device id table */
+ chip->page_data_size = type->pagesize;
+ chip->pages_per_block = type->blocksize / type->pagesize;
+ chip->spare_size = chip->page_data_size / 32;
+ chip->total_blocks = (type->chipsize*1024*1024) / type->blocksize;
+ }
+ if(type->options & NAND_SAMSUNG_LP_OPTIONS)
+ chip->block_status_offs = NAND_LARGE_BADBLOCK_POS;
+ else
+ chip->block_status_offs = NAND_SMALL_BADBLOCK_POS;
+ chip->ecc_opt = UFFS_ECC_SOFT; /* ecc option, do not use ECC,debug */
+ chip->layout_opt = UFFS_LAYOUT_UFFS; /* let UFFS do the spare layout */
+#if (0) //DEBUG trace facility
+ rt_kprintf("page_data_size = %d\n",chip->page_data_size);
+ rt_kprintf("pages_per_block = %d\n",chip->pages_per_block);
+ rt_kprintf("spare_size = %d\n",chip->spare_size);
+ rt_kprintf("total_blocks = %d\n",chip->total_blocks);
+ rt_kprintf("block_stat_offs = %d\n",chip->block_status_offs);
+#endif
+ }
+}
+
+//end of file
+
diff --git a/components/dfs/filesystems/uffs/flash/K9F2G08.h b/components/dfs/filesystems/uffs/flash/K9F2G08.h
new file mode 100644
index 0000000000..3d6397cde3
--- /dev/null
+++ b/components/dfs/filesystems/uffs/flash/K9F2G08.h
@@ -0,0 +1,27 @@
+#ifndef __K9F2G08_H__
+#define __K9F2G08_H__
+
+#include <rtdef.h>
+#include <nand.h>
+
+void K9F2G08_Program(u32 blockIndex, u32 srcAddress, u32 fileSize);
+
+//*************** H/W dependent functions ***************
+void K9F2G08_ReadChipID(u8* buf, UBOOL all);
+
+int K9F2G08_Check_badblk(u32 block);
+int K9F2G08_EraseBlock (u32 block);
+int K9F2G08_Mark_badblk (u32 block);
+int K9F2G08_ReadPage (u32 block, u32 page, u8 *buffer, int len, u8 *ecc);
+int K9F2G08_WritePage (u32 block, u32 page, const u8 *buffer, int len, const u8 *ecc);
+int K9F2G08_ReadTags (u32 block, u32 page, u8 *spare, int ofs, int len);
+int K9F2G08_WriteTags (u32 block, u32 page, const u8 *spare, int ofs, int len);
+
+void K9F2G08_Reset(void);
+
+void K9F2G08_Init(void);
+
+
+#endif
+
+
diff --git a/components/dfs/filesystems/uffs/flash/k9f2g08.c b/components/dfs/filesystems/uffs/flash/k9f2g08.c
new file mode 100644
index 0000000000..332ddf4087
--- /dev/null
+++ b/components/dfs/filesystems/uffs/flash/k9f2g08.c
@@ -0,0 +1,366 @@
+/**
+ * �û�Ҫ�Լ�ʵ������ļ��еĽӿں���,��һ����оƬ���в�ͬ�ķ�������
+ * ��������ļ��ǹ���Samsung k9f2g08оƬ��,���ڴ�ҳnandflash
+ */
+#include <nand.h>
+#include "s3c24x0.h"
+
+#include <k9f2g08.h>
+
+#define nand_write_cmd(cmd) (NFCMD = (cmd))
+#define nand_write_addr(addr) (NFADDR = (addr))
+#define nand_cs_en() (NFCONT &= ~(1<<1))
+#define nand_cs_ds() (NFCONT |= (1<<1))
+#define nand_Init_ECC() (NFCONT |= (1<<4))
+#define nand_read() (NFDATA8)
+#define nand_write(data) (NFDATA8 = (data))
+
+#define nand_wait() {while(!(NFSTAT&(1<<0)));} //wait tWB and check F_RNB pin.
+
+//NAND Flash Command.support K9F2G08
+#define K9F2G08_CMD_READ0 0x00 // Read0
+//#define K9F2G08_CMD_READ1 1 // Read1,K9F2G08 don't support the command.
+#define K9F2G08_CMD_RANDOM_DATA_OUT 0x05 // Random data output
+#define K9F2G08_CMD_PAGEPROG 0x10 // Write phase 2
+#define K9F2G08_CMD_READ30 0x30 // Read30
+#define K9F2G08_CMD_READ35 0x35 // Read35
+//#define K9F2G08_CMD_READOOB 0x50 // Read oob
+#define K9F2G08_CMD_ERASE1 0x60 // Erase phase 1
+#define K9F2G08_CMD_STATUS 0x70 // Status read
+#define K9F2G08_CMD_READ_EDC 0x7b // Read EDC Status
+#define K9F2G08_CMD_SEQIN 0x80 // Write phase 1
+#define K9F2G08_CMD_RANDOM_DATA_IN 0x85 // Random data input Copy-Back Program(0x85,0x10)
+#define K9F2G08_CMD_READID 0x90 // ReadID,all-purpose command
+#define K9F2G08_CMD_ERASE2 0xd0 // Erase phase 2
+#define K9F2G08_CMD_RESET 0xff // Reset
+
+#define BAD_CHECK (0)
+#define ECC_CHECK (0)
+
+
+//*************************************************
+//** H/W dependent functions **
+//*************************************************
+
+// HCLK=100Mhz
+#define TACLS 1 //1clk(0ns)
+#define TWRPH0 4 //3clk(25ns)
+#define TWRPH1 0 //1clk(10ns) //TACLS+TWRPH0+TWRPH1>=50ns
+
+int read_nand_stats(void) // R/B δ�Ӻ�?
+{
+ u8 stat;
+
+ nand_write_cmd(K9F2G08_CMD_STATUS);//0x70
+
+ stat = nand_read();//�������ص�����
+
+ if(stat&1) return 1; // I/O0=1ʧ��
+ else return 0; // I/O0=0�ɹ�
+}
+
+//����һ����
+//����0,successful
+//����1,error
+int K9F2G08_EraseBlock(u32 block)
+{
+ int stat;
+ u32 _page = block*PAGES_PER_BLOCK;
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_ERASE1); // Erase one block 1st command
+
+ nand_write_addr(_page&0xff); // Page number=0
+ nand_write_addr((_page>>8)&0xff);
+ nand_write_addr((_page>>16)&0xff);
+
+ nand_write_cmd(K9F2G08_CMD_ERASE2); // Erase one blcok 2nd command
+
+ nand_wait(); // Wait tBERS max 3ms.
+
+ stat = read_nand_stats();
+ nand_cs_ds();
+ return stat;
+}
+
+//return 1 if it's a bad block, 0 if it's good.
+int K9F2G08_Check_badblk(u32 block) //0:bad,1:good
+{
+ u8 data;
+ u32 _page;//�����ҳ��ַ
+
+ _page = block*PAGES_PER_BLOCK; // For 2'nd cycle I/O[7:5]
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_READ0); // Spare array read command
+ nand_write_addr(PAGE_DATA_SIZE&0xff); // Read the mark of bad block in spare array(M addr=5)
+ nand_write_addr((PAGE_DATA_SIZE>>8)&0xff);
+ nand_write_addr(_page&0xff); // The mark of bad block is in 0 page
+ nand_write_addr((_page>>8)&0xff); // For block number A[24:17]
+ nand_write_addr((_page>>16)&0xff); // For block number A[25]
+ nand_write_cmd(K9F2G08_CMD_READ30);
+
+ nand_wait(); // Wait tR(max 12us)
+
+ data=nand_read();
+ nand_cs_ds();
+ if(data==0x00)
+ return 1;//����
+ else
+ return 0;//�ÿ�
+}
+
+//return 0 if ok, 1:fail
+int K9F2G08_Mark_badblk(u32 block)
+{
+ u8 stat;
+ u32 _page = block*PAGES_PER_BLOCK;
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_SEQIN); // Write 1st command
+
+ nand_write_addr(PAGE_DATA_SIZE & 0xff); // The mark of bad block
+ nand_write_addr((PAGE_DATA_SIZE>>8)&0xff);
+ nand_write_addr(_page&0xff); // marked 5th spare array
+ nand_write_addr((_page>>8)&0xff); // in the 1st page.
+ nand_write_addr((_page>>16)&0xff); //
+
+ nand_write(0x00); //������
+
+ nand_write_cmd(K9F2G08_CMD_PAGEPROG); // Write 2nd command
+
+ nand_wait(); // Wait tPROG(200~500us)
+ stat = read_nand_stats();//��ѯ�Ƿ�ɹ�
+ nand_cs_ds();
+
+ return stat;
+}
+
+
+int K9F2G08_ReadPage(u32 block, u32 page, u8 *buffer, int len, u8 *ecc)
+{
+ int i;
+ u32 _page = block*PAGES_PER_BLOCK + page;
+
+// NF_RSTECC(); // Initialize ECC
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_READ0); // Read command
+ nand_write_addr(0x00); // Column = 0
+ nand_write_addr(0x00);
+ nand_write_addr(_page&0xff); //
+ nand_write_addr((_page>>8)&0xff); // Block & Page num.
+ nand_write_addr((_page>>16)&0xff); //
+
+ nand_write_cmd(K9F2G08_CMD_READ30);
+
+ nand_wait(); // Wait tR(max 12us)
+ for(i=0;i<len;i++)
+ {
+ buffer[i] = nand_read(); // Read one page
+ }
+
+ nand_cs_ds();
+
+ return 1;
+}
+
+int K9F2G08_ReadTags(u32 block, u32 page, u8 *spare, int ofs, int len)
+{
+ int i;
+
+ u32 _page = block*PAGES_PER_BLOCK + page;
+
+// NF_RSTECC(); // Initialize ECC
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_READ0); // Read command
+ nand_write_addr((PAGE_DATA_SIZE+ofs)&0xff); // Column = 0
+ nand_write_addr(((PAGE_DATA_SIZE+ofs)>>8)&0xff);
+ nand_write_addr(_page&0xff); //
+ nand_write_addr((_page>>8)&0xff); // Block & Page num.
+ nand_write_addr((_page>>16)&0xff); //
+
+ nand_write_cmd(K9F2G08_CMD_READ30);
+
+ nand_wait(); // Wait tR(max 12us)
+ for(i=0;i<len;i++)
+ {
+ spare[i] = nand_read(); // Read one page
+ }
+
+ nand_cs_ds();
+
+ return 1;
+}
+
+//дһҳ����
+//����0,successful
+//����1,error
+int K9F2G08_WritePage(u32 block, u32 page, const u8 *buffer, int len, const u8 *ecc)
+{
+ int i,stat;
+
+ u32 _page = block*PAGES_PER_BLOCK + page;
+
+ //nand_Init_ECC(); // Initialize ECC
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_SEQIN); //0x80 Write 1st command
+ for(i=0;i<10;i++);
+ nand_write_addr(0x00); // Column 0
+ nand_write_addr(0x00);
+ nand_write_addr(_page&0xff); //
+ nand_write_addr((_page>>8)&0xff); // Block & page num.
+ nand_write_addr((_page>>16)&0xff); //
+
+ for(i=0;i<len;i++)
+ {
+ nand_write(*buffer++); // Write one page to NFM from buffer
+ }
+ nand_write_cmd(K9F2G08_CMD_PAGEPROG); //0x10 Write 2nd command
+
+ nand_wait(); //wait tPROG 200~500us;
+
+ stat = read_nand_stats();
+ nand_cs_ds();
+
+ return stat;
+}
+
+int K9F2G08_WriteTags(u32 block, u32 page, const u8 *spare, int ofs, int len)
+{
+ int i,stat;
+ u32 _page = block*PAGES_PER_BLOCK + page;
+
+ //nand_Init_ECC(); // Initialize ECC
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_SEQIN); //0x80 Write 1st command
+ for(i=0;i<10;i++);
+ nand_write_addr((PAGE_DATA_SIZE+ofs)&0xff); // Column 0
+ nand_write_addr(((PAGE_DATA_SIZE+ofs)>>8)&0xff);
+ nand_write_addr(_page&0xff); //
+ nand_write_addr((_page>>8)&0xff); // Block & page num.
+ nand_write_addr((_page>>16)&0xff); //
+
+ for(i=0;i<len;i++)
+ {
+ nand_write(*spare++); // Write one page to NFM from buffer
+ }
+
+ nand_write_cmd(K9F2G08_CMD_PAGEPROG); //0x10 Write 2nd command
+
+ nand_wait(); //wait tPROG 200~500us;
+
+ stat = read_nand_stats();
+ if(!stat) // Page write error
+ {
+ nand_cs_ds();
+ return 0;
+ }
+ else
+ {
+ nand_cs_ds();
+ return 1;
+ }
+}
+
+//find frist shift bit
+//rt_inline int generic_ffs(int x)
+//{
+// int r = 1;
+//
+// if(!x)
+// return 0;
+//
+// if(!(x & 0xffff)) {x >>= 16;r += 16;}
+// if(!(x & 0xff)) {x >>= 8;r += 8;}
+// if(!(x & 0xf)) {x >>= 4;r += 4;}
+// if(!(x & 3)) {x >>= 2;r += 2;}
+// if(!(x & 1)) {x >>= 1;r += 1;}
+//
+// return r;
+//}
+
+/* when all is true,read all byte */
+void K9F2G08_ReadChipID(u8* buf, UBOOL all)
+{
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_READID); //0x90
+ nand_write_addr(K9F2G08_CMD_READ0);
+
+ buf[0] = nand_read();//������ID
+ buf[1] = nand_read();//оƬID
+ if(all)
+ {
+ buf[2] = nand_read();
+ buf[3] = nand_read();
+ //buf[4] = nand_read(); //�е�оƬû�е�5���ֽ�
+ }
+
+ nand_cs_ds();
+}
+
+void K9F2G08_Init(void)
+{
+ NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
+ NFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
+ NFSTAT = 0;
+ // 1 1 1 1, 1 xxx, r xxx, r xxx
+ // En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1
+}
+
+void K9F2G08_Reset(void)
+{
+ nand_cs_en();
+
+ nand_write_cmd(0xFF); //reset command
+
+ nand_wait(); //wait 200~500us;
+ nand_cs_ds();
+
+ K9F2G08_Init();
+}
+
+#if (0)
+int K9F2G08_ReadChunk(u32 chunk, u8 *data, u8 *tags)
+{
+ int i;
+
+ nand_cs_en();
+
+ nand_write_cmd(K9F2G08_CMD_READ0); // Read command
+ nand_write_addr(0x00);
+ nand_write_addr(0x00);
+ nand_write_addr(chunk & 0xff); //
+ nand_write_addr((chunk >> 8) & 0xff); // Block & Page num.
+ nand_write_addr((chunk >> 16) & 0xff); //
+ //nand_Init_ECC();
+ nand_write_cmd(K9F2G08_CMD_READ30); // Read command
+
+ nand_wait(); // Wait tR(max 12us)
+
+ for(i = 0; i < PAGE_DATA_SIZE; i++)
+ {
+ data[i] = nand_read(); // Read one page
+ }
+ for(i = 0; i < PAGE_SPARE_SIZE; i++)
+ {
+ tags[i] = nand_read(); // Read spare array
+ }
+
+ nand_cs_ds();
+
+ return 1;
+}
+#endif
+
diff --git a/components/dfs/filesystems/uffs/flash/nand.h b/components/dfs/filesystems/uffs/flash/nand.h
new file mode 100644
index 0000000000..9ea7251910
--- /dev/null
+++ b/components/dfs/filesystems/uffs/flash/nand.h
@@ -0,0 +1,77 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+//
+// Use of this source code is subject to the terms of the Microsoft end-user
+// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
+// If you did not accept the terms of the EULA, you are not authorized to use
+// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
+// install media.
+//
+/*++
+THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+PARTICULAR PURPOSE.
+--*/
+#ifndef __NAND_H__
+#define __NAND_H__
+
+#include <s3c24x0.h>
+#include <uffs/uffs_types.h>
+
+/* define low accessing value */
+#define TOTAL_BLOCKS 2048 /* total block of whole chip */
+#define PAGE_DATA_SIZE 2048 /* max size of page data */
+#define PAGE_SPARE_SIZE 64 /* max size of extended partition */
+#define PAGES_PER_BLOCK 64 /* max pages per block' */
+#define PAGE_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE)/* max size per whole page */
+#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE*PAGES_PER_BLOCK)/* max size per block' */
+
+//bad flags offset in the oob area.
+#define NAND_SMALL_BADBLOCK_POS 5 //small page FLASH
+#define NAND_LARGE_BADBLOCK_POS 0 //large page FLASH
+
+/* Option constants for bizarre disfunctionality and real
+* features
+*/
+/* Chip can not auto increment pages */
+#define NAND_NO_AUTOINCR 0x00000001
+/* Buswitdh is 16 bit */
+#define NAND_BUSWIDTH_16 0x00000002
+/* Device supports partial programming without padding */
+#define NAND_NO_PADDING 0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG 0x00000008
+/* Chip has copy back function */
+#define NAND_COPYBACK 0x00000010
+/* AND Chip which has 4 banks and a confusing page / block
+ * assignment. See Renesas datasheet for further information */
+#define NAND_IS_AND 0x00000020
+/* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+#define NAND_4PAGE_ARRAY 0x00000040
+
+/* Options valid for Samsung large page devices */
+#define NAND_SAMSUNG_LP_OPTIONS \
+ (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
+
+
+struct nand_flash_dev
+
+{
+ char *name; //chip name
+ int id; //chip ID
+ unsigned long pagesize; //max pages
+ unsigned long chipsize; //size of whole chip iMB
+ unsigned long blocksize;//size of block
+ unsigned long options; //option
+};
+
+struct nand_manufacturers
+{
+ int id;
+ char * name;
+};
+
+#endif /*__NAND_H__*/
diff --git a/components/dfs/filesystems/uffs/flash/nand_ids.c b/components/dfs/filesystems/uffs/flash/nand_ids.c
new file mode 100644
index 0000000000..a5d7c7dea9
--- /dev/null
+++ b/components/dfs/filesystems/uffs/flash/nand_ids.c
@@ -0,0 +1,135 @@
+/*
+ * drivers/mtd/nandids.c
+ *
+ * Copyright (C) 2002 Thomas Gleixner ([email protected])
+ *
+ * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
+ *
+ * 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 <rtdef.h>
+
+#include "flash/nand.h"
+
+/*
+* Chip ID list
+*
+* name, ID, pagesize, chipsize in MegaByte, eraseblock size,options
+*
+* if 0, get this information from the extended chip ID
+*/
+struct nand_flash_dev nand_flash_ids[] =
+{
+ {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
+ {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
+ {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
+ {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
+ {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
+ {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
+ {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
+ {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
+
+ {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
+ {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
+ {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+ {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+
+ {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
+ {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
+ {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
+ {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
+ {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
+ {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
+ {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+
+ {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
+
+/* {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0}, */
+ {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, 0},
+
+ /* These are the new chips with large page size. The pagesize
+ * and the erasesize is determined from the extended id bytes
+ */
+ /* 1 Gigabit */
+ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 2 Gigabit */
+ {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 4 Gigabit */
+ {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 8 Gigabit */
+ {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* 16 Gigabit */
+ {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+ /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
+ * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
+ * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
+ * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
+ * There are more speed improvements for reads and writes possible, but not implemented now
+ */
+ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+
+ {RT_NULL,}
+};
+
+/*
+ * NAND Flash �������Ҵ���
+ */
+#define NAND_MFR_TOSHIBA 0x98
+#define NAND_MFR_SAMSUNG 0xec
+#define NAND_MFR_FUJITSU 0x04
+#define NAND_MFR_NATIONAL 0x8f
+#define NAND_MFR_RENESAS 0x07
+#define NAND_MFR_STMICRO 0x20
+
+/* ������ID�б� */
+struct nand_manufacturers nand_manuf_ids[] =
+{
+ {NAND_MFR_TOSHIBA, "Toshiba"},
+ {NAND_MFR_SAMSUNG, "Samsung"},
+ {NAND_MFR_FUJITSU, "Fujitsu"},
+ {NAND_MFR_NATIONAL,"National"},
+ {NAND_MFR_RENESAS, "Renesas"},
+ {NAND_MFR_STMICRO, "ST Micro"},
+ {0x0, "Unknown"}
+};
+
+
+
diff --git a/components/dfs/filesystems/uffs/flash/uffs_nand_samsung.c b/components/dfs/filesystems/uffs/flash/uffs_nand_samsung.c
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/components/dfs/filesystems/uffs/flash/uffs_nand_samsung.c
diff --git a/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw.c b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw.c
new file mode 100644
index 0000000000..3ca1d12b3d
--- /dev/null
+++ b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw.c
@@ -0,0 +1,234 @@
+/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2010 Ricky Zheng <[email protected]>
+
+ UFFS is free software; you can redistribute it and/or modify it under
+ the GNU Library General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+ UFFS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ or GNU Library General Public License, as applicable, for more details.
+
+ You should have received a copy of the GNU General Public License
+ and GNU Library General Public License along with UFFS; if not, write
+ to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ As a special exception, if other files instantiate templates or use
+ macros or inline functions from this file, or you compile this file
+ and link it with other works to produce a work based on this file,
+ this file does not by itself cause the resulting work to be covered
+ by the GNU General Public License. However the source code for this
+ file must still be made available in accordance with section (3) of
+ the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fileem_ecc_hw.c
+ * \brief emulate uffs file system for hardware ECC.
+ *
+ * In this emulator, we call 'uffs_FlashMakeSpare()' to do the layout job
+ * and call 'uffs_EccMake()' to calculate ECC.
+ *
+ * \author Ricky Zheng @ Oct, 2010
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uffs/uffs_device.h"
+#include "uffs_fileem.h"
+#include "uffs/uffs_ecc.h"
+
+#define PFX "femu: "
+#define MSG(msg,...) uffs_PerrorRaw(UFFS_ERR_NORMAL, msg, ## __VA_ARGS__)
+#define MSGLN(msg,...) uffs_Perror(UFFS_ERR_NORMAL, msg, ## __VA_ARGS__)
+
+static int femu_hw_WritePageWithLayout(uffs_Device *dev, u32 block, u32 page,
+ const u8 *data, int data_len, const u8 *ecc, const uffs_TagStore *ts)
+{
+ int written;
+ int abs_page;
+ int full_page_size;
+ uffs_FileEmu *emu;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ u8 spare[UFFS_MAX_SPARE_SIZE];
+ u8 ecc_buf[UFFS_MAX_ECC_SIZE];
+ int spare_len;
+
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ if (!emu || !(emu->fp)) {
+ goto err;
+ }
+
+ abs_page = attr->pages_per_block * block + page;
+ full_page_size = attr->page_data_size + attr->spare_size;
+
+ if (data && data_len > 0) {
+ if (data_len > attr->page_data_size)
+ goto err;
+
+ emu->em_monitor_page[abs_page]++;
+ if (emu->em_monitor_page[abs_page] > PAGE_DATA_WRITE_COUNT_LIMIT) {
+ MSG("Warrning: block %d page %d exceed it's maximum write time!", block, page);
+ goto err;
+ }
+
+ fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
+
+ written = fwrite(data, 1, data_len, emu->fp);
+
+ if (written != data_len) {
+ MSG("write page I/O error ?");
+ goto err;
+ }
+
+ dev->st.page_write_count++;
+ dev->st.io_write += written;
+
+ }
+
+ if (ts) {
+
+ emu->em_monitor_spare[abs_page]++;
+ if (emu->em_monitor_spare[abs_page] > PAGE_SPARE_WRITE_COUNT_LIMIT) {
+ MSG("Warrning: block %d page %d (spare) exceed it's maximum write time!", block, page);
+ goto err;
+ }
+
+ uffs_Assert(data != NULL, "BUG: Write spare without data ?");
+ uffs_EccMake(data, data_len, ecc_buf);
+ uffs_FlashMakeSpare(dev, ts, ecc_buf, spare);
+ spare_len = dev->mem.spare_data_size;
+
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
+ written = fwrite(spare, 1, spare_len, emu->fp);
+ if (written != spare_len) {
+ MSG("write spare I/O error ?");
+ goto err;
+ }
+
+ dev->st.spare_write_count++;
+ dev->st.io_write += written;
+ }
+
+ if (data == NULL && ts == NULL) {
+ // mark bad block
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
+ written = fwrite("\0", 1, 1, emu->fp);
+ if (written != 1) {
+ MSG("write bad block mark I/O error ?");
+ goto err;
+ }
+ dev->st.io_write++;
+ }
+
+ fflush(emu->fp);
+ return UFFS_FLASH_NO_ERR;
+err:
+ fflush(emu->fp);
+ return UFFS_FLASH_IO_ERR;
+}
+
+
+static URET femu_hw_ReadPageWithLayout(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc,
+ uffs_TagStore *ts, u8 *ecc_store)
+{
+ int nread;
+ uffs_FileEmu *emu;
+ int abs_page;
+ int full_page_size;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ unsigned char status;
+ u8 spare[UFFS_MAX_SPARE_SIZE];
+ int spare_len;
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ if (!emu || !(emu->fp)) {
+ goto err;
+ }
+
+ abs_page = attr->pages_per_block * block + page;
+ full_page_size = attr->page_data_size + attr->spare_size;
+
+ if (data && data_len > 0) {
+ if (data_len > attr->page_data_size)
+ goto err;
+
+ fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
+ nread = fread(data, 1, data_len, emu->fp);
+
+ if (nread != data_len) {
+ MSG("read page I/O error ?");
+ goto err;
+ }
+ dev->st.io_read += nread;
+ dev->st.page_read_count++;
+
+ if (ecc) {
+ // calculate ECC for data
+ uffs_EccMake(data, data_len, ecc);
+ }
+ }
+
+ if (ts) {
+
+ spare_len = dev->mem.spare_data_size;
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
+ nread = fread(spare, 1, spare_len, emu->fp);
+
+ if (nread != spare_len) {
+ MSG("read page spare I/O error ?");
+ goto err;
+ }
+
+ // unload ts and ecc from spare
+ uffs_FlashUnloadSpare(dev, spare, ts, ecc_store);
+
+ dev->st.io_read += nread;
+ dev->st.spare_read_count++;
+ }
+
+ if (data == NULL && ts == NULL) {
+ // read bad block mark
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
+ nread = fread(&status, 1, 1, emu->fp);
+
+ if (nread != 1) {
+ MSG("read badblock mark I/O error ?");
+ goto err;
+ }
+ dev->st.io_read++;
+
+ return status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
+ }
+
+ return UFFS_FLASH_NO_ERR;
+err:
+ return UFFS_FLASH_IO_ERR;
+}
+
+
+uffs_FlashOps g_femu_ops_ecc_hw = {
+ femu_InitFlash, // InitFlash()
+ femu_ReleaseFlash, // ReleaseFlash()
+ NULL, // ReadPage()
+ femu_hw_ReadPageWithLayout, // ReadPageWithLayout()
+ NULL, // WritePage()
+ femu_hw_WritePageWithLayout,// WritePageWithLayout()
+ NULL, // IsBadBlock(), let UFFS take care of it.
+ NULL, // MarkBadBlock(), let UFFS take care of it.
+ femu_EraseBlock, // EraseBlock()
+};
diff --git a/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw_auto.c b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw_auto.c
new file mode 100644
index 0000000000..a1ee3d63dd
--- /dev/null
+++ b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_hw_auto.c
@@ -0,0 +1,350 @@
+/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2010 Ricky Zheng <[email protected]>
+
+ UFFS is free software; you can redistribute it and/or modify it under
+ the GNU Library General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+ UFFS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ or GNU Library General Public License, as applicable, for more details.
+
+ You should have received a copy of the GNU General Public License
+ and GNU Library General Public License along with UFFS; if not, write
+ to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ As a special exception, if other files instantiate templates or use
+ macros or inline functions from this file, or you compile this file
+ and link it with other works to produce a work based on this file,
+ this file does not by itself cause the resulting work to be covered
+ by the GNU General Public License. However the source code for this
+ file must still be made available in accordance with section (3) of
+ the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fileem_ecc_hw_auto.c
+ *
+ * \brief Emulate uffs file system for auto hardware ECC or RS error collection.
+ *
+ * This emulator emulate LPC32x0 MLC NAND controller which generate 10 bytes
+ * Reed-Solomon error correction code (RS-ECC) for every 518 bytes data.
+ *
+ * For small page MLC have 16 bytes spare area leves only 6 bytes for 'meta-data',
+ * no enough room for UFFS's 8 bytes tag and bad block mark. For this reason,
+ * we adjust page data/spare boundary to 508/20.
+ *
+ * This emulator does not calculate real RS-ECC code, instead, we use software ECC
+ * to calculate 6 bytes ECC code, so this solution does not have the same error
+ * correcting cabability of RS-ECC.
+ *
+ * Note: the MLC controller strictly require sequencial access to serial data buffer.
+ *
+ * \author Ricky Zheng @ Oct, 2010
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uffs/uffs_device.h"
+#include "uffs_fileem.h"
+
+#define PFX "femu: "
+#define MSG(msg,...) uffs_PerrorRaw(UFFS_ERR_NORMAL, msg, ## __VA_ARGS__)
+#define MSGLN(msg,...) uffs_Perror(UFFS_ERR_NORMAL, msg, ## __VA_ARGS__)
+
+#define RS_ECC_SIZE 10
+#define PAGE_DATA_SIZE 508
+#define PAGE_SPARE_SIZE 20
+#define PAGE_FULL_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
+static u8 g_sdata_buf[PAGE_FULL_SIZE]; // emulating LPC32x0's 528-bytes serial data buffer
+
+static int g_sdata_buf_pointer = 0;
+
+static void start_sdata_access()
+{
+ g_sdata_buf_pointer = 0;
+}
+
+static void feed_sdata(const u8 *data, int len)
+{
+ uffs_Assert(g_sdata_buf_pointer + len <= sizeof(g_sdata_buf), "BUG: Serial Data Buffer overflow !!");
+ if (data)
+ memcpy(g_sdata_buf + g_sdata_buf_pointer, data, len);
+ g_sdata_buf_pointer += len;
+}
+
+static void feed_sdata_constant(u8 val, int num)
+{
+ uffs_Assert(g_sdata_buf_pointer + num <= sizeof(g_sdata_buf), "BUG: Serial Data Buffer overflow !!");
+ memset(g_sdata_buf + g_sdata_buf_pointer, val, num);
+ g_sdata_buf_pointer += num;
+}
+
+static void drain_sdata(u8 *data, int len)
+{
+ uffs_Assert(sizeof(g_sdata_buf) - g_sdata_buf_pointer >= len, "BUG: Serial Data Buffer overdrain !!");
+ if (data)
+ memcpy(data, g_sdata_buf + g_sdata_buf_pointer, len);
+ g_sdata_buf_pointer += len;
+}
+
+static int load_sdata(uffs_Device *dev, int block, int page)
+{
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+ int abs_page;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ int nread;
+ int ret;
+ u8 ecc_buf[RS_ECC_SIZE];
+ u8 *ecc_store;
+
+ abs_page = attr->pages_per_block * block + page;
+
+ fseek(emu->fp, abs_page * PAGE_FULL_SIZE, SEEK_SET);
+ nread = fread(g_sdata_buf, 1, PAGE_FULL_SIZE, emu->fp);
+ g_sdata_buf_pointer = 0;
+
+ ret = ((nread == PAGE_FULL_SIZE) ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR);
+
+ if (ret == UFFS_FLASH_NO_ERR) {
+
+ // Perform ECC check & correction
+ // In the real world, this is done by MLC controller hardware
+ memset(ecc_buf, 0xFF, RS_ECC_SIZE);
+ uffs_EccMake(g_sdata_buf, attr->page_data_size, ecc_buf);
+
+ ecc_store = g_sdata_buf + PAGE_FULL_SIZE - RS_ECC_SIZE;
+
+ ret = uffs_EccCorrect(g_sdata_buf, attr->page_data_size, ecc_store, ecc_buf);
+
+ ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
+ (ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
+
+ }
+
+ return ret;
+}
+
+static int program_sdata(uffs_Device *dev, int block, int page)
+{
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+ int abs_page;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ u8 ecc_buf[RS_ECC_SIZE];
+ int writtern;
+
+ // In the real world, MLC controller will generate RS-ECC code in serial data buffer
+ // and might start auto programing NAND flash. Here, we use software ECC to emulate RS-ECC.
+ memset(ecc_buf, 0xFF, sizeof(ecc_buf));
+ uffs_EccMake(g_sdata_buf, attr->page_data_size, ecc_buf);
+ feed_sdata(ecc_buf, RS_ECC_SIZE);
+
+ uffs_Assert(g_sdata_buf_pointer == PAGE_FULL_SIZE, "Serial Data Buffer is not fully filled !!");
+
+ abs_page = attr->pages_per_block * block + page;
+
+ fseek(emu->fp, abs_page * PAGE_FULL_SIZE, SEEK_SET);
+ writtern = fwrite(g_sdata_buf, 1, PAGE_FULL_SIZE, emu->fp);
+
+ return (writtern == PAGE_FULL_SIZE) ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR;
+}
+
+
+static int femu_hw_auto_InitFlash(uffs_Device *dev)
+{
+ struct uffs_StorageAttrSt *attr = dev->attr;
+
+ // now this is a good chance to adjust page data/spare boundary
+ if (attr->page_data_size + attr->spare_size != PAGE_FULL_SIZE) {
+ MSGLN("This emulator emulates only for page size %d bytes !", PAGE_FULL_SIZE);
+ return -1;
+ }
+ if (attr->spare_size < PAGE_SPARE_SIZE) {
+ attr->page_data_size -= (PAGE_SPARE_SIZE - attr->spare_size);
+ attr->spare_size = PAGE_SPARE_SIZE;
+ MSGLN("Adjust page data/spare boundary to %d/%d", attr->page_data_size, attr->spare_size);
+ }
+
+ // and fix ECC size
+ attr->ecc_size = RS_ECC_SIZE;
+ MSGLN("Adjust ECC size to %d bytes", attr->ecc_size);
+
+ return femu_InitFlash(dev);
+}
+
+
+static int femu_hw_auto_WritePageWithLayout(uffs_Device *dev, u32 block, u32 page,
+ const u8 *data, int data_len, const u8 *ecc, const uffs_TagStore *ts)
+{
+ int abs_page;
+ uffs_FileEmu *emu;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ u8 spare[PAGE_SPARE_SIZE];
+ int ret = UFFS_FLASH_IO_ERR;
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ if (!emu || !(emu->fp)) {
+ goto err;
+ }
+
+ abs_page = attr->pages_per_block * block + page;
+
+ start_sdata_access();
+
+ dev->st.page_write_count++;
+ dev->st.spare_write_count++;
+ dev->st.io_write += PAGE_FULL_SIZE;
+
+ if (data || ts) {
+ // normal page write
+ if (data && data_len > 0) {
+ if (data_len > attr->page_data_size)
+ goto err;
+
+ emu->em_monitor_page[abs_page]++;
+ if (emu->em_monitor_page[abs_page] > PAGE_DATA_WRITE_COUNT_LIMIT) {
+ MSGLN("Warrning: block %d page %d exceed it's maximum write time!", block, page);
+ goto err;
+ }
+
+ // Copy data to serial data buffer
+ feed_sdata(data, data_len);
+
+ // Pad the rest data as 0xFF
+ feed_sdata_constant(0xFF, attr->page_data_size - data_len);
+
+ }
+ else {
+ // We still need to feed data to serial data buffer to make MLC controller happy
+ // The current UFFS won't write ts only, so we'll never run to here.
+ feed_sdata_constant(0xFF, attr->page_data_size);
+ }
+
+ if (ts) {
+
+ emu->em_monitor_spare[abs_page]++;
+ if (emu->em_monitor_spare[abs_page] > PAGE_SPARE_WRITE_COUNT_LIMIT) {
+ MSGLN("Warrning: block %d page %d (spare) exceed it's maximum write time!", block, page);
+ goto err;
+ }
+
+ memset(spare, 0xFF, sizeof(spare));
+ uffs_FlashMakeSpare(dev, ts, NULL, spare); // do not pack ECC, as MLC controller will
+ // automatically write RS-ECC to the latest 10 bytes.
+
+ // feed spare data to serial data buffer
+ feed_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE);
+ }
+ }
+ else {
+ // mark bad block
+
+ // feed data to serial data buffer to make MLC controller happy
+ feed_sdata_constant(0xFF, attr->page_data_size);
+
+ memset(spare, 0xFF, sizeof(spare));
+ spare[attr->block_status_offs] = 0;
+
+ // feed spare data to serial data buffer
+ feed_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE);
+
+ dev->st.io_write++;
+ }
+
+ // now, program serial data buffer to NAND flash
+ ret = program_sdata(dev, block, page);
+
+ fflush(emu->fp);
+ return ret;
+err:
+ fflush(emu->fp);
+ return ret;
+}
+
+
+static URET femu_hw_auto_ReadPageWithLayout(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc,
+ uffs_TagStore *ts, u8 *ecc_store)
+{
+ uffs_FileEmu *emu;
+ int abs_page;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ unsigned char status;
+ int spare_len;
+ u8 spare[PAGE_SPARE_SIZE];
+ u8 ecc_buf[RS_ECC_SIZE];
+ int ret = UFFS_FLASH_IO_ERR;
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ if (!emu || !(emu->fp)) {
+ goto ext;
+ }
+
+ abs_page = attr->pages_per_block * block + page;
+
+ // now load full page to serial data buffer
+ ret = load_sdata(dev, block, page);
+ if (ret != UFFS_FLASH_NO_ERR)
+ goto ext;
+
+ start_sdata_access();
+
+ dev->st.io_read += PAGE_FULL_SIZE;
+ dev->st.page_read_count++;
+ dev->st.spare_read_count++;
+
+ if (data || ts) {
+
+ if (data && data_len > 0) {
+ if (data_len > attr->page_data_size)
+ goto ext;
+
+ drain_sdata(data, data_len);
+ }
+
+ if (ts) {
+ if (g_sdata_buf_pointer < attr->page_data_size)
+ drain_sdata(NULL, attr->page_data_size - g_sdata_buf_pointer);
+
+ drain_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE);
+
+ // unload ts from spare
+ uffs_FlashUnloadSpare(dev, spare, ts, NULL);
+ }
+ }
+ else {
+ // read bad block mark
+ drain_sdata(NULL, attr->page_data_size + attr->block_status_offs - 1);
+ drain_sdata(&status, 1);
+
+ ret = (status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK);
+ }
+
+ext:
+ return ret;
+}
+
+
+uffs_FlashOps g_femu_ops_ecc_hw_auto = {
+ femu_hw_auto_InitFlash, // InitFlash()
+ femu_ReleaseFlash, // ReleaseFlash()
+ NULL, // ReadPage()
+ femu_hw_auto_ReadPageWithLayout, // ReadPageWithLayout()
+ NULL, // WritePage()
+ femu_hw_auto_WritePageWithLayout, // WirtePageWithLayout()
+ NULL, // IsBadBlock(), let UFFS take care of it.
+ NULL, // MarkBadBlock(), let UFFS take care of it.
+ femu_EraseBlock, // EraseBlock()
+};
diff --git a/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_soft.c b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_soft.c
new file mode 100644
index 0000000000..44ba0ed648
--- /dev/null
+++ b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_ecc_soft.c
@@ -0,0 +1,212 @@
+/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2010 Ricky Zheng <[email protected]>
+
+ UFFS is free software; you can redistribute it and/or modify it under
+ the GNU Library General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+ UFFS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ or GNU Library General Public License, as applicable, for more details.
+
+ You should have received a copy of the GNU General Public License
+ and GNU Library General Public License along with UFFS; if not, write
+ to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ As a special exception, if other files instantiate templates or use
+ macros or inline functions from this file, or you compile this file
+ and link it with other works to produce a work based on this file,
+ this file does not by itself cause the resulting work to be covered
+ by the GNU General Public License. However the source code for this
+ file must still be made available in accordance with section (3) of
+ the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fileem_ecc_soft.c
+ * \brief emulate uffs file system for software ECC
+ * \author Ricky Zheng @ Oct, 2010
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uffs/uffs_device.h"
+#include "uffs/uffs_flash.h"
+#include "uffs_fileem.h"
+
+#define PFX "femu: "
+#define MSG(msg,...) uffs_PerrorRaw(UFFS_ERR_NORMAL, msg, ## __VA_ARGS__)
+#define MSGLN(msg,...) uffs_Perror(UFFS_ERR_NORMAL, msg, ## __VA_ARGS__)
+
+static int femu_WritePage(uffs_Device *dev, u32 block, u32 page_num,
+ const u8 *data, int data_len, const u8 *spare, int spare_len)
+{
+ int written;
+ int abs_page;
+ int full_page_size;
+ uffs_FileEmu *emu;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ if (!emu || !(emu->fp)) {
+ goto err;
+ }
+
+ abs_page = attr->pages_per_block * block + page_num;
+ full_page_size = attr->page_data_size + attr->spare_size;
+
+ if (data && data_len > 0) {
+ if (data_len > attr->page_data_size)
+ goto err;
+
+ emu->em_monitor_page[abs_page]++;
+ if (emu->em_monitor_page[abs_page] > PAGE_DATA_WRITE_COUNT_LIMIT) {
+ MSGLN("Warrning: block %d page %d exceed it's maximum write time!", block, page_num);
+ goto err;
+ }
+
+ fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
+
+ written = fwrite(data, 1, data_len, emu->fp);
+
+ if (written != data_len) {
+ MSGLN("write page I/O error ?");
+ goto err;
+ }
+
+ dev->st.page_write_count++;
+ dev->st.io_write += written;
+ }
+
+ if (spare && spare_len > 0) {
+ if (spare_len > attr->spare_size)
+ goto err;
+
+ emu->em_monitor_spare[abs_page]++;
+ if (emu->em_monitor_spare[abs_page] > PAGE_SPARE_WRITE_COUNT_LIMIT) {
+ MSGLN("Warrning: block %d page %d (spare) exceed it's maximum write time!", block, page_num);
+ goto err;
+ }
+
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
+ written = fwrite(spare, 1, spare_len, emu->fp);
+ if (written != spare_len) {
+ MSGLN("write spare I/O error ?");
+ goto err;
+ }
+
+ dev->st.spare_write_count++;
+ dev->st.io_write += written;
+ }
+
+ if (data == NULL && spare == NULL) {
+ // mark bad block
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
+ written = fwrite("\0", 1, 1, emu->fp);
+ if (written != 1) {
+ MSGLN("write bad block mark I/O error ?");
+ goto err;
+ }
+ dev->st.io_write++;
+ }
+
+ fflush(emu->fp);
+ return UFFS_FLASH_NO_ERR;
+err:
+ fflush(emu->fp);
+ return UFFS_FLASH_IO_ERR;
+}
+
+
+static URET femu_ReadPage(uffs_Device *dev, u32 block, u32 page_num, u8 *data, int data_len, u8 *ecc,
+ u8 *spare, int spare_len)
+{
+ int nread;
+ uffs_FileEmu *emu;
+ int abs_page;
+ int full_page_size;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ unsigned char status;
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ if (!emu || !(emu->fp)) {
+ goto err;
+ }
+
+ abs_page = attr->pages_per_block * block + page_num;
+ full_page_size = attr->page_data_size + attr->spare_size;
+
+ if (data && data_len > 0) {
+ if (data_len > attr->page_data_size)
+ goto err;
+
+ fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
+ nread = fread(data, 1, data_len, emu->fp);
+
+ if (nread != data_len) {
+ MSGLN("read page I/O error ?");
+ goto err;
+ }
+ dev->st.io_read += nread;
+ dev->st.page_read_count++;
+ }
+
+ if (spare && spare_len > 0) {
+ if (spare_len > attr->spare_size)
+ goto err;
+
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
+ nread = fread(spare, 1, spare_len, emu->fp);
+
+ if (nread != spare_len) {
+ MSGLN("read page spare I/O error ?");
+ goto err;
+ }
+ dev->st.io_read += nread;
+ dev->st.spare_read_count++;
+ }
+
+ if (data == NULL && spare == NULL) {
+ // read bad block mark
+ fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
+ nread = fread(&status, 1, 1, emu->fp);
+
+ if (nread != 1) {
+ MSGLN("read badblock mark I/O error ?");
+ goto err;
+ }
+ dev->st.io_read++;
+
+ return status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
+ }
+
+ return UFFS_FLASH_NO_ERR;
+err:
+ return UFFS_FLASH_IO_ERR;
+}
+
+
+uffs_FlashOps g_femu_ops_ecc_soft = {
+ femu_InitFlash, // InitFlash()
+ femu_ReleaseFlash, // ReleaseFlash()
+ femu_ReadPage, // ReadPage()
+ NULL, // ReadPageWithLayout
+ femu_WritePage, // WritePage()
+ NULL, // WirtePageWithLayout
+ NULL, // IsBadBlock(), let UFFS take care of it.
+ NULL, // MarkBadBlock(), let UFFS take care of it.
+ femu_EraseBlock, // EraseBlock()
+};
diff --git a/components/dfs/filesystems/uffs/src/emu/uffs_fileem_share.c b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_share.c
new file mode 100644
index 0000000000..99f3b6b257
--- /dev/null
+++ b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_share.c
@@ -0,0 +1,224 @@
+/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
+
+ UFFS is free software; you can redistribute it and/or modify it under
+ the GNU Library General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+ UFFS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ or GNU Library General Public License, as applicable, for more details.
+
+ You should have received a copy of the GNU General Public License
+ and GNU Library General Public License along with UFFS; if not, write
+ to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ As a special exception, if other files instantiate templates or use
+ macros or inline functions from this file, or you compile this file
+ and link it with other works to produce a work based on this file,
+ this file does not by itself cause the resulting work to be covered
+ by the GNU General Public License. However the source code for this
+ file must still be made available in accordance with section (3) of
+ the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fileem_share.c
+ * \brief emulate uffs file system, shared functions
+ * \author Ricky Zheng, created Nov, 2010
+ */
+
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uffs/uffs_device.h"
+#include "uffs_fileem.h"
+
+#define PFX "femu: "
+
+/****************************************************************/
+/* Shared flash driver functions: */
+/* */
+/* femu_InitFlash(), femu_ReleaseFlash(), femu_EraseBlock() */
+/* */
+/****************************************************************/
+
+static u8 g_page_buf[UFFS_MAX_PAGE_SIZE + UFFS_MAX_SPARE_SIZE];
+
+/*
+ * Create emulator disk, initialise monitors, inject manufacture bad blocks, etc.
+ *
+ */
+int femu_InitFlash(uffs_Device *dev)
+{
+ int i;
+ int fSize;
+ int written;
+ u8 * p = g_page_buf;
+ uffs_FileEmu *emu;
+
+ struct uffs_StorageAttrSt *attr = dev->attr;
+
+ int full_page_size = attr->page_data_size + attr->spare_size;
+ int blk_size = full_page_size * attr->pages_per_block;
+ int total_pages = attr->total_blocks * attr->pages_per_block;
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ if (emu->initCount > 0) {
+ emu->initCount++;
+ return 0;
+ }
+
+ if (emu->emu_filename == NULL)
+ emu->emu_filename = UFFS_FEMU_FILE_NAME;
+
+ uffs_Perror(UFFS_ERR_NORMAL, "femu device init.");
+
+ emu->em_monitor_page = (u8 *) malloc(total_pages);
+ if (!emu->em_monitor_page)
+ return -1;
+ emu->em_monitor_spare = (u8 *) malloc(total_pages);
+ if (!emu->em_monitor_spare)
+ return -1;
+
+
+ //clear monitor
+ memset(emu->em_monitor_page, 0, total_pages);
+ memset(emu->em_monitor_spare, 0, total_pages);
+
+ emu->fp = fopen(emu->emu_filename, "rb");
+ if (emu->fp == NULL) {
+ emu->fp = fopen(emu->emu_filename, "ab+");
+ if (emu->fp == NULL) {
+ printf(PFX"Failed to create uffs emulation file.");
+ return -1;
+ }
+
+ fseek(emu->fp, 0, SEEK_END);
+ fSize = ftell(emu->fp);
+
+ if (fSize < total_pages * full_page_size) {
+ printf("Creating uffs emulation file\n");
+ fseek(emu->fp, 0, SEEK_SET);
+ memset(p, 0xff, full_page_size);
+ for (i = 0; i < total_pages; i++) {
+ written = fwrite(p, 1, full_page_size, emu->fp);
+ if (written != full_page_size) {
+ printf("Write failed\n");
+ fclose(emu->fp);
+ emu->fp = NULL;
+ return -1;
+ }
+ }
+ }
+ }
+
+ fflush(emu->fp);
+ fclose(emu->fp);
+
+ emu->fp = fopen(emu->emu_filename, "rb+");
+ if (emu->fp == NULL) {
+ printf(PFX"Can't open emulation file.\n");
+ return -1;
+ }
+
+ emu->initCount++;
+
+ return 0;
+}
+
+/*
+ * Release resources
+ */
+int femu_ReleaseFlash(uffs_Device *dev)
+{
+ uffs_FileEmu *emu;
+
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ emu->initCount--;
+
+ if (emu->initCount == 0) {
+
+ uffs_Perror(UFFS_ERR_NORMAL, "femu device release.");
+
+ if (emu->fp) {
+ fclose(emu->fp);
+ emu->fp = NULL;
+ }
+
+ if (emu->em_monitor_page)
+ free(emu->em_monitor_page);
+ if (emu->em_monitor_spare)
+ free(emu->em_monitor_spare);
+ emu->em_monitor_page = NULL;
+ emu->em_monitor_spare = NULL;
+ }
+
+ return 0;
+}
+
+int femu_EraseBlock(uffs_Device *dev, u32 blockNumber)
+{
+
+ int i;
+ u8 * pg = g_page_buf;
+ int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
+ uffs_FileEmu *emu;
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+ if (!emu || !(emu->fp))
+ goto err;
+
+ pg_size = dev->attr->page_data_size + dev->attr->spare_size;
+ pgd_size = dev->attr->page_data_size;
+ sp_size = dev->attr->spare_size;
+ blk_pgs = dev->attr->pages_per_block;
+ blks = dev->attr->total_blocks;
+ blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
+
+ printf("femu: erase block %d\n", blockNumber);
+
+ if ((int)blockNumber >= blks) {
+ printf("Attempt to erase non-existant block %d\n",blockNumber);
+ goto err;
+ }
+ else {
+
+ //clear this block monitors
+ memset(emu->em_monitor_page + (blockNumber * blk_pgs),
+ 0,
+ blk_pgs * sizeof(u8));
+ memset(emu->em_monitor_spare + (blockNumber * blk_pgs),
+ 0,
+ blk_pgs * sizeof(u8));
+
+ memset(pg, 0xff, (pgd_size + sp_size));
+
+ fseek(emu->fp, blockNumber * blk_pgs * (pgd_size + sp_size), SEEK_SET);
+
+ for (i = 0; i < blk_pgs; i++) {
+ fwrite(pg, 1, (pgd_size + sp_size), emu->fp);
+ }
+
+ fflush(emu->fp);
+ dev->st.block_erase_count++;
+ }
+
+ return UFFS_FLASH_NO_ERR;
+err:
+ return UFFS_FLASH_IO_ERR;
+
+}
+
diff --git a/components/dfs/filesystems/uffs/src/emu/uffs_fileem_wrap.c b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_wrap.c
new file mode 100644
index 0000000000..e0891ab9df
--- /dev/null
+++ b/components/dfs/filesystems/uffs/src/emu/uffs_fileem_wrap.c
@@ -0,0 +1,260 @@
+/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
+
+ UFFS is free software; you can redistribute it and/or modify it under
+ the GNU Library General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+ UFFS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ or GNU Library General Public License, as applicable, for more details.
+
+ You should have received a copy of the GNU General Public License
+ and GNU Library General Public License along with UFFS; if not, write
+ to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ As a special exception, if other files instantiate templates or use
+ macros or inline functions from this file, or you compile this file
+ and link it with other works to produce a work based on this file,
+ this file does not by itself cause the resulting work to be covered
+ by the GNU General Public License. However the source code for this
+ file must still be made available in accordance with section (3) of
+ the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fileem_wrap.c
+ *
+ * \brief file emulator wrapper functions for injecting bad blocks or ECC errors.
+ *
+ * \author Ricky Zheng, created Nov, 2010
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uffs/uffs_device.h"
+#include "uffs_fileem.h"
+
+#define PFX "femu: "
+
+#ifdef UFFS_FEMU_ENABLE_INJECTION
+
+struct uffs_FileEmuBitFlip {
+ int block;
+ int page;
+ int offset;
+ u8 mask;
+};
+
+/* simulate bad blocks */
+#define FILEEMU_STOCK_BAD_BLOCKS {5, 18} // bad block come from manufacture
+#define FILEEMU_ERASE_BAD_BLOCKS {10, 15} // new bad block discovered when erasing
+
+/* simulating bit flip */
+#define FILEEMU_WRITE_BIT_FLIP \
+ { \
+ {2, 2, 10, 1 << 4}, /* block 2, page 2, offset 10, bit 4 */ \
+ {2, 4, -3, 1 << 2}, /* block 2, page 4, spare offset 3, bit 2*/ \
+ {6, 1, 5, 1 << 3}, /* block 6, page 1, offset 5, bit 3 */ \
+ {6, 1, 15, 1 << 7}, /* block 6, page 1, offset 300, bit 7 */ \
+ {8, 2, 2, 1 << 1}, /* block 8, page 2, offset 2, bit 1 */ \
+ {8, 2, 100, 1 << 5},/* block 8, page 2, offset 100, bit 5 */ \
+ }
+
+
+static int femu_InitFlash_wrap(uffs_Device *dev);
+
+static int femu_ReadPage_wrap(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc,
+ u8 *spare, int spare_len);
+static int femu_WritePage_wrap(uffs_Device *dev, u32 block, u32 page,
+ const u8 *data, int data_len, const u8 *spare, int spare_len);
+static int femu_WritePageWithLayout_wrap(uffs_Device *dev, u32 block, u32 page, const u8* data, int data_len, const u8 *ecc,
+ const uffs_TagStore *ts);
+static int femu_EraseBlock_wrap(uffs_Device *dev, u32 blockNumber);
+
+
+/////////////////////////////////////////////////////////////////////////////////
+
+void femu_setup_wrapper_functions(uffs_Device *dev)
+{
+ uffs_FileEmu *emu;
+ emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ // setup wrap functions, for inject ECC errors, etc.
+
+ memcpy(&emu->ops_orig, dev->ops, sizeof(struct uffs_FlashOpsSt));
+
+ if (dev->ops->InitFlash)
+ dev->ops->InitFlash = femu_InitFlash_wrap;
+ if (dev->ops->EraseBlock)
+ dev->ops->EraseBlock = femu_EraseBlock_wrap;
+ if (dev->ops->ReadPage)
+ dev->ops->ReadPage = femu_ReadPage_wrap;
+ //if (dev->ops->ReadPageWithLayout)
+ // dev->ops->ReadPageWithLayout = femu_ReadPageWithLayout_wrap;
+ if (dev->ops->WritePage)
+ dev->ops->WritePage = femu_WritePage_wrap;
+ if (dev->ops->WritePageWithLayout)
+ dev->ops->WritePageWithLayout = femu_WritePageWithLayout_wrap;
+}
+
+static int femu_InitFlash_wrap(uffs_Device *dev)
+{
+ int ret;
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+
+#ifdef FILEEMU_STOCK_BAD_BLOCKS
+ int bad_blocks[] = FILEEMU_STOCK_BAD_BLOCKS;
+ int j;
+ u8 x = 0;
+ struct uffs_StorageAttrSt *attr = dev->attr;
+ int full_page_size = attr->page_data_size + attr->spare_size;
+ int blk_size = full_page_size * attr->pages_per_block;
+#endif
+
+ if (emu->initCount == 0) {
+ ret = emu->ops_orig.InitFlash(dev);
+#ifdef FILEEMU_STOCK_BAD_BLOCKS
+ if (ret >= 0) {
+ for (j = 0; j < ARRAY_SIZE(bad_blocks); j++) {
+ if (bad_blocks[j] < dev->attr->total_blocks) {
+ printf(" --- manufacture bad block %d ---\n", bad_blocks[j]);
+ fseek(emu->fp, bad_blocks[j] * blk_size + attr->page_data_size + dev->attr->block_status_offs, SEEK_SET);
+ fwrite(&x, 1, 1, emu->fp);
+ }
+ }
+ }
+#endif
+ }
+ else {
+ ret = emu->ops_orig.InitFlash(dev);
+ }
+
+ return ret;
+}
+
+static int femu_ReadPage_wrap(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc,
+ u8 *spare, int spare_len)
+{
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+
+ //printf("femu: Read block %d page %d data %d spare %d\n", block, page, data_len, spare_len);
+
+ return emu->ops_orig.ReadPage(dev, block, page, data, data_len, ecc, spare, spare_len);
+}
+
+////////////////////// wraper functions ///////////////////////////
+
+static void InjectBitFlip(uffs_Device *dev, u32 block, u32 page)
+{
+#ifdef FILEEMU_WRITE_BIT_FLIP
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+ struct uffs_FileEmuBitFlip flips[] = FILEEMU_WRITE_BIT_FLIP;
+ struct uffs_FileEmuBitFlip *x;
+ u8 buf[UFFS_MAX_PAGE_SIZE + UFFS_MAX_SPARE_SIZE];
+ u8 *data = buf;
+ u8 *spare = buf + dev->attr->page_data_size;
+ int full_page_size = dev->attr->page_data_size + dev->attr->spare_size;
+ int blk_size = full_page_size * dev->attr->pages_per_block;
+ int page_offset = block * blk_size + full_page_size * page;
+
+ int i;
+ u8 *p;
+
+ fseek(emu->fp, page_offset, SEEK_SET);
+ fread(buf, 1, full_page_size, emu->fp);
+
+ p = NULL;
+ for (i = 0; i < ARRAY_SIZE(flips); i++) {
+ x = &flips[i];
+ if (x->block == block && x->page == page) {
+ if (x->offset >= 0) {
+ printf(" --- Inject data bit flip at block%d, page%d, offset%d, mask%d --- \n", block, page, x->offset, x->mask);
+ p = (u8 *)(data + x->offset);
+ }
+ else {
+ printf(" --- Inject spare bit flip at block%d, page%d, offset%d, mask%d --- \n", block, page, -x->offset, x->mask);
+ p = (u8 *)(spare - x->offset);
+ }
+ *p = (*p & ~x->mask) | (~(*p & x->mask) & x->mask);
+ }
+ }
+
+ if (p) {
+ fseek(emu->fp, page_offset, SEEK_SET);
+ fwrite(buf, 1, full_page_size, emu->fp);
+ }
+#endif
+}
+
+static int femu_WritePage_wrap(uffs_Device *dev, u32 block, u32 page,
+ const u8 *data, int data_len, const u8 *spare, int spare_len)
+{
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+ int ret;
+
+ //printf("femu: Write block %d page %d data %d spare %d\n", block, page, data_len, spare_len);
+
+ ret = emu->ops_orig.WritePage(dev, block, page, data, data_len, spare, spare_len);
+
+ InjectBitFlip(dev, block, page);
+
+ return ret;
+}
+
+static int femu_WritePageWithLayout_wrap(uffs_Device *dev, u32 block, u32 page, const u8* data, int data_len, const u8 *ecc,
+ const uffs_TagStore *ts)
+{
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+ int ret;
+
+ //printf("femu: Write block %d page %d data %d spare %d\n", block, page, data_len, spare_len);
+
+ ret = emu->ops_orig.WritePageWithLayout(dev, block, page, data, data_len, ecc, ts);
+
+ InjectBitFlip(dev, block, page);
+
+ return ret;
+}
+
+
+static int femu_EraseBlock_wrap(uffs_Device *dev, u32 blockNumber)
+{
+ uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
+
+#ifdef FILEEMU_ERASE_BAD_BLOCKS
+ int blocks[] = FILEEMU_ERASE_BAD_BLOCKS;
+ int i;
+ URET ret;
+ ret = emu->ops_orig.EraseBlock(dev, blockNumber);
+
+ for (i = 0; i < ARRAY_SIZE(blocks); i++) {
+ if (blockNumber == blocks[i]) {
+ printf(" --- Inject bad block%d when erasing --- \n", blockNumber);
+ ret = UFFS_FLASH_BAD_BLK;
+ }
+ }
+
+ return ret;
+
+#else
+
+ return emu->ops_orig.EraseBlock(dev, blockNumber);
+
+#endif
+}
+
+#endif // UFFS_FEMU_ENABLE_INJECTION
+
+/////////////////////////////////////////////////////////////////////////////////
diff --git a/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fileem.h b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fileem.h
new file mode 100644
index 0000000000..e9331ce478
--- /dev/null
+++ b/components/dfs/filesystems/uffs/src/inc/uffs/uffs_fileem.h
@@ -0,0 +1,55 @@
+/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+
+ Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
+
+ UFFS is free software; you can redistribute it and/or modify it under
+ the GNU Library General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+ UFFS is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ or GNU Library General Public License, as applicable, for more details.
+
+ You should have received a copy of the GNU General Public License
+ and GNU Library General Public License along with UFFS; if not, write
+ to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ As a special exception, if other files instantiate templates or use
+ macros or inline functions from this file, or you compile this file
+ and link it with other works to produce a work based on this file,
+ this file does not by itself cause the resulting work to be covered
+ by the GNU General Public License. However the source code for this
+ file must still be made available in accordance with section (3) of
+ the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+*/
+
+/**
+ * \file uffs_fileem.h
+ * \brief Emulate NAND flash with host file.
+ * \author Ricky Zheng
+ */
+
+#ifndef _UFFS_FILEEM_H_
+#define _UFFS_FILEEM_H_
+
+#include "uffs_device.h"
+
+typedef struct uffs_FileEmuSt {
+ int initCount;
+ FILE *fp;
+ u8 *em_monitor_page;
+ u8 * em_monitor_spare;
+ const char *emu_filename;
+} uffs_FileEmu;
+
+void uffs_fileem_setup_device(uffs_Device *dev);
+
+#endif
+
diff --git a/components/dfs/filesystems/uffs/uffs_ext.c b/components/dfs/filesystems/uffs/uffs_ext.c
new file mode 100644
index 0000000000..8c5a6578ed
--- /dev/null
+++ b/components/dfs/filesystems/uffs/uffs_ext.c
@@ -0,0 +1,320 @@
+/*
+ This file is part of UFFS, the Ultra-low-cost Flash File System.
+ uffs filesystem examples.
+*/
+#include <rtthread.h>
+
+//#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "uffs/uffs_config.h"
+#include "uffs/uffs_public.h"
+#include "uffs/uffs_fs.h"
+#include "uffs/uffs_utils.h"
+#include "uffs/uffs_core.h"
+#include "uffs/uffs_mtb.h"
+#include "uffs/uffs_find.h"
+#include "uffs/uffs_fd.h"
+#include "emu/cmdline.h"
+#include "uffs_ext.h"
+
+#include <dfs_posix.h>
+#include <filerw.h>
+
+#ifdef RT_USING_FINSH
+#include <finsh.h>
+#endif
+
+#define PFX "exp: "
+
+#define MAX_PATH_LENGTH 128
+
+#if (0)
+//uffs��������,����֮��ӿո�
+//��Ҫ��elm������uffsʱ(���ļ�ϵͳ),��������ǰ��::
+//����uffs_copy("::/01.hdc /dir1/01.hdc")
+//������SD������һ���ļ�01.hdc��flash��,
+//Ҳ����dfs�ĺ���,�����Ͳ��ÿ����Ƿ���ļ�ϵͳ��.
+int uffs_copy(const char *tail)
+{
+ const char *src;
+ const char *des;
+ char buf[100];
+ int fd1=-1, fd2=-1;
+ int len;
+ int src_local = FALSE, des_local = FALSE;
+ int fd3=-1, fd4=-1;
+
+ if(!tail)
+ return FALSE;
+
+ src = cli_getparam(tail, &des);
+
+ if(!des)
+ return FALSE;
+
+ if(memcmp(src, "::", 2) == 0)
+ {
+ src += 2;
+ src_local = TRUE;
+ }
+ if(memcmp(des, "::", 2) == 0)
+ {
+ des += 2;
+ des_local = TRUE;
+ }
+
+ if(src_local)
+ {
+ //if((fp1 = fopen(src, "rb")) == NULL)
+ if((fd3 = open(src,O_RDONLY,0)) < 0)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", src);
+ goto fail_ext;
+ }
+ }
+ else
+ {
+ if((fd1 = uffs_open(src, UO_RDONLY)) < 0)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", src);
+ goto fail_ext;
+ }
+ }
+
+ if(des_local)
+ {
+ if((fd4 = open(des,O_WRONLY | O_CREAT,0)) < 0)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", des);
+ goto fail_ext;
+ }
+ }
+ else
+ {
+ if((fd2 = uffs_open(des, UO_RDWR|UO_CREATE|UO_TRUNC)) < 0)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", des);
+ goto fail_ext;
+ }
+ }
+
+ uffs_Perror(UFFS_ERR_NORMAL, "copy %s to %s... ",src,des);
+
+ while((src_local ? (1) : (uffs_eof(fd1) == 0)))
+ {
+ if(src_local)
+ {
+ len = read(fd3, buf, sizeof(buf));
+ }
+ else
+ {
+ len = uffs_read(fd1, buf, sizeof(buf));
+ }
+ if(len == 0)
+ break;
+ if(len < 0)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "read file %s fail!", src);
+ break;
+ }
+ if(des_local)
+ {
+ if(write(fd4, buf, len) != len)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "write file %s fail!", des);
+ break;
+ }
+ }
+ else
+ {
+ if(uffs_write(fd2, buf, len) != len)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "write file %s fail ?", des);
+ break;
+ }
+ }
+ }
+ uffs_Perror(UFFS_ERR_NORMAL, "succ.");
+fail_ext:
+ if(fd1 > 0)
+ uffs_close(fd1);
+ if(fd2 > 0)
+ uffs_close(fd2);
+ if(fd3 > 0)
+ close(fd3);
+ if(fd4 > 0)
+ close(fd4);
+
+ return TRUE;
+}
+FINSH_FUNCTION_EXPORT(uffs_copy, copy files. local file start with ::)
+#endif
+
+//����·���µ��ļ�(��)����
+int CountFileUnder(const char *dir)
+{
+ int count = 0;
+ uffs_DIR *dirp;
+
+ dirp = uffs_opendir(dir);
+ if(dirp)
+ {
+ while(uffs_readdir(dirp) != NULL)
+ count++;
+ if(dirp != NULL)
+ uffs_closedir(dirp);
+ }
+ return count;
+}
+
+/*
+ * ��������: �г��ļ��嵥
+ * �������: name:��������
+ * ���ز���: �ɹ�:TRUE,ʧ��:rt_false
+ */
+int uffs_ls(const char *name)
+{
+ uffs_DIR *dirp;
+ struct uffs_dirent *ent;
+ struct uffs_stat stat_buf;
+ int count = 0;
+ char buf[MAX_FILENAME_LENGTH+2];
+ char *sub;
+
+ if(name == NULL)
+ {
+ return FALSE;
+ }
+
+ dirp = uffs_opendir(name); //����һ��uffs_DIRʵ��
+
+ if(dirp == NULL)
+ {
+ rt_kprintf("Can't open '%s' for list\n", name);
+ }
+ else
+ {
+ rt_kprintf("%-16s%-8s%-8s%-8s\n","name","type","size","serial");
+ rt_kprintf("-----------------------------------------\n");
+ ent = uffs_readdir(dirp);
+ while(ent)
+ {
+ rt_kprintf("%-16s", ent->d_name);
+ strcpy(buf, name);
+ sub = buf;
+ if(name[strlen(name)-1] != '/')
+ sub = strcat(buf, "/");
+ sub = strcat(sub, ent->d_name);
+
+ if(ent->d_type & FILE_ATTR_DIR)
+ {
+ sub = strcat(sub, "/");
+ rt_kprintf("%-8s", "<DIR>");
+ rt_kprintf("%-8d", CountFileUnder(sub));
+ }
+ else
+ {
+ uffs_stat(sub, &stat_buf);
+ rt_kprintf("%-8s", "");
+ rt_kprintf("%-8d", stat_buf.st_size);
+ }
+ rt_kprintf("%-8d\n", ent->d_ino);
+ count++;
+ ent = uffs_readdir(dirp);
+ }
+
+ if(dirp != NULL)
+ uffs_closedir(dirp);
+
+ rt_kprintf("Total: %d objects.\n", count);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * ��������: ��ʽ������
+ * �������: ��������
+ * ���ز���:
+ */
+int uffs_format(const char *name)
+{
+ int ret;
+ const char *mount = "/";
+ uffs_Device *dev;
+
+ if(name)
+ {
+ mount = name;
+ }
+
+ dev = uffs_GetDeviceFromMountPoint(mount);
+ if(dev == NULL)
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "Can't get device from mount point.");
+ }
+ else
+ {
+ if(dev->ref_count == 1)
+ {
+ ret = uffs_FormatDevice(dev);
+ uffs_Perror(UFFS_ERR_NORMAL, "Format %s.",ret==RT_EOK?"succ":"fail");
+ }
+ else
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "dev->ref_count: %d, can't format this device.", dev->ref_count);
+ }
+ uffs_PutDevice(dev);
+ }
+ return TRUE;
+}
+
+/*
+ * ��������: ����һ���ļ�
+ * �������: �����
+ * ���ز���:
+ */
+int uffs_mkfile(const char *name)
+{
+ uffs_Object *fp;
+ int ret = 0;
+ int err = 0;
+
+ fp = uffs_GetObject();
+
+ if(fp != NULL)
+ {
+ if(uffs_CreateObject(fp, name, UO_CREATE) != U_SUCC)
+ {
+ err = fp->err;
+ ret = -1;
+ uffs_Perror(UFFS_ERR_NORMAL, "Create %s fail, err: %d", name, uffs_get_error());
+ }
+ else
+ {
+ uffs_Perror(UFFS_ERR_NORMAL, "Create %s succ.", name);
+ uffs_CloseObject(fp);
+ ret = 0;
+ }
+ uffs_PutObject(fp);
+ }
+ else
+ {
+ err = UEMFILE;
+ ret = -1;
+ }
+
+ uffs_set_error(-err);
+ return ret;
+}
+#if (0)
+#ifdef RT_USING_FINSH
+FINSH_FUNCTION_EXPORT(uffs_ls, list uffs system files.)
+FINSH_FUNCTION_EXPORT(uffs_mkfile, make uffs system file.)
+FINSH_FUNCTION_EXPORT(uffs_mkdir, make uffs system dir.)
+FINSH_FUNCTION_EXPORT(uffs_rmdir, remove uffs system dir.)
+FINSH_FUNCTION_EXPORT(uffs_format, format uffs partition.)
+#endif
+#endif
diff --git a/components/dfs/filesystems/uffs/uffs_ext.h b/components/dfs/filesystems/uffs/uffs_ext.h
new file mode 100644
index 0000000000..22ef33dd0d
--- /dev/null
+++ b/components/dfs/filesystems/uffs/uffs_ext.h
@@ -0,0 +1,11 @@
+
+#ifndef __UFFS_EXT_H__
+#define __UFFS_EXT_H__
+
+int CountFileUnder(const char *dir);
+int uffs_ls(const char *name);
+int uffs_format(const char *name);
+int uffs_mkfile(const char *name);
+
+#endif
+