提交 ac07efd4 编写于 作者: I iamyhw@gmail.com

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1245 bbd45198-f89e-11dd-88c7-29a3b14d5316
上级 ef0d03aa
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')
/*
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
#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
/**
* 用户要自己实现这个文件中的接口函数,不一样的芯片会有不同的访问命令
* 这个例程文件是关于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
//
// 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__*/
/*
* 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"}
};
/*
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()
};
/*
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()
};
/*
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()
};
/*
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;
}
/*
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
/////////////////////////////////////////////////////////////////////////////////
/*
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
/*
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
#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
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\*.*
\ No newline at end of file
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册