Direct import of yaffs as a tarball as of 20071113 from their public CVS-web at http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/yaffs2/ The code can also be imported on the command line with: export CVSROOT=:pserver:anonymous@cvs.aleph1.co.uk:/home/aleph1/cvs cvs logon (Hit return when asked for a password) cvs checkout yaffs2 Signed-off-by: William Juul <william.juul@tandberg.com> Signed-off-by: Stig Olsen <stig.olsen@tandberg.com>master
parent
3043c045d5
commit
0e8cc8bd92
@ -0,0 +1,176 @@ |
||||
# |
||||
# 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. |
@ -0,0 +1,40 @@ |
||||
# 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 |
@ -0,0 +1,10 @@ |
||||
#
|
||||
# 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
|
@ -0,0 +1,201 @@ |
||||
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 |
||||
------------- |
@ -0,0 +1,20 @@ |
||||
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 |
@ -0,0 +1,264 @@ |
||||
/*
|
||||
* 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 |
||||
|
||||
#if !(defined __KERNEL__) || (defined WIN32) |
||||
|
||||
/* User space defines */ |
||||
|
||||
typedef unsigned char __u8; |
||||
typedef unsigned short __u16; |
||||
typedef unsigned __u32; |
||||
|
||||
/*
|
||||
* 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 |
||||
#include <sys/stat.h> |
||||
#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 |
@ -0,0 +1,66 @@ |
||||
# 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.15 2007/07/18 19:40:38 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
|
||||
|
||||
|
||||
DIRECTTESTOBJS = dtest.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 = $(DIRECTTESTOBJS) $(BOOTTESTOBJS)
|
||||
|
||||
SYMLINKS = 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
|
||||
|
||||
#all: directtest2k boottest
|
||||
|
||||
all: directtest2k |
||||
|
||||
$(ALLOBJS): %.o: %.c |
||||
gcc -c $(CFLAGS) $< -o $@
|
||||
|
||||
$(SYMLINKS): |
||||
ln -s ../$@ $@
|
||||
|
||||
directtest2k: $(SYMLINKS) $(DIRECTTESTOBJS) |
||||
gcc -o $@ $(DIRECTTESTOBJS)
|
||||
|
||||
|
||||
boottest: $(SYMLINKS) $(BOOTTESTOBJS) |
||||
gcc -o $@ $(BOOTTESTOBJS)
|
||||
|
||||
|
||||
clean: |
||||
rm -f $(ALLOBJS) core
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,75 @@ |
||||
# 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
|
@ -0,0 +1,7 @@ |
||||
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
@ -0,0 +1,218 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
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; |
||||
} |
||||
|
||||
|
@ -0,0 +1,441 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
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; |
||||
} |
||||
|
@ -0,0 +1,50 @@ |
||||
/*
|
||||
* 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 |
||||
|
@ -0,0 +1,229 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
|
||||
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; |
||||
} |
||||
|
@ -0,0 +1,31 @@ |
||||
/*
|
||||
* 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 __YAFFS_FLASH_H__ |
||||
#define __YAFFS_FLASH_H__ |
||||
|
||||
|
||||
#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); |
||||
|
||||
#endif |
@ -0,0 +1,23 @@ |
||||
#ifndef __YAFFS_MALLOC_H__ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
void *yaffs_malloc(size_t size);
|
||||
void yaffs_free(void *ptr); |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,234 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
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; |
||||
} |
||||
|
||||
|
@ -0,0 +1,32 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* yaffs_ramdisk.h: yaffs ram disk component |
||||
*/ |
||||
|
||||
#ifndef __YAFFS_RAMDISK_H__ |
||||
#define __YAFFS_RAMDISK_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); |
||||
#endif |
@ -0,0 +1,363 @@ |
||||
/*
|
||||
* 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) |
||||
*/ |
||||
|
||||
|
||||
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
|
||||
|
@ -0,0 +1,144 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* yaffscfg.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. |
||||
*/ |
||||
|
||||
#include "yaffscfg.h" |
||||
#include "yaffsfs.h" |
||||
#include <errno.h> |
||||
|
||||
unsigned yaffs_traceMask = 0xFFFFFFFF; |
||||
|
||||
|
||||
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; |
||||
} |
||||
|
||||
void *yaffs_malloc(size_t size) |
||||
{ |
||||
return malloc(size); |
||||
} |
||||
|
||||
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" |
||||
|
||||
static yaffs_Device ramDev; |
||||
static yaffs_Device bootDev; |
||||
static yaffs_Device flashDev; |
||||
|
||||
static yaffsfs_DeviceConfiguration yaffsfs_config[] = { |
||||
|
||||
{ "/ram", &ramDev}, |
||||
{ "/boot", &bootDev}, |
||||
{ "/flash", &flashDev}, |
||||
{(void *)0,(void *)0} |
||||
}; |
||||
|
||||
|
||||
int yaffs_StartUp(void) |
||||
{ |
||||
// Stuff to configure YAFFS
|
||||
// Stuff to initialise anything special (eg lock semaphore).
|
||||
yaffsfs_LocalInitialisation(); |
||||
|
||||
// Set up devices
|
||||
|
||||
// /ram
|
||||
ramDev.nBytesPerChunk = 512; |
||||
ramDev.nChunksPerBlock = 32; |
||||
ramDev.nReservedBlocks = 2; // Set this smaller for RAM
|
||||
ramDev.startBlock = 1; // Can't 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
|
||||
bootDev.nBytesPerChunk = 612; |
||||
bootDev.nChunksPerBlock = 32; |
||||
bootDev.nReservedBlocks = 5; |
||||
bootDev.startBlock = 1; // Can't use block 0
|
||||
bootDev.endBlock = 127; // Last block in 2MB.
|
||||
bootDev.useNANDECC = 0; // use YAFFS's ECC
|
||||
bootDev.nShortOpCaches = 10; // Use caches
|
||||
bootDev.genericDevice = (void *) 1; // Used to identify the device in fstat.
|
||||
bootDev.writeChunkToNAND = yflash_WriteChunkToNAND; |
||||
bootDev.readChunkFromNAND = yflash_ReadChunkFromNAND; |
||||
bootDev.eraseBlockInNAND = yflash_EraseBlockInNAND; |
||||
bootDev.initialiseNAND = yflash_InitialiseNAND; |
||||
|
||||
// /flash
|
||||
flashDev.nBytesPerChunk = 512; |
||||
flashDev.nChunksPerBlock = 32; |
||||
flashDev.nReservedBlocks = 5; |
||||
flashDev.startBlock = 128; // First block after 2MB
|
||||
flashDev.endBlock = 1023; // Last block in 16MB
|
||||
flashDev.useNANDECC = 0; // use YAFFS's ECC
|
||||
flashDev.nShortOpCaches = 10; // Use caches
|
||||
flashDev.genericDevice = (void *) 2; // Used to identify the device in fstat.
|
||||
flashDev.writeChunkToNAND = yflash_WriteChunkToNAND; |
||||
flashDev.readChunkFromNAND = yflash_ReadChunkFromNAND; |
||||
flashDev.eraseBlockInNAND = yflash_EraseBlockInNAND; |
||||
flashDev.initialiseNAND = yflash_InitialiseNAND; |
||||
|
||||
yaffs_initialise(yaffsfs_config); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,45 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Header file for using yaffs in an application via |
||||
* a direct interface. |
||||
*/ |
||||
|
||||
|
||||
#ifndef __YAFFSCFG_H__ |
||||
#define __YAFFSCFG_H__ |
||||
|
||||
|
||||
#include "devextras.h" |
||||
|
||||
#define YAFFSFS_N_HANDLES 200 |
||||
|
||||
|
||||
typedef struct { |
||||
const char *prefix; |
||||
struct yaffs_DeviceStruct *dev; |
||||
} yaffsfs_DeviceConfiguration; |
||||
|
||||
|
||||
void yaffsfs_Lock(void); |
||||
void yaffsfs_Unlock(void); |
||||
|
||||
__u32 yaffsfs_CurrentTime(void); |
||||
|
||||
void yaffsfs_SetError(int err); |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,229 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#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; |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,233 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Header file for using yaffs in an application via |
||||
* a direct interface. |
||||
*/ |
||||
|
||||
|
||||
#ifndef __YAFFSFS_H__ |
||||
#define __YAFFSFS_H__ |
||||
|
||||
#include "yaffscfg.h" |
||||
#include "yportenv.h" |
||||
|
||||
|
||||
//typedef long off_t;
|
||||
//typedef long dev_t;
|
||||
//typedef unsigned long mode_t;
|
||||
|
||||
|
||||
#ifndef NAME_MAX |
||||
#define NAME_MAX 256 |
||||
#endif |
||||
|
||||
#ifndef O_RDONLY |
||||
#define O_RDONLY 00 |
||||
#endif |
||||
|
||||
#ifndef O_WRONLY |
||||
#define O_WRONLY 01 |
||||
#endif |
||||
|
||||
#ifndef O_RDWR |
||||
#define O_RDWR 02 |
||||
#endif |
||||
|
||||
#ifndef O_CREAT |
||||
#define O_CREAT 0100 |
||||
#endif |
||||
|
||||
#ifndef O_EXCL |
||||
#define O_EXCL 0200 |
||||
#endif |
||||
|
||||
#ifndef O_TRUNC |
||||
#define O_TRUNC 01000 |
||||
#endif |
||||
|
||||
#ifndef O_APPEND |
||||
#define O_APPEND 02000 |
||||
#endif |
||||
|
||||
#ifndef SEEK_SET |
||||
#define SEEK_SET 0 |
||||
#endif |
||||
|
||||
#ifndef SEEK_CUR |
||||
#define SEEK_CUR 1 |
||||
#endif |
||||
|
||||
#ifndef SEEK_END |
||||
#define SEEK_END 2 |
||||
#endif |
||||
|
||||
#ifndef EBUSY |
||||
#define EBUSY 16 |
||||
#endif |
||||
|
||||
#ifndef ENODEV |
||||
#define ENODEV 19 |
||||
#endif |
||||
|
||||
#ifndef EINVAL |
||||
#define EINVAL 22 |
||||
#endif |
||||
|
||||
#ifndef EBADF |
||||
#define EBADF 9 |
||||
#endif |
||||
|
||||
#ifndef EACCESS |
||||
#define EACCESS 13 |
||||
#endif |
||||
|
||||
#ifndef EXDEV |
||||
#define EXDEV 18 |
||||
#endif |
||||
|
||||
#ifndef ENOENT |
||||
#define ENOENT 2 |
||||
#endif |
||||
|
||||
#ifndef ENOSPC |
||||
#define ENOSPC 28 |
||||
#endif |
||||
|
||||
#ifndef ENOTEMPTY |
||||
#define ENOTEMPTY 39 |
||||
#endif |
||||
|
||||
#ifndef ENOMEM |
||||
#define ENOMEM 12 |
||||
#endif |
||||
|
||||
#ifndef EEXIST |
||||
#define EEXIST 17 |
||||
#endif |
||||
|
||||
#ifndef ENOTDIR |
||||
#define ENOTDIR 20 |
||||
#endif |
||||
|
||||
#ifndef EISDIR |
||||
#define EISDIR 21 |
||||
#endif |
||||
|
||||
|
||||
// Mode flags
|
||||
|
||||
#ifndef S_IFMT |
||||
#define S_IFMT 0170000 |
||||
#endif |
||||
|
||||
#ifndef S_IFLNK |
||||
#define S_IFLNK 0120000 |
||||
#endif |
||||
|
||||
#ifndef S_IFDIR |
||||
#define S_IFDIR 0040000 |
||||
#endif |
||||
|
||||
#ifndef S_IFREG |
||||
#define S_IFREG 0100000 |
||||
#endif |
||||
|
||||
#ifndef S_IREAD |
||||
#define S_IREAD 0000400 |
||||
#endif |
||||
|
||||
#ifndef S_IWRITE |
||||
#define S_IWRITE 0000200 |
||||
#endif |
||||
|
||||
|
||||
|
||||
|
||||
struct yaffs_dirent{ |
||||
long d_ino; /* inode number */ |
||||
off_t d_off; /* offset to this dirent */ |
||||
unsigned short d_reclen; /* length of this d_name */ |
||||
char d_name [NAME_MAX+1]; /* file name (null-terminated) */ |
||||
unsigned d_dont_use; /* debug pointer, not for public consumption */ |
||||
}; |
||||
|
||||
typedef struct yaffs_dirent yaffs_dirent; |
||||
|
||||
|
||||
typedef struct __opaque yaffs_DIR; |
||||
|
||||
|
||||
|
||||
struct yaffs_stat{ |
||||
int st_dev; /* device */ |
||||
int st_ino; /* inode */ |
||||
mode_t st_mode; /* protection */ |
||||
int st_nlink; /* number of hard links */ |
||||
int st_uid; /* user ID of owner */ |
||||
int st_gid; /* group ID of owner */ |
||||
unsigned st_rdev; /* device type (if inode device) */ |
||||
off_t st_size; /* total size, in bytes */ |
||||
unsigned long st_blksize; /* blocksize for filesystem I/O */ |
||||
unsigned long st_blocks; /* number of blocks allocated */ |
||||
unsigned long yst_atime; /* time of last access */ |
||||
unsigned long yst_mtime; /* time of last modification */ |
||||
unsigned long yst_ctime; /* time of last change */ |
||||
}; |
||||
|
||||
int yaffs_open(const char *path, int oflag, int mode) ; |
||||
int yaffs_read(int fd, void *buf, unsigned int nbyte) ; |
||||
int yaffs_write(int fd, const void *buf, unsigned int nbyte) ; |
||||
int yaffs_close(int fd) ; |
||||
off_t yaffs_lseek(int fd, off_t offset, int whence) ; |
||||
int yaffs_truncate(int fd, off_t newSize); |
||||
|
||||
int yaffs_unlink(const char *path) ; |
||||
int yaffs_rename(const char *oldPath, const char *newPath) ; |
||||
|
||||
int yaffs_stat(const char *path, struct yaffs_stat *buf) ; |
||||
int yaffs_lstat(const char *path, struct yaffs_stat *buf) ; |
||||
int yaffs_fstat(int fd, struct yaffs_stat *buf) ; |
||||
|
||||
int yaffs_chmod(const char *path, mode_t mode);
|
||||
int yaffs_fchmod(int fd, mode_t mode);
|
||||
|
||||
int yaffs_mkdir(const char *path, mode_t mode) ; |
||||
int yaffs_rmdir(const char *path) ; |
||||
|
||||
yaffs_DIR *yaffs_opendir(const char *dirname) ; |
||||
struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ; |
||||
void yaffs_rewinddir(yaffs_DIR *dirp) ; |
||||
int yaffs_closedir(yaffs_DIR *dirp) ; |
||||
|
||||
int yaffs_mount(const char *path) ; |
||||
int yaffs_unmount(const char *path) ; |
||||
|
||||
int yaffs_symlink(const char *oldpath, const char *newpath);
|
||||
int yaffs_readlink(const char *path, char *buf, int bufsiz);
|
||||
|
||||
int yaffs_link(const char *oldpath, const char *newpath);
|
||||
int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev); |
||||
|
||||
loff_t yaffs_freespace(const char *path); |
||||
|
||||
void yaffs_initialise(yaffsfs_DeviceConfiguration *configList); |
||||
|
||||
int yaffs_StartUp(void); |
||||
|
||||
#endif |
||||
|
||||
|
@ -0,0 +1,88 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* ydirectenv.h: Environment wrappers for YAFFS direct. |
||||
*/ |
||||
|
||||
#ifndef __YDIRECTENV_H__ |
||||
#define __YDIRECTENV_H__ |
||||
|
||||
// Direct interface
|
||||
|
||||
#include "devextras.h" |
||||
|
||||
#include "stdlib.h" |
||||
#include "stdio.h" |
||||
#include "string.h" |
||||
#include "yaffs_malloc.h" |
||||
|
||||
#include "assert.h" |
||||
#define YBUG() assert(1) |
||||
|
||||
#define YCHAR char |
||||
#define YUCHAR unsigned char |
||||
#define _Y(x) x |
||||
#define yaffs_strcpy(a,b) strcpy(a,b) |
||||
#define yaffs_strncpy(a,b,c) strncpy(a,b,c) |
||||
#define yaffs_strncmp(a,b,c) strncmp(a,b,c) |
||||
#define yaffs_strlen(s) strlen(s) |
||||
#define yaffs_sprintf sprintf |
||||
#define yaffs_toupper(a) toupper(a) |
||||
|
||||
#ifdef NO_Y_INLINE |
||||
#define Y_INLINE |
||||
#else |
||||
#define Y_INLINE inline |
||||
#endif |
||||
|
||||
#define YMALLOC(x) yaffs_malloc(x) |
||||
#define YFREE(x) free(x) |
||||
#define YMALLOC_ALT(x) yaffs_malloc(x) |
||||
#define YFREE_ALT(x) free(x) |
||||
|
||||
#define YMALLOC_DMA(x) yaffs_malloc(x) |
||||
|
||||
#define YYIELD() do {} while(0) |
||||
|
||||
|
||||
|
||||
//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
|
||||
//#define YALERT(s) YINFO(s)
|
||||
|
||||
|
||||
#define TENDSTR "\n" |
||||
#define TSTR(x) x |
||||
#define TOUT(p) printf p |
||||
|
||||
|
||||
#define YAFFS_LOSTNFOUND_NAME "lost+found" |
||||
#define YAFFS_LOSTNFOUND_PREFIX "obj" |
||||
//#define YPRINTF(x) printf x
|
||||
|
||||
#include "yaffscfg.h" |
||||
|
||||
#define Y_CURRENT_TIME yaffsfs_CurrentTime() |
||||
#define Y_TIME_CONVERT(x) x |
||||
|
||||
#define YAFFS_ROOT_MODE 0666 |
||||
#define YAFFS_LOSTNFOUND_MODE 0666 |
||||
|
||||
#define yaffs_SumCompare(x,y) ((x) == (y)) |
||||
#define yaffs_strcmp(a,b) strcmp(a,b) |
||||
|
||||
#endif |
||||
|
||||
|
@ -0,0 +1,65 @@ |
||||
/*
|
||||
* 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__ */ |
@ -0,0 +1,33 @@ |
||||
#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 $@
|
||||
|
@ -0,0 +1,121 @@ |
||||
#!/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 |
@ -0,0 +1,6 @@ |
||||
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. |
||||
|
@ -0,0 +1,258 @@ |
||||
/*
|
||||
* 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; |
||||
} |
||||
|
@ -0,0 +1,54 @@ |
||||
#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
|
@ -0,0 +1,520 @@ |
||||
/*
|
||||
* 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); |
||||
}
|
||||
|
@ -0,0 +1,590 @@ |
||||
/*
|
||||
* 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); |
||||
}
|
||||
|
@ -0,0 +1,404 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
const char *yaffs_checkptrw_c_version = |
||||
"$Id: yaffs_checkptrw.c,v 1.14 2007/05/15 20:07:40 charles Exp $"; |
||||
|
||||
|
||||
#include "yaffs_checkptrw.h" |
||||
|
||||
|
||||
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev) |
||||
{ |
||||
|
||||
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; |
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT, |
||||
(TSTR("checkpt blocks available = %d" TENDSTR), |
||||
blocksAvailable)); |
||||
|
||||
|
||||
return (blocksAvailable <= 0) ? 0 : 1; |
||||
} |
||||
|
||||
|
||||
static int yaffs_CheckpointErase(yaffs_Device *dev) |
||||
{ |
||||
|
||||
int i; |
||||
|
||||
|
||||
if(!dev->eraseBlockInNAND)
|
||||
return 0; |
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR), |
||||
dev->internalStartBlock,dev->internalEndBlock)); |
||||
|
||||
for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { |
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); |
||||
if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){ |
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i)); |
||||
if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){ |
||||
bi->blockState = YAFFS_BLOCK_STATE_EMPTY; |
||||
dev->nErasedBlocks++; |
||||
dev->nFreeChunks += dev->nChunksPerBlock; |
||||
} |
||||
else { |
||||
dev->markNANDBlockBad(dev,i); |
||||
bi->blockState = YAFFS_BLOCK_STATE_DEAD; |
||||
} |
||||
} |
||||
} |
||||
|
||||
dev->blocksInCheckpoint = 0; |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev) |
||||
{ |
||||
int i; |
||||
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks; |
||||
T(YAFFS_TRACE_CHECKPOINT, |
||||
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR), |
||||
dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock)); |
||||
|
||||
if(dev->checkpointNextBlock >= 0 && |
||||
dev->checkpointNextBlock <= dev->internalEndBlock && |
||||
blocksAvailable > 0){ |
||||
|
||||
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ |
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); |
||||
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){ |
||||
dev->checkpointNextBlock = i + 1; |
||||
dev->checkpointCurrentBlock = i; |
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i)); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR))); |
||||
|
||||
dev->checkpointNextBlock = -1; |
||||
dev->checkpointCurrentBlock = -1; |
||||
} |
||||
|
||||
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev) |
||||
{ |
||||
int i; |
||||
yaffs_ExtendedTags tags; |
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR), |
||||
dev->blocksInCheckpoint, dev->checkpointNextBlock)); |
||||
|
||||
if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
|
||||
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){ |
||||
int chunk = i * dev->nChunksPerBlock; |
||||
int realignedChunk = chunk - dev->chunkOffset; |
||||
|
||||
dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags); |
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
|
||||
i, tags.objectId,tags.sequenceNumber,tags.eccResult)); |
||||
|
||||
if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){ |
||||
/* Right kind of block */ |
||||
dev->checkpointNextBlock = tags.objectId; |
||||
dev->checkpointCurrentBlock = i; |
||||
dev->checkpointBlockList[dev->blocksInCheckpoint] = i; |
||||
dev->blocksInCheckpoint++; |
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i)); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR))); |
||||
|
||||
dev->checkpointNextBlock = -1; |
||||
dev->checkpointCurrentBlock = -1; |
||||
} |
||||
|
||||
|
||||
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting) |
||||
{ |
||||
|
||||
/* Got the functions we need? */ |
||||
if (!dev->writeChunkWithTagsToNAND || |
||||
!dev->readChunkWithTagsFromNAND || |
||||
!dev->eraseBlockInNAND || |
||||
!dev->markNANDBlockBad) |
||||
return 0; |
||||
|
||||
if(forWriting && !yaffs_CheckpointSpaceOk(dev)) |
||||
return 0; |
||||
|
||||
if(!dev->checkpointBuffer) |
||||
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk); |
||||
if(!dev->checkpointBuffer) |
||||
return 0; |
||||
|
||||
|
||||
dev->checkpointPageSequence = 0; |
||||
|
||||
dev->checkpointOpenForWrite = forWriting; |
||||
|
||||
dev->checkpointByteCount = 0; |
||||
dev->checkpointSum = 0; |
||||
dev->checkpointXor = 0; |
||||
dev->checkpointCurrentBlock = -1; |
||||
dev->checkpointCurrentChunk = -1; |
||||
dev->checkpointNextBlock = dev->internalStartBlock; |
||||
|
||||
/* Erase all the blocks in the checkpoint area */ |
||||
if(forWriting){ |
||||
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); |
||||
dev->checkpointByteOffset = 0; |
||||
return yaffs_CheckpointErase(dev); |
||||
|
||||
|
||||
} else { |
||||
int i; |
||||
/* Set to a value that will kick off a read */ |
||||
dev->checkpointByteOffset = dev->nDataBytesPerChunk; |
||||
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
|
||||
* going to be way more than we need */ |
||||
dev->blocksInCheckpoint = 0; |
||||
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2; |
||||
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks); |
||||
for(i = 0; i < dev->checkpointMaxBlocks; i++) |
||||
dev->checkpointBlockList[i] = -1; |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum) |
||||
{ |
||||
__u32 compositeSum; |
||||
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF); |
||||
*sum = compositeSum; |
||||
return 1; |
||||
} |
||||
|
||||
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev) |
||||
{ |
||||
|
||||
int chunk; |
||||
int realignedChunk; |
||||
|
||||
yaffs_ExtendedTags tags; |
||||
|
||||
if(dev->checkpointCurrentBlock < 0){ |
||||
yaffs_CheckpointFindNextErasedBlock(dev); |
||||
dev->checkpointCurrentChunk = 0; |
||||
} |
||||
|
||||
if(dev->checkpointCurrentBlock < 0) |
||||
return 0; |
||||
|
||||
tags.chunkDeleted = 0; |
||||
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */ |
||||
tags.chunkId = dev->checkpointPageSequence + 1; |
||||
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA; |
||||
tags.byteCount = dev->nDataBytesPerChunk; |
||||
if(dev->checkpointCurrentChunk == 0){ |
||||
/* First chunk we write for the block? Set block state to
|
||||
checkpoint */ |
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock); |
||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; |
||||
dev->blocksInCheckpoint++; |
||||
} |
||||
|
||||
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk; |
||||
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR), |
||||
chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
|
||||
|
||||
realignedChunk = chunk - dev->chunkOffset; |
||||
|
||||
dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags); |
||||
dev->checkpointByteOffset = 0; |
||||
dev->checkpointPageSequence++;
|
||||
dev->checkpointCurrentChunk++; |
||||
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){ |
||||
dev->checkpointCurrentChunk = 0; |
||||
dev->checkpointCurrentBlock = -1; |
||||
} |
||||
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes) |
||||
{ |
||||
int i=0; |
||||
int ok = 1; |
||||
|
||||
|
||||
__u8 * dataBytes = (__u8 *)data; |
||||
|
||||
|
||||
|
||||
if(!dev->checkpointBuffer) |
||||
return 0; |
||||
|
||||
if(!dev->checkpointOpenForWrite) |
||||
return -1; |
||||
|
||||
while(i < nBytes && ok) { |
||||
|
||||
|
||||
|
||||
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ; |
||||
dev->checkpointSum += *dataBytes; |
||||
dev->checkpointXor ^= *dataBytes; |
||||
|
||||
dev->checkpointByteOffset++; |
||||
i++; |
||||
dataBytes++; |
||||
dev->checkpointByteCount++; |
||||
|
||||
|
||||
if(dev->checkpointByteOffset < 0 || |
||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
|
||||
ok = yaffs_CheckpointFlushBuffer(dev); |
||||
|
||||
} |
||||
|
||||
return i; |
||||
} |
||||
|
||||
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes) |
||||
{ |
||||
int i=0; |
||||
int ok = 1; |
||||
yaffs_ExtendedTags tags; |
||||
|
||||
|
||||
int chunk; |
||||
int realignedChunk; |
||||
|
||||
__u8 *dataBytes = (__u8 *)data; |
||||
|
||||
if(!dev->checkpointBuffer) |
||||
return 0; |
||||
|
||||
if(dev->checkpointOpenForWrite) |
||||
return -1; |
||||
|
||||
while(i < nBytes && ok) { |
||||
|
||||
|
||||
if(dev->checkpointByteOffset < 0 || |
||||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) { |
||||
|
||||
if(dev->checkpointCurrentBlock < 0){ |
||||
yaffs_CheckpointFindNextCheckpointBlock(dev); |
||||
dev->checkpointCurrentChunk = 0; |
||||
} |
||||
|
||||
if(dev->checkpointCurrentBlock < 0) |
||||
ok = 0; |
||||
else { |
||||
|
||||
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
|
||||
dev->checkpointCurrentChunk; |
||||
|
||||
realignedChunk = chunk - dev->chunkOffset; |
||||
|
||||
/* read in the next chunk */ |
||||
/* printf("read checkpoint page %d\n",dev->checkpointPage); */ |
||||
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
|
||||
dev->checkpointBuffer, |
||||
&tags); |
||||
|
||||
if(tags.chunkId != (dev->checkpointPageSequence + 1) || |
||||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA) |
||||
ok = 0; |
||||
|
||||
dev->checkpointByteOffset = 0; |
||||
dev->checkpointPageSequence++; |
||||
dev->checkpointCurrentChunk++; |
||||
|
||||
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock) |
||||
dev->checkpointCurrentBlock = -1; |
||||
} |
||||
} |
||||
|
||||
if(ok){ |
||||
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset]; |
||||
dev->checkpointSum += *dataBytes; |
||||
dev->checkpointXor ^= *dataBytes; |
||||
dev->checkpointByteOffset++; |
||||
i++; |
||||
dataBytes++; |
||||
dev->checkpointByteCount++; |
||||
} |
||||
} |
||||
|
||||
return i; |
||||
} |
||||
|
||||
int yaffs_CheckpointClose(yaffs_Device *dev) |
||||
{ |
||||
|
||||
if(dev->checkpointOpenForWrite){
|
||||
if(dev->checkpointByteOffset != 0) |
||||
yaffs_CheckpointFlushBuffer(dev); |
||||
} else { |
||||
int i; |
||||
for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){ |
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]); |
||||
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY) |
||||
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT; |
||||
else { |
||||
// Todo this looks odd...
|
||||
} |
||||
} |
||||
YFREE(dev->checkpointBlockList); |
||||
dev->checkpointBlockList = NULL; |
||||
} |
||||
|
||||
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock; |
||||
dev->nErasedBlocks -= dev->blocksInCheckpoint; |
||||
|
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR), |
||||
dev->checkpointByteCount)); |
||||
|
||||
if(dev->checkpointBuffer){ |
||||
/* free the buffer */
|
||||
YFREE(dev->checkpointBuffer); |
||||
dev->checkpointBuffer = NULL; |
||||
return 1; |
||||
} |
||||
else |
||||
return 0; |
||||
|
||||
} |
||||
|
||||
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev) |
||||
{ |
||||
/* Erase the first checksum block */ |
||||
|
||||
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR))); |
||||
|
||||
if(!yaffs_CheckpointSpaceOk(dev)) |
||||
return 0; |
||||
|
||||
return yaffs_CheckpointErase(dev); |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,35 @@ |
||||
/*
|
||||
* 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 __YAFFS_CHECKPTRW_H__ |
||||
#define __YAFFS_CHECKPTRW_H__ |
||||
|
||||
#include "yaffs_guts.h" |
||||
|
||||
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting); |
||||
|
||||
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes); |
||||
|
||||
int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes); |
||||
|
||||
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum); |
||||
|
||||
int yaffs_CheckpointClose(yaffs_Device *dev); |
||||
|
||||
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev); |
||||
|
||||
|
||||
#endif |
||||
|
@ -0,0 +1,331 @@ |
||||
/*
|
||||
* 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 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. |
||||
* |
||||
*/ |
||||
|
||||
/* 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. |
||||
*/ |
||||
|
||||
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, |
||||
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, |
||||
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, |
||||
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, |
||||
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, |
||||
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, |
||||
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, |
||||
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, |
||||
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, |
||||
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, |
||||
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, |
||||
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, |
||||
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, |
||||
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, |
||||
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, |
||||
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, |
||||
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, |
||||
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, |
||||
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, |
||||
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, |
||||
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, |
||||
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, |
||||
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, |
||||
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, |
||||
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, |
||||
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, |
||||
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, |
||||
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, |
||||
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, |
||||
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, |
||||
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) |
||||
{ |
||||
unsigned int i; |
||||
|
||||
unsigned char col_parity = 0; |
||||
unsigned char line_parity = 0; |
||||
unsigned char line_parity_prime = 0; |
||||
unsigned char t; |
||||
unsigned char b; |
||||
|
||||
for (i = 0; i < 256; i++) { |
||||
b = column_parity_table[*data++]; |
||||
col_parity ^= b; |
||||
|
||||
if (b & 0x01) // odd number of bits in the byte
|
||||
{ |
||||
line_parity ^= i; |
||||
line_parity_prime ^= ~i; |
||||
} |
||||
|
||||
} |
||||
|
||||
ecc[2] = (~col_parity) | 0x03; |
||||
|
||||
t = 0; |
||||
if (line_parity & 0x80) |
||||
t |= 0x80; |
||||
if (line_parity_prime & 0x80) |
||||
t |= 0x40; |
||||
if (line_parity & 0x40) |
||||
t |= 0x20; |
||||
if (line_parity_prime & 0x40) |
||||
t |= 0x10; |
||||
if (line_parity & 0x20) |
||||
t |= 0x08; |
||||
if (line_parity_prime & 0x20) |
||||
t |= 0x04; |
||||
if (line_parity & 0x10) |
||||
t |= 0x02; |
||||
if (line_parity_prime & 0x10) |
||||
t |= 0x01; |
||||
ecc[1] = ~t; |
||||
|
||||
t = 0; |
||||
if (line_parity & 0x08) |
||||
t |= 0x80; |
||||
if (line_parity_prime & 0x08) |
||||
t |= 0x40; |
||||
if (line_parity & 0x04) |
||||
t |= 0x20; |
||||
if (line_parity_prime & 0x04) |
||||
t |= 0x10; |
||||
if (line_parity & 0x02) |
||||
t |= 0x08; |
||||
if (line_parity_prime & 0x02) |
||||
t |= 0x04; |
||||
if (line_parity & 0x01) |
||||
t |= 0x02; |
||||
if (line_parity_prime & 0x01) |
||||
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) |
||||
{ |
||||
unsigned char d0, d1, d2; /* deltas */ |
||||
|
||||
d0 = read_ecc[0] ^ test_ecc[0]; |
||||
d1 = read_ecc[1] ^ test_ecc[1]; |
||||
d2 = read_ecc[2] ^ test_ecc[2]; |
||||
|
||||
if ((d0 | d1 | d2) == 0) |
||||
return 0; /* no error */ |
||||
|
||||
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && |
||||
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && |
||||
((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { |
||||
/* Single bit (recoverable) error in data */ |
||||
|
||||
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) |
||||
byte |= 0x80; |
||||
if (d1 & 0x20) |
||||
byte |= 0x40; |
||||
if (d1 & 0x08) |
||||
byte |= 0x20; |
||||
if (d1 & 0x02) |
||||
byte |= 0x10; |
||||
if (d0 & 0x80) |
||||
byte |= 0x08; |
||||
if (d0 & 0x20) |
||||
byte |= 0x04; |
||||
if (d0 & 0x08) |
||||
byte |= 0x02; |
||||
if (d0 & 0x02) |
||||
byte |= 0x01; |
||||
|
||||
if (d2 & 0x80) |
||||
bit |= 0x04; |
||||
if (d2 & 0x20) |
||||
bit |= 0x02; |
||||
if (d2 & 0x08) |
||||
bit |= 0x01; |
||||
|
||||
data[byte] ^= (1 << bit); |
||||
|
||||
return 1; /* Corrected the error */ |
||||
} |
||||
|
||||
if ((yaffs_CountBits(d0) +
|
||||
yaffs_CountBits(d1) +
|
||||
yaffs_CountBits(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 */ |
||||
} |
||||
|
||||
/* Unrecoverable error */ |
||||
|
||||
return -1; |
||||
|
||||
} |
||||
|
||||
|
||||
/*
|
||||
* ECCxxxOther does ECC calcs on arbitrary n bytes of data |
||||
*/ |
||||
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, |
||||
yaffs_ECCOther * eccOther) |
||||
{ |
||||
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++) { |
||||
b = column_parity_table[*data++]; |
||||
col_parity ^= b; |
||||
|
||||
if (b & 0x01) { |
||||
/* odd number of bits in the byte */ |
||||
line_parity ^= i; |
||||
line_parity_prime ^= ~i; |
||||
} |
||||
|
||||
} |
||||
|
||||
eccOther->colParity = (col_parity >> 2) & 0x3f; |
||||
eccOther->lineParity = line_parity; |
||||
eccOther->lineParityPrime = line_parity_prime; |
||||
} |
||||
|
||||
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, |
||||
yaffs_ECCOther * read_ecc, |
||||
const yaffs_ECCOther * test_ecc) |
||||
{ |
||||
unsigned char cDelta; /* column parity delta */ |
||||
unsigned lDelta; /* line parity delta */ |
||||
unsigned lDeltaPrime; /* 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; |
||||
|
||||
if ((cDelta | lDelta | lDeltaPrime) == 0) |
||||
return 0; /* no error */ |
||||
|
||||
if (lDelta == ~lDeltaPrime &&
|
||||
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) |
||||
{ |
||||
/* Single bit (recoverable) error in data */ |
||||
|
||||
bit = 0; |
||||
|
||||
if (cDelta & 0x20) |
||||
bit |= 0x04; |
||||
if (cDelta & 0x08) |
||||
bit |= 0x02; |
||||
if (cDelta & 0x02) |
||||
bit |= 0x01; |
||||
|
||||
if(lDelta >= nBytes) |
||||
return -1; |
||||
|
||||
data[lDelta] ^= (1 << bit); |
||||
|
||||
return 1; /* corrected */ |
||||
} |
||||
|
||||
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + |
||||
yaffs_CountBits(cDelta)) == 1) { |
||||
/* Reccoverable error in ecc */ |
||||
|
||||
*read_ecc = *test_ecc; |
||||
return 1; /* corrected */ |
||||
} |
||||
|
||||
/* Unrecoverable error */ |
||||
|
||||
return -1; |
||||
|
||||
} |
||||
|
@ -0,0 +1,44 @@ |
||||
/*
|
||||
* 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 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; |
||||
|
||||
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_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); |
||||
#endif |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,902 @@ |
||||
/*
|
||||
* 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 __YAFFS_GUTS_H__ |
||||
#define __YAFFS_GUTS_H__ |
||||
|
||||
#include "devextras.h" |
||||
#include "yportenv.h" |
||||
|
||||
#define YAFFS_OK 1 |
||||
#define YAFFS_FAIL 0 |
||||
|
||||
/* Give us a Y=0x59,
|
||||
* Give us an A=0x41,
|
||||
* Give us an FF=0xFF
|
||||
* Give us an S=0x53 |
||||
* And what have we got...
|
||||
*/ |
||||
#define YAFFS_MAGIC 0x5941FF53 |
||||
|
||||
#define YAFFS_NTNODES_LEVEL0 16 |
||||
#define YAFFS_TNODES_LEVEL0_BITS 4 |
||||
#define YAFFS_TNODES_LEVEL0_MASK 0xf |
||||
|
||||
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) |
||||
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) |
||||
#define YAFFS_TNODES_INTERNAL_MASK 0x7 |
||||
#define YAFFS_TNODES_MAX_LEVEL 6 |
||||
|
||||
#ifndef CONFIG_YAFFS_NO_YAFFS1 |
||||
#define YAFFS_BYTES_PER_SPARE 16 |
||||
#define YAFFS_BYTES_PER_CHUNK 512 |
||||
#define YAFFS_CHUNK_SIZE_SHIFT 9 |
||||
#define YAFFS_CHUNKS_PER_BLOCK 32 |
||||
#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) |
||||
#endif |
||||
|
||||
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 |
||||
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 |
||||
|
||||
#define YAFFS_MAX_CHUNK_ID 0x000FFFFF |
||||
|
||||
#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF |
||||
|
||||
#define YAFFS_ALLOCATION_NOBJECTS 100 |
||||
#define YAFFS_ALLOCATION_NTNODES 100 |
||||
#define YAFFS_ALLOCATION_NLINKS 100 |
||||
|
||||
#define YAFFS_NOBJECT_BUCKETS 256 |
||||
|
||||
|
||||
#define YAFFS_OBJECT_SPACE 0x40000 |
||||
|
||||
#define YAFFS_CHECKPOINT_VERSION 3 |
||||
|
||||
#ifdef CONFIG_YAFFS_UNICODE |
||||
#define YAFFS_MAX_NAME_LENGTH 127 |
||||
#define YAFFS_MAX_ALIAS_LENGTH 79 |
||||
#else |
||||
#define YAFFS_MAX_NAME_LENGTH 255 |
||||
#define YAFFS_MAX_ALIAS_LENGTH 159 |
||||
#endif |
||||
|
||||
#define YAFFS_SHORT_NAME_LENGTH 15 |
||||
|
||||
/* Some special object ids for pseudo objects */ |
||||
#define YAFFS_OBJECTID_ROOT 1 |
||||
#define YAFFS_OBJECTID_LOSTNFOUND 2 |
||||
#define YAFFS_OBJECTID_UNLINKED 3 |
||||
#define YAFFS_OBJECTID_DELETED 4 |
||||
|
||||
/* Sseudo object ids for checkpointing */ |
||||
#define YAFFS_OBJECTID_SB_HEADER 0x10 |
||||
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 |
||||
#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 |
||||
|
||||
/* */ |
||||
|
||||
#define YAFFS_MAX_SHORT_OP_CACHES 20 |
||||
|
||||
#define YAFFS_N_TEMP_BUFFERS 4 |
||||
|
||||
/* We limit the number attempts at sucessfully saving a chunk of data.
|
||||
* Small-page devices have 32 pages per block; large-page devices have 64. |
||||
* Default to something in the order of 5 to 10 blocks worth of chunks. |
||||
*/ |
||||
#define YAFFS_WR_ATTEMPTS (5*64) |
||||
|
||||
/* Sequence numbers are used in YAFFS2 to determine block allocation order.
|
||||
* The range is limited slightly to help distinguish bad numbers from good. |
||||
* This also allows us to perhaps in the future use special numbers for |
||||
* special purposes. |
||||
* EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
|
||||
* and is a larger number than the lifetime of a 2GB device. |
||||
*/ |
||||
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 |
||||
#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00 |
||||
|
||||
/* ChunkCache is used for short read/write operations.*/ |
||||
typedef struct { |
||||
struct yaffs_ObjectStruct *object; |
||||
int chunkId; |
||||
int lastUse; |
||||
int dirty; |
||||
int nBytes; /* Only valid if the cache is dirty */ |
||||
int locked; /* Can't push out or flush while locked. */ |
||||
#ifdef CONFIG_YAFFS_YAFFS2 |
||||
__u8 *data; |
||||
#else |
||||
__u8 data[YAFFS_BYTES_PER_CHUNK]; |
||||
#endif |
||||
} yaffs_ChunkCache; |
||||
|
||||
|
||||
|
||||
/* Tags structures in RAM
|
||||
* NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise |
||||
* the structure size will get blown out. |
||||
*/ |
||||
|
||||
#ifndef CONFIG_YAFFS_NO_YAFFS1 |
||||
typedef struct { |
||||
unsigned chunkId:20; |
||||
unsigned serialNumber:2; |
||||
unsigned byteCount:10; |
||||
unsigned objectId:18; |
||||
unsigned ecc:12; |
||||
unsigned unusedStuff:2; |
||||
|
||||
} yaffs_Tags; |
||||
|
||||
typedef union { |
||||
yaffs_Tags asTags; |
||||
__u8 asBytes[8]; |
||||
} yaffs_TagsUnion; |
||||
|
||||
#endif |
||||
|
||||
/* Stuff used for extended tags in YAFFS2 */ |
||||
|
||||
typedef enum { |
||||
YAFFS_ECC_RESULT_UNKNOWN, |
||||
YAFFS_ECC_RESULT_NO_ERROR, |
||||
YAFFS_ECC_RESULT_FIXED, |
||||
YAFFS_ECC_RESULT_UNFIXED |
||||
} yaffs_ECCResult; |
||||
|
||||
typedef enum { |
||||
YAFFS_OBJECT_TYPE_UNKNOWN, |
||||
YAFFS_OBJECT_TYPE_FILE, |
||||
YAFFS_OBJECT_TYPE_SYMLINK, |
||||
YAFFS_OBJECT_TYPE_DIRECTORY, |
||||
YAFFS_OBJECT_TYPE_HARDLINK, |
||||
YAFFS_OBJECT_TYPE_SPECIAL |
||||
} yaffs_ObjectType; |
||||
|
||||
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL |
||||
|
||||
typedef struct { |
||||
|
||||
unsigned validMarker0; |
||||
unsigned chunkUsed; /* Status of the chunk: used or unused */ |
||||
unsigned objectId; /* If 0 then this is not part of an object (unused) */ |
||||
unsigned chunkId; /* If 0 then this is a header, else a data chunk */ |
||||
unsigned byteCount; /* Only valid for data chunks */ |
||||
|
||||
/* The following stuff only has meaning when we read */ |
||||
yaffs_ECCResult eccResult; |
||||
unsigned blockBad;
|
||||
|
||||
/* YAFFS 1 stuff */ |
||||
unsigned chunkDeleted; /* The chunk is marked deleted */ |
||||
unsigned serialNumber; /* Yaffs1 2-bit serial number */ |
||||
|
||||
/* YAFFS2 stuff */ |
||||
unsigned sequenceNumber; /* The sequence number of this block */ |
||||
|
||||
/* Extra info if this is an object header (YAFFS2 only) */ |
||||
|
||||
unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */ |
||||
unsigned extraParentObjectId; /* The parent object */ |
||||
unsigned extraIsShrinkHeader; /* Is it a shrink header? */ |
||||
unsigned extraShadows; /* Does this shadow another object? */ |
||||
|
||||
yaffs_ObjectType extraObjectType; /* What object type? */ |
||||
|
||||
unsigned extraFileLength; /* Length if it is a file */ |
||||
unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */ |
||||
|
||||
unsigned validMarker1; |
||||
|
||||
} yaffs_ExtendedTags; |
||||
|
||||
/* Spare structure for YAFFS1 */ |
||||
typedef struct { |
||||
__u8 tagByte0; |
||||
__u8 tagByte1; |
||||
__u8 tagByte2; |
||||
__u8 tagByte3; |
||||
__u8 pageStatus; /* set to 0 to delete the chunk */ |
||||
__u8 blockStatus; |
||||
__u8 tagByte4; |
||||
__u8 tagByte5; |
||||
__u8 ecc1[3]; |
||||
__u8 tagByte6; |
||||
__u8 tagByte7; |
||||
__u8 ecc2[3]; |
||||
} yaffs_Spare; |
||||
|
||||
/*Special structure for passing through to mtd */ |
||||
struct yaffs_NANDSpare { |
||||
yaffs_Spare spare; |
||||
int eccres1; |
||||
int eccres2; |
||||
}; |
||||
|
||||
/* Block data in RAM */ |
||||
|
||||
typedef enum { |
||||
YAFFS_BLOCK_STATE_UNKNOWN = 0, |
||||
|
||||
YAFFS_BLOCK_STATE_SCANNING, |
||||
YAFFS_BLOCK_STATE_NEEDS_SCANNING, |
||||
/* The block might have something on it (ie it is allocating or full, perhaps empty)
|
||||
* but it needs to be scanned to determine its true state. |
||||
* This state is only valid during yaffs_Scan. |
||||
* NB We tolerate empty because the pre-scanner might be incapable of deciding |
||||
* However, if this state is returned on a YAFFS2 device, then we expect a sequence number |
||||
*/ |
||||
|
||||
YAFFS_BLOCK_STATE_EMPTY, |
||||
/* This block is empty */ |
||||
|
||||
YAFFS_BLOCK_STATE_ALLOCATING, |
||||
/* This block is partially allocated.
|
||||
* At least one page holds valid data. |
||||
* This is the one currently being used for page |
||||
* allocation. Should never be more than one of these |
||||
*/ |
||||
|
||||
YAFFS_BLOCK_STATE_FULL,
|
||||
/* All the pages in this block have been allocated.
|
||||
*/ |
||||
|
||||
YAFFS_BLOCK_STATE_DIRTY, |
||||
/* All pages have been allocated and deleted.
|
||||
* Erase me, reuse me. |
||||
*/ |
||||
|
||||
YAFFS_BLOCK_STATE_CHECKPOINT,
|
||||
/* This block is assigned to holding checkpoint data.
|
||||
*/ |
||||
|
||||
YAFFS_BLOCK_STATE_COLLECTING,
|
||||
/* This block is being garbage collected */ |
||||
|
||||
YAFFS_BLOCK_STATE_DEAD
|
||||
/* This block has failed and is not in use */ |
||||
} yaffs_BlockState; |
||||
|
||||
#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) |
||||
|
||||
|
||||
typedef struct { |
||||
|
||||
int softDeletions:10; /* number of soft deleted pages */ |
||||
int pagesInUse:10; /* number of pages in use */ |
||||
unsigned blockState:4; /* One of the above block states. NB use unsigned because enum is sometimes an int */ |
||||
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ |
||||
/* and retire the block. */ |
||||
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */ |
||||
__u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block.
|
||||
It should be prioritised for GC */ |
||||
__u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */ |
||||
|
||||
#ifdef CONFIG_YAFFS_YAFFS2 |
||||
__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */ |
||||
__u32 sequenceNumber; /* block sequence number for yaffs2 */ |
||||
#endif |
||||
|
||||
} yaffs_BlockInfo; |
||||
|
||||
/* -------------------------- Object structure -------------------------------*/ |
||||
/* This is the object structure as stored on NAND */ |
||||
|
||||
typedef struct { |
||||
yaffs_ObjectType type; |
||||
|
||||
/* Apply to everything */ |
||||
int parentObjectId; |
||||
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */ |
||||
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; |
||||
|
||||
/* Thes following apply to directories, files, symlinks - not hard links */ |
||||
__u32 yst_mode; /* protection */ |
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE |
||||
__u32 notForWinCE[5]; |
||||
#else |
||||
__u32 yst_uid; |
||||
__u32 yst_gid; |
||||
__u32 yst_atime; |
||||
__u32 yst_mtime; |
||||
__u32 yst_ctime; |
||||
#endif |
||||
|
||||
/* File size applies to files only */ |
||||
int fileSize; |
||||
|
||||
/* Equivalent object id applies to hard links only. */ |
||||
int equivalentObjectId; |
||||
|
||||
/* Alias is for symlinks only. */ |
||||
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; |
||||
|
||||
__u32 yst_rdev; /* device stuff for block and char devices (major/min) */ |
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE |
||||
__u32 win_ctime[2]; |
||||
__u32 win_atime[2]; |
||||
__u32 win_mtime[2]; |
||||
__u32 roomToGrow[4]; |
||||
#else |
||||
__u32 roomToGrow[10]; |
||||
#endif |
||||
|
||||
int shadowsObject; /* This object header shadows the specified object if > 0 */ |
||||
|
||||
/* isShrink applies to object headers written when we shrink the file (ie resize) */ |
||||
__u32 isShrink; |
||||
|
||||
} yaffs_ObjectHeader; |
||||
|
||||
/*--------------------------- Tnode -------------------------- */ |
||||
|
||||
union yaffs_Tnode_union { |
||||
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG |
||||
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1]; |
||||
#else |
||||
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; |
||||
#endif |
||||
/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */ |
||||
|
||||
}; |
||||
|
||||
typedef union yaffs_Tnode_union yaffs_Tnode; |
||||
|
||||
struct yaffs_TnodeList_struct { |
||||
struct yaffs_TnodeList_struct *next; |
||||
yaffs_Tnode *tnodes; |
||||
}; |
||||
|
||||
typedef struct yaffs_TnodeList_struct yaffs_TnodeList; |
||||
|
||||
/*------------------------ Object -----------------------------*/ |
||||
/* An object can be one of:
|
||||
* - a directory (no data, has children links |
||||
* - a regular file (data.... not prunes :->). |
||||
* - a symlink [symbolic link] (the alias). |
||||
* - a hard link |
||||
*/ |
||||
|
||||
typedef struct { |
||||
__u32 fileSize; |
||||
__u32 scannedFileSize; |
||||
__u32 shrinkSize; |
||||
int topLevel; |
||||
yaffs_Tnode *top; |
||||
} yaffs_FileStructure; |
||||
|
||||
typedef struct { |
||||
struct list_head children; /* list of child links */ |
||||
} yaffs_DirectoryStructure; |
||||
|
||||
typedef struct { |
||||
YCHAR *alias; |
||||
} yaffs_SymLinkStructure; |
||||
|
||||
typedef struct { |
||||
struct yaffs_ObjectStruct *equivalentObject; |
||||
__u32 equivalentObjectId; |
||||
} yaffs_HardLinkStructure; |
||||
|
||||
typedef union { |
||||
yaffs_FileStructure fileVariant; |
||||
yaffs_DirectoryStructure directoryVariant; |
||||
yaffs_SymLinkStructure symLinkVariant; |
||||
yaffs_HardLinkStructure hardLinkVariant; |
||||
} yaffs_ObjectVariant; |
||||
|
||||
struct yaffs_ObjectStruct { |
||||
__u8 deleted:1; /* This should only apply to unlinked files. */ |
||||
__u8 softDeleted:1; /* it has also been soft deleted */ |
||||
__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/ |
||||
__u8 fake:1; /* A fake object has no presence on NAND. */ |
||||
__u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ |
||||
__u8 unlinkAllowed:1; |
||||
__u8 dirty:1; /* the object needs to be written to flash */ |
||||
__u8 valid:1; /* When the file system is being loaded up, this
|
||||
* object might be created before the data |
||||
* is available (ie. file data records appear before the header). |
||||
*/ |
||||
__u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */ |
||||
|
||||
__u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
|
||||
* still in the inode cache. Free of object is defered. |
||||
* until the inode is released. |
||||
*/ |
||||
|
||||
__u8 serial; /* serial number of chunk in NAND. Cached here */ |
||||
__u16 sum; /* sum of the name to speed searching */ |
||||
|
||||
struct yaffs_DeviceStruct *myDev; /* The device I'm on */ |
||||
|
||||
struct list_head hashLink; /* list of objects in this hash bucket */ |
||||
|
||||
struct list_head hardLinks; /* all the equivalent hard linked objects */ |
||||
|
||||
/* directory structure stuff */ |
||||
/* also used for linking up the free list */ |
||||
struct yaffs_ObjectStruct *parent;
|
||||
struct list_head siblings; |
||||
|
||||
/* Where's my object header in NAND? */ |
||||
int chunkId;
|
||||
|
||||
int nDataChunks; /* Number of data chunks attached to the file. */ |
||||
|
||||
__u32 objectId; /* the object id value */ |
||||
|
||||
__u32 yst_mode; |
||||
|
||||
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM |
||||
YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; |
||||
#endif |
||||
|
||||
#ifndef __KERNEL__ |
||||
__u32 inUse; |
||||
#endif |
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE |
||||
__u32 win_ctime[2]; |
||||
__u32 win_mtime[2]; |
||||
__u32 win_atime[2]; |
||||
#else |
||||
__u32 yst_uid; |
||||
__u32 yst_gid; |
||||
__u32 yst_atime; |
||||
__u32 yst_mtime; |
||||
__u32 yst_ctime; |
||||
#endif |
||||
|
||||
__u32 yst_rdev; |
||||
|
||||
#ifdef __KERNEL__ |
||||
struct inode *myInode; |
||||
|
||||
#endif |
||||
|
||||
yaffs_ObjectType variantType; |
||||
|
||||
yaffs_ObjectVariant variant; |
||||
|
||||
}; |
||||
|
||||
typedef struct yaffs_ObjectStruct yaffs_Object; |
||||
|
||||
struct yaffs_ObjectList_struct { |
||||
yaffs_Object *objects; |
||||
struct yaffs_ObjectList_struct *next; |
||||
}; |
||||
|
||||
typedef struct yaffs_ObjectList_struct yaffs_ObjectList; |
||||
|
||||
typedef struct { |
||||
struct list_head list; |
||||
int count; |
||||
} yaffs_ObjectBucket; |
||||
|
||||
|
||||
/* yaffs_CheckpointObject holds the definition of an object as dumped
|
||||
* by checkpointing. |
||||
*/ |
||||
|
||||
typedef struct { |
||||
int structType; |
||||
__u32 objectId;
|
||||
__u32 parentId; |
||||
int chunkId; |
||||
|
||||
yaffs_ObjectType variantType:3; |
||||
__u8 deleted:1;
|
||||
__u8 softDeleted:1;
|
||||
__u8 unlinked:1;
|
||||
__u8 fake:1;
|
||||
__u8 renameAllowed:1; |
||||
__u8 unlinkAllowed:1; |
||||
__u8 serial;
|
||||
|
||||
int nDataChunks;
|
||||
__u32 fileSizeOrEquivalentObjectId; |
||||
|
||||
}yaffs_CheckpointObject; |
||||
|
||||
/*--------------------- Temporary buffers ----------------
|
||||
* |
||||
* These are chunk-sized working buffers. Each device has a few |
||||
*/ |
||||
|
||||
typedef struct { |
||||
__u8 *buffer; |
||||
int line; /* track from whence this buffer was allocated */ |
||||
int maxLine; |
||||
} yaffs_TempBuffer; |
||||
|
||||
/*----------------- Device ---------------------------------*/ |
||||
|
||||
struct yaffs_DeviceStruct { |
||||
struct list_head devList; |
||||
const char *name; |
||||
|
||||
/* Entry parameters set up way early. Yaffs sets up the rest.*/ |
||||
int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */ |
||||
int nChunksPerBlock; /* does not need to be a power of 2 */ |
||||
int nBytesPerSpare; /* spare area size */ |
||||
int startBlock; /* Start block we're allowed to use */ |
||||
int endBlock; /* End block we're allowed to use */ |
||||
int nReservedBlocks; /* We want this tuneable so that we can reduce */ |
||||
/* reserved blocks on NOR and RAM. */ |
||||
|
||||
|
||||
/* Stuff used by the shared space checkpointing mechanism */ |
||||
/* If this value is zero, then this mechanism is disabled */ |
||||
|
||||
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */ |
||||
|
||||
|
||||
|
||||
|
||||
int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
|
||||
* the number of short op caches (don't use too many) |
||||
*/ |
||||
|
||||
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ |
||||
|
||||
int useNANDECC; /* Flag to decide whether or not to use NANDECC */ |
||||
|
||||
void *genericDevice; /* Pointer to device context
|
||||
* On an mtd this holds the mtd pointer. |
||||
*/ |
||||
void *superBlock; |
||||
|
||||
/* NAND access functions (Must be set before calling YAFFS)*/ |
||||
|
||||
int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev, |
||||
int chunkInNAND, const __u8 * data, |
||||
const yaffs_Spare * spare); |
||||
int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev, |
||||
int chunkInNAND, __u8 * data, |
||||
yaffs_Spare * spare); |
||||
int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev, |
||||
int blockInNAND); |
||||
int (*initialiseNAND) (struct yaffs_DeviceStruct * dev); |
||||
|
||||
#ifdef CONFIG_YAFFS_YAFFS2 |
||||
int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev, |
||||
int chunkInNAND, const __u8 * data, |
||||
const yaffs_ExtendedTags * tags); |
||||
int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev, |
||||
int chunkInNAND, __u8 * data, |
||||
yaffs_ExtendedTags * tags); |
||||
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo); |
||||
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo, |
||||
yaffs_BlockState * state, int *sequenceNumber); |
||||
#endif |
||||
|
||||
int isYaffs2; |
||||
|
||||
/* The removeObjectCallback function must be supplied by OS flavours that
|
||||
* need it. The Linux kernel does not use this, but yaffs direct does use |
||||
* it to implement the faster readdir |
||||
*/ |
||||
void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); |
||||
|
||||
/* Callback to mark the superblock dirsty */ |
||||
void (*markSuperBlockDirty)(void * superblock); |
||||
|
||||
int wideTnodesDisabled; /* Set to disable wide tnodes */ |
||||
|
||||
|
||||
/* End of stuff that must be set before initialisation. */ |
||||
|
||||
/* Checkpoint control. Can be set before or after initialisation */ |
||||
__u8 skipCheckpointRead; |
||||
__u8 skipCheckpointWrite; |
||||
|
||||
/* Runtime parameters. Set up by YAFFS. */ |
||||
|
||||
__u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ |
||||
__u16 chunkGroupSize; /* == 2^^chunkGroupBits */ |
||||
|
||||
/* Stuff to support wide tnodes */ |
||||
__u32 tnodeWidth; |
||||
__u32 tnodeMask; |
||||
|
||||
/* Stuff to support various file offses to chunk/offset translations */ |
||||
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */ |
||||
__u32 crumbMask; |
||||
__u32 crumbShift; |
||||
__u32 crumbsPerChunk; |
||||
|
||||
/* Straight shifting for nDataBytesPerChunk being a power of 2 */ |
||||
__u32 chunkShift; |
||||
__u32 chunkMask; |
||||
|
||||
|
||||
#ifdef __KERNEL__ |
||||
|
||||
struct semaphore sem; /* Semaphore for waiting on erasure.*/ |
||||
struct semaphore grossLock; /* Gross locking semaphore */ |
||||
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
|
||||
* at compile time so we have to allocate it. |
||||
*/ |
||||
void (*putSuperFunc) (struct super_block * sb); |
||||
#endif |
||||
|
||||
int isMounted; |
||||
|
||||
int isCheckpointed; |
||||
|
||||
|
||||
/* Stuff to support block offsetting to support start block zero */ |
||||
int internalStartBlock; |
||||
int internalEndBlock; |
||||
int blockOffset; |
||||
int chunkOffset; |
||||
|
||||
|
||||
/* Runtime checkpointing stuff */ |
||||
int checkpointPageSequence; /* running sequence number of checkpoint pages */ |
||||
int checkpointByteCount; |
||||
int checkpointByteOffset; |
||||
__u8 *checkpointBuffer; |
||||
int checkpointOpenForWrite; |
||||
int blocksInCheckpoint; |
||||
int checkpointCurrentChunk; |
||||
int checkpointCurrentBlock; |
||||
int checkpointNextBlock; |
||||
int *checkpointBlockList; |
||||
int checkpointMaxBlocks; |
||||
__u32 checkpointSum; |
||||
__u32 checkpointXor; |
||||
|
||||
/* Block Info */ |
||||
yaffs_BlockInfo *blockInfo; |
||||
__u8 *chunkBits; /* bitmap of chunks in use */ |
||||
unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ |
||||
unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ |
||||
int chunkBitmapStride; /* Number of bytes of chunkBits per block.
|
||||
* Must be consistent with nChunksPerBlock. |
||||
*/ |
||||
|
||||
int nErasedBlocks; |
||||
int allocationBlock; /* Current block being allocated off */ |
||||
__u32 allocationPage; |
||||
int allocationBlockFinder; /* Used to search for next allocation block */ |
||||
|
||||
/* Runtime state */ |
||||
int nTnodesCreated; |
||||
yaffs_Tnode *freeTnodes; |
||||
int nFreeTnodes; |
||||
yaffs_TnodeList *allocatedTnodeList; |
||||
|
||||
int isDoingGC; |
||||
|
||||
int nObjectsCreated; |
||||
yaffs_Object *freeObjects; |
||||
int nFreeObjects; |
||||
|
||||
yaffs_ObjectList *allocatedObjectList; |
||||
|
||||
yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; |
||||
|
||||
int nFreeChunks; |
||||
|
||||
int currentDirtyChecker; /* Used to find current dirtiest block */ |
||||
|
||||
__u32 *gcCleanupList; /* objects to delete at the end of a GC. */ |
||||
int nonAggressiveSkip; /* GC state/mode */ |
||||
|
||||
/* Statistcs */ |
||||
int nPageWrites; |
||||
int nPageReads; |
||||
int nBlockErasures; |
||||
int nErasureFailures; |
||||
int nGCCopies; |
||||
int garbageCollections; |
||||
int passiveGarbageCollections; |
||||
int nRetriedWrites; |
||||
int nRetiredBlocks; |
||||
int eccFixed; |
||||
int eccUnfixed; |
||||
int tagsEccFixed; |
||||
int tagsEccUnfixed; |
||||
int nDeletions; |
||||
int nUnmarkedDeletions; |
||||
|
||||
int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */ |
||||
|
||||
/* Special directories */ |
||||
yaffs_Object *rootDir; |
||||
yaffs_Object *lostNFoundDir; |
||||
|
||||
/* Buffer areas for storing data to recover from write failures TODO
|
||||
* __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; |
||||
* yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; |
||||
*/ |
||||
|
||||
int bufferedBlock; /* Which block is buffered here? */ |
||||
int doingBufferedBlockRewrite; |
||||
|
||||
yaffs_ChunkCache *srCache; |
||||
int srLastUse; |
||||
|
||||
int cacheHits; |
||||
|
||||
/* Stuff for background deletion and unlinked files.*/ |
||||
yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */ |
||||
yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */ |
||||
yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/ |
||||
int nDeletedFiles; /* Count of files awaiting deletion;*/ |
||||
int nUnlinkedFiles; /* Count of unlinked files. */ |
||||
int nBackgroundDeletions; /* Count of background deletions. */ |
||||
|
||||
|
||||
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; |
||||
int maxTemp; |
||||
int unmanagedTempAllocations; |
||||
int unmanagedTempDeallocations; |
||||
|
||||
/* yaffs2 runtime stuff */ |
||||
unsigned sequenceNumber; /* Sequence number of currently allocating block */ |
||||
unsigned oldestDirtySequence; |
||||
|
||||
}; |
||||
|
||||
typedef struct yaffs_DeviceStruct yaffs_Device; |
||||
|
||||
/* The static layout of bllock usage etc is stored in the super block header */ |
||||
typedef struct { |
||||
int StructType; |
||||
int version; |
||||
int checkpointStartBlock; |
||||
int checkpointEndBlock; |
||||
int startBlock; |
||||
int endBlock; |
||||
int rfu[100]; |
||||
} yaffs_SuperBlockHeader; |
||||
|
||||
/* The CheckpointDevice structure holds the device information that changes at runtime and
|
||||
* must be preserved over unmount/mount cycles. |
||||
*/ |
||||
typedef struct { |
||||
int structType; |
||||
int nErasedBlocks; |
||||
int allocationBlock; /* Current block being allocated off */ |
||||
__u32 allocationPage; |
||||
int nFreeChunks; |
||||
|
||||
int nDeletedFiles; /* Count of files awaiting deletion;*/ |
||||
int nUnlinkedFiles; /* Count of unlinked files. */ |
||||
int nBackgroundDeletions; /* Count of background deletions. */ |
||||
|
||||
/* yaffs2 runtime stuff */ |
||||
unsigned sequenceNumber; /* Sequence number of currently allocating block */ |
||||
unsigned oldestDirtySequence; |
||||
|
||||
} yaffs_CheckpointDevice; |
||||
|
||||
|
||||
typedef struct { |
||||
int structType; |
||||
__u32 magic; |
||||
__u32 version; |
||||
__u32 head; |
||||
} yaffs_CheckpointValidity; |
||||
|
||||
/* Function to manipulate block info */ |
||||
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) |
||||
{ |
||||
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), |
||||
blk)); |
||||
YBUG(); |
||||
} |
||||
return &dev->blockInfo[blk - dev->internalStartBlock]; |
||||
} |
||||
|
||||
/*----------------------- YAFFS Functions -----------------------*/ |
||||
|
||||
int yaffs_GutsInitialise(yaffs_Device * dev); |
||||
void yaffs_Deinitialise(yaffs_Device * dev); |
||||
|
||||
int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev); |
||||
|
||||
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, |
||||
yaffs_Object * newDir, const YCHAR * newName); |
||||
|
||||
int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name); |
||||
int yaffs_DeleteFile(yaffs_Object * obj); |
||||
|
||||
int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize); |
||||
int yaffs_GetObjectFileLength(yaffs_Object * obj); |
||||
int yaffs_GetObjectInode(yaffs_Object * obj); |
||||
unsigned yaffs_GetObjectType(yaffs_Object * obj); |
||||
int yaffs_GetObjectLinkCount(yaffs_Object * obj); |
||||
|
||||
int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr); |
||||
int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr); |
||||
|
||||
/* File operations */ |
||||
int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset, |
||||
int nBytes); |
||||
int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset, |
||||
int nBytes, int writeThrough); |
||||
int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize); |
||||
|
||||
yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, |
||||
__u32 mode, __u32 uid, __u32 gid); |
||||
int yaffs_FlushFile(yaffs_Object * obj, int updateTime); |
||||
|
||||
/* Flushing and checkpointing */ |
||||
void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); |
||||
|
||||
int yaffs_CheckpointSave(yaffs_Device *dev); |
||||
int yaffs_CheckpointRestore(yaffs_Device *dev); |
||||
|
||||
/* Directory operations */ |
||||
yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name, |
||||
__u32 mode, __u32 uid, __u32 gid); |
||||
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name); |
||||
int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir, |
||||
int (*fn) (yaffs_Object *)); |
||||
|
||||
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number); |
||||
|
||||
/* Link operations */ |
||||
yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name, |
||||
yaffs_Object * equivalentObject); |
||||
|
||||
yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj); |
||||
|
||||
/* Symlink operations */ |
||||
yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name, |
||||
__u32 mode, __u32 uid, __u32 gid, |
||||
const YCHAR * alias); |
||||
YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj); |
||||
|
||||
/* Special inodes (fifos, sockets and devices) */ |
||||
yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name, |
||||
__u32 mode, __u32 uid, __u32 gid, __u32 rdev); |
||||
|
||||
/* Special directories */ |
||||
yaffs_Object *yaffs_Root(yaffs_Device * dev); |
||||
yaffs_Object *yaffs_LostNFound(yaffs_Device * dev); |
||||
|
||||
#ifdef CONFIG_YAFFS_WINCE |
||||
/* CONFIG_YAFFS_WINCE special stuff */ |
||||
void yfsd_WinFileTimeNow(__u32 target[2]); |
||||
#endif |
||||
|
||||
#ifdef __KERNEL__ |
||||
|
||||
void yaffs_HandleDeferedFree(yaffs_Object * obj); |
||||
#endif |
||||
|
||||
/* Debug dump */ |
||||
int yaffs_DumpObject(yaffs_Object * obj); |
||||
|
||||
void yaffs_GutsTest(yaffs_Device * dev); |
||||
|
||||
/* A few useful functions */ |
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags); |
||||
void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn); |
||||
int yaffs_CheckFF(__u8 * buffer, int nBytes); |
||||
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi); |
||||
|
||||
#endif |
@ -0,0 +1,241 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
const char *yaffs_mtdif_c_version = |
||||
"$Id: yaffs_mtdif.c,v 1.19 2007/02/14 01:09:06 wookey Exp $"; |
||||
|
||||
#include "yportenv.h" |
||||
|
||||
|
||||
#include "yaffs_mtdif.h" |
||||
|
||||
#include "linux/mtd/mtd.h" |
||||
#include "linux/types.h" |
||||
#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) |
||||
{ |
||||
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; |
||||
} |
||||
|
||||
static inline void translate_oob2spare(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; |
||||
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff; |
||||
spare->tagByte6 = oob[6]; |
||||
spare->tagByte7 = 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) |
||||
{ |
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) |
||||
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 */ |
||||
|
||||
if (data && !spare) |
||||
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk, |
||||
&dummy, data); |
||||
else if (spare) { |
||||
if (dev->useNANDECC) { |
||||
translate_spare2oob(spare, spareAsBytes); |
||||
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.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; |
||||
else |
||||
return YAFFS_FAIL; |
||||
} |
||||
|
||||
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data, |
||||
yaffs_Spare * spare) |
||||
{ |
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) |
||||
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 */ |
||||
|
||||
if (data && !spare) |
||||
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, |
||||
&dummy, data); |
||||
else if (spare) { |
||||
if (dev->useNANDECC) { |
||||
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.datbuf = data; |
||||
ops.ooboffs = 0; |
||||
ops.oobbuf = spareAsBytes; |
||||
retval = mtd->read_oob(mtd, addr, &ops); |
||||
if (dev->useNANDECC) |
||||
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; |
||||
else |
||||
return YAFFS_FAIL; |
||||
} |
||||
|
||||
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber) |
||||
{ |
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
||||
__u32 addr = |
||||
((loff_t) blockNumber) * dev->nDataBytesPerChunk |
||||
* dev->nChunksPerBlock; |
||||
struct erase_info ei; |
||||
int retval = 0; |
||||
|
||||
ei.mtd = mtd; |
||||
ei.addr = addr; |
||||
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock; |
||||
ei.time = 1000; |
||||
ei.retries = 2; |
||||
ei.callback = NULL; |
||||
ei.priv = (u_long) dev; |
||||
|
||||
/* Todo finish off the ei if required */ |
||||
|
||||
sema_init(&dev->sem, 0); |
||||
|
||||
retval = mtd->erase(mtd, &ei); |
||||
|
||||
if (retval == 0) |
||||
return YAFFS_OK; |
||||
else |
||||
return YAFFS_FAIL; |
||||
} |
||||
|
||||
int nandmtd_InitialiseNAND(yaffs_Device * dev) |
||||
{ |
||||
return YAFFS_OK; |
||||
} |
||||
|
@ -0,0 +1,27 @@ |
||||
/*
|
||||
* 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 __YAFFS_MTDIF_H__ |
||||
#define __YAFFS_MTDIF_H__ |
||||
|
||||
#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); |
||||
#endif |
@ -0,0 +1,369 @@ |
||||
/*
|
||||
* 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*/ |
@ -0,0 +1,28 @@ |
||||
/*
|
||||
* 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 |
@ -0,0 +1,232 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/* mtd interface for YAFFS2 */ |
||||
|
||||
const char *yaffs_mtdif2_c_version = |
||||
"$Id: yaffs_mtdif2.c,v 1.17 2007/02/14 01:09:06 wookey 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" |
||||
|
||||
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, |
||||
const __u8 * data, |
||||
const yaffs_ExtendedTags * tags) |
||||
{ |
||||
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) |
||||
struct mtd_oob_ops ops; |
||||
#else |
||||
size_t dummy; |
||||
#endif |
||||
int retval = 0; |
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; |
||||
|
||||
yaffs_PackedTags2 pt; |
||||
|
||||
T(YAFFS_TRACE_MTD, |
||||
(TSTR |
||||
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" |
||||
TENDSTR), chunkInNAND, data, tags)); |
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) |
||||
if (tags) |
||||
yaffs_PackTags2(&pt, tags); |
||||
else |
||||
BUG(); /* both tags and data should always be present */ |
||||
|
||||
if (data) { |
||||
ops.mode = MTD_OOB_AUTO; |
||||
ops.ooblen = sizeof(pt); |
||||
ops.len = dev->nDataBytesPerChunk; |
||||
ops.ooboffs = 0; |
||||
ops.datbuf = (__u8 *)data; |
||||
ops.oobbuf = (void *)&pt; |
||||
retval = mtd->write_oob(mtd, addr, &ops); |
||||
} else |
||||
BUG(); /* both tags and data should always be present */ |
||||
#else |
||||
if (tags) { |
||||
yaffs_PackTags2(&pt, tags); |
||||
} |
||||
|
||||
if (data && tags) { |
||||
if (dev->useNANDECC) |
||||
retval = |
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, |
||||
&dummy, data, (__u8 *) & pt, NULL); |
||||
else |
||||
retval = |
||||
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk, |
||||
&dummy, data, (__u8 *) & pt, NULL); |
||||
} else { |
||||
if (data) |
||||
retval = |
||||
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy, |
||||
data); |
||||
if (tags) |
||||
retval = |
||||
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy, |
||||
(__u8 *) & pt); |
||||
|
||||
} |
||||
#endif |
||||
|
||||
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); |
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) |
||||
struct mtd_oob_ops ops; |
||||
#endif |
||||
size_t dummy; |
||||
int retval = 0; |
||||
|
||||
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk; |
||||
|
||||
yaffs_PackedTags2 pt; |
||||
|
||||
T(YAFFS_TRACE_MTD, |
||||
(TSTR |
||||
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p" |
||||
TENDSTR), chunkInNAND, data, tags)); |
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) |
||||
if (data && !tags) |
||||
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, |
||||
&dummy, data); |
||||
else if (tags) { |
||||
ops.mode = MTD_OOB_AUTO; |
||||
ops.ooblen = sizeof(pt); |
||||
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt); |
||||
ops.ooboffs = 0; |
||||
ops.datbuf = data; |
||||
ops.oobbuf = dev->spareBuffer; |
||||
retval = mtd->read_oob(mtd, addr, &ops); |
||||
} |
||||
#else |
||||
if (data && tags) { |
||||
if (dev->useNANDECC) { |
||||
retval = |
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, |
||||
&dummy, data, dev->spareBuffer, |
||||
NULL); |
||||
} else { |
||||
retval = |
||||
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk, |
||||
&dummy, data, dev->spareBuffer, |
||||
NULL); |
||||
} |
||||
} else { |
||||
if (data) |
||||
retval = |
||||
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy, |
||||
data); |
||||
if (tags) |
||||
retval = |
||||
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, |
||||
dev->spareBuffer); |
||||
} |
||||
#endif |
||||
|
||||
memcpy(&pt, dev->spareBuffer, sizeof(pt)); |
||||
|
||||
if (tags) |
||||
yaffs_UnpackTags2(tags, &pt); |
||||
|
||||
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR) |
||||
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED; |
||||
|
||||
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->nDataBytesPerChunk); |
||||
|
||||
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->nDataBytesPerChunk); |
||||
|
||||
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 bad seq %d state %d" TENDSTR), *sequenceNumber, |
||||
*state)); |
||||
|
||||
if (retval == 0) |
||||
return YAFFS_OK; |
||||
else |
||||
return YAFFS_FAIL; |
||||
} |
||||
|
@ -0,0 +1,29 @@ |
||||
/*
|
||||
* 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 __YAFFS_MTDIF2_H__ |
||||
#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); |
||||
|
||||
#endif |
@ -0,0 +1,134 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
const char *yaffs_nand_c_version = |
||||
"$Id: yaffs_nand.c,v 1.7 2007/02/14 01:09:06 wookey Exp $"; |
||||
|
||||
#include "yaffs_nand.h" |
||||
#include "yaffs_tagscompat.h" |
||||
#include "yaffs_tagsvalidity.h" |
||||
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, |
||||
__u8 * buffer, |
||||
yaffs_ExtendedTags * tags) |
||||
{ |
||||
int result; |
||||
yaffs_ExtendedTags localTags; |
||||
|
||||
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset; |
||||
|
||||
/* If there are no tags provided, use local tags to get prioritised gc working */ |
||||
if(!tags) |
||||
tags = &localTags; |
||||
|
||||
if (dev->readChunkWithTagsFromNAND) |
||||
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer, |
||||
tags); |
||||
else |
||||
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev, |
||||
realignedChunkInNAND, |
||||
buffer, |
||||
tags);
|
||||
if(tags &&
|
||||
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){ |
||||
|
||||
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock); |
||||
yaffs_HandleChunkError(dev,bi); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev, |
||||
int chunkInNAND, |
||||
const __u8 * buffer, |
||||
yaffs_ExtendedTags * tags) |
||||
{ |
||||
chunkInNAND -= dev->chunkOffset; |
||||
|
||||
|
||||
if (tags) { |
||||
tags->sequenceNumber = dev->sequenceNumber; |
||||
tags->chunkUsed = 1; |
||||
if (!yaffs_ValidateTags(tags)) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR("Writing uninitialised tags" TENDSTR))); |
||||
YBUG(); |
||||
} |
||||
T(YAFFS_TRACE_WRITE, |
||||
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND, |
||||
tags->objectId, tags->chunkId)); |
||||
} else { |
||||
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR))); |
||||
YBUG(); |
||||
} |
||||
|
||||
if (dev->writeChunkWithTagsToNAND) |
||||
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer, |
||||
tags); |
||||
else |
||||
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev, |
||||
chunkInNAND, |
||||
buffer, |
||||
tags); |
||||
} |
||||
|
||||
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo) |
||||
{ |
||||
blockNo -= dev->blockOffset; |
||||
|
||||
; |
||||
if (dev->markNANDBlockBad) |
||||
return dev->markNANDBlockBad(dev, blockNo); |
||||
else |
||||
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo); |
||||
} |
||||
|
||||
int yaffs_QueryInitialBlockState(yaffs_Device * dev, |
||||
int blockNo, |
||||
yaffs_BlockState * state, |
||||
unsigned *sequenceNumber) |
||||
{ |
||||
blockNo -= dev->blockOffset; |
||||
|
||||
if (dev->queryNANDBlock) |
||||
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber); |
||||
else |
||||
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo, |
||||
state, |
||||
sequenceNumber); |
||||
} |
||||
|
||||
|
||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, |
||||
int blockInNAND) |
||||
{ |
||||
int result; |
||||
|
||||
blockInNAND -= dev->blockOffset; |
||||
|
||||
|
||||
dev->nBlockErasures++; |
||||
result = dev->eraseBlockInNAND(dev, blockInNAND); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) |
||||
{ |
||||
return dev->initialiseNAND(dev); |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,44 @@ |
||||
/*
|
||||
* 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 __YAFFS_NAND_H__ |
||||
#define __YAFFS_NAND_H__ |
||||
#include "yaffs_guts.h" |
||||
|
||||
|
||||
|
||||
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, |
||||
__u8 * buffer, |
||||
yaffs_ExtendedTags * tags); |
||||
|
||||
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev, |
||||
int chunkInNAND, |
||||
const __u8 * buffer, |
||||
yaffs_ExtendedTags * tags); |
||||
|
||||
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo); |
||||
|
||||
int yaffs_QueryInitialBlockState(yaffs_Device * dev, |
||||
int blockNo, |
||||
yaffs_BlockState * state, |
||||
unsigned *sequenceNumber); |
||||
|
||||
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, |
||||
int blockInNAND); |
||||
|
||||
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev); |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,39 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/* Interface to emulated NAND functions (2k page size) */ |
||||
|
||||
#ifndef __YAFFS_NANDEMUL2K_H__ |
||||
#define __YAFFS_NANDEMUL2K_H__ |
||||
|
||||
#include "yaffs_guts.h" |
||||
|
||||
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, |
||||
int chunkInNAND, const __u8 * data, |
||||
yaffs_ExtendedTags * tags); |
||||
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev, |
||||
int chunkInNAND, __u8 * data, |
||||
yaffs_ExtendedTags * tags); |
||||
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo); |
||||
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
||||
yaffs_BlockState * state, int *sequenceNumber); |
||||
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev, |
||||
int blockInNAND); |
||||
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev); |
||||
int nandemul2k_GetBytesPerChunk(void); |
||||
int nandemul2k_GetChunksPerBlock(void); |
||||
int nandemul2k_GetNumberOfBlocks(void); |
||||
|
||||
#endif |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#include "yaffs_packedtags1.h" |
||||
#include "yportenv.h" |
||||
|
||||
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t) |
||||
{ |
||||
pt->chunkId = t->chunkId; |
||||
pt->serialNumber = t->serialNumber; |
||||
pt->byteCount = t->byteCount; |
||||
pt->objectId = t->objectId; |
||||
pt->ecc = 0; |
||||
pt->deleted = (t->chunkDeleted) ? 0 : 1; |
||||
pt->unusedStuff = 0; |
||||
pt->shouldBeFF = 0xFFFFFFFF; |
||||
|
||||
} |
||||
|
||||
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt) |
||||
{ |
||||
static const __u8 allFF[] = |
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
||||
0xff }; |
||||
|
||||
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) { |
||||
t->blockBad = 0; |
||||
if (pt->shouldBeFF != 0xFFFFFFFF) { |
||||
t->blockBad = 1; |
||||
} |
||||
t->chunkUsed = 1; |
||||
t->objectId = pt->objectId; |
||||
t->chunkId = pt->chunkId; |
||||
t->byteCount = pt->byteCount; |
||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
||||
t->chunkDeleted = (pt->deleted) ? 0 : 1; |
||||
t->serialNumber = pt->serialNumber; |
||||
} else { |
||||
memset(t, 0, sizeof(yaffs_ExtendedTags)); |
||||
|
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
/*
|
||||
* 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 is used to pack YAFFS1 tags, not YAFFS2 tags. */ |
||||
|
||||
#ifndef __YAFFS_PACKEDTAGS1_H__ |
||||
#define __YAFFS_PACKEDTAGS1_H__ |
||||
|
||||
#include "yaffs_guts.h" |
||||
|
||||
typedef struct { |
||||
unsigned chunkId:20; |
||||
unsigned serialNumber:2; |
||||
unsigned byteCount:10; |
||||
unsigned objectId:18; |
||||
unsigned ecc:12; |
||||
unsigned deleted:1; |
||||
unsigned unusedStuff:1; |
||||
unsigned shouldBeFF; |
||||
|
||||
} yaffs_PackedTags1; |
||||
|
||||
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t); |
||||
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt); |
||||
#endif |
@ -0,0 +1,182 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#include "yaffs_packedtags2.h" |
||||
#include "yportenv.h" |
||||
#include "yaffs_tagsvalidity.h" |
||||
|
||||
/* This code packs a set of extended tags into a binary structure for
|
||||
* NAND storage |
||||
*/ |
||||
|
||||
/* Some of the information is "extra" struff which can be packed in to
|
||||
* speed scanning |
||||
* This is defined by having the EXTRA_HEADER_INFO_FLAG set. |
||||
*/ |
||||
|
||||
/* Extra flags applied to chunkId */ |
||||
|
||||
#define EXTRA_HEADER_INFO_FLAG 0x80000000 |
||||
#define EXTRA_SHRINK_FLAG 0x40000000 |
||||
#define EXTRA_SHADOWS_FLAG 0x20000000 |
||||
#define EXTRA_SPARE_FLAGS 0x10000000 |
||||
|
||||
#define ALL_EXTRA_FLAGS 0xF0000000 |
||||
|
||||
/* Also, the top 4 bits of the object Id are set to the object type. */ |
||||
#define EXTRA_OBJECT_TYPE_SHIFT (28) |
||||
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) |
||||
|
||||
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) |
||||
{ |
||||
T(YAFFS_TRACE_MTD, |
||||
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), |
||||
pt->t.objectId, pt->t.chunkId, pt->t.byteCount, |
||||
pt->t.sequenceNumber)); |
||||
} |
||||
|
||||
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) |
||||
{ |
||||
T(YAFFS_TRACE_MTD, |
||||
(TSTR |
||||
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " |
||||
"%d del %d ser %d seq %d" |
||||
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, |
||||
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, |
||||
t->sequenceNumber)); |
||||
|
||||
} |
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t) |
||||
{ |
||||
pt->t.chunkId = t->chunkId; |
||||
pt->t.sequenceNumber = t->sequenceNumber; |
||||
pt->t.byteCount = t->byteCount; |
||||
pt->t.objectId = t->objectId; |
||||
|
||||
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { |
||||
/* Store the extra header info instead */ |
||||
/* We save the parent object in the chunkId */ |
||||
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG |
||||
| t->extraParentObjectId; |
||||
if (t->extraIsShrinkHeader) { |
||||
pt->t.chunkId |= EXTRA_SHRINK_FLAG; |
||||
} |
||||
if (t->extraShadows) { |
||||
pt->t.chunkId |= EXTRA_SHADOWS_FLAG; |
||||
} |
||||
|
||||
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK; |
||||
pt->t.objectId |= |
||||
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); |
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { |
||||
pt->t.byteCount = t->extraEquivalentObjectId; |
||||
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) { |
||||
pt->t.byteCount = t->extraFileLength; |
||||
} else { |
||||
pt->t.byteCount = 0; |
||||
} |
||||
} |
||||
|
||||
yaffs_DumpPackedTags2(pt); |
||||
yaffs_DumpTags2(t); |
||||
|
||||
#ifndef YAFFS_IGNORE_TAGS_ECC |
||||
{ |
||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t, |
||||
sizeof(yaffs_PackedTags2TagsPart), |
||||
&pt->ecc); |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) |
||||
{ |
||||
|
||||
memset(t, 0, sizeof(yaffs_ExtendedTags)); |
||||
|
||||
yaffs_InitialiseTags(t); |
||||
|
||||
if (pt->t.sequenceNumber != 0xFFFFFFFF) { |
||||
/* Page is in use */ |
||||
#ifdef YAFFS_IGNORE_TAGS_ECC |
||||
{ |
||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
||||
} |
||||
#else |
||||
{ |
||||
yaffs_ECCOther ecc; |
||||
int result; |
||||
yaffs_ECCCalculateOther((unsigned char *)&pt->t, |
||||
sizeof |
||||
(yaffs_PackedTags2TagsPart), |
||||
&ecc); |
||||
result = |
||||
yaffs_ECCCorrectOther((unsigned char *)&pt->t, |
||||
sizeof |
||||
(yaffs_PackedTags2TagsPart), |
||||
&pt->ecc, &ecc); |
||||
switch(result){ |
||||
case 0:
|
||||
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
|
||||
break; |
||||
case 1:
|
||||
t->eccResult = YAFFS_ECC_RESULT_FIXED; |
||||
break; |
||||
case -1: |
||||
t->eccResult = YAFFS_ECC_RESULT_UNFIXED; |
||||
break; |
||||
default: |
||||
t->eccResult = YAFFS_ECC_RESULT_UNKNOWN; |
||||
} |
||||
} |
||||
#endif |
||||
t->blockBad = 0; |
||||
t->chunkUsed = 1; |
||||
t->objectId = pt->t.objectId; |
||||
t->chunkId = pt->t.chunkId; |
||||
t->byteCount = pt->t.byteCount; |
||||
t->chunkDeleted = 0; |
||||
t->serialNumber = 0; |
||||
t->sequenceNumber = pt->t.sequenceNumber; |
||||
|
||||
/* Do extra header info stuff */ |
||||
|
||||
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) { |
||||
t->chunkId = 0; |
||||
t->byteCount = 0; |
||||
|
||||
t->extraHeaderInfoAvailable = 1; |
||||
t->extraParentObjectId = |
||||
pt->t.chunkId & (~(ALL_EXTRA_FLAGS)); |
||||
t->extraIsShrinkHeader = |
||||
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; |
||||
t->extraShadows = |
||||
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; |
||||
t->extraObjectType = |
||||
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT; |
||||
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; |
||||
|
||||
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { |
||||
t->extraEquivalentObjectId = pt->t.byteCount; |
||||
} else { |
||||
t->extraFileLength = pt->t.byteCount; |
||||
} |
||||
} |
||||
} |
||||
|
||||
yaffs_DumpPackedTags2(pt); |
||||
yaffs_DumpTags2(t); |
||||
|
||||
} |
@ -0,0 +1,38 @@ |
||||
/*
|
||||
* 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 is used to pack YAFFS2 tags, not YAFFS1tags. */ |
||||
|
||||
#ifndef __YAFFS_PACKEDTAGS2_H__ |
||||
#define __YAFFS_PACKEDTAGS2_H__ |
||||
|
||||
#include "yaffs_guts.h" |
||||
#include "yaffs_ecc.h" |
||||
|
||||
typedef struct { |
||||
unsigned sequenceNumber; |
||||
unsigned objectId; |
||||
unsigned chunkId; |
||||
unsigned byteCount; |
||||
} yaffs_PackedTags2TagsPart; |
||||
|
||||
typedef struct { |
||||
yaffs_PackedTags2TagsPart t; |
||||
yaffs_ECCOther ecc; |
||||
} yaffs_PackedTags2; |
||||
|
||||
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t); |
||||
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt); |
||||
#endif |
@ -0,0 +1,160 @@ |
||||
/*
|
||||
* Copyright (c) 1992, 1993 |
||||
* The Regents of the University of California. All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the University nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
*/ |
||||
|
||||
#include "yportenv.h" |
||||
//#include <linux/string.h>
|
||||
|
||||
/*
|
||||
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". |
||||
*/ |
||||
#define swapcode(TYPE, parmi, parmj, n) { \ |
||||
long i = (n) / sizeof (TYPE); \
|
||||
register TYPE *pi = (TYPE *) (parmi); \
|
||||
register TYPE *pj = (TYPE *) (parmj); \
|
||||
do { \
|
||||
register TYPE t = *pi; \
|
||||
*pi++ = *pj; \
|
||||
*pj++ = t; \
|
||||
} while (--i > 0); \
|
||||
} |
||||
|
||||
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ |
||||
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; |
||||
|
||||
static __inline void |
||||
swapfunc(char *a, char *b, int n, int swaptype) |
||||
{ |
||||
if (swaptype <= 1)
|
||||
swapcode(long, a, b, n) |
||||
else |
||||
swapcode(char, a, b, n) |
||||
} |
||||
|
||||
#define swap(a, b) \ |
||||
if (swaptype == 0) { \
|
||||
long t = *(long *)(a); \
|
||||
*(long *)(a) = *(long *)(b); \
|
||||
*(long *)(b) = t; \
|
||||
} else \
|
||||
swapfunc(a, b, es, swaptype) |
||||
|
||||
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) |
||||
|
||||
static __inline char * |
||||
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) |
||||
{ |
||||
return cmp(a, b) < 0 ? |
||||
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) |
||||
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); |
||||
} |
||||
|
||||
#ifndef min |
||||
#define min(a,b) (((a) < (b)) ? (a) : (b)) |
||||
#endif |
||||
|
||||
void |
||||
yaffs_qsort(void *aa, size_t n, size_t es, |
||||
int (*cmp)(const void *, const void *)) |
||||
{ |
||||
char *pa, *pb, *pc, *pd, *pl, *pm, *pn; |
||||
int d, r, swaptype, swap_cnt; |
||||
register char *a = aa; |
||||
|
||||
loop: SWAPINIT(a, es); |
||||
swap_cnt = 0; |
||||
if (n < 7) { |
||||
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) |
||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; |
||||
pl -= es) |
||||
swap(pl, pl - es); |
||||
return; |
||||
} |
||||
pm = (char *)a + (n / 2) * es; |
||||
if (n > 7) { |
||||
pl = (char *)a; |
||||
pn = (char *)a + (n - 1) * es; |
||||
if (n > 40) { |
||||
d = (n / 8) * es; |
||||
pl = med3(pl, pl + d, pl + 2 * d, cmp); |
||||
pm = med3(pm - d, pm, pm + d, cmp); |
||||
pn = med3(pn - 2 * d, pn - d, pn, cmp); |
||||
} |
||||
pm = med3(pl, pm, pn, cmp); |
||||
} |
||||
swap(a, pm); |
||||
pa = pb = (char *)a + es; |
||||
|
||||
pc = pd = (char *)a + (n - 1) * es; |
||||
for (;;) { |
||||
while (pb <= pc && (r = cmp(pb, a)) <= 0) { |
||||
if (r == 0) { |
||||
swap_cnt = 1; |
||||
swap(pa, pb); |
||||
pa += es; |
||||
} |
||||
pb += es; |
||||
} |
||||
while (pb <= pc && (r = cmp(pc, a)) >= 0) { |
||||
if (r == 0) { |
||||
swap_cnt = 1; |
||||
swap(pc, pd); |
||||
pd -= es; |
||||
} |
||||
pc -= es; |
||||
} |
||||
if (pb > pc) |
||||
break; |
||||
swap(pb, pc); |
||||
swap_cnt = 1; |
||||
pb += es; |
||||
pc -= es; |
||||
} |
||||
if (swap_cnt == 0) { /* Switch to insertion sort */ |
||||
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) |
||||
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
|
||||
pl -= es) |
||||
swap(pl, pl - es); |
||||
return; |
||||
} |
||||
|
||||
pn = (char *)a + n * es; |
||||
r = min(pa - (char *)a, pb - pa); |
||||
vecswap(a, pb - r, r); |
||||
r = min((long)(pd - pc), (long)(pn - pd - es)); |
||||
vecswap(pb, pn - r, r); |
||||
if ((r = pb - pa) > es) |
||||
yaffs_qsort(a, r / es, es, cmp); |
||||
if ((r = pd - pc) > es) {
|
||||
/* Iterate rather than recurse to save stack space */ |
||||
a = pn - r; |
||||
n = r / es; |
||||
goto loop; |
||||
} |
||||
/* yaffs_qsort(pn - r, r / es, es, cmp);*/ |
||||
} |
@ -0,0 +1,23 @@ |
||||
/*
|
||||
* 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 __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 *)); |
||||
|
||||
#endif |
@ -0,0 +1,530 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#include "yaffs_guts.h" |
||||
#include "yaffs_tagscompat.h" |
||||
#include "yaffs_ecc.h" |
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND); |
||||
#ifdef NOTYET |
||||
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND); |
||||
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, |
||||
const __u8 * data, |
||||
const yaffs_Spare * spare); |
||||
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, |
||||
const yaffs_Spare * spare); |
||||
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND); |
||||
#endif |
||||
|
||||
static const char yaffs_countBitsTable[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_CountBits(__u8 x) |
||||
{ |
||||
int retVal; |
||||
retVal = yaffs_countBitsTable[x]; |
||||
return retVal; |
||||
} |
||||
|
||||
/********** Tags ECC calculations *********/ |
||||
|
||||
void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare) |
||||
{ |
||||
yaffs_ECCCalculate(data, spare->ecc1); |
||||
yaffs_ECCCalculate(&data[256], spare->ecc2); |
||||
} |
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags * tags) |
||||
{ |
||||
/* Calculate an ecc */ |
||||
|
||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; |
||||
unsigned i, j; |
||||
unsigned ecc = 0; |
||||
unsigned bit = 0; |
||||
|
||||
tags->ecc = 0; |
||||
|
||||
for (i = 0; i < 8; i++) { |
||||
for (j = 1; j & 0xff; j <<= 1) { |
||||
bit++; |
||||
if (b[i] & j) { |
||||
ecc ^= bit; |
||||
} |
||||
} |
||||
} |
||||
|
||||
tags->ecc = ecc; |
||||
|
||||
} |
||||
|
||||
int yaffs_CheckECCOnTags(yaffs_Tags * tags) |
||||
{ |
||||
unsigned ecc = tags->ecc; |
||||
|
||||
yaffs_CalcTagsECC(tags); |
||||
|
||||
ecc ^= tags->ecc; |
||||
|
||||
if (ecc && ecc <= 64) { |
||||
/* TODO: Handle the failure better. Retire? */ |
||||
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; |
||||
|
||||
ecc--; |
||||
|
||||
b[ecc / 8] ^= (1 << (ecc & 7)); |
||||
|
||||
/* Now recvalc the ecc */ |
||||
yaffs_CalcTagsECC(tags); |
||||
|
||||
return 1; /* recovered error */ |
||||
} else if (ecc) { |
||||
/* Wierd ecc failure value */ |
||||
/* TODO Need to do somethiong here */ |
||||
return -1; /* unrecovered error */ |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/********** Tags **********/ |
||||
|
||||
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]; |
||||
} |
||||
|
||||
static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr, |
||||
yaffs_Tags * tagsPtr) |
||||
{ |
||||
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; |
||||
int result; |
||||
|
||||
tu->asBytes[0] = sparePtr->tagByte0; |
||||
tu->asBytes[1] = sparePtr->tagByte1; |
||||
tu->asBytes[2] = sparePtr->tagByte2; |
||||
tu->asBytes[3] = sparePtr->tagByte3; |
||||
tu->asBytes[4] = sparePtr->tagByte4; |
||||
tu->asBytes[5] = sparePtr->tagByte5; |
||||
tu->asBytes[6] = sparePtr->tagByte6; |
||||
tu->asBytes[7] = sparePtr->tagByte7; |
||||
|
||||
result = yaffs_CheckECCOnTags(tagsPtr); |
||||
if (result > 0) { |
||||
dev->tagsEccFixed++; |
||||
} else if (result < 0) { |
||||
dev->tagsEccUnfixed++; |
||||
} |
||||
} |
||||
|
||||
static void yaffs_SpareInitialise(yaffs_Spare * spare) |
||||
{ |
||||
memset(spare, 0xFF, sizeof(yaffs_Spare)); |
||||
} |
||||
|
||||
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, |
||||
int chunkInNAND, const __u8 * data, |
||||
yaffs_Spare * spare) |
||||
{ |
||||
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR), |
||||
chunkInNAND)); |
||||
return YAFFS_FAIL; |
||||
} |
||||
|
||||
dev->nPageWrites++; |
||||
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); |
||||
} |
||||
|
||||
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, |
||||
int chunkInNAND, |
||||
__u8 * data, |
||||
yaffs_Spare * spare, |
||||
yaffs_ECCResult * eccResult, |
||||
int doErrorCorrection) |
||||
{ |
||||
int retVal; |
||||
yaffs_Spare localSpare; |
||||
|
||||
dev->nPageReads++; |
||||
|
||||
if (!spare && data) { |
||||
/* If we don't have a real spare, then we use a local one. */ |
||||
/* Need this for the calculation of the ecc */ |
||||
spare = &localSpare; |
||||
} |
||||
|
||||
if (!dev->useNANDECC) { |
||||
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); |
||||
if (data && doErrorCorrection) { |
||||
/* Do ECC correction */ |
||||
/* Todo handle any errors */ |
||||
int eccResult1, eccResult2; |
||||
__u8 calcEcc[3]; |
||||
|
||||
yaffs_ECCCalculate(data, calcEcc); |
||||
eccResult1 = |
||||
yaffs_ECCCorrect(data, spare->ecc1, calcEcc); |
||||
yaffs_ECCCalculate(&data[256], calcEcc); |
||||
eccResult2 = |
||||
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc); |
||||
|
||||
if (eccResult1 > 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>yaffs ecc error fix performed on chunk %d:0" |
||||
TENDSTR), chunkInNAND)); |
||||
dev->eccFixed++; |
||||
} else if (eccResult1 < 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>yaffs ecc error unfixed on chunk %d:0" |
||||
TENDSTR), chunkInNAND)); |
||||
dev->eccUnfixed++; |
||||
} |
||||
|
||||
if (eccResult2 > 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>yaffs ecc error fix performed on chunk %d:1" |
||||
TENDSTR), chunkInNAND)); |
||||
dev->eccFixed++; |
||||
} else if (eccResult2 < 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>yaffs ecc error unfixed on chunk %d:1" |
||||
TENDSTR), chunkInNAND)); |
||||
dev->eccUnfixed++; |
||||
} |
||||
|
||||
if (eccResult1 || eccResult2) { |
||||
/* We had a data problem on this page */ |
||||
yaffs_HandleReadDataError(dev, chunkInNAND); |
||||
} |
||||
|
||||
if (eccResult1 < 0 || eccResult2 < 0) |
||||
*eccResult = YAFFS_ECC_RESULT_UNFIXED; |
||||
else if (eccResult1 > 0 || eccResult2 > 0) |
||||
*eccResult = YAFFS_ECC_RESULT_FIXED; |
||||
else |
||||
*eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
||||
} |
||||
} else { |
||||
/* Must allocate enough memory for spare+2*sizeof(int) */ |
||||
/* for ecc results from device. */ |
||||
struct yaffs_NANDSpare nspare; |
||||
retVal = |
||||
dev->readChunkFromNAND(dev, chunkInNAND, data, |
||||
(yaffs_Spare *) & nspare); |
||||
memcpy(spare, &nspare, sizeof(yaffs_Spare)); |
||||
if (data && doErrorCorrection) { |
||||
if (nspare.eccres1 > 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>mtd ecc error fix performed on chunk %d:0" |
||||
TENDSTR), chunkInNAND)); |
||||
} else if (nspare.eccres1 < 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>mtd ecc error unfixed on chunk %d:0" |
||||
TENDSTR), chunkInNAND)); |
||||
} |
||||
|
||||
if (nspare.eccres2 > 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>mtd ecc error fix performed on chunk %d:1" |
||||
TENDSTR), chunkInNAND)); |
||||
} else if (nspare.eccres2 < 0) { |
||||
T(YAFFS_TRACE_ERROR, |
||||
(TSTR |
||||
("**>>mtd ecc error unfixed on chunk %d:1" |
||||
TENDSTR), chunkInNAND)); |
||||
} |
||||
|
||||
if (nspare.eccres1 || nspare.eccres2) { |
||||
/* We had a data problem on this page */ |
||||
yaffs_HandleReadDataError(dev, chunkInNAND); |
||||
} |
||||
|
||||
if (nspare.eccres1 < 0 || nspare.eccres2 < 0) |
||||
*eccResult = YAFFS_ECC_RESULT_UNFIXED; |
||||
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) |
||||
*eccResult = YAFFS_ECC_RESULT_FIXED; |
||||
else |
||||
*eccResult = YAFFS_ECC_RESULT_NO_ERROR; |
||||
|
||||
} |
||||
} |
||||
return retVal; |
||||
} |
||||
|
||||
#ifdef NOTYET |
||||
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, |
||||
int chunkInNAND) |
||||
{ |
||||
|
||||
static int init = 0; |
||||
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; |
||||
static __u8 data[YAFFS_BYTES_PER_CHUNK]; |
||||
/* Might as well always allocate the larger size for */ |
||||
/* dev->useNANDECC == true; */ |
||||
static __u8 spare[sizeof(struct yaffs_NANDSpare)]; |
||||
|
||||
dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); |
||||
|
||||
if (!init) { |
||||
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); |
||||
init = 1; |
||||
} |
||||
|
||||
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK)) |
||||
return YAFFS_FAIL; |
||||
if (memcmp(cmpbuf, spare, 16)) |
||||
return YAFFS_FAIL; |
||||
|
||||
return YAFFS_OK; |
||||
|
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* Functions for robustisizing |
||||
*/ |
||||
|
||||
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND) |
||||
{ |
||||
int blockInNAND = chunkInNAND / dev->nChunksPerBlock; |
||||
|
||||
/* Mark the block for retirement */ |
||||
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; |
||||
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, |
||||
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND)); |
||||
|
||||
/* TODO:
|
||||
* Just do a garbage collection on the affected block |
||||
* then retire the block |
||||
* NB recursion |
||||
*/ |
||||
} |
||||
|
||||
#ifdef NOTYET |
||||
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND) |
||||
{ |
||||
} |
||||
|
||||
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, |
||||
const __u8 * data, |
||||
const yaffs_Spare * spare) |
||||
{ |
||||
} |
||||
|
||||
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, |
||||
const yaffs_Spare * spare) |
||||
{ |
||||
} |
||||
|
||||
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND) |
||||
{ |
||||
int blockInNAND = chunkInNAND / dev->nChunksPerBlock; |
||||
|
||||
/* Mark the block for retirement */ |
||||
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; |
||||
/* Delete the chunk */ |
||||
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); |
||||
} |
||||
|
||||
static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1, |
||||
const yaffs_Spare * s0, const yaffs_Spare * s1) |
||||
{ |
||||
|
||||
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 || |
||||
s0->tagByte0 != s1->tagByte0 || |
||||
s0->tagByte1 != s1->tagByte1 || |
||||
s0->tagByte2 != s1->tagByte2 || |
||||
s0->tagByte3 != s1->tagByte3 || |
||||
s0->tagByte4 != s1->tagByte4 || |
||||
s0->tagByte5 != s1->tagByte5 || |
||||
s0->tagByte6 != s1->tagByte6 || |
||||
s0->tagByte7 != s1->tagByte7 || |
||||
s0->ecc1[0] != s1->ecc1[0] || |
||||
s0->ecc1[1] != s1->ecc1[1] || |
||||
s0->ecc1[2] != s1->ecc1[2] || |
||||
s0->ecc2[0] != s1->ecc2[0] || |
||||
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) { |
||||
return 0; |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
#endif /* NOTYET */ |
||||
|
||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev, |
||||
int chunkInNAND, |
||||
const __u8 * data, |
||||
const yaffs_ExtendedTags * |
||||
eTags) |
||||
{ |
||||
yaffs_Spare spare; |
||||
yaffs_Tags tags; |
||||
|
||||
yaffs_SpareInitialise(&spare); |
||||
|
||||
if (eTags->chunkDeleted) { |
||||
spare.pageStatus = 0; |
||||
} else { |
||||
tags.objectId = eTags->objectId; |
||||
tags.chunkId = eTags->chunkId; |
||||
tags.byteCount = eTags->byteCount; |
||||
tags.serialNumber = eTags->serialNumber; |
||||
|
||||
if (!dev->useNANDECC && data) { |
||||
yaffs_CalcECC(data, &spare); |
||||
} |
||||
yaffs_LoadTagsIntoSpare(&spare, &tags); |
||||
|
||||
} |
||||
|
||||
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare); |
||||
} |
||||
|
||||
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev, |
||||
int chunkInNAND, |
||||
__u8 * data, |
||||
yaffs_ExtendedTags * eTags) |
||||
{ |
||||
|
||||
yaffs_Spare spare; |
||||
yaffs_Tags tags; |
||||
yaffs_ECCResult eccResult; |
||||
|
||||
static yaffs_Spare spareFF; |
||||
static int init; |
||||
|
||||
if (!init) { |
||||
memset(&spareFF, 0xFF, sizeof(spareFF)); |
||||
init = 1; |
||||
} |
||||
|
||||
if (yaffs_ReadChunkFromNAND |
||||
(dev, chunkInNAND, data, &spare, &eccResult, 1)) { |
||||
/* eTags may be NULL */ |
||||
if (eTags) { |
||||
|
||||
int deleted = |
||||
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; |
||||
|
||||
eTags->chunkDeleted = deleted; |
||||
eTags->eccResult = eccResult; |
||||
eTags->blockBad = 0; /* We're reading it */ |
||||
/* therefore it is not a bad block */ |
||||
eTags->chunkUsed = |
||||
(memcmp(&spareFF, &spare, sizeof(spareFF)) != |
||||
0) ? 1 : 0; |
||||
|
||||
if (eTags->chunkUsed) { |
||||
yaffs_GetTagsFromSpare(dev, &spare, &tags); |
||||
|
||||
eTags->objectId = tags.objectId; |
||||
eTags->chunkId = tags.chunkId; |
||||
eTags->byteCount = tags.byteCount; |
||||
eTags->serialNumber = tags.serialNumber; |
||||
} |
||||
} |
||||
|
||||
return YAFFS_OK; |
||||
} else { |
||||
return YAFFS_FAIL; |
||||
} |
||||
} |
||||
|
||||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, |
||||
int blockInNAND) |
||||
{ |
||||
|
||||
yaffs_Spare spare; |
||||
|
||||
memset(&spare, 0xff, sizeof(yaffs_Spare)); |
||||
|
||||
spare.blockStatus = 'Y'; |
||||
|
||||
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, |
||||
&spare); |
||||
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, |
||||
NULL, &spare); |
||||
|
||||
return YAFFS_OK; |
||||
|
||||
} |
||||
|
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, |
||||
int blockNo, yaffs_BlockState * |
||||
state, |
||||
int *sequenceNumber) |
||||
{ |
||||
|
||||
yaffs_Spare spare0, spare1; |
||||
static yaffs_Spare spareFF; |
||||
static int init; |
||||
yaffs_ECCResult dummy; |
||||
|
||||
if (!init) { |
||||
memset(&spareFF, 0xFF, sizeof(spareFF)); |
||||
init = 1; |
||||
} |
||||
|
||||
*sequenceNumber = 0; |
||||
|
||||
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, |
||||
&spare0, &dummy, 1); |
||||
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, |
||||
&spare1, &dummy, 1); |
||||
|
||||
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) |
||||
*state = YAFFS_BLOCK_STATE_DEAD; |
||||
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0) |
||||
*state = YAFFS_BLOCK_STATE_EMPTY; |
||||
else |
||||
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; |
||||
|
||||
return YAFFS_OK; |
||||
} |
@ -0,0 +1,40 @@ |
||||
/*
|
||||
* 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 __YAFFS_TAGSCOMPAT_H__ |
||||
#define __YAFFS_TAGSCOMPAT_H__ |
||||
|
||||
#include "yaffs_guts.h" |
||||
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev, |
||||
int chunkInNAND, |
||||
const __u8 * data, |
||||
const yaffs_ExtendedTags * |
||||
tags); |
||||
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev, |
||||
int chunkInNAND, |
||||
__u8 * data, |
||||
yaffs_ExtendedTags * |
||||
tags); |
||||
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, |
||||
int blockNo); |
||||
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, |
||||
int blockNo, yaffs_BlockState * |
||||
state, int *sequenceNumber); |
||||
|
||||
void yaffs_CalcTagsECC(yaffs_Tags * tags); |
||||
int yaffs_CheckECCOnTags(yaffs_Tags * tags); |
||||
int yaffs_CountBits(__u8 byte); |
||||
|
||||
#endif |
@ -0,0 +1,28 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#include "yaffs_tagsvalidity.h" |
||||
|
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags) |
||||
{ |
||||
memset(tags, 0, sizeof(yaffs_ExtendedTags)); |
||||
tags->validMarker0 = 0xAAAAAAAA; |
||||
tags->validMarker1 = 0x55555555; |
||||
} |
||||
|
||||
int yaffs_ValidateTags(yaffs_ExtendedTags * tags) |
||||
{ |
||||
return (tags->validMarker0 == 0xAAAAAAAA && |
||||
tags->validMarker1 == 0x55555555); |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* 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 __YAFFS_TAGS_VALIDITY_H__ |
||||
#define __YAFFS_TAGS_VALIDITY_H__ |
||||
|
||||
#include "yaffs_guts.h" |
||||
|
||||
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags); |
||||
int yaffs_ValidateTags(yaffs_ExtendedTags * tags); |
||||
#endif |
@ -0,0 +1,21 @@ |
||||
/*
|
||||
* 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 __YAFFSINTERFACE_H__ |
||||
#define __YAFFSINTERFACE_H__ |
||||
|
||||
int yaffs_Initialise(unsigned nBlocks); |
||||
|
||||
#endif |
@ -0,0 +1,187 @@ |
||||
/*
|
||||
* 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 __YPORTENV_H__ |
||||
#define __YPORTENV_H__ |
||||
|
||||
#if defined CONFIG_YAFFS_WINCE |
||||
|
||||
#include "ywinceenv.h" |
||||
|
||||
#elif defined __KERNEL__ |
||||
|
||||
#include "moduleconfig.h" |
||||
|
||||
/* Linux kernel */ |
||||
#include <linux/version.h> |
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) |
||||
#include <linux/config.h> |
||||
#endif |
||||
#include <linux/kernel.h> |
||||
#include <linux/mm.h> |
||||
#include <linux/sched.h> |
||||
#include <linux/string.h> |
||||
#include <linux/slab.h> |
||||
#include <linux/vmalloc.h> |
||||
|
||||
#define YCHAR char |
||||
#define YUCHAR unsigned char |
||||
#define _Y(x) x |
||||
#define yaffs_strcpy(a,b) strcpy(a,b) |
||||
#define yaffs_strncpy(a,b,c) strncpy(a,b,c) |
||||
#define yaffs_strncmp(a,b,c) strncmp(a,b,c) |
||||
#define yaffs_strlen(s) strlen(s) |
||||
#define yaffs_sprintf sprintf |
||||
#define yaffs_toupper(a) toupper(a) |
||||
|
||||
#define Y_INLINE inline |
||||
|
||||
#define YAFFS_LOSTNFOUND_NAME "lost+found" |
||||
#define YAFFS_LOSTNFOUND_PREFIX "obj" |
||||
|
||||
/* #define YPRINTF(x) printk x */ |
||||
#define YMALLOC(x) kmalloc(x,GFP_KERNEL) |
||||
#define YFREE(x) kfree(x) |
||||
#define YMALLOC_ALT(x) vmalloc(x) |
||||
#define YFREE_ALT(x) vfree(x) |
||||
#define YMALLOC_DMA(x) YMALLOC(x) |
||||
|
||||
// KR - added for use in scan so processes aren't blocked indefinitely.
|
||||
#define YYIELD() schedule() |
||||
|
||||
#define YAFFS_ROOT_MODE 0666 |
||||
#define YAFFS_LOSTNFOUND_MODE 0666 |
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) |
||||
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec |
||||
#define Y_TIME_CONVERT(x) (x).tv_sec |
||||
#else |
||||
#define Y_CURRENT_TIME CURRENT_TIME |
||||
#define Y_TIME_CONVERT(x) (x) |
||||
#endif |
||||
|
||||
#define yaffs_SumCompare(x,y) ((x) == (y)) |
||||
#define yaffs_strcmp(a,b) strcmp(a,b) |
||||
|
||||
#define TENDSTR "\n" |
||||
#define TSTR(x) KERN_WARNING x |
||||
#define TOUT(p) printk p |
||||
|
||||
#define yaffs_trace(mask, fmt, args...) \ |
||||
do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
|
||||
printk(KERN_WARNING "yaffs: " fmt, ## args); \
|
||||
} while (0) |
||||
|
||||
#define compile_time_assertion(assertion) \ |
||||
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; }) |
||||
|
||||
#elif defined CONFIG_YAFFS_DIRECT |
||||
|
||||
/* Direct interface */ |
||||
#include "ydirectenv.h" |
||||
|
||||
#elif defined CONFIG_YAFFS_UTIL |
||||
|
||||
/* Stuff for YAFFS utilities */ |
||||
|
||||
#include "stdlib.h" |
||||
#include "stdio.h" |
||||
#include "string.h" |
||||
|
||||
#include "devextras.h" |
||||
|
||||
#define YMALLOC(x) malloc(x) |
||||
#define YFREE(x) free(x) |
||||
#define YMALLOC_ALT(x) malloc(x) |
||||
#define YFREE_ALT(x) free(x) |
||||
|
||||
#define YCHAR char |
||||
#define YUCHAR unsigned char |
||||
#define _Y(x) x |
||||
#define yaffs_strcpy(a,b) strcpy(a,b) |
||||
#define yaffs_strncpy(a,b,c) strncpy(a,b,c) |
||||
#define yaffs_strlen(s) strlen(s) |
||||
#define yaffs_sprintf sprintf |
||||
#define yaffs_toupper(a) toupper(a) |
||||
|
||||
#define Y_INLINE inline |
||||
|
||||
/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */ |
||||
/* #define YALERT(s) YINFO(s) */ |
||||
|
||||
#define TENDSTR "\n" |
||||
#define TSTR(x) x |
||||
#define TOUT(p) printf p |
||||
|
||||
#define YAFFS_LOSTNFOUND_NAME "lost+found" |
||||
#define YAFFS_LOSTNFOUND_PREFIX "obj" |
||||
/* #define YPRINTF(x) printf x */ |
||||
|
||||
#define YAFFS_ROOT_MODE 0666 |
||||
#define YAFFS_LOSTNFOUND_MODE 0666 |
||||
|
||||
#define yaffs_SumCompare(x,y) ((x) == (y)) |
||||
#define yaffs_strcmp(a,b) strcmp(a,b) |
||||
|
||||
#else |
||||
/* Should have specified a configuration type */ |
||||
#error Unknown configuration |
||||
|
||||
#endif |
||||
|
||||
/* see yaffs_fs.c */ |
||||
extern unsigned int yaffs_traceMask; |
||||
extern unsigned int yaffs_wr_attempts; |
||||
|
||||
/*
|
||||
* Tracing flags. |
||||
* The flags masked in YAFFS_TRACE_ALWAYS are always traced. |
||||
*/ |
||||
|
||||
#define YAFFS_TRACE_OS 0x00000002 |
||||
#define YAFFS_TRACE_ALLOCATE 0x00000004 |
||||
#define YAFFS_TRACE_SCAN 0x00000008 |
||||
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 |
||||
#define YAFFS_TRACE_ERASE 0x00000020 |
||||
#define YAFFS_TRACE_GC 0x00000040 |
||||
#define YAFFS_TRACE_WRITE 0x00000080 |
||||
#define YAFFS_TRACE_TRACING 0x00000100 |
||||
#define YAFFS_TRACE_DELETION 0x00000200 |
||||
#define YAFFS_TRACE_BUFFERS 0x00000400 |
||||
#define YAFFS_TRACE_NANDACCESS 0x00000800 |
||||
#define YAFFS_TRACE_GC_DETAIL 0x00001000 |
||||
#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 |
||||
#define YAFFS_TRACE_MTD 0x00004000 |
||||
#define YAFFS_TRACE_CHECKPOINT 0x00008000 |
||||
|
||||
#define YAFFS_TRACE_VERIFY 0x00010000 |
||||
#define YAFFS_TRACE_VERIFY_NAND 0x00020000 |
||||
#define YAFFS_TRACE_VERIFY_FULL 0x00040000 |
||||
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000 |
||||
|
||||
|
||||
#define YAFFS_TRACE_ERROR 0x40000000 |
||||
#define YAFFS_TRACE_BUG 0x80000000 |
||||
#define YAFFS_TRACE_ALWAYS 0xF0000000 |
||||
|
||||
|
||||
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0) |
||||
|
||||
#ifndef CONFIG_YAFFS_WINCE |
||||
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__)) |
||||
#endif |
||||
|
||||
#endif |
Loading…
Reference in new issue