提交 753ac610 编写于 作者: C Charles Manning 提交者: Wolfgang Denk

u-boot: Update yaffs2 file system

This patch updates the yaffs2 in u-boot to correspond to
git://www.aleph1.co.uk/yaffs2
commit id 9ee5d0643e559568dbe62215f76e0a7bd5a63d93
Signed-off-by: NCharles Manning <cdhmanning@gmail.com>
上级 3874a377
/* Yaffs commands.
* Modified by Charles Manning by adding ydevconfig command.
*
* Use ydevconfig to configure a mountpoint before use.
* For example:
* # Configure mountpt xxx using nand device 0 using blocks 100-500
* ydevconfig xxx 0 100 500
* # Mount it
* ymount xxx
* # yls, yrdm etc
* yls -l xxx
* yrdm xxx/boot-image 82000000
* ...
*/
#include <common.h>
#include <config.h>
#include <command.h>
#ifdef YAFFS2_DEBUG
#define PRINTF(fmt,args...) printf (fmt ,##args)
#ifdef YAFFS2_DEBUG
#define PRINTF(fmt, args...) printf(fmt, ##args)
#else
#define PRINTF(fmt,args...)
#define PRINTF(fmt, args...) do { } while (0)
#endif
extern void cmd_yaffs_dev_ls(void);
extern void cmd_yaffs_tracemask(unsigned set, unsigned mask);
extern void cmd_yaffs_devconfig(char *mp, int flash_dev,
int start_block, int end_block);
extern void cmd_yaffs_mount(char *mp);
extern void cmd_yaffs_umount(char *mp);
extern void cmd_yaffs_read_file(char *fn);
extern void cmd_yaffs_write_file(char *fn,char bval,int sizeOfFile);
extern void cmd_yaffs_write_file(char *fn, char bval, int sizeOfFile);
extern void cmd_yaffs_ls(const char *mountpt, int longlist);
extern void cmd_yaffs_mwrite_file(char *fn, char *addr, int size);
extern void cmd_yaffs_mread_file(char *fn, char *addr);
......@@ -21,193 +40,287 @@ extern void cmd_yaffs_rmdir(const char *dir);
extern void cmd_yaffs_rm(const char *path);
extern void cmd_yaffs_mv(const char *oldPath, const char *newPath);
extern int yaffs_DumpDevStruct(const char *path);
extern int yaffs_dump_dev(const char *path);
/* ytrace - show/set yaffs trace mask */
int do_ytrace(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
if (argc > 1)
cmd_yaffs_tracemask(1, simple_strtol(argv[1], NULL, 16));
else
cmd_yaffs_tracemask(0, 0);
return 0;
}
int do_ymount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* ydevls - lists yaffs mount points. */
int do_ydevls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *mtpoint = argv[1];
cmd_yaffs_mount(mtpoint);
cmd_yaffs_dev_ls();
return(0);
return 0;
}
int do_yumount (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
/* ydevconfig mount_pt mtd_dev_num start_block end_block */
int do_ydevconfig(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *mtpoint = argv[1];
cmd_yaffs_umount(mtpoint);
char *mtpoint;
int mtd_dev;
int start_block;
int end_block;
if (argc != 5) {
printf
("Bad arguments: ydevconfig mount_pt mtd_dev start_block end_block\n");
return -1;
}
mtpoint = argv[1];
mtd_dev = simple_strtol(argv[2], NULL, 16);
start_block = simple_strtol(argv[3], NULL, 16);
end_block = simple_strtol(argv[4], NULL, 16);
return(0);
cmd_yaffs_devconfig(mtpoint, mtd_dev, start_block, end_block);
return 0;
}
int do_yls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ymount(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[argc-1];
char *mtpoint;
if (argc != 2) {
printf("Bad arguments: ymount mount_pt\n");
return -1;
}
mtpoint = argv[1];
printf("Mounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_ls(dirname, (argc>2)?1:0);
cmd_yaffs_mount(mtpoint);
return(0);
return 0;
}
int do_yrd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yumount(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
printf ("Reading file %s ", filename);
char *mtpoint;
cmd_yaffs_read_file(filename);
if (argc != 2) {
printf("Bad arguments: yumount mount_pt\n");
return -1;
}
printf ("done\n");
return(0);
mtpoint = argv[1];
printf("Unmounting yaffs2 mount point %s\n", mtpoint);
cmd_yaffs_umount(mtpoint);
return 0;
}
int do_ywr (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
ulong value = simple_strtoul(argv[2], NULL, 16);
ulong numValues = simple_strtoul(argv[3], NULL, 16);
char *dirname;
if (argc < 2 || argc > 3 || (argc == 3 && strcmp(argv[1], "-l"))) {
printf("Bad arguments: yls [-l] dir\n");
return -1;
}
printf ("Writing value (%lx) %lx times to %s... ", value, numValues, filename);
dirname = argv[argc - 1];
cmd_yaffs_write_file(filename,value,numValues);
cmd_yaffs_ls(dirname, (argc > 2) ? 1 : 0);
printf ("done\n");
return(0);
return 0;
}
int do_yrdm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrd(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
ulong addr = simple_strtoul(argv[2], NULL, 16);
char *filename;
if (argc != 2) {
printf("Bad arguments: yrd file_name\n");
return -1;
}
cmd_yaffs_mread_file(filename, (char *)addr);
filename = argv[1];
return(0);
printf("Reading file %s ", filename);
cmd_yaffs_read_file(filename);
printf("done\n");
return 0;
}
int do_ywrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ywr(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *filename = argv[1];
ulong addr = simple_strtoul(argv[2], NULL, 16);
ulong size = simple_strtoul(argv[3], NULL, 16);
char *filename;
ulong value;
ulong numValues;
if (argc != 4) {
printf("Bad arguments: ywr file_name value n_values\n");
return -1;
}
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
filename = argv[1];
value = simple_strtoul(argv[2], NULL, 16);
numValues = simple_strtoul(argv[3], NULL, 16);
return(0);
printf("Writing value (%lx) %lx times to %s... ", value, numValues,
filename);
cmd_yaffs_write_file(filename, value, numValues);
printf("done\n");
return 0;
}
int do_ymkdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrdm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[1];
char *filename;
ulong addr;
if (argc != 3) {
printf("Bad arguments: yrdm file_name addr\n");
return -1;
}
cmd_yaffs_mkdir(dirname);
filename = argv[1];
addr = simple_strtoul(argv[2], NULL, 16);
return(0);
cmd_yaffs_mread_file(filename, (char *)addr);
return 0;
}
int do_yrmdir (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ywrm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[1];
char *filename;
ulong addr;
ulong size;
if (argc != 4) {
printf("Bad arguments: ywrm file_name addr size\n");
return -1;
}
filename = argv[1];
addr = simple_strtoul(argv[2], NULL, 16);
size = simple_strtoul(argv[3], NULL, 16);
cmd_yaffs_rmdir(dirname);
cmd_yaffs_mwrite_file(filename, (char *)addr, size);
return(0);
return 0;
}
int do_yrm (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_ymkdir(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *path = argv[1];
char *dirname;
cmd_yaffs_rm(path);
if (argc != 2) {
printf("Bad arguments: ymkdir dir_name\n");
return -1;
}
return(0);
dirname = argv[1];
cmd_yaffs_mkdir(dirname);
return 0;
}
int do_ymv (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrmdir(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *oldPath = argv[1];
char *newPath = argv[2];
char *dirname;
if (argc != 2) {
printf("Bad arguments: yrmdir dir_name\n");
return -1;
}
cmd_yaffs_mv(newPath, oldPath);
dirname = argv[1];
cmd_yaffs_rmdir(dirname);
return(0);
return 0;
}
int do_ydump (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_yrm(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *dirname = argv[1];
if (yaffs_DumpDevStruct(dirname) != 0)
printf("yaffs_DumpDevStruct returning error when dumping path: , %s\n", dirname);
return 0;
char *name;
if (argc != 2) {
printf("Bad arguments: yrm name\n");
return -1;
}
name = argv[1];
cmd_yaffs_rm(name);
return 0;
}
int do_ymv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
char *oldPath;
char *newPath;
if (argc != 3) {
printf("Bad arguments: ymv old_path new_path\n");
return -1;
}
oldPath = argv[1];
newPath = argv[2];
cmd_yaffs_mv(newPath, oldPath);
return 0;
}
U_BOOT_CMD(
ymount, 3, 0, do_ymount,
"mount yaffs",
""
);
U_BOOT_CMD(
yumount, 3, 0, do_yumount,
"unmount yaffs",
""
);
U_BOOT_CMD(
yls, 4, 0, do_yls,
"yaffs ls",
"[-l] name"
);
U_BOOT_CMD(
yrd, 2, 0, do_yrd,
"read file from yaffs",
"filename"
);
U_BOOT_CMD(
ywr, 4, 0, do_ywr,
"write file to yaffs",
"filename value num_vlues"
);
U_BOOT_CMD(
yrdm, 3, 0, do_yrdm,
"read file to memory from yaffs",
"filename offset"
);
U_BOOT_CMD(
ywrm, 4, 0, do_ywrm,
"write file from memory to yaffs",
"filename offset size"
);
U_BOOT_CMD(
ymkdir, 2, 0, do_ymkdir,
"YAFFS mkdir",
"dirname"
);
U_BOOT_CMD(
yrmdir, 2, 0, do_yrmdir,
"YAFFS rmdir",
"dirname"
);
U_BOOT_CMD(
yrm, 2, 0, do_yrm,
"YAFFS rm",
"path"
);
U_BOOT_CMD(
ymv, 4, 0, do_ymv,
"YAFFS mv",
"oldPath newPath"
);
U_BOOT_CMD(
ydump, 2, 0, do_ydump,
"YAFFS device struct",
"dirname"
);
U_BOOT_CMD(ytrace, 2, 0, do_ytrace,
"show/set yaffs trace mask",
"ytrace [new_mask] show/set yaffs trace mask");
U_BOOT_CMD(ydevls, 1, 0, do_ydevls,
"list yaffs mount points", "list yaffs mount points");
U_BOOT_CMD(ydevconfig, 5, 0, do_ydevconfig,
"configure yaffs mount point",
"ydevconfig mtpoint mtd_id start_block end_block configures a yaffs2 mount point");
U_BOOT_CMD(ymount, 2, 0, do_ymount,
"mount yaffs", "ymount mtpoint mounts a yaffs2 mount point");
U_BOOT_CMD(yumount, 2, 0, do_yumount,
"unmount yaffs", "yunmount mtpoint unmounts a yaffs2 mount point");
U_BOOT_CMD(yls, 3, 0, do_yls, "yaffs ls", "yls [-l] dirname");
U_BOOT_CMD(yrd, 2, 0, do_yrd,
"read file from yaffs", "yrd path read file from yaffs");
U_BOOT_CMD(ywr, 4, 0, do_ywr,
"write file to yaffs",
"ywr filename value num_vlues write values to yaffs file");
U_BOOT_CMD(yrdm, 3, 0, do_yrdm,
"read file to memory from yaffs",
"yrdm filename offset reads yaffs file into memory");
U_BOOT_CMD(ywrm, 4, 0, do_ywrm,
"write file from memory to yaffs",
"ywrm filename offset size writes memory to yaffs file");
U_BOOT_CMD(ymkdir, 2, 0, do_ymkdir,
"YAFFS mkdir", "ymkdir dir create a yaffs directory");
U_BOOT_CMD(yrmdir, 2, 0, do_yrmdir,
"YAFFS rmdir", "yrmdir dirname removes a yaffs directory");
U_BOOT_CMD(yrm, 2, 0, do_yrm, "YAFFS rm", "yrm path removes a yaffs file");
U_BOOT_CMD(ymv, 4, 0, do_ymv,
"YAFFS mv",
"ymv old_path new_path moves/rename files within a yaffs mount point");
......@@ -16,28 +16,43 @@
#
# $Id: Makefile,v 1.15 2007/07/18 19:40:38 charles Exp $
#EXTRA_COMPILE_FLAGS = -DYAFFS_IGNORE_TAGS_ECC
include $(TOPDIR)/config.mk
LIB = $(obj)libyaffs2.o
COBJS-$(CONFIG_YAFFS2) := \
yaffscfg.o yaffs_ecc.o yaffsfs.o yaffs_guts.o yaffs_packedtags1.o \
yaffs_tagscompat.o yaffs_packedtags2.o yaffs_tagsvalidity.o \
yaffs_nand.o yaffs_checkptrw.o yaffs_qsort.o yaffs_mtdif.o \
yaffs_mtdif2.o
yaffs_allocator.o yaffs_attribs.o yaffs_bitmap.o yaffs_uboot_glue.o\
yaffs_checkptrw.o yaffs_ecc.o yaffs_error.o \
yaffsfs.o yaffs_guts.o yaffs_hweight.o yaffs_nameval.o yaffs_nand.o\
yaffs_packedtags1.o yaffs_packedtags2.o yaffs_qsort.o \
yaffs_summary.o yaffs_tagscompat.o yaffs_verify.o yaffs_yaffs1.o \
yaffs_yaffs2.o yaffs_mtdif.o yaffs_mtdif2.o
SRCS := $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(COBJS-y))
# -DCONFIG_YAFFS_NO_YAFFS1
CFLAGS += -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM -DCONFIG_YAFFS_YAFFS2 -DLINUX_VERSION_CODE=0x20622
YCFLAGS = -DCONFIG_YAFFS_DIRECT -DCONFIG_YAFFS_SHORT_NAMES_IN_RAM
YCFLAGS += -DCONFIG_YAFFS_YAFFS2 -DNO_Y_INLINE
YCFLAGS += -DCONFIG_YAFFS_PROVIDE_DEFS -DCONFIG_YAFFSFS_PROVIDE_VALUES
CFLAGS += $(YCFLAGS)
CPPFLAGS += $(YCFLAGS)
all: $(LIB)
$(LIB): $(obj).depend $(OBJS)
$(obj)libyaffs2.a: $(obj).depend $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
$(obj)libyaffs2.o: $(obj).depend $(OBJS)
$(call cmd_link_o_target, $(OBJS))
.PHONY: clean distclean
clean:
rm -f $(OBJS)
distclean: clean
rm -f $(LIB) core *.bak .depend
#########################################################################
# defines $(obj).depend target
......
Welcome to YAFFS, the first file system developed specifically for NAND flash.
It is now YAFFS2 - original YAFFS (AYFFS1) only supports 512-byte page
NAND and is now deprectated. YAFFS2 supports 512b page in 'YAFFS1
compatibility' mode (CONFIG_YAFFS_YAFFS1) and 2K or larger page NAND
in YAFFS2 mode (CONFIG_YAFFS_YAFFS2).
A note on licencing
-------------------
YAFFS is available under the GPL and via alternative licensing
arrangements with Aleph One. If you're using YAFFS as a Linux kernel
file system then it will be under the GPL. For use in other situations
you should discuss licensing issues with Aleph One.
Terminology
-----------
Page - NAND addressable unit (normally 512b or 2Kbyte size) - can
be read, written, marked bad. Has associated OOB.
Block - Eraseable unit. 64 Pages. (128K on 2K NAND, 32K on 512b NAND)
OOB - 'spare area' of each page for ECC, bad block marked and YAFFS
tags. 16 bytes per 512b - 64 bytes for 2K page size.
Chunk - Basic YAFFS addressable unit. Same size as Page.
Object - YAFFS Object: File, Directory, Link, Device etc.
YAFFS design
------------
YAFFS is a log-structured filesystem. It is designed particularly for
NAND (as opposed to NOR) flash, to be flash-friendly, robust due to
journalling, and to have low RAM and boot time overheads. File data is
stored in 'chunks'. Chunks are the same size as NAND pages. Each page
is marked with file id and chunk number. These marking 'tags' are
stored in the OOB (or 'spare') region of the flash. The chunk number
is determined by dividing the file position by the chunk size. Each
chunk has a number of valid bytes, which equals the page size for all
except the last chunk in a file.
File 'headers' are stored as the first page in a file, marked as a
different type to data pages. The same mechanism is used to store
directories, device files, links etc. The first page describes which
type of object it is.
YAFFS2 never re-writes a page, because the spec of NAND chips does not
allow it. (YAFFS1 used to mark a block 'deleted' in the OOB). Deletion
is managed by moving deleted objects to the special, hidden 'unlinked'
directory. These records are preserved until all the pages containing
the object have been erased (We know when this happen by keeping a
count of chunks remaining on the system for each object - when it
reaches zero the object really is gone).
When data in a file is overwritten, the relevant chunks are replaced
by writing new pages to flash containing the new data but the same
tags.
Pages are also marked with a short (2 bit) serial number that
increments each time the page at this position is incremented. The
reason for this is that if power loss/crash/other act of demonic
forces happens before the replaced page is marked as discarded, it is
possible to have two pages with the same tags. The serial number is
used to arbitrate.
A block containing only discarded pages (termed a dirty block) is an
obvious candidate for garbage collection. Otherwise valid pages can be
copied off a block thus rendering the whole block discarded and ready
for garbage collection.
In theory you don't need to hold the file structure in RAM... you
could just scan the whole flash looking for pages when you need them.
In practice though you'd want better file access times than that! The
mechanism proposed here is to have a list of __u16 page addresses
associated with each file. Since there are 2^18 pages in a 128MB NAND,
a __u16 is insufficient to uniquely identify a page but is does
identify a group of 4 pages - a small enough region to search
exhaustively. This mechanism is clearly expandable to larger NAND
devices - within reason. The RAM overhead with this approach is approx
2 bytes per page - 512kB of RAM for a whole 128MB NAND.
Boot-time scanning to build the file structure lists only requires
one pass reading NAND. If proper shutdowns happen the current RAM
summary of the filesystem status is saved to flash, called
'checkpointing'. This saves re-scanning the flash on startup, and gives
huge boot/mount time savings.
YAFFS regenerates its state by 'replaying the tape' - i.e. by
scanning the chunks in their allocation order (i.e. block sequence ID
order), which is usually different form the media block order. Each
block is still only read once - starting from the end of the media and
working back.
YAFFS tags in YAFFS1 mode:
18-bit Object ID (2^18 files, i.e. > 260,000 files). File id 0- is not
valid and indicates a deleted page. File od 0x3ffff is also not valid.
Synonymous with inode.
2-bit serial number
20-bit Chunk ID within file. Limit of 2^20 chunks/pages per file (i.e.
> 500MB max file size). Chunk ID 0 is the file header for the file.
10-bit counter of the number of bytes used in the page.
12 bit ECC on tags
YAFFS tags in YAFFS2 mode:
4 bytes 32-bit chunk ID
4 bytes 32-bit object ID
2 bytes Number of data bytes in this chunk
4 bytes Sequence number for this block
3 bytes ECC on tags
12 bytes ECC on data (3 bytes per 256 bytes of data)
Page allocation and garbage collection
Pages are allocated sequentially from the currently selected block.
When all the pages in the block are filled, another clean block is
selected for allocation. At least two or three clean blocks are
reserved for garbage collection purposes. If there are insufficient
clean blocks available, then a dirty block ( ie one containing only
discarded pages) is erased to free it up as a clean block. If no dirty
blocks are available, then the dirtiest block is selected for garbage
collection.
Garbage collection is performed by copying the valid data pages into
new data pages thus rendering all the pages in this block dirty and
freeing it up for erasure. I also like the idea of selecting a block
at random some small percentage of the time - thus reducing the chance
of wear differences.
YAFFS is single-threaded. Garbage-collection is done as a parasitic
task of writing data. So each time some data is written, a bit of
pending garbage collection is done. More pages are garbage-collected
when free space is tight.
Flash writing
YAFFS only ever writes each page once, complying with the requirements
of the most restricitve NAND devices.
Wear levelling
This comes as a side-effect of the block-allocation strategy. Data is
always written on the next free block, so they are all used equally.
Blocks containing data that is written but never erased will not get
back into the free list, so wear is levelled over only blocks which
are free or become free, not blocks which never change.
Some helpful info
-----------------
Formatting a YAFFS device is simply done by erasing it.
Making an initial filesystem can be tricky because YAFFS uses the OOB
and thus the bytes that get written depend on the YAFFS data (tags),
and the ECC bytes and bad block markers which are dictated by the
hardware and/or the MTD subsystem. The data layout also depends on the
device page size (512b or 2K). Because YAFFS is only responsible for
some of the OOB data, generating a filesystem offline requires
detailed knowledge of what the other parts (MTD and NAND
driver/hardware) are going to do.
To make a YAFFS filesystem you have 3 options:
1) Boot the system with an empty NAND device mounted as YAFFS and copy
stuff on.
2) Make a filesystem image offline, then boot the system and use
MTDutils to write an image to flash.
3) Make a filesystem image offline and use some tool like a bootloader to
write it to flash.
Option 1 avoids a lot of issues because all the parts
(YAFFS/MTD/hardware) all take care of their own bits and (if you have
put things together properly) it will 'just work'. YAFFS just needs to
know how many bytes of the OOB it can use. However sometimes it is not
practical.
Option 2 lets MTD/hardware take care of the ECC so the filesystem
image just had to know which bytes to use for YAFFS Tags.
Option 3 is hardest as the image creator needs to know exactly what
ECC bytes, endianness and algorithm to use as well as which bytes are
available to YAFFS.
mkyaffs2image creates an image suitable for option 3 for the
particular case of yaffs2 on 2K page NAND with default MTD layout.
mkyaffsimage creates an equivalent image for 512b page NAND (i.e.
yaffs1 format).
Bootloaders
-----------
A bootloader using YAFFS needs to know how MTD is laying out the OOB
so that it can skip bad blocks.
YAFFS Tracing
-------------
/*
* 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.
*/
/*
* This file is just holds extra declarations used during development.
* Most of these are from kernel includes placed here so we can use them in
* applications.
*
*/
#ifndef __EXTRAS_H__
#define __EXTRAS_H__
#if defined WIN32
#define __inline__ __inline
#define new newHack
#endif
/* XXX U-BOOT XXX */
#if 1 /* !(defined __KERNEL__) || (defined WIN32) */
/* User space defines */
/* XXX U-BOOT XXX */
#if 0
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned __u32;
#endif
#include <asm/types.h>
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#define prefetch(x) 1
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new,
struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev,
struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/**
* list_for_each_safe - iterate over a list safe against removal
* of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#ifndef WIN32
/* XXX U-BOOT XXX */
#if 0
#include <sys/stat.h>
#else
#include "common.h"
#endif
#endif
/*
* Attribute flags. These should be or-ed together to figure out what
* has been changed!
*/
#define ATTR_MODE 1
#define ATTR_UID 2
#define ATTR_GID 4
#define ATTR_SIZE 8
#define ATTR_ATIME 16
#define ATTR_MTIME 32
#define ATTR_CTIME 64
#define ATTR_ATIME_SET 128
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
struct iattr {
unsigned int ia_valid;
unsigned ia_mode;
unsigned ia_uid;
unsigned ia_gid;
unsigned ia_size;
unsigned ia_atime;
unsigned ia_mtime;
unsigned ia_ctime;
unsigned int ia_attr_flags;
};
#define KERN_DEBUG
#else
#ifndef WIN32
#include <linux/types.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/stat.h>
#endif
#endif
#if defined WIN32
#undef new
#endif
#endif
/* Dummy header for u-boot */
/* Dummy header for u-boot */
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <common.h>
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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.
*/
#include "yaffs_allocator.h"
#include "yaffs_guts.h"
#include "yaffs_trace.h"
#include "yportenv.h"
/*
* Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
* of approx 100 objects that are themn allocated singly.
* This is basically a simplified slab allocator.
*
* We don't use the Linux slab allocator because slab does not allow
* us to dump all the objects in one hit when we do a umount and tear
* down all the tnodes and objects. slab requires that we first free
* the individual objects.
*
* Once yaffs has been mainlined I shall try to motivate for a change
* to slab to provide the extra features we need here.
*/
struct yaffs_tnode_list {
struct yaffs_tnode_list *next;
struct yaffs_tnode *tnodes;
};
struct yaffs_obj_list {
struct yaffs_obj_list *next;
struct yaffs_obj *objects;
};
struct yaffs_allocator {
int n_tnodes_created;
struct yaffs_tnode *free_tnodes;
int n_free_tnodes;
struct yaffs_tnode_list *alloc_tnode_list;
int n_obj_created;
struct list_head free_objs;
int n_free_objects;
struct yaffs_obj_list *allocated_obj_list;
};
static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
struct yaffs_tnode_list *tmp;
if (!allocator) {
BUG();
return;
}
while (allocator->alloc_tnode_list) {
tmp = allocator->alloc_tnode_list->next;
kfree(allocator->alloc_tnode_list->tnodes);
kfree(allocator->alloc_tnode_list);
allocator->alloc_tnode_list = tmp;
}
allocator->free_tnodes = NULL;
allocator->n_free_tnodes = 0;
allocator->n_tnodes_created = 0;
}
static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
allocator->alloc_tnode_list = NULL;
allocator->free_tnodes = NULL;
allocator->n_free_tnodes = 0;
allocator->n_tnodes_created = 0;
}
static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
{
struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
int i;
struct yaffs_tnode *new_tnodes;
u8 *mem;
struct yaffs_tnode *curr;
struct yaffs_tnode *next;
struct yaffs_tnode_list *tnl;
if (!allocator) {
BUG();
return YAFFS_FAIL;
}
if (n_tnodes < 1)
return YAFFS_OK;
/* make these things */
new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
mem = (u8 *) new_tnodes;
if (!new_tnodes) {
yaffs_trace(YAFFS_TRACE_ERROR,
"yaffs: Could not allocate Tnodes");
return YAFFS_FAIL;
}
/* New hookup for wide tnodes */
for (i = 0; i < n_tnodes - 1; i++) {
curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
curr->internal[0] = next;
}
curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
curr->internal[0] = allocator->free_tnodes;
allocator->free_tnodes = (struct yaffs_tnode *)mem;
allocator->n_free_tnodes += n_tnodes;
allocator->n_tnodes_created += n_tnodes;
/* Now add this bunch of tnodes to a list for freeing up.
* NB If we can't add this to the management list it isn't fatal
* but it just means we can't free this bunch of tnodes later.
*/
tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
if (!tnl) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Could not add tnodes to management list");
return YAFFS_FAIL;
} else {
tnl->tnodes = new_tnodes;
tnl->next = allocator->alloc_tnode_list;
allocator->alloc_tnode_list = tnl;
}
yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
return YAFFS_OK;
}
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator =
(struct yaffs_allocator *)dev->allocator;
struct yaffs_tnode *tn = NULL;
if (!allocator) {
BUG();
return NULL;
}
/* If there are none left make more */
if (!allocator->free_tnodes)
yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
if (allocator->free_tnodes) {
tn = allocator->free_tnodes;
allocator->free_tnodes = allocator->free_tnodes->internal[0];
allocator->n_free_tnodes--;
}
return tn;
}
/* FreeTnode frees up a tnode and puts it back on the free list */
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
if (tn) {
tn->internal[0] = allocator->free_tnodes;
allocator->free_tnodes = tn;
allocator->n_free_tnodes++;
}
dev->checkpoint_blocks_required = 0; /* force recalculation */
}
/*--------------- yaffs_obj alloaction ------------------------
*
* Free yaffs_objs are stored in a list using obj->siblings.
* The blocks of allocated objects are stored in a linked list.
*/
static void yaffs_init_raw_objs(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
allocator->allocated_obj_list = NULL;
INIT_LIST_HEAD(&allocator->free_objs);
allocator->n_free_objects = 0;
}
static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator = dev->allocator;
struct yaffs_obj_list *tmp;
if (!allocator) {
BUG();
return;
}
while (allocator->allocated_obj_list) {
tmp = allocator->allocated_obj_list->next;
kfree(allocator->allocated_obj_list->objects);
kfree(allocator->allocated_obj_list);
allocator->allocated_obj_list = tmp;
}
INIT_LIST_HEAD(&allocator->free_objs);
allocator->n_free_objects = 0;
allocator->n_obj_created = 0;
}
static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
{
struct yaffs_allocator *allocator = dev->allocator;
int i;
struct yaffs_obj *new_objs;
struct yaffs_obj_list *list;
if (!allocator) {
BUG();
return YAFFS_FAIL;
}
if (n_obj < 1)
return YAFFS_OK;
/* make these things */
new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
if (!new_objs || !list) {
kfree(new_objs);
new_objs = NULL;
kfree(list);
list = NULL;
yaffs_trace(YAFFS_TRACE_ALLOCATE,
"Could not allocate more objects");
return YAFFS_FAIL;
}
/* Hook them into the free list */
for (i = 0; i < n_obj; i++)
list_add(&new_objs[i].siblings, &allocator->free_objs);
allocator->n_free_objects += n_obj;
allocator->n_obj_created += n_obj;
/* Now add this bunch of Objects to a list for freeing up. */
list->objects = new_objs;
list->next = allocator->allocated_obj_list;
allocator->allocated_obj_list = list;
return YAFFS_OK;
}
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
{
struct yaffs_obj *obj = NULL;
struct list_head *lh;
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return obj;
}
/* If there are none left make more */
if (list_empty(&allocator->free_objs))
yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
if (!list_empty(&allocator->free_objs)) {
lh = allocator->free_objs.next;
obj = list_entry(lh, struct yaffs_obj, siblings);
list_del_init(lh);
allocator->n_free_objects--;
}
return obj;
}
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
{
struct yaffs_allocator *allocator = dev->allocator;
if (!allocator) {
BUG();
return;
}
/* Link into the free list. */
list_add(&obj->siblings, &allocator->free_objs);
allocator->n_free_objects++;
}
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
{
if (!dev->allocator) {
BUG();
return;
}
yaffs_deinit_raw_tnodes(dev);
yaffs_deinit_raw_objs(dev);
kfree(dev->allocator);
dev->allocator = NULL;
}
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
{
struct yaffs_allocator *allocator;
if (dev->allocator) {
BUG();
return;
}
allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
if (allocator) {
dev->allocator = allocator;
yaffs_init_raw_tnodes(dev);
yaffs_init_raw_objs(dev);
}
}
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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 __YAFFS_ALLOCATOR_H__
#define __YAFFS_ALLOCATOR_H__
#include "yaffs_guts.h"
void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
#endif
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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.
*/
#include "yaffs_attribs.h"
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
{
obj->yst_uid = oh->yst_uid;
obj->yst_gid = oh->yst_gid;
obj->yst_atime = oh->yst_atime;
obj->yst_mtime = oh->yst_mtime;
obj->yst_ctime = oh->yst_ctime;
obj->yst_rdev = oh->yst_rdev;
}
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
{
#ifdef CONFIG_YAFFS_WINCE
oh->win_atime[0] = obj->win_atime[0];
oh->win_ctime[0] = obj->win_ctime[0];
oh->win_mtime[0] = obj->win_mtime[0];
oh->win_atime[1] = obj->win_atime[1];
oh->win_ctime[1] = obj->win_ctime[1];
oh->win_mtime[1] = obj->win_mtime[1];
#else
oh->yst_uid = obj->yst_uid;
oh->yst_gid = obj->yst_gid;
oh->yst_atime = obj->yst_atime;
oh->yst_mtime = obj->yst_mtime;
oh->yst_ctime = obj->yst_ctime;
oh->yst_rdev = obj->yst_rdev;
#endif
}
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_win_file_time_now(obj->win_atime);
obj->win_ctime[0] = obj->win_mtime[0] = obj->win_atime[0];
obj->win_ctime[1] = obj->win_mtime[1] = obj->win_atime[1];
#else
yaffs_load_current_time(obj, 1, 1);
obj->yst_rdev = rdev;
obj->yst_uid = uid;
obj->yst_gid = gid;
#endif
}
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
{
#ifdef CONFIG_YAFFS_WINCE
yfsd_win_file_time_now(the_obj->win_atime);
the_obj->win_ctime[0] = the_obj->win_mtime[0] =
the_obj->win_atime[0];
the_obj->win_ctime[1] = the_obj->win_mtime[1] =
the_obj->win_atime[1];
#else
obj->yst_mtime = Y_CURRENT_TIME;
if (do_a)
obj->yst_atime = obj->yst_atime;
if (do_c)
obj->yst_ctime = obj->yst_atime;
#endif
}
loff_t yaffs_get_file_size(struct yaffs_obj *obj)
{
YCHAR *alias = NULL;
obj = yaffs_get_equivalent_obj(obj);
switch (obj->variant_type) {
case YAFFS_OBJECT_TYPE_FILE:
return obj->variant.file_variant.file_size;
case YAFFS_OBJECT_TYPE_SYMLINK:
alias = obj->variant.symlink_variant.alias;
if (!alias)
return 0;
return yaffs_strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
default:
return 0;
}
}
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
{
unsigned int valid = attr->ia_valid;
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
obj->yst_uid = attr->ia_uid;
if (valid & ATTR_GID)
obj->yst_gid = attr->ia_gid;
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
if (valid & ATTR_CTIME)
obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
if (valid & ATTR_MTIME)
obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
if (valid & ATTR_SIZE)
yaffs_resize_file(obj, attr->ia_size);
yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
return YAFFS_OK;
}
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
{
unsigned int valid = 0;
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
attr->ia_uid = obj->yst_uid;
valid |= ATTR_UID;
attr->ia_gid = obj->yst_gid;
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
valid |= ATTR_ATIME;
Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
valid |= ATTR_CTIME;
Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
valid |= ATTR_MTIME;
attr->ia_size = yaffs_get_file_size(obj);
valid |= ATTR_SIZE;
attr->ia_valid = valid;
return YAFFS_OK;
}
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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 __YAFFS_ATTRIBS_H__
#define __YAFFS_ATTRIBS_H__
#include "yaffs_guts.h"
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
#endif
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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.
*/
#include "yaffs_bitmap.h"
#include "yaffs_trace.h"
/*
* Chunk bitmap manipulations
*/
static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"BlockBits block %d is not valid",
blk);
BUG();
}
return dev->chunk_bits +
(dev->chunk_bit_stride * (blk - dev->internal_start_block));
}
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
chunk < 0 || chunk >= dev->param.chunks_per_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Chunk Id (%d:%d) invalid",
blk, chunk);
BUG();
}
}
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
memset(blk_bits, 0, dev->chunk_bit_stride);
}
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
}
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
blk_bits[chunk / 8] |= (1 << (chunk & 7));
}
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
yaffs_verify_chunk_bit_id(dev, blk, chunk);
return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
}
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
int i;
for (i = 0; i < dev->chunk_bit_stride; i++) {
if (*blk_bits)
return 1;
blk_bits++;
}
return 0;
}
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
{
u8 *blk_bits = yaffs_block_bits(dev, blk);
int i;
int n = 0;
for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
n += hweight8(*blk_bits);
return n;
}
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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.
*/
/*
* Chunk bitmap manipulations
*/
#ifndef __YAFFS_BITMAP_H__
#define __YAFFS_BITMAP_H__
#include "yaffs_guts.h"
void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
#endif
此差异已折叠。
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -18,17 +18,16 @@
#include "yaffs_guts.h"
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
int yaffs_CheckpointClose(yaffs_Device *dev);
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
int yaffs_checkpt_close(struct yaffs_dev *dev);
int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
#endif
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -16,28 +16,22 @@
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
* blocks are used on a 512-byte NAND page.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two
* such ECC blocks are used on a 512-byte NAND page.
*
*/
#include "yportenv.h"
#include "yaffs_ecc.h"
/* Table generated by gen-ecc.c
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
* for each byte of data. These are instead provided in a table in bits7..2.
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
* this bytes influence on the line parity.
* Bit 0 of each entry indicates whether the entry has an odd or even parity,
* and therefore this bytes influence on the line parity.
*/
/* XXX U-BOOT XXX */
#include <common.h>
const char *yaffs_ecc_c_version =
"$Id: yaffs_ecc.c,v 1.9 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_ecc.h"
static const unsigned char column_parity_table[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
......@@ -73,35 +67,11 @@ static const unsigned char column_parity_table[] = {
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
};
/* Count the bits in an unsigned char or a U32 */
static int yaffs_CountBits(unsigned char x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
static int yaffs_CountBits32(unsigned x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
/* Calculate the ECC for a 256-byte block of data */
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned char line_parity = 0;
unsigned char line_parity_prime = 0;
......@@ -112,12 +82,10 @@ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) // odd number of bits in the byte
{
if (b & 0x01) { /* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc[2] = (~col_parity) | 0x03;
......@@ -160,19 +128,12 @@ void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
t |= 0x01;
ecc[0] = ~t;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// Swap the bytes into the wrong order
t = ecc[0];
ecc[0] = ecc[1];
ecc[1] = t;
#endif
}
/* Correct the ECC on a 256 byte block of data */
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
{
unsigned char d0, d1, d2; /* deltas */
......@@ -181,7 +142,7 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0)
return 0; /* no error */
return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
......@@ -191,15 +152,6 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
unsigned byte;
unsigned bit;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// swap the bytes to correct for the wrong order
unsigned char t;
t = d0;
d0 = d1;
d1 = t;
#endif
bit = byte = 0;
if (d1 & 0x80)
......@@ -228,19 +180,17 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
data[byte] ^= (1 << bit);
return 1; /* Corrected the error */
return 1; /* Corrected the error */
}
if ((yaffs_CountBits(d0) +
yaffs_CountBits(d1) +
yaffs_CountBits(d2)) == 1) {
if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
/* Reccoverable error in ecc */
read_ecc[0] = test_ecc[0];
read_ecc[1] = test_ecc[1];
read_ecc[2] = test_ecc[2];
return 1; /* Corrected the error */
return 1; /* Corrected the error */
}
/* Unrecoverable error */
......@@ -249,25 +199,23 @@ int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
}
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * eccOther)
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *ecc_other)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned line_parity = 0;
unsigned line_parity_prime = 0;
unsigned char b;
for (i = 0; i < nBytes; i++) {
for (i = 0; i < n_bytes; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) {
if (b & 0x01) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
......@@ -275,59 +223,59 @@ void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
}
eccOther->colParity = (col_parity >> 2) & 0x3f;
eccOther->lineParity = line_parity;
eccOther->lineParityPrime = line_parity_prime;
ecc_other->col_parity = (col_parity >> 2) & 0x3f;
ecc_other->line_parity = line_parity;
ecc_other->line_parity_prime = line_parity_prime;
}
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc)
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *read_ecc,
const struct yaffs_ecc_other *test_ecc)
{
unsigned char cDelta; /* column parity delta */
unsigned lDelta; /* line parity delta */
unsigned lDeltaPrime; /* line parity delta */
unsigned char delta_col; /* column parity delta */
unsigned delta_line; /* line parity delta */
unsigned delta_line_prime; /* line parity delta */
unsigned bit;
cDelta = read_ecc->colParity ^ test_ecc->colParity;
lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
delta_line_prime =
read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
if ((cDelta | lDelta | lDeltaPrime) == 0)
return 0; /* no error */
if ((delta_col | delta_line | delta_line_prime) == 0)
return 0; /* no error */
if (lDelta == ~lDeltaPrime &&
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
{
if (delta_line == ~delta_line_prime &&
(((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
/* Single bit (recoverable) error in data */
bit = 0;
if (cDelta & 0x20)
if (delta_col & 0x20)
bit |= 0x04;
if (cDelta & 0x08)
if (delta_col & 0x08)
bit |= 0x02;
if (cDelta & 0x02)
if (delta_col & 0x02)
bit |= 0x01;
if(lDelta >= nBytes)
if (delta_line >= n_bytes)
return -1;
data[lDelta] ^= (1 << bit);
data[delta_line] ^= (1 << bit);
return 1; /* corrected */
return 1; /* corrected */
}
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
yaffs_CountBits(cDelta)) == 1) {
if ((hweight32(delta_line) +
hweight32(delta_line_prime) +
hweight8(delta_col)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;
return 1; /* corrected */
return 1; /* corrected */
}
/* Unrecoverable error */
return -1;
}
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -13,32 +13,32 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
* blocks are used on a 512-byte NAND page.
*
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data.
* Thus, two such ECC blocks are used on a 512-byte NAND page.
*
*/
#ifndef __YAFFS_ECC_H__
#define __YAFFS_ECC_H__
typedef struct {
unsigned char colParity;
unsigned lineParity;
unsigned lineParityPrime;
} yaffs_ECCOther;
struct yaffs_ecc_other {
unsigned char col_parity;
unsigned line_parity;
unsigned line_parity_prime;
};
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc);
void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc);
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * ecc);
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc);
void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *ecc);
int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
struct yaffs_ecc_other *read_ecc,
const struct yaffs_ecc_other *test_ecc);
#endif
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Timothy Manning <timothy@yaffs.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffsfs.h"
struct error_entry {
int code;
const char *text;
};
static const struct error_entry error_list[] = {
{ ENOMEM , "ENOMEM" },
{ EBUSY , "EBUSY"},
{ ENODEV , "ENODEV"},
{ EINVAL , "EINVAL"},
{ EBADF , "EBADF"},
{ EACCES , "EACCES"},
{ EXDEV , "EXDEV" },
{ ENOENT , "ENOENT"},
{ ENOSPC , "ENOSPC"},
{ ERANGE , "ERANGE"},
{ ENODATA, "ENODATA"},
{ ENOTEMPTY, "ENOTEMPTY"},
{ ENAMETOOLONG, "ENAMETOOLONG"},
{ ENOMEM , "ENOMEM"},
{ EEXIST , "EEXIST"},
{ ENOTDIR , "ENOTDIR"},
{ EISDIR , "EISDIR"},
{ ENFILE, "ENFILE"},
{ EROFS, "EROFS"},
{ EFAULT, "EFAULT"},
{ 0, NULL }
};
const char *yaffs_error_to_str(int err)
{
const struct error_entry *e = error_list;
if (err < 0)
err = -err;
while (e->code && e->text) {
if (err == e->code)
return e->text;
e++;
}
return "Unknown error code";
}
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -18,14 +18,18 @@
#include "yaffs_guts.h"
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yflash_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags);
int yflash_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);
int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yflash_InitialiseNAND(yaffs_Device *dev);
int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
int yflash_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int yflash_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_spare *spare);
int yflash_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
int yflash_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_spare *spare);
int yflash_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags);
int yflash_InitialiseNAND(struct yaffs_dev *dev);
int yflash_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
int yflash_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state, u32 *seq_number);
#endif
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -13,20 +13,23 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* yaffs_ramdisk.h: yaffs ram disk component
*/
#ifndef __YAFFS_RAMDISK_H__
#define __YAFFS_RAMDISK_H__
#ifndef __YAFFS_FLASH2_H__
#define __YAFFS_FLASH2_H__
#include "yaffs_guts.h"
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yramdisk_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags);
int yramdisk_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags);
int yramdisk_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
int yramdisk_InitialiseNAND(yaffs_Device *dev);
int yramdisk_MarkNANDBlockBad(yaffs_Device *dev,int blockNumber);
int yramdisk_QueryNANDBlock(yaffs_Device *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber);
int yflash2_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int yflash2_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_spare *spare);
int yflash2_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
const u8 *data, const struct yaffs_ext_tags *tags);
int yflash2_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_spare *spare);
int yflash2_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
u8 *data, struct yaffs_ext_tags *tags);
int yflash2_InitialiseNAND(struct yaffs_dev *dev);
int yflash2_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no);
int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no,
enum yaffs_block_state *state, u32 *seq_number);
#endif
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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 __YAFFS_GETBLOCKINFO_H__
#define __YAFFS_GETBLOCKINFO_H__
#include "yaffs_guts.h"
#include "yaffs_trace.h"
/* Function to manipulate block info */
static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
*dev, int blk)
{
if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
yaffs_trace(YAFFS_TRACE_ERROR,
"**>> yaffs: get_block_info block %d is not valid",
blk);
BUG();
}
return &dev->block_info[blk - dev->internal_start_block];
}
#endif
此差异已折叠。
此差异已折叠。
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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.
*/
/* These functions have been renamed to hweightxx to match the
* equivaqlent functions in the Linux kernel.
*/
#include "yaffs_hweight.h"
static const char yaffs_count_bits_table[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int yaffs_hweight8(u8 x)
{
int ret_val;
ret_val = yaffs_count_bits_table[x];
return ret_val;
}
int yaffs_hweight32(u32 x)
{
return yaffs_hweight8(x & 0xff) +
yaffs_hweight8((x >> 8) & 0xff) +
yaffs_hweight8((x >> 16) & 0xff) +
yaffs_hweight8((x >> 24) & 0xff);
}
#ifndef __YAFFS_MALLOC_H__
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -14,12 +13,12 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* XXX U-BOOT XXX */
#if 0
#include <stdlib.h>
#endif
#ifndef __YAFFS_HWEIGHT_H__
#define __YAFFS_HWEIGHT_H__
#include "yportenv.h"
void *yaffs_malloc(size_t size);
void yaffs_free(void *ptr);
int yaffs_hweight8(u8 x);
int yaffs_hweight32(u32 x);
#endif
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <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.
*/
/*
* This file is just holds extra declarations of macros that would normally
* be providesd in the Linux kernel. These macros have been written from
* scratch but are functionally equivalent to the Linux ones.
*
*/
#ifndef __YAFFS_LIST_H__
#define __YAFFS_LIST_H__
/*
* This is a simple doubly linked list implementation that matches the
* way the Linux kernel doubly linked list implementation works.
*/
struct list_head {
struct list_head *next; /* next in chain */
struct list_head *prev; /* previous in chain */
};
/* Initialise a static list */
#define LIST_HEAD(name) \
struct list_head name = { &(name), &(name)}
/* Initialise a list head to an empty list */
#define INIT_LIST_HEAD(p) \
do { \
(p)->next = (p);\
(p)->prev = (p); \
} while (0)
/* Add an element to a list */
static inline void list_add(struct list_head *new_entry,
struct list_head *list)
{
struct list_head *list_next = list->next;
list->next = new_entry;
new_entry->prev = list;
new_entry->next = list_next;
list_next->prev = new_entry;
}
static inline void list_add_tail(struct list_head *new_entry,
struct list_head *list)
{
struct list_head *list_prev = list->prev;
list->prev = new_entry;
new_entry->next = list;
new_entry->prev = list_prev;
list_prev->next = new_entry;
}
/* Take an element out of its current list, with or without
* reinitialising the links.of the entry*/
static inline void list_del(struct list_head *entry)
{
struct list_head *list_next = entry->next;
struct list_head *list_prev = entry->prev;
list_next->prev = list_prev;
list_prev->next = list_next;
}
static inline void list_del_init(struct list_head *entry)
{
list_del(entry);
entry->next = entry->prev = entry;
}
/* Test if the list is empty */
static inline int list_empty(struct list_head *entry)
{
return (entry->next == entry);
}
/* list_entry takes a pointer to a list entry and offsets it to that
* we can find a pointer to the object it is embedded in.
*/
#define list_entry(entry, type, member) \
((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
/* list_for_each and list_for_each_safe iterate over lists.
* list_for_each_safe uses temporary storage to make the list delete safe
*/
#define list_for_each(itervar, list) \
for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
#define list_for_each_safe(itervar, save_var, list) \
for (itervar = (list)->next, save_var = (list)->next->next; \
itervar != (list); \
itervar = save_var, save_var = save_var->next)
#endif
......@@ -14,9 +14,6 @@
/* XXX U-BOOT XXX */
#include <common.h>
const char *yaffs_mtdif_c_version =
"$Id: yaffs_mtdif.c,v 1.19 2007/02/14 01:09:06 wookey Exp $";
#include "yportenv.h"
......@@ -27,72 +24,56 @@ const char *yaffs_mtdif_c_version =
#include "linux/time.h"
#include "linux/mtd/nand.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
static struct nand_oobinfo yaffs_oobinfo = {
.useecc = 1,
.eccbytes = 6,
.eccpos = {8, 9, 10, 13, 14, 15}
};
static struct nand_oobinfo yaffs_noeccinfo = {
.useecc = 0,
};
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
static inline void translate_spare2oob(const struct yaffs_spare *spare, u8 *oob)
{
oob[0] = spare->tagByte0;
oob[1] = spare->tagByte1;
oob[2] = spare->tagByte2;
oob[3] = spare->tagByte3;
oob[4] = spare->tagByte4;
oob[5] = spare->tagByte5 & 0x3f;
oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
oob[6] = spare->tagByte6;
oob[7] = spare->tagByte7;
oob[0] = spare->tb0;
oob[1] = spare->tb1;
oob[2] = spare->tb2;
oob[3] = spare->tb3;
oob[4] = spare->tb4;
oob[5] = spare->tb5 & 0x3f;
oob[5] |= spare->block_status == 'Y' ? 0 : 0x80;
oob[5] |= spare->page_status == 0 ? 0 : 0x40;
oob[6] = spare->tb6;
oob[7] = spare->tb7;
}
static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
static inline void translate_oob2spare(struct yaffs_spare *spare, u8 *oob)
{
struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
spare->tagByte0 = oob[0];
spare->tagByte1 = oob[1];
spare->tagByte2 = oob[2];
spare->tagByte3 = oob[3];
spare->tagByte4 = oob[4];
spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
struct yaffs_nand_spare *nspare = (struct yaffs_nand_spare *)spare;
spare->tb0 = oob[0];
spare->tb1 = oob[1];
spare->tb2 = oob[2];
spare->tb3 = oob[3];
spare->tb4 = oob[4];
spare->tb5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
spare->block_status = oob[5] & 0x80 ? 0xff : 'Y';
spare->page_status = oob[5] & 0x40 ? 0xff : 0;
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
spare->tagByte6 = oob[6];
spare->tagByte7 = oob[7];
spare->tb6 = oob[6];
spare->tb7 = oob[7];
spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
}
#endif
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare)
int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data, const struct yaffs_spare *spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
retval = mtd->write(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
if (dev->param.use_nand_ecc) {
translate_spare2oob(spare, spareAsBytes);
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
......@@ -100,37 +81,12 @@ int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
ops.datbuf = (u8 *)data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->write_oob(mtd, addr, &ops);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
} else {
if (data)
retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
......@@ -138,69 +94,36 @@ int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
return YAFFS_FAIL;
}
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare)
int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
struct yaffs_spare *spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
retval = mtd->read(mtd, addr, dev->data_bytes_per_chunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
if (dev->param.use_nand_ecc) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
ops.datbuf = data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->read_oob(mtd, addr, &ops);
if (dev->useNANDECC)
if (dev->param.use_nand_ecc)
translate_oob2spare(spare, spareAsBytes);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC) {
/* Careful, this call adds 2 ints */
/* to the end of the spare data. Calling function */
/* should allocate enough memory for spare, */
/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
}
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
......@@ -208,18 +131,18 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
return YAFFS_FAIL;
}
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
__u32 addr =
((loff_t) blockNumber) * dev->nDataBytesPerChunk
* dev->nChunksPerBlock;
((loff_t) blockNumber) * dev->data_bytes_per_chunk
* dev->param.chunks_per_block;
struct erase_info ei;
int retval = 0;
ei.mtd = mtd;
ei.addr = addr;
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
ei.len = dev->data_bytes_per_chunk * dev->param.chunks_per_block;
ei.time = 1000;
ei.retries = 2;
ei.callback = NULL;
......@@ -227,10 +150,6 @@ int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
/* Todo finish off the ei if required */
/* XXX U-BOOT XXX */
#if 0
sema_init(&dev->sem, 0);
#endif
retval = mtd->erase(mtd, &ei);
......@@ -240,7 +159,7 @@ int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
return YAFFS_FAIL;
}
int nandmtd_InitialiseNAND(yaffs_Device * dev)
int nandmtd_InitialiseNAND(struct yaffs_dev *dev)
{
return YAFFS_OK;
}
......@@ -18,10 +18,10 @@
#include "yaffs_guts.h"
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_Device * dev);
int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data, const struct yaffs_spare *spare);
int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
struct yaffs_spare *spare);
int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber);
int nandmtd_InitialiseNAND(struct yaffs_dev *dev);
#endif
此差异已折叠。
......@@ -17,13 +17,14 @@
#define __YAFFS_MTDIF2_H__
#include "yaffs_guts.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags);
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int chunkInNAND,
const u8 *data,
const struct yaffs_ext_tags *tags);
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int chunkInNAND,
u8 *data, struct yaffs_ext_tags *tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo,
enum yaffs_block_state *state, u32 *sequenceNumber);
#endif
此差异已折叠。
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -13,11 +13,16 @@
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __NAMEVAL_H__
#define __NAMEVAL_H__
#ifndef __YAFFS_QSORT_H__
#define __YAFFS_QSORT_H__
extern void yaffs_qsort (void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *));
#include "yportenv.h"
int nval_del(char *xb, int xb_size, const YCHAR * name);
int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
int bsize, int flags);
int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
int bsize);
int nval_list(const char *xb, int xb_size, char *buf, int bsize);
int nval_hasvalues(const char *xb, int xb_size);
#endif
此差异已折叠。
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* Copyright (C) 2002-2011 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
......@@ -17,27 +17,22 @@
#define __YAFFS_NAND_H__
#include "yaffs_guts.h"
int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
u8 *buffer, struct yaffs_ext_tags *tags);
int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
int nand_chunk,
const u8 *buffer, struct yaffs_ext_tags *tags);
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_query_init_block_state(struct yaffs_dev *dev,
int block_no,
enum yaffs_block_state *state,
unsigned *seq_number);
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
int *sequenceNumber);
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
int yaffs_init_nand(struct yaffs_dev *dev);
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册