mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
Clean out unneeded files
Signed-off-by: William Juul <william.juul@tandberg.com>
This commit is contained in:
parent
ec29a32b5a
commit
98824ce3f9
27 changed files with 0 additions and 10446 deletions
|
@ -1,176 +0,0 @@
|
|||
#
|
||||
# YAFFS file system configurations
|
||||
#
|
||||
|
||||
config YAFFS_FS
|
||||
tristate "YAFFS2 file system support"
|
||||
default n
|
||||
depends on MTD
|
||||
select YAFFS_YAFFS1
|
||||
select YAFFS_YAFFS2
|
||||
help
|
||||
YAFFS2, or Yet Another Flash Filing System, is a filing system
|
||||
optimised for NAND Flash chips.
|
||||
|
||||
To compile the YAFFS2 file system support as a module, choose M
|
||||
here: the module will be called yaffs2.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
Further information on YAFFS2 is available at
|
||||
<http://www.aleph1.co.uk/yaffs/>.
|
||||
|
||||
config YAFFS_YAFFS1
|
||||
bool "512 byte / page devices"
|
||||
depends on YAFFS_FS
|
||||
default y
|
||||
help
|
||||
Enable YAFFS1 support -- yaffs for 512 byte / page devices
|
||||
|
||||
Not needed for 2K-page devices.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config YAFFS_9BYTE_TAGS
|
||||
bool "Use older-style on-NAND data format with pageStatus byte"
|
||||
depends on YAFFS_YAFFS1
|
||||
default n
|
||||
help
|
||||
|
||||
Older-style on-NAND data format has a "pageStatus" byte to record
|
||||
chunk/page state. This byte is zero when the page is discarded.
|
||||
Choose this option if you have existing on-NAND data using this
|
||||
format that you need to continue to support. New data written
|
||||
also uses the older-style format. Note: Use of this option
|
||||
generally requires that MTD's oob layout be adjusted to use the
|
||||
older-style format. See notes on tags formats and MTD versions
|
||||
in yaffs_mtdif1.c.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_DOES_ECC
|
||||
bool "Lets Yaffs do its own ECC"
|
||||
depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
|
||||
default n
|
||||
help
|
||||
This enables Yaffs to use its own ECC functions instead of using
|
||||
the ones from the generic MTD-NAND driver.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_ECC_WRONG_ORDER
|
||||
bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
|
||||
depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
|
||||
default n
|
||||
help
|
||||
This makes yaffs_ecc.c use the same ecc byte order as Steven
|
||||
Hill's nand_ecc.c. If not set, then you get the same ecc byte
|
||||
order as SmartMedia.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_YAFFS2
|
||||
bool "2048 byte (or larger) / page devices"
|
||||
depends on YAFFS_FS
|
||||
default y
|
||||
help
|
||||
Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config YAFFS_AUTO_YAFFS2
|
||||
bool "Autoselect yaffs2 format"
|
||||
depends on YAFFS_YAFFS2
|
||||
default y
|
||||
help
|
||||
Without this, you need to explicitely use yaffs2 as the file
|
||||
system type. With this, you can say "yaffs" and yaffs or yaffs2
|
||||
will be used depending on the device page size (yaffs on
|
||||
512-byte page devices, yaffs2 on 2K page devices).
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config YAFFS_DISABLE_LAZY_LOAD
|
||||
bool "Disable lazy loading"
|
||||
depends on YAFFS_YAFFS2
|
||||
default n
|
||||
help
|
||||
"Lazy loading" defers loading file details until they are
|
||||
required. This saves mount time, but makes the first look-up
|
||||
a bit longer.
|
||||
|
||||
Lazy loading will only happen if enabled by this option being 'n'
|
||||
and if the appropriate tags are available, else yaffs2 will
|
||||
automatically fall back to immediate loading and do the right
|
||||
thing.
|
||||
|
||||
Lazy laoding will be required by checkpointing.
|
||||
|
||||
Setting this to 'y' will disable lazy loading.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
|
||||
int "Reserved blocks for checkpointing"
|
||||
depends on YAFFS_YAFFS2
|
||||
default 10
|
||||
help
|
||||
Give the number of Blocks to reserve for checkpointing.
|
||||
Checkpointing saves the state at unmount so that mounting is
|
||||
much faster as a scan of all the flash to regenerate this state
|
||||
is not needed. These Blocks are reserved per partition, so if
|
||||
you have very small partitions the default (10) may be a mess
|
||||
for you. You can set this value to 0, but that does not mean
|
||||
checkpointing is disabled at all. There only won't be any
|
||||
specially reserved blocks for checkpointing, so if there is
|
||||
enough free space on the filesystem, it will be used for
|
||||
checkpointing.
|
||||
|
||||
If unsure, leave at default (10), but don't wonder if there are
|
||||
always 2MB used on your large page device partition (10 x 2k
|
||||
pagesize). When using small partitions or when being very small
|
||||
on space, you probably want to set this to zero.
|
||||
|
||||
config YAFFS_DISABLE_WIDE_TNODES
|
||||
bool "Turn off wide tnodes"
|
||||
depends on YAFFS_FS
|
||||
default n
|
||||
help
|
||||
Wide tnodes are only used for NAND arrays >=32MB for 512-byte
|
||||
page devices and >=128MB for 2k page devices. They use slightly
|
||||
more RAM but are faster since they eliminate chunk group
|
||||
searching.
|
||||
|
||||
Setting this to 'y' will force tnode width to 16 bits and save
|
||||
memory but make large arrays slower.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
|
||||
bool "Force chunk erase check"
|
||||
depends on YAFFS_FS
|
||||
default n
|
||||
help
|
||||
Normally YAFFS only checks chunks before writing until an erased
|
||||
chunk is found. This helps to detect any partially written
|
||||
chunks that might have happened due to power loss.
|
||||
|
||||
Enabling this forces on the test that chunks are erased in flash
|
||||
before writing to them. This takes more time but is potentially
|
||||
a bit more secure.
|
||||
|
||||
Suggest setting Y during development and ironing out driver
|
||||
issues etc. Suggest setting to N if you want faster writing.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config YAFFS_SHORT_NAMES_IN_RAM
|
||||
bool "Cache short names in RAM"
|
||||
depends on YAFFS_FS
|
||||
default y
|
||||
help
|
||||
If this config is set, then short names are stored with the
|
||||
yaffs_Object. This costs an extra 16 bytes of RAM per object,
|
||||
but makes look-ups faster.
|
||||
|
||||
If unsure, say Y.
|
|
@ -1,40 +0,0 @@
|
|||
# Main Makefile for YAFFS
|
||||
#
|
||||
#
|
||||
# YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
#
|
||||
# Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
# for Toby Churchill Ltd and Brightstar Engineering
|
||||
#
|
||||
# Created by Charles Manning <charles@aleph1.co.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
EXTRA_CFLAGS += -DYAFFS_OUT_OF_TREE
|
||||
|
||||
obj-m := yaffs2.o
|
||||
|
||||
yaffs2-objs := yaffs_mtdif.o yaffs_mtdif2.o
|
||||
yaffs2-objs += yaffs_mtdif1.o yaffs_packedtags1.o
|
||||
yaffs2-objs += yaffs_ecc.o yaffs_fs.o yaffs_guts.o
|
||||
yaffs2-objs += yaffs_packedtags2.o yaffs_qsort.o
|
||||
yaffs2-objs += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||
yaffs2-objs += yaffs_checkptrw.o yaffs_nand.o
|
||||
|
||||
else
|
||||
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
modules default:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
|
||||
mi modules_install:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
|
||||
endif
|
|
@ -1,10 +0,0 @@
|
|||
#
|
||||
# Makefile for the linux YAFFS filesystem routines.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_YAFFS_FS) += yaffs.o
|
||||
|
||||
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
|
||||
yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
|
||||
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
|
||||
yaffs-y += yaffs_mtdif.o yaffs_mtdif1.o yaffs_mtdif2.o
|
|
@ -1,20 +0,0 @@
|
|||
To build YAFFS in the Linux kernel tree you need to run the patch-ker.sh
|
||||
script from the yaffs source directory, giving your choice as to whether
|
||||
you wish to copy (c) or link (l) the code and the path to your kernel
|
||||
sources, e.g:
|
||||
|
||||
./patch-ker.sh c /usr/src/linux
|
||||
|
||||
This will copy the yaffs files into fs/yaffs2 and modify the Kconfig
|
||||
and Makefiles in the fs directory.
|
||||
|
||||
./patch-ker.sh l /usr/src/linux
|
||||
|
||||
This does the same as the above but makes symbolic links instead.
|
||||
|
||||
After you've run the script, go back to your normal kernel making procedure
|
||||
and configure the yaffs settings you want.
|
||||
|
||||
Prolems? Contact the yaffs mailing list:
|
||||
|
||||
http://www.aleph1.co.uk/mailman/listinfo/yaffs
|
File diff suppressed because it is too large
Load diff
|
@ -1,75 +0,0 @@
|
|||
# Makefile for YAFFS direct test
|
||||
#
|
||||
#
|
||||
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
|
||||
#
|
||||
# Copyright (C) 2003 Aleph One Ltd.
|
||||
#
|
||||
#
|
||||
# Created by Charles Manning <charles@aleph1.co.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# NB Warning this Makefile does not include header dependencies.
|
||||
#
|
||||
# $Id: Makefile,v 1.1 2007/10/16 00:46:33 charles Exp $
|
||||
|
||||
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
|
||||
|
||||
CFLAGS = -Wall -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -g $(EXTRA_COMPILE_FLAGS) -DNO_Y_INLINE
|
||||
CFLAGS+= -fstack-check -O0
|
||||
|
||||
#CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
|
||||
#CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
|
||||
|
||||
|
||||
FSXTESTOBJS = yaffs_fsx.o yaffscfg2k.o yaffs_ecc.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
|
||||
yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
|
||||
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o yaffs_nand.o \
|
||||
yaffs_checkptrw.o yaffs_qsort.o \
|
||||
# yaffs_checkptrwtest.o\
|
||||
|
||||
|
||||
BOOTTESTOBJS = bootldtst.o yboot.o yaffs_fileem.o nand_ecc.o
|
||||
|
||||
#ALLOBJS = dtest.o nand_ecc.o yaffscfg.o yaffs_fileem.o yaffsfs.o yaffs_ramdisk.o bootldtst.o yboot.o yaffs_ramem2k.o
|
||||
|
||||
ALLOBJS = $(FSXTESTOBJS) $(BOOTTESTOBJS)
|
||||
|
||||
YAFFSSYMLINKS = devextras.h yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h yaffsinterface.h yportenv.h yaffs_tagscompat.c yaffs_tagscompat.h \
|
||||
yaffs_packedtags1.c yaffs_packedtags1.h yaffs_packedtags2.c yaffs_packedtags2.h yaffs_nandemul2k.h \
|
||||
yaffs_nand.c yaffs_nand.h \
|
||||
yaffs_tagsvalidity.c yaffs_tagsvalidity.h yaffs_checkptrw.h yaffs_checkptrw.c \
|
||||
yaffs_qsort.c yaffs_qsort.h
|
||||
|
||||
YAFFSDIRECTSYMLINKS = yaffscfg2k.c yaffs_fileem2k.c yaffsfs.c yaffs_flashif.h \
|
||||
yaffs_fileem2k.h yaffsfs.h yaffs_malloc.h yaffs_ramdisk.h ydirectenv.h \
|
||||
yaffscfg.h yaffs_fileem.c yaffs_flashif.c yaffs_ramdisk.c yaffs_ramem2k.c
|
||||
|
||||
|
||||
|
||||
#all: fsxtest boottest
|
||||
|
||||
all: fsxtest
|
||||
|
||||
$(ALLOBJS): %.o: %.c
|
||||
gcc -c $(CFLAGS) $< -o $@
|
||||
|
||||
$(YAFFSSYMLINKS):
|
||||
ln -s ../../$@ $@
|
||||
|
||||
$(YAFFSDIRECTSYMLINKS):
|
||||
ln -s ../$@ $@
|
||||
|
||||
fsxtest: $(YAFFSSYMLINKS) $(YAFFSDIRECTSYMLINKS) $(FSXTESTOBJS)
|
||||
gcc -o $@ $(FSXTESTOBJS)
|
||||
|
||||
|
||||
boottest: $(SYMLINKS) $(BOOTTESTOBJS)
|
||||
gcc -o $@ $(BOOTTESTOBJS)
|
||||
|
||||
|
||||
clean:
|
||||
rm -f $(ALLOBJS) core
|
|
@ -1,7 +0,0 @@
|
|||
NB THis directory uses a hacked version of fsx.c which is released under
|
||||
Apple Public Source License.
|
||||
|
||||
From what I have been able to determine, it is legally OK to release a hacked
|
||||
version for the purposes of testing.
|
||||
|
||||
If anyone knows otherwise, please contact me: manningc2@actrix.gen.nz
|
File diff suppressed because it is too large
Load diff
|
@ -1,219 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides a YAFFS nand emulation on a file.
|
||||
* This is only intended as test code to test persistence etc.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_flashif_c_version = "$Id: yaffs_fileem.c,v 1.3 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
#include "yaffs_flashif.h"
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
#include "devextras.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
#define SIZE_IN_MB 16
|
||||
|
||||
#define BLOCK_SIZE (32 * 528)
|
||||
#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__u8 data[528]; // Data + spare
|
||||
} yflash_Page;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
yflash_Page page[32]; // The pages in the block
|
||||
|
||||
} yflash_Block;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int handle;
|
||||
int nBlocks;
|
||||
} yflash_Device;
|
||||
|
||||
static yflash_Device filedisk;
|
||||
|
||||
static int CheckInit(yaffs_Device *dev)
|
||||
{
|
||||
static int initialised = 0;
|
||||
|
||||
int i;
|
||||
|
||||
|
||||
int fSize;
|
||||
int written;
|
||||
|
||||
yflash_Page p;
|
||||
|
||||
if(initialised)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
initialised = 1;
|
||||
|
||||
|
||||
filedisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024);
|
||||
|
||||
filedisk.handle = open("yaffsemfile", O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
|
||||
|
||||
if(filedisk.handle < 0)
|
||||
{
|
||||
perror("Failed to open yaffs emulation file");
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
|
||||
fSize = lseek(filedisk.handle,0,SEEK_END);
|
||||
|
||||
if(fSize < SIZE_IN_MB * 1024 * 1024)
|
||||
{
|
||||
printf("Creating yaffs emulation file\n");
|
||||
|
||||
lseek(filedisk.handle,0,SEEK_SET);
|
||||
|
||||
memset(&p,0xff,sizeof(yflash_Page));
|
||||
|
||||
for(i = 0; i < SIZE_IN_MB * 1024 * 1024; i+= 512)
|
||||
{
|
||||
written = write(filedisk.handle,&p,sizeof(yflash_Page));
|
||||
|
||||
if(written != sizeof(yflash_Page))
|
||||
{
|
||||
printf("Write failed\n");
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
|
||||
{
|
||||
int written;
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET);
|
||||
written = write(filedisk.handle,data,512);
|
||||
|
||||
if(written != 512) return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
if(spare)
|
||||
{
|
||||
lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET);
|
||||
written = write(filedisk.handle,spare,16);
|
||||
|
||||
if(written != 16) return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
|
||||
{
|
||||
int nread;
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
lseek(filedisk.handle,chunkInNAND * 528,SEEK_SET);
|
||||
nread = read(filedisk.handle,data,512);
|
||||
|
||||
if(nread != 512) return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
if(spare)
|
||||
{
|
||||
lseek(filedisk.handle,chunkInNAND * 528 + 512,SEEK_SET);
|
||||
nread= read(filedisk.handle,spare,16);
|
||||
|
||||
if(nread != 16) return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
|
||||
{
|
||||
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
yflash_Page pg;
|
||||
|
||||
memset(&pg,0xff,sizeof(yflash_Page));
|
||||
|
||||
lseek(filedisk.handle, blockNumber * 32 * 528, SEEK_SET);
|
||||
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
write(filedisk.handle,&pg,528);
|
||||
}
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int yflash_InitialiseNAND(yaffs_Device *dev)
|
||||
{
|
||||
dev->useNANDECC = 1; // force on useNANDECC which gets faked.
|
||||
// This saves us doing ECC checks.
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
|
@ -1,443 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides a YAFFS nand emulation on a file for emulating 2kB pages.
|
||||
* This is only intended as test code to test persistence etc.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.12 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
#include "yaffs_flashif.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "devextras.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "yaffs_fileem2k.h"
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
//#define SIMULATE_FAILURES
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__u8 data[PAGE_SIZE]; // Data + spare
|
||||
} yflash_Page;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
|
||||
|
||||
} yflash_Block;
|
||||
|
||||
|
||||
|
||||
#define MAX_HANDLES 20
|
||||
#define BLOCKS_PER_HANDLE 8000
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int handle[MAX_HANDLES];
|
||||
int nBlocks;
|
||||
} yflash_Device;
|
||||
|
||||
static yflash_Device filedisk;
|
||||
|
||||
int yaffs_testPartialWrite = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
static __u8 localBuffer[PAGE_SIZE];
|
||||
|
||||
static char *NToName(char *buf,int n)
|
||||
{
|
||||
sprintf(buf,"emfile%d",n);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char dummyBuffer[BLOCK_SIZE];
|
||||
|
||||
static int GetBlockFileHandle(int n)
|
||||
{
|
||||
int h;
|
||||
int requiredSize;
|
||||
|
||||
char name[40];
|
||||
NToName(name,n);
|
||||
int fSize;
|
||||
int i;
|
||||
|
||||
h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
|
||||
if(h >= 0){
|
||||
fSize = lseek(h,0,SEEK_END);
|
||||
requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
|
||||
if(fSize < requiredSize){
|
||||
for(i = 0; i < BLOCKS_PER_HANDLE; i++)
|
||||
if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
|
||||
return -1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
|
||||
}
|
||||
|
||||
static int CheckInit(void)
|
||||
{
|
||||
static int initialised = 0;
|
||||
int h;
|
||||
int i;
|
||||
|
||||
|
||||
off_t fSize;
|
||||
off_t requiredSize;
|
||||
int written;
|
||||
int blk;
|
||||
|
||||
yflash_Page p;
|
||||
|
||||
if(initialised)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
initialised = 1;
|
||||
|
||||
memset(dummyBuffer,0xff,sizeof(dummyBuffer));
|
||||
|
||||
|
||||
filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
|
||||
|
||||
for(i = 0; i < MAX_HANDLES; i++)
|
||||
filedisk.handle[i] = -1;
|
||||
|
||||
for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
|
||||
filedisk.handle[i] = GetBlockFileHandle(i);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int yflash_GetNumberOfBlocks(void)
|
||||
{
|
||||
CheckInit();
|
||||
|
||||
return filedisk.nBlocks;
|
||||
}
|
||||
|
||||
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
|
||||
{
|
||||
int written;
|
||||
int pos;
|
||||
int h;
|
||||
int i;
|
||||
int nRead;
|
||||
int error;
|
||||
|
||||
T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
|
||||
|
||||
CheckInit();
|
||||
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
|
||||
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
|
||||
|
||||
lseek(h,pos,SEEK_SET);
|
||||
nRead = read(h, localBuffer,dev->nDataBytesPerChunk);
|
||||
for(i = error = 0; i < dev->nDataBytesPerChunk && !error; i++){
|
||||
if(localBuffer[i] != 0xFF){
|
||||
printf("nand simulation: chunk %d data byte %d was %0x2\n",
|
||||
chunkInNAND,i,localBuffer[i]);
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < dev->nDataBytesPerChunk; i++)
|
||||
localBuffer[i] &= data[i];
|
||||
|
||||
if(memcmp(localBuffer,data,dev->nDataBytesPerChunk))
|
||||
printf("nand simulator: data does not match\n");
|
||||
|
||||
lseek(h,pos,SEEK_SET);
|
||||
written = write(h,localBuffer,dev->nDataBytesPerChunk);
|
||||
|
||||
if(yaffs_testPartialWrite){
|
||||
close(h);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef SIMULATE_FAILURES
|
||||
if((chunkInNAND >> 6) == 100)
|
||||
written = 0;
|
||||
|
||||
if((chunkInNAND >> 6) == 110)
|
||||
written = 0;
|
||||
#endif
|
||||
|
||||
|
||||
if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
if(tags)
|
||||
{
|
||||
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
|
||||
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
|
||||
|
||||
lseek(h,pos,SEEK_SET);
|
||||
|
||||
if( 0 && dev->isYaffs2)
|
||||
{
|
||||
|
||||
written = write(h,tags,sizeof(yaffs_ExtendedTags));
|
||||
if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
yaffs_PackedTags2 pt;
|
||||
yaffs_PackTags2(&pt,tags);
|
||||
__u8 * ptab = (__u8 *)&pt;
|
||||
|
||||
nRead = read(h,localBuffer,sizeof(pt));
|
||||
for(i = error = 0; i < sizeof(pt) && !error; i++){
|
||||
if(localBuffer[i] != 0xFF){
|
||||
printf("nand simulation: chunk %d oob byte %d was %0x2\n",
|
||||
chunkInNAND,i,localBuffer[i]);
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < sizeof(pt); i++)
|
||||
localBuffer[i] &= ptab[i];
|
||||
|
||||
if(memcmp(localBuffer,&pt,sizeof(pt)))
|
||||
printf("nand sim: tags corruption\n");
|
||||
|
||||
lseek(h,pos,SEEK_SET);
|
||||
|
||||
written = write(h,localBuffer,sizeof(pt));
|
||||
if(written != sizeof(pt)) return YAFFS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int yaffs_CheckAllFF(const __u8 *ptr, int n)
|
||||
{
|
||||
while(n)
|
||||
{
|
||||
n--;
|
||||
if(*ptr!=0xFF) return 0;
|
||||
ptr++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int fail300 = 1;
|
||||
static int fail320 = 1;
|
||||
|
||||
static int failRead10 = 2;
|
||||
|
||||
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
|
||||
{
|
||||
int nread;
|
||||
int pos;
|
||||
int h;
|
||||
|
||||
T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
|
||||
|
||||
CheckInit();
|
||||
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
|
||||
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
|
||||
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
|
||||
lseek(h,pos,SEEK_SET);
|
||||
nread = read(h,data,dev->nDataBytesPerChunk);
|
||||
|
||||
|
||||
if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
if(tags)
|
||||
{
|
||||
pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
|
||||
h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
|
||||
lseek(h,pos,SEEK_SET);
|
||||
|
||||
if(0 && dev->isYaffs2)
|
||||
{
|
||||
nread= read(h,tags,sizeof(yaffs_ExtendedTags));
|
||||
if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
|
||||
if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
|
||||
{
|
||||
yaffs_InitialiseTags(tags);
|
||||
}
|
||||
else
|
||||
{
|
||||
tags->chunkUsed = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yaffs_PackedTags2 pt;
|
||||
nread= read(h,&pt,sizeof(pt));
|
||||
yaffs_UnpackTags2(tags,&pt);
|
||||
#ifdef SIMULATE_FAILURES
|
||||
if((chunkInNAND >> 6) == 100) {
|
||||
if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
|
||||
tags->eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
fail300 = 0;
|
||||
}
|
||||
|
||||
}
|
||||
if((chunkInNAND >> 6) == 110) {
|
||||
if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
|
||||
tags->eccResult = YAFFS_ECC_RESULT_FIXED;
|
||||
fail320 = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(failRead10>0 && chunkInNAND == 10){
|
||||
failRead10--;
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
if(nread != sizeof(pt)) return YAFFS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
{
|
||||
int written;
|
||||
int h;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
CheckInit();
|
||||
|
||||
memset(&pt,0,sizeof(pt));
|
||||
h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
|
||||
lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
|
||||
written = write(h,&pt,sizeof(pt));
|
||||
|
||||
if(written != sizeof(pt)) return YAFFS_FAIL;
|
||||
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||
{
|
||||
|
||||
int i;
|
||||
int h;
|
||||
|
||||
CheckInit();
|
||||
|
||||
printf("erase block %d\n",blockNumber);
|
||||
|
||||
if(blockNumber == 320)
|
||||
fail320 = 1;
|
||||
|
||||
if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
|
||||
{
|
||||
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
__u8 pg[PAGE_SIZE];
|
||||
int syz = PAGE_SIZE;
|
||||
int pos;
|
||||
|
||||
memset(pg,0xff,syz);
|
||||
|
||||
|
||||
h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
|
||||
lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);
|
||||
for(i = 0; i < dev->nChunksPerBlock; i++)
|
||||
{
|
||||
write(h,pg,PAGE_SIZE);
|
||||
}
|
||||
pos = lseek(h, 0,SEEK_CUR);
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int yflash_InitialiseNAND(yaffs_Device *dev)
|
||||
{
|
||||
CheckInit();
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
|
||||
{
|
||||
yaffs_ExtendedTags tags;
|
||||
int chunkNo;
|
||||
|
||||
*sequenceNumber = 0;
|
||||
|
||||
chunkNo = blockNo * dev->nChunksPerBlock;
|
||||
|
||||
yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
|
||||
if(tags.blockBad)
|
||||
{
|
||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
else if(!tags.chunkUsed)
|
||||
{
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
}
|
||||
else if(tags.chunkUsed)
|
||||
{
|
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
*sequenceNumber = tags.sequenceNumber;
|
||||
}
|
||||
return YAFFS_OK;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __FILEEM2K_H__
|
||||
#define __FILEEM2K_H__
|
||||
|
||||
#if 1
|
||||
|
||||
#define SIZE_IN_MB 128
|
||||
//#define SIZE_IN_MB 8000
|
||||
#define PAGE_DATA_SIZE (2048)
|
||||
#define PAGE_SPARE_SIZE (64)
|
||||
#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
|
||||
#define PAGES_PER_BLOCK (64)
|
||||
#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK)
|
||||
#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
|
||||
#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
|
||||
#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
|
||||
|
||||
#else
|
||||
|
||||
#define SIZE_IN_MB 128
|
||||
#define PAGE_DATA_SIZE (512)
|
||||
#define SPARE_SIZE (16)
|
||||
#define PAGE_SIZE (PAGE_DATA_SIZE + SPARE_SIZE)
|
||||
#define PAGES_PER_BLOCK (32)
|
||||
#define BLOCK_DATA_SIZE (PAGE_SIZE * PAGES_PER_BLOCK)
|
||||
#define BLOCK_SIZE (PAGES_PER_BLOCK * (PAGE_SIZE))
|
||||
#define BLOCKS_PER_MB ((1024*1024)/BLOCK_DATA_SIZE)
|
||||
#define SIZE_IN_BLOCKS (BLOCKS_PER_MB * SIZE_IN_MB)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int yflash_GetNumberOfBlocks(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_flashif_c_version = "$Id: yaffs_flashif.c,v 1.3 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
#include "yaffs_flashif.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "devextras.h"
|
||||
|
||||
|
||||
#define SIZE_IN_MB 16
|
||||
|
||||
#define BLOCK_SIZE (32 * 528)
|
||||
#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__u8 data[528]; // Data + spare
|
||||
} yflash_Page;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
yflash_Page page[32]; // The pages in the block
|
||||
|
||||
} yflash_Block;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
yflash_Block **block;
|
||||
int nBlocks;
|
||||
} yflash_Device;
|
||||
|
||||
static yflash_Device ramdisk;
|
||||
|
||||
static int CheckInit(yaffs_Device *dev)
|
||||
{
|
||||
static int initialised = 0;
|
||||
|
||||
int i;
|
||||
int fail = 0;
|
||||
int nAllocated = 0;
|
||||
|
||||
if(initialised)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
initialised = 1;
|
||||
|
||||
|
||||
ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024);
|
||||
|
||||
ramdisk.block = YMALLOC(sizeof(yflash_Block *) * ramdisk.nBlocks);
|
||||
|
||||
if(!ramdisk.block) return 0;
|
||||
|
||||
for(i=0; i <ramdisk.nBlocks; i++)
|
||||
{
|
||||
ramdisk.block[i] = NULL;
|
||||
}
|
||||
|
||||
for(i=0; i <ramdisk.nBlocks && !fail; i++)
|
||||
{
|
||||
if((ramdisk.block[i] = YMALLOC(sizeof(yflash_Block))) == 0)
|
||||
{
|
||||
fail = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
yflash_EraseBlockInNAND(dev,i);
|
||||
nAllocated++;
|
||||
}
|
||||
}
|
||||
|
||||
if(fail)
|
||||
{
|
||||
for(i = 0; i < nAllocated; i++)
|
||||
{
|
||||
YFREE(ramdisk.block[i]);
|
||||
}
|
||||
YFREE(ramdisk.block);
|
||||
|
||||
T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
|
||||
nAllocated/64,ramdisk.nBlocks * YAFFS_BYTES_PER_BLOCK));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
blk = chunkInNAND/32;
|
||||
pg = chunkInNAND%32;
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
memcpy(ramdisk.block[blk]->page[pg].data,data,512);
|
||||
}
|
||||
|
||||
|
||||
if(tags)
|
||||
{
|
||||
yaffs_PackedTags pt;
|
||||
yaffs_PackTags(&pt,tags);
|
||||
memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt));
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Tags *tags)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
blk = chunkInNAND/32;
|
||||
pg = chunkInNAND%32;
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
memcpy(data,ramdisk.block[blk]->page[pg].data,512);
|
||||
}
|
||||
|
||||
|
||||
if(tags)
|
||||
{
|
||||
yaffs_PackedTags pt;
|
||||
memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(yaffs_PackedTags));
|
||||
yaffs_UnpackTags(tags,&pt);
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
int yflash_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
int i;
|
||||
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
blk = chunkInNAND/32;
|
||||
pg = chunkInNAND%32;
|
||||
|
||||
|
||||
for(i = 0; i < 528; i++)
|
||||
{
|
||||
if(ramdisk.block[blk]->page[pg].data[i] != 0xFF)
|
||||
{
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||
{
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks)
|
||||
{
|
||||
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(ramdisk.block[blockNumber],0xFF,sizeof(yflash_Block));
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
|
||||
{
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
*sequenceNumber = 0;
|
||||
}
|
||||
|
||||
|
||||
int yflash_InitialiseNAND(yaffs_Device *dev)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
|
@ -1,235 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* yaffs_ramdisk.c: yaffs ram disk component
|
||||
* This provides a ram disk under yaffs.
|
||||
* NB this is not intended for NAND emulation.
|
||||
* Use this with dev->useNANDECC enabled, then ECC overheads are not required.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_ramdisk_c_version = "$Id: yaffs_ramdisk.c,v 1.4 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
#include "yaffs_ramdisk.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "devextras.h"
|
||||
#include "yaffs_packedtags1.h"
|
||||
|
||||
|
||||
|
||||
#define SIZE_IN_MB 2
|
||||
|
||||
#define BLOCK_SIZE (32 * 528)
|
||||
#define BLOCKS_PER_MEG ((1024*1024)/(32 * 512))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__u8 data[528]; // Data + spare
|
||||
} yramdisk_Page;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
yramdisk_Page page[32]; // The pages in the block
|
||||
|
||||
} yramdisk_Block;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
yramdisk_Block **block;
|
||||
int nBlocks;
|
||||
} yramdisk_Device;
|
||||
|
||||
static yramdisk_Device ramdisk;
|
||||
|
||||
static int CheckInit(yaffs_Device *dev)
|
||||
{
|
||||
static int initialised = 0;
|
||||
|
||||
int i;
|
||||
int fail = 0;
|
||||
//int nBlocks;
|
||||
int nAllocated = 0;
|
||||
|
||||
if(initialised)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
initialised = 1;
|
||||
|
||||
|
||||
ramdisk.nBlocks = (SIZE_IN_MB * 1024 * 1024)/(16 * 1024);
|
||||
|
||||
ramdisk.block = YMALLOC(sizeof(yramdisk_Block *) * ramdisk.nBlocks);
|
||||
|
||||
if(!ramdisk.block) return 0;
|
||||
|
||||
for(i=0; i <ramdisk.nBlocks; i++)
|
||||
{
|
||||
ramdisk.block[i] = NULL;
|
||||
}
|
||||
|
||||
for(i=0; i <ramdisk.nBlocks && !fail; i++)
|
||||
{
|
||||
if((ramdisk.block[i] = YMALLOC(sizeof(yramdisk_Block))) == 0)
|
||||
{
|
||||
fail = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
yramdisk_EraseBlockInNAND(dev,i);
|
||||
nAllocated++;
|
||||
}
|
||||
}
|
||||
|
||||
if(fail)
|
||||
{
|
||||
for(i = 0; i < nAllocated; i++)
|
||||
{
|
||||
YFREE(ramdisk.block[i]);
|
||||
}
|
||||
YFREE(ramdisk.block);
|
||||
|
||||
T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
|
||||
nAllocated/64,ramdisk.nBlocks * 528));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
blk = chunkInNAND/32;
|
||||
pg = chunkInNAND%32;
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
memcpy(ramdisk.block[blk]->page[pg].data,data,512);
|
||||
}
|
||||
|
||||
|
||||
if(tags)
|
||||
{
|
||||
yaffs_PackedTags1 pt;
|
||||
|
||||
yaffs_PackTags1(&pt,tags);
|
||||
memcpy(&ramdisk.block[blk]->page[pg].data[512],&pt,sizeof(pt));
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
blk = chunkInNAND/32;
|
||||
pg = chunkInNAND%32;
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
memcpy(data,ramdisk.block[blk]->page[pg].data,512);
|
||||
}
|
||||
|
||||
|
||||
if(tags)
|
||||
{
|
||||
yaffs_PackedTags1 pt;
|
||||
|
||||
memcpy(&pt,&ramdisk.block[blk]->page[pg].data[512],sizeof(pt));
|
||||
yaffs_UnpackTags1(tags,&pt);
|
||||
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
int yramdisk_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
int i;
|
||||
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
blk = chunkInNAND/32;
|
||||
pg = chunkInNAND%32;
|
||||
|
||||
|
||||
for(i = 0; i < 528; i++)
|
||||
{
|
||||
if(ramdisk.block[blk]->page[pg].data[i] != 0xFF)
|
||||
{
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||
{
|
||||
|
||||
CheckInit(dev);
|
||||
|
||||
if(blockNumber < 0 || blockNumber >= ramdisk.nBlocks)
|
||||
{
|
||||
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(ramdisk.block[blockNumber],0xFF,sizeof(yramdisk_Block));
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int yramdisk_InitialiseNAND(yaffs_Device *dev)
|
||||
{
|
||||
//dev->useNANDECC = 1; // force on useNANDECC which gets faked.
|
||||
// This saves us doing ECC checks.
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
|
@ -1,364 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* yaffs_ramem2k.c: RAM emulation in-kernel for 2K pages (YAFFS2)
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
const char *yaffs_ramem2k_c_version = "$Id: yaffs_ramem2k.c,v 1.3 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define CONFIG_YAFFS_RAM_ENABLED
|
||||
#else
|
||||
#include <linux/config.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_YAFFS_RAM_ENABLED
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
#include "yaffs_nandemul2k.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffsinterface.h"
|
||||
#include "devextras.h"
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
|
||||
|
||||
#define EM_SIZE_IN_MEG (32)
|
||||
#define PAGE_DATA_SIZE (2048)
|
||||
#define PAGE_SPARE_SIZE (64)
|
||||
#define PAGES_PER_BLOCK (64)
|
||||
|
||||
|
||||
|
||||
#define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20))
|
||||
|
||||
#define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE)
|
||||
|
||||
#define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE)
|
||||
|
||||
#define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE))
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__u8 data[PAGE_TOTAL_SIZE]; // Data + spare
|
||||
int empty; // is this empty?
|
||||
} nandemul_Page;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nandemul_Page *page[PAGES_PER_BLOCK];
|
||||
int damaged;
|
||||
} nandemul_Block;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nandemul_Block**block;
|
||||
int nBlocks;
|
||||
} nandemul_Device;
|
||||
|
||||
static nandemul_Device ned;
|
||||
|
||||
static int sizeInMB = EM_SIZE_IN_MEG;
|
||||
|
||||
|
||||
static void nandemul_yield(int n)
|
||||
{
|
||||
#ifdef __KERNEL__
|
||||
if(n > 0) schedule_timeout(n);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void nandemul_ReallyEraseBlock(int blockNumber)
|
||||
{
|
||||
int i;
|
||||
|
||||
nandemul_Block *blk;
|
||||
|
||||
if(blockNumber < 0 || blockNumber >= ned.nBlocks)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
blk = ned.block[blockNumber];
|
||||
|
||||
for(i = 0; i < PAGES_PER_BLOCK; i++)
|
||||
{
|
||||
memset(blk->page[i],0xff,sizeof(nandemul_Page));
|
||||
blk->page[i]->empty = 1;
|
||||
}
|
||||
nandemul_yield(2);
|
||||
}
|
||||
|
||||
|
||||
static int nandemul2k_CalcNBlocks(void)
|
||||
{
|
||||
return EM_SIZE_IN_MEG * BLOCKS_PER_MEG;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int CheckInit(void)
|
||||
{
|
||||
static int initialised = 0;
|
||||
|
||||
int i,j;
|
||||
|
||||
int fail = 0;
|
||||
int nBlocks;
|
||||
|
||||
int nAllocated = 0;
|
||||
|
||||
if(initialised)
|
||||
{
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks();
|
||||
|
||||
|
||||
ned.block = YMALLOC(sizeof(nandemul_Block*) * nBlocks );
|
||||
|
||||
if(!ned.block) return YAFFS_FAIL;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for(i=fail=0; i <nBlocks; i++)
|
||||
{
|
||||
|
||||
nandemul_Block *blk;
|
||||
|
||||
if(!(blk = ned.block[i] = YMALLOC(sizeof(nandemul_Block))))
|
||||
{
|
||||
fail = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(j = 0; j < PAGES_PER_BLOCK; j++)
|
||||
{
|
||||
if((blk->page[j] = YMALLOC(sizeof(nandemul_Page))) == 0)
|
||||
{
|
||||
fail = 1;
|
||||
}
|
||||
}
|
||||
nandemul_ReallyEraseBlock(i);
|
||||
ned.block[i]->damaged = 0;
|
||||
nAllocated++;
|
||||
}
|
||||
}
|
||||
|
||||
if(fail)
|
||||
{
|
||||
//Todo thump pages
|
||||
|
||||
for(i = 0; i < nAllocated; i++)
|
||||
{
|
||||
YFREE(ned.block[i]);
|
||||
}
|
||||
YFREE(ned.block);
|
||||
|
||||
T(YAFFS_TRACE_ALWAYS,("Allocation failed, could only allocate %dMB of %dMB requested.\n",
|
||||
nAllocated/64,sizeInMB));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ned.nBlocks = nBlocks;
|
||||
|
||||
initialised = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nandemul2k_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
int i;
|
||||
|
||||
__u8 *x;
|
||||
|
||||
|
||||
blk = chunkInNAND/PAGES_PER_BLOCK;
|
||||
pg = chunkInNAND%PAGES_PER_BLOCK;
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
x = ned.block[blk]->page[pg]->data;
|
||||
|
||||
for(i = 0; i < PAGE_DATA_SIZE; i++)
|
||||
{
|
||||
x[i] &=data[i];
|
||||
}
|
||||
|
||||
ned.block[blk]->page[pg]->empty = 0;
|
||||
}
|
||||
|
||||
|
||||
if(tags)
|
||||
{
|
||||
x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
|
||||
|
||||
yaffs_PackTags2((yaffs_PackedTags2 *)x,tags);
|
||||
|
||||
}
|
||||
|
||||
if(tags || data)
|
||||
{
|
||||
nandemul_yield(1);
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
int nandemul2k_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
|
||||
__u8 *x;
|
||||
|
||||
|
||||
|
||||
blk = chunkInNAND/PAGES_PER_BLOCK;
|
||||
pg = chunkInNAND%PAGES_PER_BLOCK;
|
||||
|
||||
|
||||
if(data)
|
||||
{
|
||||
memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE);
|
||||
}
|
||||
|
||||
|
||||
if(tags)
|
||||
{
|
||||
x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
|
||||
|
||||
yaffs_UnpackTags2(tags,(yaffs_PackedTags2 *)x);
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
static int nandemul2k_CheckChunkErased(yaffs_Device *dev,int chunkInNAND)
|
||||
{
|
||||
int blk;
|
||||
int pg;
|
||||
int i;
|
||||
|
||||
|
||||
|
||||
blk = chunkInNAND/PAGES_PER_BLOCK;
|
||||
pg = chunkInNAND%PAGES_PER_BLOCK;
|
||||
|
||||
|
||||
for(i = 0; i < PAGE_TOTAL_SIZE; i++)
|
||||
{
|
||||
if(ned.block[blk]->page[pg]->data[i] != 0xFF)
|
||||
{
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int nandemul2k_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
|
||||
{
|
||||
|
||||
|
||||
if(blockNumber < 0 || blockNumber >= ned.nBlocks)
|
||||
{
|
||||
T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
|
||||
}
|
||||
else if(ned.block[blockNumber]->damaged)
|
||||
{
|
||||
T(YAFFS_TRACE_ALWAYS,("Attempt to erase damaged block %d\n",blockNumber));
|
||||
}
|
||||
else
|
||||
{
|
||||
nandemul_ReallyEraseBlock(blockNumber);
|
||||
}
|
||||
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
int nandemul2k_InitialiseNAND(yaffs_Device *dev)
|
||||
{
|
||||
CheckInit();
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
{
|
||||
|
||||
__u8 *x;
|
||||
|
||||
x = &ned.block[blockNo]->page[0]->data[PAGE_DATA_SIZE];
|
||||
|
||||
memset(x,0,sizeof(yaffs_PackedTags2));
|
||||
|
||||
|
||||
return YAFFS_OK;
|
||||
|
||||
}
|
||||
|
||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
|
||||
{
|
||||
yaffs_ExtendedTags tags;
|
||||
int chunkNo;
|
||||
|
||||
*sequenceNumber = 0;
|
||||
|
||||
chunkNo = blockNo * dev->nChunksPerBlock;
|
||||
|
||||
nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
|
||||
if(tags.blockBad)
|
||||
{
|
||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
else if(!tags.chunkUsed)
|
||||
{
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
}
|
||||
else if(tags.chunkUsed)
|
||||
{
|
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
*sequenceNumber = tags.sequenceNumber;
|
||||
}
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;}
|
||||
|
||||
int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; }
|
||||
int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();}
|
||||
|
||||
|
||||
#endif //YAFFS_RAM_ENABLED
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* yaffscfg2k.c The configuration for the "direct" use of yaffs.
|
||||
*
|
||||
* This file is intended to be modified to your requirements.
|
||||
* There is no need to redistribute this file.
|
||||
*/
|
||||
|
||||
/* XXX U-BOOT XXX */
|
||||
#include <common.h>
|
||||
|
||||
#include "yaffscfg.h"
|
||||
#include "yaffsfs.h"
|
||||
#include "yaffs_fileem2k.h"
|
||||
#include "yaffs_nandemul2k.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
unsigned yaffs_traceMask =
|
||||
|
||||
YAFFS_TRACE_SCAN |
|
||||
YAFFS_TRACE_GC | YAFFS_TRACE_GC_DETAIL |
|
||||
YAFFS_TRACE_ERASE |
|
||||
YAFFS_TRACE_TRACING |
|
||||
YAFFS_TRACE_ALLOCATE |
|
||||
YAFFS_TRACE_CHECKPOINT |
|
||||
YAFFS_TRACE_BAD_BLOCKS |
|
||||
YAFFS_TRACE_VERIFY |
|
||||
YAFFS_TRACE_VERIFY_NAND |
|
||||
YAFFS_TRACE_VERIFY_FULL |
|
||||
// (~0) |
|
||||
|
||||
0;
|
||||
|
||||
|
||||
|
||||
void yaffsfs_SetError(int err)
|
||||
{
|
||||
//Do whatever to set error
|
||||
errno = err;
|
||||
}
|
||||
|
||||
void yaffsfs_Lock(void)
|
||||
{
|
||||
}
|
||||
|
||||
void yaffsfs_Unlock(void)
|
||||
{
|
||||
}
|
||||
|
||||
__u32 yaffsfs_CurrentTime(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int yaffs_kill_alloc = 0;
|
||||
static size_t total_malloced = 0;
|
||||
static size_t malloc_limit = 0 & 6000000;
|
||||
|
||||
void *yaffs_malloc(size_t size)
|
||||
{
|
||||
size_t this;
|
||||
if(yaffs_kill_alloc)
|
||||
return NULL;
|
||||
if(malloc_limit && malloc_limit <(total_malloced + size) )
|
||||
return NULL;
|
||||
|
||||
this = malloc(size);
|
||||
if(this)
|
||||
total_malloced += size;
|
||||
return this;
|
||||
}
|
||||
|
||||
void yaffs_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void yaffsfs_LocalInitialisation(void)
|
||||
{
|
||||
// Define locking semaphore.
|
||||
}
|
||||
|
||||
// Configuration for:
|
||||
// /ram 2MB ramdisk
|
||||
// /boot 2MB boot disk (flash)
|
||||
// /flash 14MB flash disk (flash)
|
||||
// NB Though /boot and /flash occupy the same physical device they
|
||||
// are still disticnt "yaffs_Devices. You may think of these as "partitions"
|
||||
// using non-overlapping areas in the same device.
|
||||
//
|
||||
|
||||
#include "yaffs_ramdisk.h"
|
||||
#include "yaffs_flashif.h"
|
||||
#include "yaffs_nandemul2k.h"
|
||||
|
||||
static yaffs_Device ramDev;
|
||||
static yaffs_Device bootDev;
|
||||
static yaffs_Device flashDev;
|
||||
static yaffs_Device ram2kDev;
|
||||
|
||||
static yaffsfs_DeviceConfiguration yaffsfs_config[] = {
|
||||
#if 0
|
||||
{ "/ram", &ramDev},
|
||||
{ "/boot", &bootDev},
|
||||
{ "/flash/", &flashDev},
|
||||
{ "/ram2k", &ram2kDev},
|
||||
{(void *)0,(void *)0}
|
||||
#else
|
||||
{ "/", &ramDev},
|
||||
{ "/flash/boot", &bootDev},
|
||||
{ "/flash/flash", &flashDev},
|
||||
{ "/ram2k", &ram2kDev},
|
||||
{(void *)0,(void *)0} /* Null entry to terminate list */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
int yaffs_StartUp(void)
|
||||
{
|
||||
// Stuff to configure YAFFS
|
||||
// Stuff to initialise anything special (eg lock semaphore).
|
||||
yaffsfs_LocalInitialisation();
|
||||
|
||||
// Set up devices
|
||||
// /ram
|
||||
memset(&ramDev,0,sizeof(ramDev));
|
||||
ramDev.nDataBytesPerChunk = 512;
|
||||
ramDev.nChunksPerBlock = 32;
|
||||
ramDev.nReservedBlocks = 2; // Set this smaller for RAM
|
||||
ramDev.startBlock = 0; // Can use block 0
|
||||
ramDev.endBlock = 127; // Last block in 2MB.
|
||||
//ramDev.useNANDECC = 1;
|
||||
ramDev.nShortOpCaches = 0; // Disable caching on this device.
|
||||
ramDev.genericDevice = (void *) 0; // Used to identify the device in fstat.
|
||||
ramDev.writeChunkWithTagsToNAND = yramdisk_WriteChunkWithTagsToNAND;
|
||||
ramDev.readChunkWithTagsFromNAND = yramdisk_ReadChunkWithTagsFromNAND;
|
||||
ramDev.eraseBlockInNAND = yramdisk_EraseBlockInNAND;
|
||||
ramDev.initialiseNAND = yramdisk_InitialiseNAND;
|
||||
|
||||
// /boot
|
||||
memset(&bootDev,0,sizeof(bootDev));
|
||||
bootDev.nDataBytesPerChunk = 512;
|
||||
bootDev.nChunksPerBlock = 32;
|
||||
bootDev.nReservedBlocks = 5;
|
||||
bootDev.startBlock = 0; // Can use block 0
|
||||
bootDev.endBlock = 63; // Last block
|
||||
//bootDev.useNANDECC = 0; // use YAFFS's ECC
|
||||
bootDev.nShortOpCaches = 10; // Use caches
|
||||
bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat.
|
||||
bootDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND;
|
||||
bootDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND;
|
||||
bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
|
||||
bootDev.initialiseNAND = yflash_InitialiseNAND;
|
||||
bootDev.markNANDBlockBad = yflash_MarkNANDBlockBad;
|
||||
bootDev.queryNANDBlock = yflash_QueryNANDBlock;
|
||||
|
||||
|
||||
|
||||
// /flash
|
||||
// Set this puppy up to use
|
||||
// the file emulation space as
|
||||
// 2kpage/64chunk per block/128MB device
|
||||
memset(&flashDev,0,sizeof(flashDev));
|
||||
|
||||
flashDev.nDataBytesPerChunk = 2048;
|
||||
flashDev.nChunksPerBlock = 64;
|
||||
flashDev.nReservedBlocks = 5;
|
||||
flashDev.nCheckpointReservedBlocks = 5;
|
||||
//flashDev.checkpointStartBlock = 1;
|
||||
//flashDev.checkpointEndBlock = 20;
|
||||
flashDev.startBlock = 0;
|
||||
flashDev.endBlock = 200; // Make it smaller
|
||||
//flashDev.endBlock = yflash_GetNumberOfBlocks()-1;
|
||||
flashDev.isYaffs2 = 1;
|
||||
flashDev.wideTnodesDisabled=0;
|
||||
flashDev.nShortOpCaches = 10; // Use caches
|
||||
flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat.
|
||||
flashDev.writeChunkWithTagsToNAND = yflash_WriteChunkWithTagsToNAND;
|
||||
flashDev.readChunkWithTagsFromNAND = yflash_ReadChunkWithTagsFromNAND;
|
||||
flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND;
|
||||
flashDev.initialiseNAND = yflash_InitialiseNAND;
|
||||
flashDev.markNANDBlockBad = yflash_MarkNANDBlockBad;
|
||||
flashDev.queryNANDBlock = yflash_QueryNANDBlock;
|
||||
|
||||
// /ram2k
|
||||
// Set this puppy up to use
|
||||
// the file emulation space as
|
||||
// 2kpage/64chunk per block/128MB device
|
||||
memset(&ram2kDev,0,sizeof(ram2kDev));
|
||||
|
||||
ram2kDev.nDataBytesPerChunk = nandemul2k_GetBytesPerChunk();
|
||||
ram2kDev.nChunksPerBlock = nandemul2k_GetChunksPerBlock();
|
||||
ram2kDev.nReservedBlocks = 5;
|
||||
ram2kDev.startBlock = 0; // First block after /boot
|
||||
//ram2kDev.endBlock = 127; // Last block in 16MB
|
||||
ram2kDev.endBlock = nandemul2k_GetNumberOfBlocks() - 1; // Last block in 512MB
|
||||
ram2kDev.isYaffs2 = 1;
|
||||
ram2kDev.nShortOpCaches = 10; // Use caches
|
||||
ram2kDev.genericDevice = (void *) 3; // Used to identify the device in fstat.
|
||||
ram2kDev.writeChunkWithTagsToNAND = nandemul2k_WriteChunkWithTagsToNAND;
|
||||
ram2kDev.readChunkWithTagsFromNAND = nandemul2k_ReadChunkWithTagsFromNAND;
|
||||
ram2kDev.eraseBlockInNAND = nandemul2k_EraseBlockInNAND;
|
||||
ram2kDev.initialiseNAND = nandemul2k_InitialiseNAND;
|
||||
ram2kDev.markNANDBlockBad = nandemul2k_MarkNANDBlockBad;
|
||||
ram2kDev.queryNANDBlock = nandemul2k_QueryNANDBlock;
|
||||
|
||||
yaffs_initialise(yaffsfs_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SetCheckpointReservedBlocks(int n)
|
||||
{
|
||||
flashDev.nCheckpointReservedBlocks = n;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_CONFIG_H__
|
||||
#define __YAFFS_CONFIG_H__
|
||||
|
||||
#ifdef YAFFS_OUT_OF_TREE
|
||||
|
||||
/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
|
||||
#define CONFIG_YAFFS_FS
|
||||
#define CONFIG_YAFFS_YAFFS1
|
||||
#define CONFIG_YAFFS_YAFFS2
|
||||
|
||||
/* These options are independent of each other. Select those that matter. */
|
||||
|
||||
/* Default: Not selected */
|
||||
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
|
||||
//#define CONFIG_YAFFS_DOES_ECC
|
||||
|
||||
/* Default: Not selected */
|
||||
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
|
||||
/* CONFIG_YAFFS_DOES_ECC is set */
|
||||
//#define CONFIG_YAFFS_ECC_WRONG_ORDER
|
||||
|
||||
/* Default: Selected */
|
||||
/* Meaning: Disables testing whether chunks are erased before writing to them*/
|
||||
#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
|
||||
|
||||
/* Default: Selected */
|
||||
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
|
||||
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
|
||||
|
||||
/* Default: 10 */
|
||||
/* Meaning: set the count of blocks to reserve for checkpointing */
|
||||
#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
|
||||
|
||||
/*
|
||||
Older-style on-NAND data format has a "pageStatus" byte to record
|
||||
chunk/page state. This byte is zeroed when the page is discarded.
|
||||
Choose this option if you have existing on-NAND data in this format
|
||||
that you need to continue to support. New data written also uses the
|
||||
older-style format.
|
||||
Note: Use of this option generally requires that MTD's oob layout be
|
||||
adjusted to use the older-style format. See notes on tags formats and
|
||||
MTD versions in yaffs_mtdif1.c.
|
||||
*/
|
||||
/* Default: Not selected */
|
||||
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
|
||||
//#define CONFIG_YAFFS_9BYTE_TAGS
|
||||
|
||||
#endif /* YAFFS_OUT_OF_TREE */
|
||||
|
||||
#endif /* __YAFFS_CONFIG_H__ */
|
|
@ -1,33 +0,0 @@
|
|||
#Makefile for NANDemul MTD
|
||||
#
|
||||
# NB this is not yet suitable for putting into the kernel tree.
|
||||
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
|
||||
#
|
||||
# Copyright (C) 2002 Aleph One Ltd.
|
||||
# for Toby Churchill Ltd and Brightstar Engineering
|
||||
#
|
||||
# Created by Charles Manning <charles@aleph1.co.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
|
||||
## Change or override KERNELDIR to your kernel
|
||||
## comment out USE_xxxx if you don't want these features.
|
||||
|
||||
KERNELDIR = /usr/src/kernel-headers-2.4.27
|
||||
|
||||
CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O2 -Wall -g
|
||||
|
||||
|
||||
|
||||
TARGET = nandemul2k.o
|
||||
|
||||
default: $(TARGET)
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
|
||||
$(TARGET): %.o: %.c
|
||||
gcc -c $(CFLAGS) $< -o $@
|
||||
|
|
@ -1,714 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This version hacked for emulating 2kpage NAND for YAFFS2 testing.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/string.h>
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
|
||||
#include <linux/locks.h>
|
||||
#endif
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include "../yaffs_nandemul2k.h"
|
||||
|
||||
#define ALLOCATE(x) kmalloc(x,GFP_KERNEL)
|
||||
#define FREE(x) kfree(x)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define NAND_SHIFT (11) // Shifter for 2k
|
||||
#define PAGE_DATA_SIZE (1 << NAND_SHIFT)
|
||||
#define PAGE_SPARE_SIZE (64)
|
||||
#define BLK_SHIFT 6
|
||||
#define PAGES_PER_BLOCK (1 << BLK_SHIFT) // = 64
|
||||
|
||||
|
||||
#define EM_SIZE_IN_MEG 4
|
||||
#define EM_SIZE_IN_BYTES (EM_SIZE_IN_MEG * (1<<20))
|
||||
|
||||
#define PAGE_TOTAL_SIZE (PAGE_DATA_SIZE+PAGE_SPARE_SIZE)
|
||||
|
||||
#define BLOCK_TOTAL_SIZE (PAGES_PER_BLOCK * PAGE_TOTAL_SIZE)
|
||||
|
||||
#define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE))
|
||||
|
||||
|
||||
static struct mtd_info nandemul2k_mtd;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
__u8 data[PAGE_TOTAL_SIZE]; // Data + spare
|
||||
int empty; // is this empty?
|
||||
} nandemul_Page;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nandemul_Page *page[PAGES_PER_BLOCK];
|
||||
int damaged;
|
||||
} nandemul_Block;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nandemul_Block**block;
|
||||
int nBlocks;
|
||||
} nandemul_Device;
|
||||
|
||||
static nandemul_Device ned;
|
||||
|
||||
static int sizeInMB = EM_SIZE_IN_MEG;
|
||||
|
||||
|
||||
static void nandemul_yield(int n)
|
||||
{
|
||||
#ifdef __KERNEL__
|
||||
if(n > 0) schedule_timeout(n);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void nandemul2k_Read(void *buffer, int page, int start, int nBytes)
|
||||
{
|
||||
int pg = page%PAGES_PER_BLOCK;
|
||||
int blk = page/PAGES_PER_BLOCK;
|
||||
if(buffer && nBytes > 0)
|
||||
{
|
||||
memcpy(buffer,&ned.block[blk]->page[pg]->data[start],nBytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void nandemul2k_Program(const void *buffer, int page, int start, int nBytes)
|
||||
{
|
||||
int pg = page%PAGES_PER_BLOCK;
|
||||
int blk = page/PAGES_PER_BLOCK;
|
||||
__u8 *p;
|
||||
__u8 *b = (__u8 *)buffer;
|
||||
|
||||
p = &ned.block[blk]->page[pg]->data[start];
|
||||
|
||||
while(buffer && nBytes>0)
|
||||
{
|
||||
*p = *p & *b;
|
||||
p++;
|
||||
b++;
|
||||
nBytes--;
|
||||
}
|
||||
}
|
||||
|
||||
static void nandemul2k_DoErase(int blockNumber)
|
||||
{
|
||||
int i;
|
||||
|
||||
nandemul_Block *blk;
|
||||
|
||||
if(blockNumber < 0 || blockNumber >= ned.nBlocks)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
blk = ned.block[blockNumber];
|
||||
|
||||
for(i = 0; i < PAGES_PER_BLOCK; i++)
|
||||
{
|
||||
memset(blk->page[i],0xff,sizeof(nandemul_Page));
|
||||
blk->page[i]->empty = 1;
|
||||
}
|
||||
nandemul_yield(2);
|
||||
}
|
||||
|
||||
|
||||
static int nandemul2k_CalcNBlocks(void)
|
||||
{
|
||||
return EM_SIZE_IN_MEG * BLOCKS_PER_MEG;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int CheckInit(void)
|
||||
{
|
||||
static int initialised = 0;
|
||||
|
||||
int i,j;
|
||||
|
||||
int fail = 0;
|
||||
int nBlocks;
|
||||
|
||||
int nAllocated = 0;
|
||||
|
||||
if(initialised)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks();
|
||||
|
||||
|
||||
ned.block = ALLOCATE(sizeof(nandemul_Block*) * nBlocks );
|
||||
|
||||
if(!ned.block) return ENOMEM;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for(i=fail=0; i <nBlocks; i++)
|
||||
{
|
||||
|
||||
nandemul_Block *blk;
|
||||
|
||||
if(!(blk = ned.block[i] = ALLOCATE(sizeof(nandemul_Block))))
|
||||
{
|
||||
fail = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(j = 0; j < PAGES_PER_BLOCK; j++)
|
||||
{
|
||||
if((blk->page[j] = ALLOCATE(sizeof(nandemul_Page))) == 0)
|
||||
{
|
||||
fail = 1;
|
||||
}
|
||||
}
|
||||
nandemul2k_DoErase(i);
|
||||
ned.block[i]->damaged = 0;
|
||||
nAllocated++;
|
||||
}
|
||||
}
|
||||
|
||||
if(fail)
|
||||
{
|
||||
//Todo thump pages
|
||||
|
||||
for(i = 0; i < nAllocated; i++)
|
||||
{
|
||||
FREE(ned.block[i]);
|
||||
}
|
||||
FREE(ned.block);
|
||||
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
ned.nBlocks = nBlocks;
|
||||
|
||||
initialised = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void nandemul2k_CleanUp(void)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
for(i = 0; i < ned.nBlocks; i++)
|
||||
{
|
||||
for(j = 0; j < PAGES_PER_BLOCK; j++)
|
||||
{
|
||||
FREE(ned.block[i]->page[j]);
|
||||
}
|
||||
FREE(ned.block[i]);
|
||||
|
||||
}
|
||||
FREE(ned.block);
|
||||
ned.block = 0;
|
||||
}
|
||||
|
||||
int nandemul2k_GetBytesPerChunk(void) { return PAGE_DATA_SIZE;}
|
||||
|
||||
int nandemul2k_GetChunksPerBlock(void) { return PAGES_PER_BLOCK; }
|
||||
int nandemul2k_GetNumberOfBlocks(void) {return nandemul2k_CalcNBlocks();}
|
||||
|
||||
|
||||
|
||||
static int nandemul2k_ReadId(__u8 *vendorId, __u8 *deviceId)
|
||||
{
|
||||
*vendorId = 'Y';
|
||||
*deviceId = '2';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int nandemul2k_ReadStatus(__u8 *status)
|
||||
{
|
||||
*status = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_MTD_NAND_ECC
|
||||
#include <linux/mtd/nand_ecc.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NAND low-level MTD interface functions
|
||||
*/
|
||||
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf, u_char *oob_buf, struct nand_oobinfo *dummy);
|
||||
static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf);
|
||||
static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf,
|
||||
u_char *oob_buf, struct nand_oobinfo *dummy);
|
||||
static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf);
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
|
||||
static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
#else
|
||||
static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen);
|
||||
#endif
|
||||
static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
|
||||
static void nand_sync (struct mtd_info *mtd);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* NAND read
|
||||
*/
|
||||
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
return nand_read_ecc (mtd, from, len, retlen, buf, NULL,NULL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NAND read with ECC
|
||||
*/
|
||||
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf, u_char *oob_buf,struct nand_oobinfo *oobsel)
|
||||
{
|
||||
int start, page;
|
||||
int n = len;
|
||||
int nToCopy;
|
||||
|
||||
|
||||
|
||||
/* Do not allow reads past end of device */
|
||||
if ((from + len) > mtd->size) {
|
||||
*retlen = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize return value */
|
||||
*retlen = 0;
|
||||
|
||||
while(n > 0)
|
||||
{
|
||||
|
||||
/* First we calculate the starting page */
|
||||
page = from >> NAND_SHIFT;
|
||||
|
||||
/* Get raw starting column */
|
||||
|
||||
start = from & (mtd->oobblock-1);
|
||||
|
||||
// OK now check for the curveball where the start and end are in
|
||||
// the same page
|
||||
if((start + n) < mtd->oobblock)
|
||||
{
|
||||
nToCopy = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
nToCopy = mtd->oobblock - start;
|
||||
}
|
||||
|
||||
nandemul2k_Read(buf, page, start, nToCopy);
|
||||
nandemul2k_Read(oob_buf,page,PAGE_DATA_SIZE,PAGE_SPARE_SIZE);
|
||||
|
||||
n -= nToCopy;
|
||||
from += nToCopy;
|
||||
buf += nToCopy;
|
||||
if(oob_buf) oob_buf += PAGE_SPARE_SIZE;
|
||||
*retlen += nToCopy;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAND read out-of-band
|
||||
*/
|
||||
static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
int col, page;
|
||||
|
||||
T(0,("nand_read_oob: from = 0x%08x, buf = 0x%08x, len = %i\n", (unsigned int) from, (unsigned int) buf,
|
||||
(int) len));
|
||||
|
||||
/* Shift to get page */
|
||||
page = ((int) from) >> NAND_SHIFT;
|
||||
|
||||
/* Mask to get column */
|
||||
col = from & 0x0f;
|
||||
|
||||
/* Initialize return length value */
|
||||
*retlen = 0;
|
||||
|
||||
/* Do not allow reads past end of device */
|
||||
if ((from + len) > mtd->size) {
|
||||
T(0,
|
||||
("nand_read_oob: Attempt read beyond end of device\n"));
|
||||
*retlen = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nandemul2k_Read(buf,page,PAGE_DATA_SIZE + col,len);
|
||||
|
||||
/* Return happy */
|
||||
*retlen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAND write
|
||||
*/
|
||||
static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
return nand_write_ecc (mtd, to, len, retlen, buf, NULL,NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* NAND write with ECC
|
||||
*/
|
||||
static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf,
|
||||
u_char *oob_buf, struct nand_oobinfo *dummy)
|
||||
{
|
||||
|
||||
int start, page;
|
||||
int n = len;
|
||||
int nToCopy;
|
||||
|
||||
|
||||
|
||||
/* Do not allow reads past end of device */
|
||||
if ((to + len) > mtd->size) {
|
||||
*retlen = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/* Initialize return value */
|
||||
*retlen = 0;
|
||||
|
||||
while(n > 0)
|
||||
{
|
||||
|
||||
/* First we calculate the starting page */
|
||||
page = to >> NAND_SHIFT;
|
||||
|
||||
/* Get raw starting column */
|
||||
|
||||
start = to & (mtd->oobblock - 1);
|
||||
|
||||
// OK now check for the curveball where the start and end are in
|
||||
// the same page
|
||||
if((start + n) < mtd->oobblock)
|
||||
{
|
||||
nToCopy = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
nToCopy = mtd->oobblock - start;
|
||||
}
|
||||
|
||||
nandemul2k_Program(buf, page, start, nToCopy);
|
||||
nandemul2k_Program(oob_buf, page, PAGE_DATA_SIZE, PAGE_SPARE_SIZE);
|
||||
|
||||
n -= nToCopy;
|
||||
to += nToCopy;
|
||||
buf += nToCopy;
|
||||
if(oob_buf) oob_buf += PAGE_SPARE_SIZE;
|
||||
*retlen += nToCopy;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAND write out-of-band
|
||||
*/
|
||||
static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
|
||||
size_t *retlen, const u_char *buf)
|
||||
{
|
||||
int col, page;
|
||||
|
||||
|
||||
T(0,(
|
||||
"nand_read_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
|
||||
(int) len));
|
||||
|
||||
/* Shift to get page */
|
||||
page = ((int) to) >> NAND_SHIFT;
|
||||
|
||||
/* Mask to get column */
|
||||
col = to & 0x0f;
|
||||
|
||||
/* Initialize return length value */
|
||||
*retlen = 0;
|
||||
|
||||
/* Do not allow reads past end of device */
|
||||
if ((to + len) > mtd->size) {
|
||||
T(0,(
|
||||
"nand_read_oob: Attempt read beyond end of device\n"));
|
||||
*retlen = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nandemul2k_Program(buf,page,512 + col,len);
|
||||
|
||||
/* Return happy */
|
||||
*retlen = len;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* NAND write with iovec
|
||||
*/
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,7))
|
||||
static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen)
|
||||
#else
|
||||
static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
|
||||
unsigned long count, loff_t to, size_t *retlen)
|
||||
#endif
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAND erase a block
|
||||
*/
|
||||
static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
int i, nBlocks,block;
|
||||
|
||||
T(0,(
|
||||
"nand_erase: start = 0x%08x, len = %i\n",
|
||||
(unsigned int) instr->addr, (unsigned int) instr->len));
|
||||
|
||||
/* Start address must align on block boundary */
|
||||
if (instr->addr & (mtd->erasesize - 1)) {
|
||||
T(0,(
|
||||
"nand_erase: Unaligned address\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Length must align on block boundary */
|
||||
if (instr->len & (mtd->erasesize - 1)) {
|
||||
T(0,(
|
||||
"nand_erase: Length not block aligned\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Do not allow erase past end of device */
|
||||
if ((instr->len + instr->addr) > mtd->size) {
|
||||
T(0,(
|
||||
"nand_erase: Erase past end of device\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nBlocks = instr->len >> (NAND_SHIFT + BLK_SHIFT);
|
||||
block = instr->addr >> (NAND_SHIFT + BLK_SHIFT);
|
||||
|
||||
for(i = 0; i < nBlocks; i++)
|
||||
{
|
||||
nandemul2k_DoErase(block);
|
||||
block++;
|
||||
}
|
||||
|
||||
instr->state = MTD_ERASE_DONE; * change state to ERASE_DONE */
|
||||
|
||||
instr->callback(instr); * wake up */
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int nand_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NAND sync
|
||||
*/
|
||||
static void nand_sync (struct mtd_info *mtd)
|
||||
{
|
||||
T(0,("nand_sync: called\n"));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan for the NAND device
|
||||
*/
|
||||
static int nandemul2k_scan (struct mtd_info *mtd,int nchips)
|
||||
{
|
||||
mtd->oobblock = PAGE_DATA_SIZE;
|
||||
mtd->oobsize = PAGE_SPARE_SIZE;
|
||||
mtd->erasesize = PAGE_DATA_SIZE * PAGES_PER_BLOCK;
|
||||
mtd->size = sizeInMB * 1024*1024;
|
||||
|
||||
|
||||
|
||||
/* Fill in remaining MTD driver data */
|
||||
mtd->type = MTD_NANDFLASH;
|
||||
mtd->flags = MTD_CAP_NANDFLASH;
|
||||
mtd->owner = THIS_MODULE;
|
||||
mtd->ecctype = MTD_ECC_NONE;
|
||||
mtd->erase = nand_erase;
|
||||
mtd->point = NULL;
|
||||
mtd->unpoint = NULL;
|
||||
mtd->read = nand_read;
|
||||
mtd->write = nand_write;
|
||||
mtd->read_ecc = nand_read_ecc;
|
||||
mtd->write_ecc = nand_write_ecc;
|
||||
mtd->read_oob = nand_read_oob;
|
||||
mtd->write_oob = nand_write_oob;
|
||||
mtd->block_isbad = nand_block_isbad;
|
||||
mtd->block_markbad = nand_block_markbad;
|
||||
mtd->readv = NULL;
|
||||
mtd->writev = nand_writev;
|
||||
mtd->sync = nand_sync;
|
||||
mtd->lock = NULL;
|
||||
mtd->unlock = NULL;
|
||||
mtd->suspend = NULL;
|
||||
mtd->resume = NULL;
|
||||
|
||||
mtd->name = "NANDemul2k";
|
||||
|
||||
/* Return happy */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef MODULE
|
||||
MODULE_PARM(sizeInMB, "i");
|
||||
|
||||
__setup("sizeInMB=",sizeInMB);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define partitions for flash devices
|
||||
*/
|
||||
|
||||
static struct mtd_partition nandemul2k_partition[] =
|
||||
{
|
||||
{ .name = "NANDemul partition 1",
|
||||
.offset = 0,
|
||||
.size = 0 },
|
||||
};
|
||||
|
||||
static int nPartitions = sizeof(nandemul2k_partition)/sizeof(nandemul2k_partition[0]);
|
||||
|
||||
/*
|
||||
* Main initialization routine
|
||||
*/
|
||||
int __init nandemul2k_init (void)
|
||||
{
|
||||
|
||||
// Do the nand init
|
||||
|
||||
CheckInit();
|
||||
|
||||
nandemul2k_scan(&nandemul2k_mtd,1);
|
||||
|
||||
// Build the partition table
|
||||
|
||||
nandemul2k_partition[0].size = sizeInMB * 1024 * 1024;
|
||||
|
||||
// Register the partition
|
||||
add_mtd_partitions(&nandemul2k_mtd,nandemul2k_partition,nPartitions);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
module_init(nandemul2k_init);
|
||||
|
||||
/*
|
||||
* Clean up routine
|
||||
*/
|
||||
#ifdef MODULE
|
||||
static void __exit nandemul2k_cleanup (void)
|
||||
{
|
||||
|
||||
nandemul2k_CleanUp();
|
||||
|
||||
/* Unregister partitions */
|
||||
del_mtd_partitions(&nandemul2k_mtd);
|
||||
|
||||
/* Unregister the device */
|
||||
del_mtd_device (&nandemul2k_mtd);
|
||||
|
||||
}
|
||||
module_exit(nandemul2k_cleanup);
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Charles Manning <manningc@aleph1.co.uk>");
|
||||
MODULE_DESCRIPTION("2k Page/128k Block NAND emulated in RAM");
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# YAFFS: Yet another FFS. A NAND-flash specific file system.
|
||||
#
|
||||
# Copyright (C) 2002-2006 Aleph One Ltd.
|
||||
#
|
||||
# Created by Charles Manning <charles@aleph1.co.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# Patch YAFFS into the kernel
|
||||
#
|
||||
# args: kpath : Full path to kernel sources to be patched
|
||||
#
|
||||
# Somewhat "inspired by" the mtd patchin script
|
||||
#
|
||||
# $Id: patch-ker.sh,v 1.3 2007/07/25 01:04:38 charles Exp $
|
||||
|
||||
VERSION=0
|
||||
PATCHLEVEL=0
|
||||
SUBLEVEL=0
|
||||
COPYORLINK=$1
|
||||
LINUXDIR=$2
|
||||
|
||||
# To be a Linux directory, it must have a Makefile
|
||||
|
||||
|
||||
# Display usage of this script
|
||||
usage () {
|
||||
echo "usage: $0 c/l kernelpath"
|
||||
echo " if c/l is c, then copy. If l then link"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
if [ -z $LINUXDIR ]
|
||||
then
|
||||
usage;
|
||||
fi
|
||||
|
||||
if [ $COPYORLINK = l ]; then
|
||||
CPY="ln -s"
|
||||
elif [ $COPYORLINK = c ]; then
|
||||
CPY="cp"
|
||||
else
|
||||
echo "unknown copy or link type"
|
||||
usage;
|
||||
fi
|
||||
|
||||
|
||||
# Check if kerneldir contains a Makefile
|
||||
if [ ! -f $LINUXDIR/Makefile ]
|
||||
then
|
||||
echo "Directory $LINUXDIR does not exist or is not a kernel source directory";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
# Get kernel version
|
||||
VERSION=`grep -s VERSION <$LINUXDIR/Makefile | head -n 1 | sed s/'VERSION = '//`
|
||||
PATCHLEVEL=`grep -s PATCHLEVEL <$LINUXDIR/Makefile | head -n 1 | sed s/'PATCHLEVEL = '//`
|
||||
SUBLEVEL=`grep -s SUBLEVEL <$LINUXDIR/Makefile | head -n 1 | sed s/'SUBLEVEL = '//`
|
||||
|
||||
# Can we handle this version?
|
||||
if [ $VERSION -ne 2 -o $PATCHLEVEL -lt 6 ]
|
||||
then
|
||||
echo "Cannot patch kernel version $VERSION.$PATCHLEVEL.$SUBLEVEL, must be 2.6.x or higher"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
||||
KCONFIG=$LINUXDIR/fs/Kconfig
|
||||
KCONFIGOLD=$LINUXDIR/fs/Kconfig.pre.yaffs
|
||||
YAFFS_PATCHED_STRING=`grep -s yaffs <$KCONFIG | head -n 1`
|
||||
|
||||
MAKEFILE=$LINUXDIR/fs/Makefile
|
||||
MAKEFILEOLD=$LINUXDIR/fs/Makefile.pre.yaffs
|
||||
|
||||
if [ ! -z "$YAFFS_PATCHED_STRING" ]
|
||||
then
|
||||
YAFFS_PATCHED=0
|
||||
echo "$KCONFIG already mentions YAFFS, so we will not change it"
|
||||
else
|
||||
# Change the fs/Kconfig file
|
||||
# Save the old Kconfig
|
||||
# Copy all stuff up to JFFS
|
||||
# Insert some YAFFS stuff
|
||||
# Copy all the rest of the stuff
|
||||
|
||||
YAFFS_PATCHED=1
|
||||
echo "Updating $KCONFIG"
|
||||
mv -f $KCONFIG $KCONFIGOLD
|
||||
sed -n -e "/JFFS/,99999 ! p" $KCONFIGOLD >$KCONFIG
|
||||
echo "">>$KCONFIG
|
||||
echo "# Patched by YAFFS" >>$KCONFIG
|
||||
echo "source \"fs/yaffs2/Kconfig\"">>$KCONFIG
|
||||
echo "">>$KCONFIG
|
||||
sed -n -e "/JFFS/,99999 p" $KCONFIGOLD >>$KCONFIG
|
||||
|
||||
# now do fs/Makefile -- simply add the target at the end
|
||||
echo "Updating $MAKEFILE"
|
||||
cp -f $MAKEFILE $MAKEFILEOLD
|
||||
echo "">>$MAKEFILE
|
||||
echo "# Patched by YAFFS" >>$MAKEFILE
|
||||
echo "obj-\$(CONFIG_YAFFS_FS) += yaffs2/" >>$MAKEFILE
|
||||
|
||||
fi
|
||||
|
||||
YAFFSDIR=$LINUXDIR/fs/yaffs2
|
||||
|
||||
if [ -e $YAFFSDIR ]
|
||||
then
|
||||
echo "$YAFFSDIR exists, not patching"
|
||||
else
|
||||
mkdir $LINUXDIR/fs/yaffs2
|
||||
$CPY $PWD/Makefile.kernel $LINUXDIR/fs/yaffs2/Makefile
|
||||
$CPY $PWD/Kconfig $LINUXDIR/fs/yaffs2
|
||||
$CPY $PWD/*.c $PWD/*.h $LINUXDIR/fs/yaffs2
|
||||
fi
|
|
@ -1,6 +0,0 @@
|
|||
This directory holds patches that are useful for Linux integration.
|
||||
|
||||
Right now there is only one patched file, yaffs_mtdif2.c. This has been
|
||||
patched with a tweaked version of "Sergey's patch" and typically makes a
|
||||
stock mtd work properly.
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet another FFS. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* mtd interface for YAFFS2 */
|
||||
|
||||
const char *yaffs_mtdif2_c_version =
|
||||
"$Id: yaffs_mtdif2.c,v 1.2 2007/03/07 08:05:58 colin Exp $";
|
||||
|
||||
#include "yportenv.h"
|
||||
|
||||
|
||||
#include "yaffs_mtdif2.h"
|
||||
|
||||
#include "linux/mtd/mtd.h"
|
||||
#include "linux/types.h"
|
||||
#include "linux/time.h"
|
||||
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
|
||||
void nandmtd2_pt2buf(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
__u8 *ptab = (__u8 *)pt; /* packed tags as bytes */
|
||||
|
||||
int i, j = 0, k, n;
|
||||
|
||||
/* Pack buffer with 0xff */
|
||||
for (i = 0; i < mtd->oobsize; i++)
|
||||
dev->spareBuffer[i] = 0xff;
|
||||
|
||||
if(!is_raw){
|
||||
memcpy(dev->spareBuffer,pt,sizeof(yaffs_PackedTags2));
|
||||
} else {
|
||||
j = 0;
|
||||
k = mtd->oobinfo.oobfree[j][0];
|
||||
n = mtd->oobinfo.oobfree[j][1];
|
||||
|
||||
if (n == 0) {
|
||||
T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(yaffs_PackedTags2); i++) {
|
||||
if (n == 0) {
|
||||
j++;
|
||||
k = mtd->oobinfo.oobfree[j][0];
|
||||
n = mtd->oobinfo.oobfree[j][1];
|
||||
if (n == 0) {
|
||||
T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
}
|
||||
dev->spareBuffer[k] = ptab[i];
|
||||
k++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nandmtd2_buf2pt(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
int i, j = 0, k, n;
|
||||
__u8 *ptab = (__u8 *)pt; /* packed tags as bytes */
|
||||
|
||||
|
||||
if (!is_raw) {
|
||||
|
||||
memcpy(pt,dev->spareBuffer,sizeof(yaffs_PackedTags2));
|
||||
} else {
|
||||
j = 0;
|
||||
k = mtd->oobinfo.oobfree[j][0];
|
||||
n = mtd->oobinfo.oobfree[j][1];
|
||||
|
||||
if (n == 0) {
|
||||
T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(yaffs_PackedTags2); i++) {
|
||||
if (n == 0) {
|
||||
j++;
|
||||
k = mtd->oobinfo.oobfree[j][0];
|
||||
n = mtd->oobinfo.oobfree[j][1];
|
||||
if (n == 0) {
|
||||
T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
}
|
||||
ptab[i] = dev->spareBuffer[k];
|
||||
k++;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data,
|
||||
const yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
if (tags) {
|
||||
yaffs_PackTags2(&pt, tags);
|
||||
}
|
||||
|
||||
if (data && tags) {
|
||||
nandmtd2_pt2buf(dev, &pt, 0);
|
||||
retval =
|
||||
mtd->write_ecc(mtd, addr, dev->nBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
|
||||
} else {
|
||||
|
||||
T(YAFFS_TRACE_ALWAYS,
|
||||
(TSTR
|
||||
("Write chunk with null tags or data!" TENDSTR)));
|
||||
YBUG();
|
||||
}
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * data, yaffs_ExtendedTags * tags)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
size_t dummy;
|
||||
int retval = 0;
|
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk;
|
||||
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR
|
||||
("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p"
|
||||
TENDSTR), chunkInNAND, data, tags));
|
||||
|
||||
if (0 && data && tags) {
|
||||
retval =
|
||||
mtd->read_ecc(mtd, addr, dev->nBytesPerChunk,
|
||||
&dummy, data, dev->spareBuffer,
|
||||
NULL);
|
||||
nandmtd2_buf2pt(dev, &pt, 0);
|
||||
} else {
|
||||
if (data)
|
||||
retval =
|
||||
mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy,
|
||||
data);
|
||||
if (tags) {
|
||||
retval =
|
||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
|
||||
dev->spareBuffer);
|
||||
nandmtd2_buf2pt(dev, &pt, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (tags)
|
||||
yaffs_UnpackTags2(tags, &pt);
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
int retval;
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
|
||||
|
||||
retval =
|
||||
mtd->block_markbad(mtd,
|
||||
blockNo * dev->nChunksPerBlock *
|
||||
dev->nBytesPerChunk);
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
|
||||
}
|
||||
|
||||
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber)
|
||||
{
|
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
|
||||
int retval;
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
|
||||
retval =
|
||||
mtd->block_isbad(mtd,
|
||||
blockNo * dev->nChunksPerBlock *
|
||||
dev->nBytesPerChunk);
|
||||
|
||||
if (retval) {
|
||||
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
|
||||
|
||||
*state = YAFFS_BLOCK_STATE_DEAD;
|
||||
*sequenceNumber = 0;
|
||||
} else {
|
||||
yaffs_ExtendedTags t;
|
||||
nandmtd2_ReadChunkWithTagsFromNAND(dev,
|
||||
blockNo *
|
||||
dev->nChunksPerBlock, NULL,
|
||||
&t);
|
||||
|
||||
if (t.chunkUsed) {
|
||||
*sequenceNumber = t.sequenceNumber;
|
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
} else {
|
||||
*sequenceNumber = 0;
|
||||
*state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
}
|
||||
|
||||
T(YAFFS_TRACE_MTD,
|
||||
(TSTR("block is OK seq %d state %d" TENDSTR), *sequenceNumber,
|
||||
*state));
|
||||
}
|
||||
|
||||
if (retval == 0)
|
||||
return YAFFS_OK;
|
||||
else
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
#Makefile for mkyaffs
|
||||
#
|
||||
# NB this is not yet suitable for putting into the kernel tree.
|
||||
# YAFFS: Yet another Flash File System. A NAND-flash specific file system.
|
||||
#
|
||||
# Copyright (C) 2002 Aleph One Ltd.
|
||||
# for Toby Churchill Ltd and Brightstar Engineering
|
||||
#
|
||||
# Created by Charles Manning <charles@aleph1.co.uk>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
|
||||
## Change or override KERNELDIR to your kernel
|
||||
|
||||
#KERNELDIR = /usr/src/kernel-headers-2.4.18
|
||||
|
||||
CFLAGS = -I/usr/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL
|
||||
CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations
|
||||
CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline
|
||||
|
||||
## Change if you are using a cross-compiler
|
||||
MAKETOOLS =
|
||||
|
||||
CC=$(MAKETOOLS)gcc
|
||||
|
||||
COMMONLINKS = yaffs_ecc.c
|
||||
COMMONOBJS = $(COMMONLINKS:.c=.o)
|
||||
|
||||
MKYAFFSSOURCES = mkyaffsimage.c
|
||||
MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o)
|
||||
|
||||
MKYAFFS2SOURCES = mkyaffs2image.c
|
||||
MKYAFFS2LINKS = yaffs_packedtags2.c yaffs_tagsvalidity.c
|
||||
MKYAFFS2IMAGEOBJS = $(MKYAFFS2SOURCES:.c=.o) $(MKYAFFS2LINKS:.c=.o)
|
||||
|
||||
all: mkyaffsimage mkyaffs2image
|
||||
|
||||
$(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS):
|
||||
ln -s ../$@ $@
|
||||
|
||||
$(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) : %.o: %.c
|
||||
$(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
mkyaffsimage: $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
|
||||
$(CC) -o $@ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS)
|
||||
|
||||
mkyaffs2image: $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS)
|
||||
$(CC) -o $@ $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS)
|
||||
|
||||
|
||||
clean:
|
||||
rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) mkyaffsimage mkyaffs2image core
|
|
@ -1,520 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
* Nick Bane modifications flagged NCB
|
||||
* Endian handling patches by James Ng.
|
||||
* mkyaffs2image hacks by NCB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* makeyaffs2image.c
|
||||
*
|
||||
* Makes a YAFFS2 file system image that can be used to load up a file system.
|
||||
* Uses default Linux MTD layout - change if you need something different.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "yaffs_ecc.h"
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
#include "yaffs_tagsvalidity.h"
|
||||
#include "yaffs_packedtags2.h"
|
||||
|
||||
unsigned yaffs_traceMask=0;
|
||||
|
||||
#define MAX_OBJECTS 10000
|
||||
|
||||
#define chunkSize 2048
|
||||
#define spareSize 64
|
||||
|
||||
const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.4 2007/02/14 01:09:06 wookey Exp $";
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
int obj;
|
||||
} objItem;
|
||||
|
||||
|
||||
static objItem obj_list[MAX_OBJECTS];
|
||||
static int n_obj = 0;
|
||||
static int obj_id = YAFFS_NOBJECT_BUCKETS + 1;
|
||||
|
||||
static int nObjects, nDirectories, nPages;
|
||||
|
||||
static int outFile;
|
||||
|
||||
static int error;
|
||||
|
||||
static int convert_endian = 0;
|
||||
|
||||
static int obj_compare(const void *a, const void * b)
|
||||
{
|
||||
objItem *oa, *ob;
|
||||
|
||||
oa = (objItem *)a;
|
||||
ob = (objItem *)b;
|
||||
|
||||
if(oa->dev < ob->dev) return -1;
|
||||
if(oa->dev > ob->dev) return 1;
|
||||
if(oa->ino < ob->ino) return -1;
|
||||
if(oa->ino > ob->ino) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void add_obj_to_list(dev_t dev, ino_t ino, int obj)
|
||||
{
|
||||
if(n_obj < MAX_OBJECTS)
|
||||
{
|
||||
obj_list[n_obj].dev = dev;
|
||||
obj_list[n_obj].ino = ino;
|
||||
obj_list[n_obj].obj = obj;
|
||||
n_obj++;
|
||||
qsort(obj_list,n_obj,sizeof(objItem),obj_compare);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// oops! not enough space in the object array
|
||||
fprintf(stderr,"Not enough space in object array\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int find_obj_in_list(dev_t dev, ino_t ino)
|
||||
{
|
||||
objItem *i = NULL;
|
||||
objItem test;
|
||||
|
||||
test.dev = dev;
|
||||
test.ino = ino;
|
||||
|
||||
if(n_obj > 0)
|
||||
{
|
||||
i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare);
|
||||
}
|
||||
|
||||
if(i)
|
||||
{
|
||||
return i->obj;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This little function converts a little endian tag to a big endian tag.
|
||||
* NOTE: The tag is not usable after this other than calculating the CRC
|
||||
* with.
|
||||
*/
|
||||
static void little_to_big_endian(yaffs_Tags *tagsPtr)
|
||||
{
|
||||
#if 0 // FIXME NCB
|
||||
yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes.
|
||||
yaffs_TagsUnion temp;
|
||||
|
||||
memset(&temp, 0, sizeof(temp));
|
||||
// Ick, I hate magic numbers.
|
||||
temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4);
|
||||
temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4);
|
||||
temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6);
|
||||
temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6);
|
||||
temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2);
|
||||
temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2);
|
||||
temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F);
|
||||
temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6);
|
||||
|
||||
// Now copy it back.
|
||||
tags->asBytes[0] = temp.asBytes[0];
|
||||
tags->asBytes[1] = temp.asBytes[1];
|
||||
tags->asBytes[2] = temp.asBytes[2];
|
||||
tags->asBytes[3] = temp.asBytes[3];
|
||||
tags->asBytes[4] = temp.asBytes[4];
|
||||
tags->asBytes[5] = temp.asBytes[5];
|
||||
tags->asBytes[6] = temp.asBytes[6];
|
||||
tags->asBytes[7] = temp.asBytes[7];
|
||||
#endif
|
||||
}
|
||||
|
||||
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
|
||||
{
|
||||
yaffs_ExtendedTags t;
|
||||
yaffs_PackedTags2 pt;
|
||||
|
||||
error = write(outFile,data,chunkSize);
|
||||
if(error < 0) return error;
|
||||
|
||||
yaffs_InitialiseTags(&t);
|
||||
|
||||
t.chunkId = chunkId;
|
||||
// t.serialNumber = 0;
|
||||
t.serialNumber = 1; // **CHECK**
|
||||
t.byteCount = nBytes;
|
||||
t.objectId = objId;
|
||||
|
||||
t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
|
||||
|
||||
// added NCB **CHECK**
|
||||
t.chunkUsed = 1;
|
||||
|
||||
if (convert_endian)
|
||||
{
|
||||
little_to_big_endian(&t);
|
||||
}
|
||||
|
||||
nPages++;
|
||||
|
||||
yaffs_PackTags2(&pt,&t);
|
||||
|
||||
// return write(outFile,&pt,sizeof(yaffs_PackedTags2));
|
||||
return write(outFile,&pt,spareSize);
|
||||
|
||||
}
|
||||
|
||||
#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \
|
||||
(((x) & 0x0000FF00) << 8 ) | \
|
||||
(((x) & 0x00FF0000) >> 8 ) | \
|
||||
(((x) & 0xFF000000) >> 24))
|
||||
|
||||
#define SWAP16(x) ((((x) & 0x00FF) << 8) | \
|
||||
(((x) & 0xFF00) >> 8))
|
||||
|
||||
// This one is easier, since the types are more standard. No funky shifts here.
|
||||
static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh)
|
||||
{
|
||||
oh->type = SWAP32(oh->type); // GCC makes enums 32 bits.
|
||||
oh->parentObjectId = SWAP32(oh->parentObjectId); // int
|
||||
oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness.
|
||||
// name = skip. Char array. Not swapped.
|
||||
oh->yst_mode = SWAP32(oh->yst_mode);
|
||||
#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case.
|
||||
// In fact, WinCE would be *THE* place where this would be an issue!
|
||||
oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]);
|
||||
oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]);
|
||||
oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]);
|
||||
oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]);
|
||||
oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]);
|
||||
#else
|
||||
// Regular POSIX.
|
||||
oh->yst_uid = SWAP32(oh->yst_uid);
|
||||
oh->yst_gid = SWAP32(oh->yst_gid);
|
||||
oh->yst_atime = SWAP32(oh->yst_atime);
|
||||
oh->yst_mtime = SWAP32(oh->yst_mtime);
|
||||
oh->yst_ctime = SWAP32(oh->yst_ctime);
|
||||
#endif
|
||||
|
||||
oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that!
|
||||
oh->equivalentObjectId = SWAP32(oh->equivalentObjectId);
|
||||
// alias - char array.
|
||||
oh->yst_rdev = SWAP32(oh->yst_rdev);
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
oh->win_ctime[0] = SWAP32(oh->win_ctime[0]);
|
||||
oh->win_ctime[1] = SWAP32(oh->win_ctime[1]);
|
||||
oh->win_atime[0] = SWAP32(oh->win_atime[0]);
|
||||
oh->win_atime[1] = SWAP32(oh->win_atime[1]);
|
||||
oh->win_mtime[0] = SWAP32(oh->win_mtime[0]);
|
||||
oh->win_mtime[1] = SWAP32(oh->win_mtime[1]);
|
||||
oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
|
||||
oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
|
||||
oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
|
||||
oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
|
||||
oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
|
||||
oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
|
||||
#else
|
||||
oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
|
||||
oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
|
||||
oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
|
||||
oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
|
||||
oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
|
||||
oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
|
||||
oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]);
|
||||
oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]);
|
||||
oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]);
|
||||
oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]);
|
||||
oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]);
|
||||
oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
|
||||
{
|
||||
__u8 bytes[chunkSize];
|
||||
|
||||
|
||||
yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes;
|
||||
|
||||
memset(bytes,0xff,sizeof(bytes));
|
||||
|
||||
oh->type = t;
|
||||
|
||||
oh->parentObjectId = parent;
|
||||
|
||||
strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
|
||||
|
||||
|
||||
if(t != YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
{
|
||||
oh->yst_mode = s->st_mode;
|
||||
oh->yst_uid = s->st_uid;
|
||||
// NCB 12/9/02 oh->yst_gid = s->yst_uid;
|
||||
oh->yst_gid = s->st_gid;
|
||||
oh->yst_atime = s->st_atime;
|
||||
oh->yst_mtime = s->st_mtime;
|
||||
oh->yst_ctime = s->st_ctime;
|
||||
oh->yst_rdev = s->st_rdev;
|
||||
}
|
||||
|
||||
if(t == YAFFS_OBJECT_TYPE_FILE)
|
||||
{
|
||||
oh->fileSize = s->st_size;
|
||||
}
|
||||
|
||||
if(t == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
{
|
||||
oh->equivalentObjectId = equivalentObj;
|
||||
}
|
||||
|
||||
if(t == YAFFS_OBJECT_TYPE_SYMLINK)
|
||||
{
|
||||
strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH);
|
||||
}
|
||||
|
||||
if (convert_endian)
|
||||
{
|
||||
object_header_little_to_big_endian(oh);
|
||||
}
|
||||
|
||||
return write_chunk(bytes,objId,0,0xffff);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int process_directory(int parent, const char *path)
|
||||
{
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
nDirectories++;
|
||||
|
||||
dir = opendir(path);
|
||||
|
||||
if(dir)
|
||||
{
|
||||
while((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
|
||||
/* Ignore . and .. */
|
||||
if(strcmp(entry->d_name,".") &&
|
||||
strcmp(entry->d_name,".."))
|
||||
{
|
||||
char full_name[500];
|
||||
struct stat stats;
|
||||
int equivalentObj;
|
||||
int newObj;
|
||||
|
||||
sprintf(full_name,"%s/%s",path,entry->d_name);
|
||||
|
||||
lstat(full_name,&stats);
|
||||
|
||||
if(S_ISLNK(stats.st_mode) ||
|
||||
S_ISREG(stats.st_mode) ||
|
||||
S_ISDIR(stats.st_mode) ||
|
||||
S_ISFIFO(stats.st_mode) ||
|
||||
S_ISBLK(stats.st_mode) ||
|
||||
S_ISCHR(stats.st_mode) ||
|
||||
S_ISSOCK(stats.st_mode))
|
||||
{
|
||||
|
||||
newObj = obj_id++;
|
||||
nObjects++;
|
||||
|
||||
printf("Object %d, %s is a ",newObj,full_name);
|
||||
|
||||
/* We're going to create an object for it */
|
||||
if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
|
||||
{
|
||||
/* we need to make a hard link */
|
||||
printf("hard link to object %d\n",equivalentObj);
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
|
||||
|
||||
if(S_ISLNK(stats.st_mode))
|
||||
{
|
||||
|
||||
char symname[500];
|
||||
|
||||
memset(symname,0, sizeof(symname));
|
||||
|
||||
readlink(full_name,symname,sizeof(symname) -1);
|
||||
|
||||
printf("symlink to \"%s\"\n",symname);
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);
|
||||
|
||||
}
|
||||
else if(S_ISREG(stats.st_mode))
|
||||
{
|
||||
printf("file, ");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL);
|
||||
|
||||
if(error >= 0)
|
||||
{
|
||||
int h;
|
||||
__u8 bytes[chunkSize];
|
||||
int nBytes;
|
||||
int chunk = 0;
|
||||
|
||||
h = open(full_name,O_RDONLY);
|
||||
if(h >= 0)
|
||||
{
|
||||
memset(bytes,0xff,sizeof(bytes));
|
||||
while((nBytes = read(h,bytes,sizeof(bytes))) > 0)
|
||||
{
|
||||
chunk++;
|
||||
write_chunk(bytes,newObj,chunk,nBytes);
|
||||
memset(bytes,0xff,sizeof(bytes));
|
||||
}
|
||||
if(nBytes < 0)
|
||||
error = nBytes;
|
||||
|
||||
printf("%d data chunks written\n",chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("Error opening file");
|
||||
}
|
||||
close(h);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if(S_ISSOCK(stats.st_mode))
|
||||
{
|
||||
printf("socket\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISFIFO(stats.st_mode))
|
||||
{
|
||||
printf("fifo\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISCHR(stats.st_mode))
|
||||
{
|
||||
printf("character device\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISBLK(stats.st_mode))
|
||||
{
|
||||
printf("block device\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISDIR(stats.st_mode))
|
||||
{
|
||||
printf("directory\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL);
|
||||
// NCB modified 10/9/2001 process_directory(1,full_name);
|
||||
process_directory(newObj,full_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" we don't handle this type\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct stat stats;
|
||||
|
||||
printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n");
|
||||
|
||||
if(argc < 3)
|
||||
{
|
||||
printf("usage: mkyaffs2image dir image_file [convert]\n");
|
||||
printf(" dir the directory tree to be converted\n");
|
||||
printf(" image_file the output file to hold the image\n");
|
||||
printf(" 'convert' produce a big-endian image from a little-endian machine\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert"))))
|
||||
{
|
||||
convert_endian = 1;
|
||||
}
|
||||
|
||||
if(stat(argv[1],&stats) < 0)
|
||||
{
|
||||
printf("Could not stat %s\n",argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!S_ISDIR(stats.st_mode))
|
||||
{
|
||||
printf(" %s is not a directory\n",argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);
|
||||
|
||||
|
||||
if(outFile < 0)
|
||||
{
|
||||
printf("Could not open output file %s\n",argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Processing directory %s into image file %s\n",argv[1],argv[2]);
|
||||
error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL);
|
||||
if(error)
|
||||
error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]);
|
||||
|
||||
close(outFile);
|
||||
|
||||
if(error < 0)
|
||||
{
|
||||
perror("operation incomplete");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Operation complete.\n"
|
||||
"%d objects in %d directories\n"
|
||||
"%d NAND pages\n",nObjects, nDirectories, nPages);
|
||||
}
|
||||
|
||||
close(outFile);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
@ -1,590 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* Created by Charles Manning <charles@aleph1.co.uk>
|
||||
* Nick Bane modifications flagged NCB
|
||||
* Endian handling patches by James Ng
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* makeyaffsimage.c
|
||||
*
|
||||
* Makes a YAFFS file system image that can be used to load up a file system.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "yaffs_ecc.h"
|
||||
#include "yaffs_guts.h"
|
||||
|
||||
|
||||
#define MAX_OBJECTS 10000
|
||||
|
||||
const char * mkyaffsimage_c_version = "$Id: mkyaffsimage.c,v 1.7 2003/07/16 03:00:48 charles Exp $";
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
int obj;
|
||||
} objItem;
|
||||
|
||||
|
||||
static objItem obj_list[MAX_OBJECTS];
|
||||
static int n_obj = 0;
|
||||
static int obj_id = YAFFS_NOBJECT_BUCKETS + 1;
|
||||
|
||||
static int nObjects, nDirectories, nPages;
|
||||
|
||||
static int outFile;
|
||||
|
||||
static int error;
|
||||
|
||||
static int convert_endian = 0;
|
||||
|
||||
static int obj_compare(const void *a, const void * b)
|
||||
{
|
||||
objItem *oa, *ob;
|
||||
|
||||
oa = (objItem *)a;
|
||||
ob = (objItem *)b;
|
||||
|
||||
if(oa->dev < ob->dev) return -1;
|
||||
if(oa->dev > ob->dev) return 1;
|
||||
if(oa->ino < ob->ino) return -1;
|
||||
if(oa->ino > ob->ino) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void add_obj_to_list(dev_t dev, ino_t ino, int obj)
|
||||
{
|
||||
if(n_obj < MAX_OBJECTS)
|
||||
{
|
||||
obj_list[n_obj].dev = dev;
|
||||
obj_list[n_obj].ino = ino;
|
||||
obj_list[n_obj].obj = obj;
|
||||
n_obj++;
|
||||
qsort(obj_list,n_obj,sizeof(objItem),obj_compare);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// oops! not enough space in the object array
|
||||
fprintf(stderr,"Not enough space in object array\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int find_obj_in_list(dev_t dev, ino_t ino)
|
||||
{
|
||||
objItem *i = NULL;
|
||||
objItem test;
|
||||
|
||||
test.dev = dev;
|
||||
test.ino = ino;
|
||||
|
||||
if(n_obj > 0)
|
||||
{
|
||||
i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare);
|
||||
}
|
||||
|
||||
if(i)
|
||||
{
|
||||
return i->obj;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NCB added 10/9/2002
|
||||
static __u16 yaffs_CalcNameSum(const char *name)
|
||||
{
|
||||
__u16 sum = 0;
|
||||
__u16 i = 1;
|
||||
|
||||
__u8 *bname = (__u8 *)name;
|
||||
|
||||
while (*bname)
|
||||
{
|
||||
sum += (*bname) * i;
|
||||
i++;
|
||||
bname++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
static void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
|
||||
{
|
||||
yaffs_ECCCalculate(data , spare->ecc1);
|
||||
yaffs_ECCCalculate(&data[256] , spare->ecc2);
|
||||
}
|
||||
|
||||
static void yaffs_CalcTagsECC(yaffs_Tags *tags)
|
||||
{
|
||||
// Todo don't do anything yet. Need to calculate ecc
|
||||
unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
|
||||
unsigned i,j;
|
||||
unsigned ecc = 0;
|
||||
unsigned bit = 0;
|
||||
|
||||
// Clear ECC fields
|
||||
if (!convert_endian)
|
||||
{
|
||||
tags->ecc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Because we're in "munged tag" mode, we have to clear it manually
|
||||
b[6] &= 0xC0;
|
||||
b[7] &= 0x03;
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
// NCB modified 20-9-02 for(j = 1; j &0x7f; j<<=1)
|
||||
for(j = 1; j &0xff; j<<=1)
|
||||
{
|
||||
bit++;
|
||||
if(b[i] & j)
|
||||
{
|
||||
ecc ^= bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write out ECC
|
||||
if (!convert_endian)
|
||||
{
|
||||
tags->ecc = ecc;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have to munge the ECC again.
|
||||
b[6] |= ((ecc >> 6) & 0x3F);
|
||||
b[7] |= ((ecc & 0x3F) << 2);
|
||||
}
|
||||
}
|
||||
static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
|
||||
{
|
||||
yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
|
||||
|
||||
//yaffs_CalcTagsECC(tagsPtr);
|
||||
|
||||
sparePtr->tagByte0 = tu->asBytes[0];
|
||||
sparePtr->tagByte1 = tu->asBytes[1];
|
||||
sparePtr->tagByte2 = tu->asBytes[2];
|
||||
sparePtr->tagByte3 = tu->asBytes[3];
|
||||
sparePtr->tagByte4 = tu->asBytes[4];
|
||||
sparePtr->tagByte5 = tu->asBytes[5];
|
||||
sparePtr->tagByte6 = tu->asBytes[6];
|
||||
sparePtr->tagByte7 = tu->asBytes[7];
|
||||
}
|
||||
|
||||
/* This little function converts a little endian tag to a big endian tag.
|
||||
* NOTE: The tag is not usable after this other than calculating the CRC
|
||||
* with.
|
||||
*/
|
||||
static void little_to_big_endian(yaffs_Tags *tagsPtr)
|
||||
{
|
||||
yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes.
|
||||
yaffs_TagsUnion temp;
|
||||
|
||||
memset(&temp, 0, sizeof(temp));
|
||||
// Ick, I hate magic numbers.
|
||||
temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4);
|
||||
temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4);
|
||||
temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6);
|
||||
temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6);
|
||||
temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2);
|
||||
temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2);
|
||||
temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F);
|
||||
temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6);
|
||||
|
||||
// Now copy it back.
|
||||
tags->asBytes[0] = temp.asBytes[0];
|
||||
tags->asBytes[1] = temp.asBytes[1];
|
||||
tags->asBytes[2] = temp.asBytes[2];
|
||||
tags->asBytes[3] = temp.asBytes[3];
|
||||
tags->asBytes[4] = temp.asBytes[4];
|
||||
tags->asBytes[5] = temp.asBytes[5];
|
||||
tags->asBytes[6] = temp.asBytes[6];
|
||||
tags->asBytes[7] = temp.asBytes[7];
|
||||
}
|
||||
|
||||
static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)
|
||||
{
|
||||
yaffs_Tags t;
|
||||
yaffs_Spare s;
|
||||
|
||||
error = write(outFile,data,512);
|
||||
if(error < 0) return error;
|
||||
|
||||
memset(&t,0xff,sizeof (yaffs_Tags));
|
||||
memset(&s,0xff,sizeof (yaffs_Spare));
|
||||
|
||||
t.chunkId = chunkId;
|
||||
t.serialNumber = 0;
|
||||
t.byteCount = nBytes;
|
||||
t.objectId = objId;
|
||||
|
||||
if (convert_endian)
|
||||
{
|
||||
little_to_big_endian(&t);
|
||||
}
|
||||
|
||||
yaffs_CalcTagsECC(&t);
|
||||
yaffs_LoadTagsIntoSpare(&s,&t);
|
||||
yaffs_CalcECC(data,&s);
|
||||
|
||||
nPages++;
|
||||
|
||||
return write(outFile,&s,sizeof(yaffs_Spare));
|
||||
|
||||
}
|
||||
|
||||
#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \
|
||||
(((x) & 0x0000FF00) << 8 ) | \
|
||||
(((x) & 0x00FF0000) >> 8 ) | \
|
||||
(((x) & 0xFF000000) >> 24))
|
||||
|
||||
#define SWAP16(x) ((((x) & 0x00FF) << 8) | \
|
||||
(((x) & 0xFF00) >> 8))
|
||||
|
||||
// This one is easier, since the types are more standard. No funky shifts here.
|
||||
static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh)
|
||||
{
|
||||
oh->type = SWAP32(oh->type); // GCC makes enums 32 bits.
|
||||
oh->parentObjectId = SWAP32(oh->parentObjectId); // int
|
||||
oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness.
|
||||
// name = skip. Char array. Not swapped.
|
||||
oh->yst_mode = SWAP32(oh->yst_mode);
|
||||
#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case.
|
||||
// In fact, WinCE would be *THE* place where this would be an issue!
|
||||
oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]);
|
||||
oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]);
|
||||
oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]);
|
||||
oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]);
|
||||
oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]);
|
||||
#else
|
||||
// Regular POSIX.
|
||||
oh->yst_uid = SWAP32(oh->yst_uid);
|
||||
oh->yst_gid = SWAP32(oh->yst_gid);
|
||||
oh->yst_atime = SWAP32(oh->yst_atime);
|
||||
oh->yst_mtime = SWAP32(oh->yst_mtime);
|
||||
oh->yst_ctime = SWAP32(oh->yst_ctime);
|
||||
#endif
|
||||
|
||||
oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that!
|
||||
oh->equivalentObjectId = SWAP32(oh->equivalentObjectId);
|
||||
// alias - char array.
|
||||
oh->yst_rdev = SWAP32(oh->yst_rdev);
|
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE
|
||||
oh->win_ctime[0] = SWAP32(oh->win_ctime[0]);
|
||||
oh->win_ctime[1] = SWAP32(oh->win_ctime[1]);
|
||||
oh->win_atime[0] = SWAP32(oh->win_atime[0]);
|
||||
oh->win_atime[1] = SWAP32(oh->win_atime[1]);
|
||||
oh->win_mtime[0] = SWAP32(oh->win_mtime[0]);
|
||||
oh->win_mtime[1] = SWAP32(oh->win_mtime[1]);
|
||||
oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
|
||||
oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
|
||||
oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
|
||||
oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
|
||||
oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
|
||||
oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
|
||||
#else
|
||||
oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]);
|
||||
oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]);
|
||||
oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]);
|
||||
oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]);
|
||||
oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]);
|
||||
oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]);
|
||||
oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]);
|
||||
oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]);
|
||||
oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]);
|
||||
oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]);
|
||||
oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]);
|
||||
oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias)
|
||||
{
|
||||
__u8 bytes[512];
|
||||
|
||||
|
||||
yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes;
|
||||
|
||||
memset(bytes,0xff,512);
|
||||
|
||||
oh->type = t;
|
||||
|
||||
oh->parentObjectId = parent;
|
||||
|
||||
strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
|
||||
|
||||
|
||||
if(t != YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
{
|
||||
oh->yst_mode = s->st_mode;
|
||||
oh->yst_uid = s->st_uid;
|
||||
// NCB 12/9/02 oh->yst_gid = s->yst_uid;
|
||||
oh->yst_gid = s->st_gid;
|
||||
oh->yst_atime = s->st_atime;
|
||||
oh->yst_mtime = s->st_mtime;
|
||||
oh->yst_ctime = s->st_ctime;
|
||||
oh->yst_rdev = s->st_rdev;
|
||||
}
|
||||
|
||||
if(t == YAFFS_OBJECT_TYPE_FILE)
|
||||
{
|
||||
oh->fileSize = s->st_size;
|
||||
}
|
||||
|
||||
if(t == YAFFS_OBJECT_TYPE_HARDLINK)
|
||||
{
|
||||
oh->equivalentObjectId = equivalentObj;
|
||||
}
|
||||
|
||||
if(t == YAFFS_OBJECT_TYPE_SYMLINK)
|
||||
{
|
||||
strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH);
|
||||
}
|
||||
|
||||
if (convert_endian)
|
||||
{
|
||||
object_header_little_to_big_endian(oh);
|
||||
}
|
||||
|
||||
return write_chunk(bytes,objId,0,0xffff);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int process_directory(int parent, const char *path)
|
||||
{
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
nDirectories++;
|
||||
|
||||
dir = opendir(path);
|
||||
|
||||
if(dir)
|
||||
{
|
||||
while((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
|
||||
/* Ignore . and .. */
|
||||
if(strcmp(entry->d_name,".") &&
|
||||
strcmp(entry->d_name,".."))
|
||||
{
|
||||
char full_name[500];
|
||||
struct stat stats;
|
||||
int equivalentObj;
|
||||
int newObj;
|
||||
|
||||
sprintf(full_name,"%s/%s",path,entry->d_name);
|
||||
|
||||
lstat(full_name,&stats);
|
||||
|
||||
if(S_ISLNK(stats.st_mode) ||
|
||||
S_ISREG(stats.st_mode) ||
|
||||
S_ISDIR(stats.st_mode) ||
|
||||
S_ISFIFO(stats.st_mode) ||
|
||||
S_ISBLK(stats.st_mode) ||
|
||||
S_ISCHR(stats.st_mode) ||
|
||||
S_ISSOCK(stats.st_mode))
|
||||
{
|
||||
|
||||
newObj = obj_id++;
|
||||
nObjects++;
|
||||
|
||||
printf("Object %d, %s is a ",newObj,full_name);
|
||||
|
||||
/* We're going to create an object for it */
|
||||
if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0)
|
||||
{
|
||||
/* we need to make a hard link */
|
||||
printf("hard link to object %d\n",equivalentObj);
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
add_obj_to_list(stats.st_dev,stats.st_ino,newObj);
|
||||
|
||||
if(S_ISLNK(stats.st_mode))
|
||||
{
|
||||
|
||||
char symname[500];
|
||||
|
||||
memset(symname,0, sizeof(symname));
|
||||
|
||||
readlink(full_name,symname,sizeof(symname) -1);
|
||||
|
||||
printf("symlink to \"%s\"\n",symname);
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname);
|
||||
|
||||
}
|
||||
else if(S_ISREG(stats.st_mode))
|
||||
{
|
||||
printf("file, ");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL);
|
||||
|
||||
if(error >= 0)
|
||||
{
|
||||
int h;
|
||||
__u8 bytes[512];
|
||||
int nBytes;
|
||||
int chunk = 0;
|
||||
|
||||
h = open(full_name,O_RDONLY);
|
||||
if(h >= 0)
|
||||
{
|
||||
memset(bytes,0xff,512);
|
||||
while((nBytes = read(h,bytes,512)) > 0)
|
||||
{
|
||||
chunk++;
|
||||
write_chunk(bytes,newObj,chunk,nBytes);
|
||||
memset(bytes,0xff,512);
|
||||
}
|
||||
if(nBytes < 0)
|
||||
error = nBytes;
|
||||
|
||||
printf("%d data chunks written\n",chunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("Error opening file");
|
||||
}
|
||||
close(h);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if(S_ISSOCK(stats.st_mode))
|
||||
{
|
||||
printf("socket\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISFIFO(stats.st_mode))
|
||||
{
|
||||
printf("fifo\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISCHR(stats.st_mode))
|
||||
{
|
||||
printf("character device\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISBLK(stats.st_mode))
|
||||
{
|
||||
printf("block device\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL);
|
||||
}
|
||||
else if(S_ISDIR(stats.st_mode))
|
||||
{
|
||||
printf("directory\n");
|
||||
error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL);
|
||||
// NCB modified 10/9/2001 process_directory(1,full_name);
|
||||
process_directory(newObj,full_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" we don't handle this type\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct stat stats;
|
||||
|
||||
printf("mkyaffsimage: image building tool for YAFFS built "__DATE__"\n");
|
||||
|
||||
if(argc < 3)
|
||||
{
|
||||
printf("usage: mkyaffsimage dir image_file [convert]\n");
|
||||
printf(" dir the directory tree to be converted\n");
|
||||
printf(" image_file the output file to hold the image\n");
|
||||
printf(" 'convert' produce a big-endian image from a little-endian machine\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert"))))
|
||||
{
|
||||
convert_endian = 1;
|
||||
}
|
||||
|
||||
if(stat(argv[1],&stats) < 0)
|
||||
{
|
||||
printf("Could not stat %s\n",argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(!S_ISDIR(stats.st_mode))
|
||||
{
|
||||
printf(" %s is not a directory\n",argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);
|
||||
|
||||
|
||||
if(outFile < 0)
|
||||
{
|
||||
printf("Could not open output file %s\n",argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Processing directory %s into image file %s\n",argv[1],argv[2]);
|
||||
error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL);
|
||||
if(error)
|
||||
error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]);
|
||||
|
||||
close(outFile);
|
||||
|
||||
if(error < 0)
|
||||
{
|
||||
perror("operation incomplete");
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Operation complete.\n"
|
||||
"%d objects in %d directories\n"
|
||||
"%d NAND pages\n",nObjects, nDirectories, nPages);
|
||||
}
|
||||
|
||||
close(outFile);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
2299
fs/yaffs2/yaffs_fs.c
2299
fs/yaffs2/yaffs_fs.c
File diff suppressed because it is too large
Load diff
|
@ -1,369 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet another FFS. A NAND-flash specific file system.
|
||||
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
|
||||
*
|
||||
* Copyright (C) 2002 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module provides the interface between yaffs_nand.c and the
|
||||
* MTD API. This version is used when the MTD interface supports the
|
||||
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
|
||||
* and we have small-page NAND device.
|
||||
*
|
||||
* These functions are invoked via function pointers in yaffs_nand.c.
|
||||
* This replaces functionality provided by functions in yaffs_mtdif.c
|
||||
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
|
||||
* called in yaffs_mtdif.c when the function pointers are NULL.
|
||||
* We assume the MTD layer is performing ECC (useNANDECC is true).
|
||||
*/
|
||||
|
||||
#include "yportenv.h"
|
||||
#include "yaffs_guts.h"
|
||||
#include "yaffs_packedtags1.h"
|
||||
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
|
||||
|
||||
#include "linux/kernel.h"
|
||||
#include "linux/version.h"
|
||||
#include "linux/types.h"
|
||||
#include "linux/mtd/mtd.h"
|
||||
|
||||
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
|
||||
|
||||
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.5 2007/10/29 14:59:57 imcd Exp $";
|
||||
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
# define YTAG1_SIZE 8
|
||||
#else
|
||||
# define YTAG1_SIZE 9
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Use the following nand_ecclayout with MTD when using
|
||||
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
|
||||
* If you have existing Yaffs images and the byte order differs from this,
|
||||
* adjust 'oobfree' to match your existing Yaffs data.
|
||||
*
|
||||
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
|
||||
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
|
||||
* the 9th byte.
|
||||
*
|
||||
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
|
||||
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
|
||||
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
|
||||
* byte and B is the small-page bad-block indicator byte.
|
||||
*/
|
||||
static struct nand_ecclayout nand_oob_16 = {
|
||||
.eccbytes = 6,
|
||||
.eccpos = { 8, 9, 10, 13, 14, 15 },
|
||||
.oobavail = 9,
|
||||
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Write a chunk (page) of data to NAND.
|
||||
*
|
||||
* Caller always provides ExtendedTags data which are converted to a more
|
||||
* compact (packed) form for storage in NAND. A mini-ECC runs over the
|
||||
* contents of the tags meta-data; used to valid the tags when read.
|
||||
*
|
||||
* - Pack ExtendedTags to PackedTags1 form
|
||||
* - Compute mini-ECC for PackedTags1
|
||||
* - Write data and packed tags to NAND.
|
||||
*
|
||||
* Note: Due to the use of the PackedTags1 meta-data which does not include
|
||||
* a full sequence number (as found in the larger PackedTags2 form) it is
|
||||
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
|
||||
* discarded and dirty. This is not ideal: newer NAND parts are supposed
|
||||
* to be written just once. When Yaffs performs this operation, this
|
||||
* function is called with a NULL data pointer -- calling MTD write_oob
|
||||
* without data is valid usage (2.6.17).
|
||||
*
|
||||
* Any underlying MTD error results in YAFFS_FAIL.
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
|
||||
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
|
||||
{
|
||||
struct mtd_info * mtd = dev->genericDevice;
|
||||
int chunkBytes = dev->nDataBytesPerChunk;
|
||||
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||
struct mtd_oob_ops ops;
|
||||
yaffs_PackedTags1 pt1;
|
||||
int retval;
|
||||
|
||||
/* we assume that PackedTags1 and yaffs_Tags are compatible */
|
||||
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
|
||||
compile_time_assertion(sizeof(yaffs_Tags) == 8);
|
||||
|
||||
dev->nPageWrites++;
|
||||
|
||||
yaffs_PackTags1(&pt1, etags);
|
||||
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
|
||||
|
||||
/* When deleting a chunk, the upper layer provides only skeletal
|
||||
* etags, one with chunkDeleted set. However, we need to update the
|
||||
* tags, not erase them completely. So we use the NAND write property
|
||||
* that only zeroed-bits stick and set tag bytes to all-ones and
|
||||
* zero just the (not) deleted bit.
|
||||
*/
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
if (etags->chunkDeleted) {
|
||||
memset(&pt1, 0xff, 8);
|
||||
/* clear delete status bit to indicate deleted */
|
||||
pt1.deleted = 0;
|
||||
}
|
||||
#else
|
||||
((__u8 *)&pt1)[8] = 0xff;
|
||||
if (etags->chunkDeleted) {
|
||||
memset(&pt1, 0xff, 8);
|
||||
/* zero pageStatus byte to indicate deleted */
|
||||
((__u8 *)&pt1)[8] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&ops, 0, sizeof(ops));
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.len = (data) ? chunkBytes : 0;
|
||||
ops.ooblen = YTAG1_SIZE;
|
||||
ops.datbuf = (__u8 *)data;
|
||||
ops.oobbuf = (__u8 *)&pt1;
|
||||
|
||||
retval = mtd->write_oob(mtd, addr, &ops);
|
||||
if (retval) {
|
||||
yaffs_trace(YAFFS_TRACE_MTD,
|
||||
"write_oob failed, chunk %d, mtd error %d\n",
|
||||
chunkInNAND, retval);
|
||||
}
|
||||
return retval ? YAFFS_FAIL : YAFFS_OK;
|
||||
}
|
||||
|
||||
/* Return with empty ExtendedTags but add eccResult.
|
||||
*/
|
||||
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
|
||||
{
|
||||
if (etags) {
|
||||
memset(etags, 0, sizeof(*etags));
|
||||
etags->eccResult = eccResult;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Read a chunk (page) from NAND.
|
||||
*
|
||||
* Caller expects ExtendedTags data to be usable even on error; that is,
|
||||
* all members except eccResult and blockBad are zeroed.
|
||||
*
|
||||
* - Check ECC results for data (if applicable)
|
||||
* - Check for blank/erased block (return empty ExtendedTags if blank)
|
||||
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
|
||||
* - Convert PackedTags1 to ExtendedTags
|
||||
* - Update eccResult and blockBad members to refect state.
|
||||
*
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
|
||||
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
|
||||
{
|
||||
struct mtd_info * mtd = dev->genericDevice;
|
||||
int chunkBytes = dev->nDataBytesPerChunk;
|
||||
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
|
||||
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
struct mtd_oob_ops ops;
|
||||
yaffs_PackedTags1 pt1;
|
||||
int retval;
|
||||
int deleted;
|
||||
|
||||
dev->nPageReads++;
|
||||
|
||||
memset(&ops, 0, sizeof(ops));
|
||||
ops.mode = MTD_OOB_AUTO;
|
||||
ops.len = (data) ? chunkBytes : 0;
|
||||
ops.ooblen = YTAG1_SIZE;
|
||||
ops.datbuf = data;
|
||||
ops.oobbuf = (__u8 *)&pt1;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
|
||||
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
|
||||
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
|
||||
*/
|
||||
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
|
||||
#endif
|
||||
/* Read page and oob using MTD.
|
||||
* Check status and determine ECC result.
|
||||
*/
|
||||
retval = mtd->read_oob(mtd, addr, &ops);
|
||||
if (retval) {
|
||||
yaffs_trace(YAFFS_TRACE_MTD,
|
||||
"read_oob failed, chunk %d, mtd error %d\n",
|
||||
chunkInNAND, retval);
|
||||
}
|
||||
|
||||
switch (retval) {
|
||||
case 0:
|
||||
/* no error */
|
||||
break;
|
||||
|
||||
case -EUCLEAN:
|
||||
/* MTD's ECC fixed the data */
|
||||
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||
dev->eccFixed++;
|
||||
break;
|
||||
|
||||
case -EBADMSG:
|
||||
/* MTD's ECC could not fix the data */
|
||||
dev->eccUnfixed++;
|
||||
/* fall into... */
|
||||
default:
|
||||
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
|
||||
etags->blockBad = (mtd->block_isbad)(mtd, addr);
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
/* Check for a blank/erased chunk.
|
||||
*/
|
||||
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
|
||||
/* when blank, upper layers want eccResult to be <= NO_ERROR */
|
||||
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_YAFFS_9BYTE_TAGS
|
||||
/* Read deleted status (bit) then return it to it's non-deleted
|
||||
* state before performing tags mini-ECC check. pt1.deleted is
|
||||
* inverted.
|
||||
*/
|
||||
deleted = !pt1.deleted;
|
||||
pt1.deleted = 1;
|
||||
#else
|
||||
deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
|
||||
#endif
|
||||
|
||||
/* Check the packed tags mini-ECC and correct if necessary/possible.
|
||||
*/
|
||||
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
|
||||
switch (retval) {
|
||||
case 0:
|
||||
/* no tags error, use MTD result */
|
||||
break;
|
||||
case 1:
|
||||
/* recovered tags-ECC error */
|
||||
dev->tagsEccFixed++;
|
||||
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
|
||||
eccres = YAFFS_ECC_RESULT_FIXED;
|
||||
break;
|
||||
default:
|
||||
/* unrecovered tags-ECC error */
|
||||
dev->tagsEccUnfixed++;
|
||||
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
|
||||
}
|
||||
|
||||
/* Unpack the tags to extended form and set ECC result.
|
||||
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
|
||||
*/
|
||||
pt1.shouldBeFF = 0xFFFFFFFF;
|
||||
yaffs_UnpackTags1(etags, &pt1);
|
||||
etags->eccResult = eccres;
|
||||
|
||||
/* Set deleted state */
|
||||
etags->chunkDeleted = deleted;
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
/* Mark a block bad.
|
||||
*
|
||||
* This is a persistant state.
|
||||
* Use of this function should be rare.
|
||||
*
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
|
||||
{
|
||||
struct mtd_info * mtd = dev->genericDevice;
|
||||
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
|
||||
int retval;
|
||||
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
|
||||
|
||||
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
|
||||
return (retval) ? YAFFS_FAIL : YAFFS_OK;
|
||||
}
|
||||
|
||||
/* Check any MTD prerequists.
|
||||
*
|
||||
* Returns YAFFS_OK or YAFFS_FAIL.
|
||||
*/
|
||||
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
|
||||
{
|
||||
/* 2.6.18 has mtd->ecclayout->oobavail */
|
||||
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
|
||||
int oobavail = mtd->ecclayout->oobavail;
|
||||
|
||||
if (oobavail < YTAG1_SIZE) {
|
||||
yaffs_trace(YAFFS_TRACE_ERROR,
|
||||
"mtd device has only %d bytes for tags, need %d\n",
|
||||
oobavail, YTAG1_SIZE);
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
/* Query for the current state of a specific block.
|
||||
*
|
||||
* Examine the tags of the first chunk of the block and return the state:
|
||||
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
|
||||
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
|
||||
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
|
||||
*
|
||||
* Always returns YAFFS_OK.
|
||||
*/
|
||||
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * pState, int *pSequenceNumber)
|
||||
{
|
||||
struct mtd_info * mtd = dev->genericDevice;
|
||||
int chunkNo = blockNo * dev->nChunksPerBlock;
|
||||
loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
|
||||
yaffs_ExtendedTags etags;
|
||||
int state = YAFFS_BLOCK_STATE_DEAD;
|
||||
int seqnum = 0;
|
||||
int retval;
|
||||
|
||||
/* We don't yet have a good place to test for MTD config prerequists.
|
||||
* Do it here as we are called during the initial scan.
|
||||
*/
|
||||
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
|
||||
return YAFFS_FAIL;
|
||||
}
|
||||
|
||||
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
|
||||
etags.blockBad = (mtd->block_isbad)(mtd, addr);
|
||||
if (etags.blockBad) {
|
||||
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
|
||||
"block %d is marked bad\n", blockNo);
|
||||
state = YAFFS_BLOCK_STATE_DEAD;
|
||||
}
|
||||
else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
|
||||
/* bad tags, need to look more closely */
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
}
|
||||
else if (etags.chunkUsed) {
|
||||
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
|
||||
seqnum = etags.sequenceNumber;
|
||||
}
|
||||
else {
|
||||
state = YAFFS_BLOCK_STATE_EMPTY;
|
||||
}
|
||||
|
||||
*pState = state;
|
||||
*pSequenceNumber = seqnum;
|
||||
|
||||
/* query always succeeds */
|
||||
return YAFFS_OK;
|
||||
}
|
||||
|
||||
#endif /*KERNEL_VERSION*/
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* YAFFS: Yet another Flash File System. A NAND-flash specific file system.
|
||||
*
|
||||
* Copyright (C) 2002-2007 Aleph One Ltd.
|
||||
* for Toby Churchill Ltd and Brightstar Engineering
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 2.1 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
|
||||
*/
|
||||
|
||||
#ifndef __YAFFS_MTDIF1_H__
|
||||
#define __YAFFS_MTDIF1_H__
|
||||
|
||||
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
const __u8 * data, const yaffs_ExtendedTags * tags);
|
||||
|
||||
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
|
||||
__u8 * data, yaffs_ExtendedTags * tags);
|
||||
|
||||
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
|
||||
|
||||
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
|
||||
yaffs_BlockState * state, int *sequenceNumber);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue