Переглянути джерело

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1245 bbd45198-f89e-11dd-88c7-29a3b14d5316

iamyhw@gmail.com 14 роки тому
батько
коміт
ac07efd463

+ 126 - 0
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')

+ 293 - 0
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 <ricky_gz_zheng@yahoo.co.nz>
+
+  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																				 
+

+ 27 - 0
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
+
+

+ 366 - 0
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
+

+ 77 - 0
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__*/

+ 135 - 0
components/dfs/filesystems/uffs/flash/nand_ids.c

@@ -0,0 +1,135 @@
+/*
+ *  drivers/mtd/nandids.c
+ *
+ *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
+  *
+ * $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"}
+};
+
+
+

+ 0 - 0
components/dfs/filesystems/uffs/flash/uffs_nand_samsung.c


+ 234 - 0
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 <ricky_gz_zheng@yahoo.co.nz>
+
+  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()
+};

+ 350 - 0
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 <ricky_gz_zheng@yahoo.co.nz>
+
+  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()
+};

+ 212 - 0
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 <ricky_gz_zheng@yahoo.co.nz>
+
+  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()
+};

+ 224 - 0
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 <ricky_gz_zheng@yahoo.co.nz>
+
+  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;
+	
+}
+

+ 260 - 0
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 <ricky_gz_zheng@yahoo.co.nz>
+
+  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
+
+/////////////////////////////////////////////////////////////////////////////////

+ 55 - 0
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 <ricky_gz_zheng@yahoo.co.nz>
+
+  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
+

+ 320 - 0
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

+ 11 - 0
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
+

+ 8 - 0
tools/readme

@@ -0,0 +1,8 @@
+About uffs_demo_win32.exe?
+Compile OS: Windows XP SP3
+Compile Tools:Visul C++ 6.0
+
+This is a uffs filesystem demo applet.
+you can make it ,in accordance with you resource.
+ Use document :
+ \uffs\src\emu\*.*

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
tools/uffs.bin


BIN
tools/uffs_demo_win32.exe


Деякі файли не було показано, через те що забагато файлів було змінено