git-svn-id: https://rt-thread.googlecode.com/svn/trunk@888 bbd45198-f89e-11dd-88c7-29a3b14d5316
This commit is contained in:
bernard.xiong@gmail.com 2010-09-02 23:55:14 +00:00
parent a3ca8e33db
commit 7b76fb6ecd
66 changed files with 16377 additions and 0 deletions

View File

@ -0,0 +1 @@
Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>

View File

@ -0,0 +1,3 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6 )
PROJECT( uffs )
ADD_SUBDIRECTORY( src )

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,275 @@
# Doxyfile 1.4.1-KDevelop
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = uffs-doc
PROJECT_NUMBER = 0.1
OUTPUT_DIRECTORY = doc/doxygen-doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = ./
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 4
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = NO
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = YES
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = YES
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = YES
SORT_BY_SCOPE_NAME = YES
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ./src
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.mm \
*.dox \
*.C \
*.CC \
*.C++ \
*.II \
*.I++ \
*.H \
*.HH \
*.H++ \
*.CS \
*.PHP \
*.PHP3 \
*.M \
*.MM \
*.C \
*.H \
*.tlh \
*.diff \
*.patch \
*.moc \
*.xpm \
*.dox
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE = uffs.tag
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

View File

@ -0,0 +1,213 @@
UFFS: Ultra-low-cost Flash File System
Project: http://uffs.sf.net/
Blog: http://all-about-uffs.blogspot.com/
Q/A: http://groups.google.com/group/uffs/
Author: Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
INTRODUCTION
------------
UFFS is a nand flash file system designed for embedded system.
UFFS have some unique and advanced features:
* Low cost: e.g. it needs only 41K bytes RAM for 64MB NAND flash (page size 2048).
* Fast booting: it reads only a few spares from each block, typically
mounting a fully filled file system (Gbits) within one second.
* Superb Reliability:
- The file system is designed for the embedded system which may
frequently lost power/reset without care.
- Journal file system, the file system will automatically rollback
to the last state when lost power on the middle of flash programing.
- When 'write' return without error, the data is guarenteed been
saved on flash.
* Fast file create/read/write/seek.
* Bad-block tolerant, ECC enable and good ware-leveling.
* There is no garbage collection needed for UFFS.
* Support multiple NAND flash class in one system.
* Support bare flash hardware, no operating system needed.
* Support static memory allocation (works without 'malloc').
* Fully simulated on PC (Windows/Linux) platform.
Disadvantage:
* space inefficency for small files: UFFS use at least one
'block'(the minial erase unit for NAND flash, e.g. 16K ) for a file.
* maximum supported blocks: 2^16 = 65535
Memory consuming example:
For page size = 512:
[VARY]Tree nodes: 16 * total_blocks
[CONST]Page Bufs: MAX_CACHED_BUFFERS(10) * (40 + pageSize(512)) = 5.4K
[CONST]Block Info caches: (24 + 14 * pages_per_block (32)) * MAX_CACHED_BLOCK_INFO (10) = 4.6K
Example 1: 128M bytes NAND, 8192 blocks, total memory cost:
(16 * 8192)128K + 5.4K + 4.6K = 138K bytes.
Example 2: 32M Bytes NAND, 2048 blocks, total memory cost:
(16 * 2048)32K + 5.4K + 4.6K = 42K bytes.
Example 3: 16M bytes NAND, 1024 blocks, total memory cost:
(16 * 1024)16K + 5.4K + 4.6K = 26K bytes.
For page size = 2048:
[VARY]Tree nodes: 16 * total_blocks
[CONST]Page Bufs: MAX_CACHED_BUFFERS(10) * (40 + pageSize(2048)) = 20.4K
[CONST]Block Info caches: (24 + 14 * pages_per_block (32)) * MAX_CACHED_BLOCK_INFO (10) = 4.6K
Example 1: 512M bytes NAND, 8192 blocks, total memory cost:
(16 * 8192)128K + 20.4K + 4.6K = 153K bytes.
Example 2: 128M Bytes NAND, 2048 blocks, total memory cost:
(16 * 2048)32K + 20.4K + 4.6K = 57K bytes.
Example 3: 64M bytes NAND, 1024 blocks, total memory cost:
(16 * 1024)16K + 20.4K + 4.6K = 41K bytes.
BUILD SIMULATOR REQUIREMENT
---------------------------
From V1.2.0, build uffs simulator requires 'cmake'.
'cmake' can be downloaded from: http://www.cmake.org/
or, under Debian/Ubuntu:
sudo apt-get install cmake
BUILD SIMULATOR ON LINUX
------------------------
1) create a 'build' dir along with uffs source dir, for example:
/+
+--build/
+--uffs-1.2.0/
|
2) create Makefiles and build:
cd build
cmake ../uffs-1.2.0
make
5) run simulator (interactive mode):
src/utils/mkuffs
BUILD SIMULATOR ON WINDOWS
--------------------------
1) create a 'build' dir along with uffs source dir,
/+
+--build/
+--uffs-1.2.0/
|
2) Create VC project files:
cd build
cmake ../uffs-1.2.0
3) Open uffs.dsw (or uffs.sln for VC > 6 ), compile & run.
LATEST SOURCE CODE
------------------
You can get the latest source code from git repository:
git clone git://uffs.git.sourceforge.net/gitroot/uffs/uffs
CURRENT STATUS
--------------
UFFS 0.1.x is a working version on PC simulator, also has been ported to
uBase embedded OS as a 'real world' product for thousands of copies,
it works fine so far.
UFFS 0.2.0 implementes full directory.
UFFS 1.0.0 is the first stable release at sf.net.
UFFS 1.1.0: support NAND flash with large page size (up to 2K).
UFFS 1.1.1: bug fixes. a tool for making uffs disk image.
UFFS 1.1.2: bug fixes. add more Flash Class. change Licence from GNU GPLv2 to GNU LGPLv2
UFFS 1.2.0:
- eliminate 'current path' and relatives. Now you should use absolute path in all
uffs APIs. For dir, the fullname should end with '/'.
- allow using static memory allocation, 'malloc' is no longer needed.
- using cmake for building simulator.
- bug fixes & minor changes.
UFFS 1.2.1:
- improve bad block management
- bug fixes
- change Licence to modified GNU GPLv2.
UFFS 1.3.0:
- improved flash interface
- support hardware ECC
- support user defined spare layout (for customized NAND flash controller)
- support 4K page size
- no partial page program required, support MLC NAND flash
- reduced buffer flushes by grouping buffers
- structual improvments and bug fixes
UFFS v1.3.1:
- Tidy up three memory allocators: static, native and system.
- Fix bugs in flash interface example.
- Fix memory allocation bugs when using static memory allocator.
- Add flash driver interface 'WriteFullPage()'.
- Fix compilation errors for BlackFin DSP compiler.
UFFS v1.3.2:
- Add POSIX like file system APIs.
- Bug fixes.
LICENCE
-------
From v1.2.1, UFFS is released under a midified GNU GPLv2. (the same as eCos Licence)
The full licence text can be found in the header of source files:
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
ACKNOWLEDGMENT
---------------
Special thanks for your contributions to:
(list in no particular order)
* Chen Jun <chj@nlscan.com>
* Michail <digiolog@mail.ru>
* Sjpu <sjpu@163.com>
* RobertGray <xennex@hotmail.com>
* Dongbo <dongbo@ftsafe.com>
* Cag <seucag@hotmail.com>
* Sergey <s_sazonov@m2m-t.ru>
* Chris Conrad <chris.conrad@halliburton.com>
* Vladimir <decoder@rambler.ru>
* Thien Pham <thienpham2008@yahoo.com>
* Emmanuel Blot <eblot.ml@gmail.com>
* Michael <yowong2@gmail.com>

View File

@ -0,0 +1,5 @@
TODO list for v1.3:
* New API: int uffs_SkipObject(uffs_Object *obj, int size);
* Introduce buffer group
* Interface to Linux MTD

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,4 @@
ADD_SUBDIRECTORY(emu)
ADD_SUBDIRECTORY(uffs)
ADD_SUBDIRECTORY(utils)
ADD_SUBDIRECTORY(example)

View File

@ -0,0 +1,5 @@
SET(libemu_SRCS cmdline.c cmdline.h helper_cmds.c uffs_fileem.c uffs_fileem.h uffs_os_posix.c test_cmds.c)
INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
ADD_LIBRARY(emu STATIC ${libemu_SRCS} )

View File

@ -0,0 +1,265 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file cmdline.c
* \brief command line test interface
* \author Ricky Zheng, created in 22th Feb, 2007
*/
#include <string.h>
#include <stdio.h>
//#include <conio.h>
#include "cmdline.h"
#include "uffs/uffs_fs.h"
#define PROMPT "UFFS>"
static BOOL m_exit = FALSE;
static struct cli_commandset cmdset[200] = {0};
static int m_cmdCount = 0;
static char str_buf[128];
const char * cli_getparam(const char *tail, const char **next)
{
char *p;
if (tail == NULL)
return NULL;
strcpy(str_buf, tail);
p = str_buf;
while (*tail != ' ' && *tail != 0) {
tail++; p++;
}
if (*tail == ' ') {
*p = 0;
while(*tail == ' ')
tail++;
}
if(next)
*next = (char *)(*tail ? tail : NULL);
return str_buf;
}
static BOOL cmdExit(const char *tail)
{
m_exit = TRUE;
return TRUE;
}
static BOOL cmdHelp(const char *tail);
static struct cli_commandset default_cmdset[] =
{
{ cmdHelp, "help|?", "[<command>]", "Show commands or help on one command" },
{ cmdExit, "exit", NULL, "exit command line" },
{ NULL, NULL, NULL, NULL }
};
static BOOL match_cmd(const char *src, int start, int end, const char *des)
{
while (src[start] == ' ' && start < end)
start++;
while (src[end] == ' ' && start < end)
end--;
if ((int)strlen(des) == (end - start + 1)) {
if (memcmp(src + start, des, end - start + 1) == 0) {
return TRUE;
}
}
return FALSE;
}
static BOOL check_cmd(const char *cmds, const char *cmd)
{
int start, end;
for (start = end = 0; cmds[end] != 0 && cmds[end] != '|'; end++);
while (end > start) {
if (match_cmd(cmds, start, end - 1, cmd) == TRUE)
return TRUE;
if (cmds[end] == 0)
break;
if (cmds[end] == '|') {
end++;
for (start = end; cmds[end] != 0 && cmds[end] != '|'; end++);
}
}
return FALSE;
}
static int cmdFind(const char *cmd)
{
int icmd;
for (icmd = 0; cmdset[icmd].cmd != NULL; icmd++) {
//printf("cmdFind: Check cmd: %s with %s\n", cmd, cmdset[icmd].cmd);
if (check_cmd(cmdset[icmd].cmd, cmd) == TRUE)
return icmd;
}
return -1;
}
static BOOL cmdHelp(const char *tail)
{
int icmd;
if (tail == NULL) {
printf("Available commands:\n");
for (icmd = 0; cmdset[icmd].cmd != NULL; icmd++) {
int i;
printf("%s", cmdset[icmd].cmd);
for (i = strlen(cmdset[icmd].cmd); i%10; i++,printf(" "));
//if ((icmd & 7) == 7 || cmdset[icmd+1].cmd == NULL) printf("\n");
}
printf("\n");
}
else {
icmd = cmdFind(tail);
if (icmd < 0) {
printf("No such command\n");
}
else {
printf("%s: %s\n", cmdset[icmd].cmd, cmdset[icmd].descr);
printf("Usage: %s %s\n", cmdset[icmd].cmd, cmdset[icmd].args);
}
}
return TRUE;
}
void cliInterpret(const char *line)
{
char cmd[64];
const char *tail;
const char *psep;
int icmd;
psep = strchr(line, ' ');
cmd[0] = 0;
if (psep == NULL) {
strncat(cmd, line, sizeof(cmd) - 1);
tail = NULL;
}
else {
strncat(cmd, line, psep - line);
for (tail = psep; *tail == ' '; ++tail);
if (*tail == 0)
tail = NULL;
}
icmd = cmdFind(cmd);
if (icmd < 0) {
printf("Unknown command - try help\n");
return;
}
else {
//printf("Command idx: %d\n", icmd);
if (!cmdset[icmd].handler(tail)) {
cmdHelp(cmd);
}
}
}
void cli_add_commandset(struct cli_commandset *cmds)
{
int icmd;
for (icmd = 0; cmds[icmd].cmd != NULL; icmd++) {
memcpy(&(cmdset[m_cmdCount++]), &(cmds[icmd]), sizeof(struct cli_commandset));
}
}
void cliMain()
{
char line[80];
int linelen = 0;
printf("$ ");
cli_add_commandset(default_cmdset);
while (!m_exit) {
char ch;
ch = getc(stdin);
switch (ch) {
case 8:
case 127:
if (linelen > 0) {
--linelen;
printf("\x08 \x08");
}
break;
case '\r':
case '\n':
//printf("\r\n");
if (linelen > 0) {
line[linelen] = 0;
cliInterpret(line);
}
linelen = 0;
printf("$ ");
break;
case 21:
while (linelen > 0) {
--linelen;
printf("\x08 \x08");
}
break;
default:
if (ch >= ' ' && ch < 127 && linelen < sizeof(line) - 1) {
line[linelen++] = ch;
//printf("%c", ch);
}
}
}
}

View File

@ -0,0 +1,64 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef _UFFS_CLI_H_
#define _UFFS_CLI_H_
#ifndef BOOL
#define BOOL int
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef BOOL command_t(const char *tail);
struct cli_commandset {
command_t *handler;
const char *cmd;
const char *args;
const char *descr;
};
const char * cli_getparam(const char *tail, const char **next);
void cli_add_commandset(struct cli_commandset *cmds);
void cliInterpret(const char *line);
void cliMain();
#endif

View File

@ -0,0 +1,854 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file helper_cmds.c
* \brief helper commands for test uffs
* \author Ricky Zheng
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uffs/uffs_config.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_fs.h"
#include "uffs/uffs_utils.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_mtb.h"
#include "uffs/uffs_find.h"
#include "cmdline.h"
#include "uffs/uffs_fd.h"
#define PFX "cmd: "
#define MAX_PATH_LENGTH 128
BOOL cmdFormat(const char *tail)
{
URET ret;
const char *mount = "/";
uffs_Device *dev;
if (tail) {
mount = cli_getparam(tail, NULL);
}
uffs_Perror(UFFS_ERR_NORMAL, "Formating %s ... ", mount);
dev = uffs_GetDeviceFromMountPoint(mount);
if (dev == NULL) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't get device from mount point.");
}
else {
if (dev->ref_count == 1) {
ret = uffs_FormatDevice(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_NORMAL, "Format fail.");
}
else {
uffs_Perror(UFFS_ERR_NORMAL, "Format succ.");
}
}
else {
uffs_Perror(UFFS_ERR_NORMAL, "dev->ref_count: %d, can't format this device.", dev->ref_count);
}
uffs_PutDevice(dev);
}
return TRUE;
}
BOOL cmdMkf(const char *tail)
{
int fd;
const char *name;
int oflags = UO_RDWR | UO_CREATE;
if (tail == NULL) {
return FALSE;
}
name = cli_getparam(tail, NULL);
fd = uffs_open(name, oflags);
if (fd < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Create %s fail, err: %d", name, uffs_get_error());
}
else {
uffs_Perror(UFFS_ERR_NORMAL, "Create %s succ.", name);
uffs_close(fd);
}
return TRUE;
}
BOOL cmdMkdir(const char *tail)
{
const char *name;
if (tail == NULL) {
return FALSE;
}
name = cli_getparam(tail, NULL);
if (uffs_mkdir(name) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Create %s fail, err: %d", name, uffs_get_error());
}
else {
uffs_Perror(UFFS_ERR_NORMAL, "Create %s succ.", name);
}
return TRUE;
}
static int CountObjectUnder(const char *dir)
{
int count = 0;
uffs_DIR *dirp;
dirp = uffs_opendir(dir);
if (dirp) {
while (uffs_readdir(dirp) != NULL)
count++;
uffs_closedir(dirp);
}
return count;
}
BOOL cmdPwd(const char *tail)
{
uffs_Perror(UFFS_ERR_NORMAL, "not supported.");
return TRUE;
}
BOOL cmdCd(const char *tail)
{
uffs_Perror(UFFS_ERR_NORMAL, "Not supported");
return TRUE;
}
BOOL cmdLs(const char *tail)
{
uffs_DIR *dirp;
struct uffs_dirent *ent;
struct uffs_stat stat_buf;
int count = 0;
char buf[MAX_PATH_LENGTH+2];
char *name = (char *)tail;
char *sub;
if (name == NULL) {
uffs_Perror(UFFS_ERR_NORMAL, "Must provide file/dir name.");
return FALSE;
}
dirp = uffs_opendir(name);
if (dirp == NULL) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open '%s' for list", name);
}
else {
uffs_PerrorRaw(UFFS_ERR_NORMAL, "------name-----------size---------serial-----" TENDSTR);
ent = uffs_readdir(dirp);
while (ent) {
uffs_PerrorRaw(UFFS_ERR_NORMAL, "%9s", ent->d_name);
strcpy(buf, name);
sub = buf;
if (name[strlen(name)-1] != '/')
sub = strcat(buf, "/");
sub = strcat(sub, ent->d_name);
if (ent->d_type & FILE_ATTR_DIR) {
sub = strcat(sub, "/");
uffs_PerrorRaw(UFFS_ERR_NORMAL, "/ \t<%8d>", CountObjectUnder(sub));
}
else {
uffs_stat(sub, &stat_buf);
uffs_PerrorRaw(UFFS_ERR_NORMAL, " \t %8d ", stat_buf.st_size);
}
uffs_PerrorRaw(UFFS_ERR_NORMAL, "\t%6d" TENDSTR, ent->d_ino);
count++;
ent = uffs_readdir(dirp);
}
uffs_closedir(dirp);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Total: %d objects." TENDSTR, count);
}
return TRUE;
}
BOOL cmdRm(const char *tail)
{
const char *name = NULL;
int ret = 0;
struct uffs_stat st;
if (tail == NULL) return FALSE;
name = cli_getparam(tail, NULL);
if (uffs_stat(name, &st) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't stat '%s'", name);
return TRUE;
}
if (st.st_mode & US_IFDIR) {
ret = uffs_rmdir(name);
}
else {
ret = uffs_remove(name);
}
if (ret == 0)
uffs_Perror(UFFS_ERR_NORMAL, "Delete '%s' succ.", name);
else
uffs_Perror(UFFS_ERR_NORMAL, "Delete '%s' fail!", name);
return TRUE;
}
BOOL cmdRen(const char *tail)
{
const char *oldname;
const char *newname;
if (tail == NULL)
return FALSE;
oldname = cli_getparam(tail, &newname);
if (newname == NULL)
return FALSE;
if (uffs_rename(oldname, newname) == 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Rename from '%s' to '%s' succ.", oldname, newname);
}
else {
uffs_Perror(UFFS_ERR_NORMAL, "Rename from '%s' to '%s' fail!", oldname, newname);
}
return TRUE;
}
BOOL cmdSt(const char *tail)
{
uffs_Device *dev;
const char *mount = "/";
uffs_FlashStat *s;
TreeNode *node;
if (tail) {
mount = cli_getparam(tail, NULL);
}
dev = uffs_GetDeviceFromMountPoint(mount);
if (dev == NULL) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't get device from mount point %s", mount);
return TRUE;
}
s = &(dev->st);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "----------- basic info -----------" TENDSTR);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "TreeNode size: %d" TENDSTR, sizeof(TreeNode));
uffs_PerrorRaw(UFFS_ERR_NORMAL, "TagStore size: %d" TENDSTR, sizeof(struct uffs_TagStoreSt));
uffs_PerrorRaw(UFFS_ERR_NORMAL, "MaxCachedBlockInfo: %d" TENDSTR, MAX_CACHED_BLOCK_INFO);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "MaxPageBuffers: %d" TENDSTR, MAX_PAGE_BUFFERS);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "MaxDirtyPagesPerBlock: %d" TENDSTR, MAX_DIRTY_PAGES_IN_A_BLOCK);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "MaxPathLength: %d" TENDSTR, MAX_PATH_LENGTH);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "MaxObjectHandles: %d" TENDSTR, MAX_OBJECT_HANDLE);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "FreeObjectHandles: %d" TENDSTR, uffs_PoolGetFreeCount(uffs_GetObjectPool()));
uffs_PerrorRaw(UFFS_ERR_NORMAL, "MaxDirHandles: %d" TENDSTR, MAX_DIR_HANDLE);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "FreeDirHandles: %d" TENDSTR, uffs_PoolGetFreeCount(uffs_GetDirEntryBufPool()));
uffs_PerrorRaw(UFFS_ERR_NORMAL, "----------- statistics for '%s' -----------" TENDSTR, mount);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Block Erased: %d" TENDSTR, s->block_erase_count);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Write Page: %d" TENDSTR, s->page_write_count);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Write Spare: %d" TENDSTR, s->spare_write_count);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Read Page: %d" TENDSTR, s->page_read_count - s->page_header_read_count);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Read Header: %d" TENDSTR, s->page_header_read_count);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Read Spare: %d" TENDSTR, s->spare_read_count);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "--------- partition info for '%s' ---------" TENDSTR, mount);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Space total: %d" TENDSTR, uffs_GetDeviceTotal(dev));
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Space used: %d" TENDSTR, uffs_GetDeviceUsed(dev));
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Space free: %d" TENDSTR, uffs_GetDeviceFree(dev));
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Page Size: %d" TENDSTR, dev->attr->page_data_size);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Spare Size: %d" TENDSTR, dev->attr->spare_size);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Pages Per Block: %d" TENDSTR, dev->attr->pages_per_block);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Block size: %d" TENDSTR, dev->attr->page_data_size * dev->attr->pages_per_block);
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Total blocks: %d of %d" TENDSTR, (dev->par.end - dev->par.start + 1), dev->attr->total_blocks);
if (dev->tree.bad) {
uffs_PerrorRaw(UFFS_ERR_NORMAL, "Bad blocks: ");
node = dev->tree.bad;
while(node) {
uffs_PerrorRaw(UFFS_ERR_NORMAL, "%d, ", node->u.list.block);
node = node->u.list.next;
}
uffs_PerrorRaw(UFFS_ERR_NORMAL, TENDSTR);
}
uffs_BufInspect(dev);
uffs_PutDevice(dev);
return TRUE;
}
BOOL cmdCp(const char *tail)
{
const char *src;
const char *des;
char buf[100];
int fd1 = -1, fd2 = -1;
int len;
BOOL src_local = FALSE, des_local = FALSE;
FILE *fp1 = NULL, *fp2 = NULL;
if (!tail)
return FALSE;
src = cli_getparam(tail, &des);
if (!des)
return FALSE;
if (memcmp(src, "::", 2) == 0) {
src += 2;
src_local = TRUE;
}
if (memcmp(des, "::", 2) == 0) {
des += 2;
des_local = TRUE;
}
if (src_local) {
if ((fp1 = fopen(src, "rb")) == NULL) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", src);
goto fail_ext;
}
}
else {
if ((fd1 = uffs_open(src, UO_RDONLY)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", src);
goto fail_ext;
}
}
if (des_local) {
if ((fp2 = fopen(des, "wb")) == NULL) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", des);
goto fail_ext;
}
}
else {
if ((fd2 = uffs_open(des, UO_RDWR|UO_CREATE|UO_TRUNC)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s for copy.", des);
goto fail_ext;
}
}
while ( (src_local ? (feof(fp1) == 0) : (uffs_eof(fd1) == 0)) ) {
if (src_local) {
len = fread(buf, 1, sizeof(buf), fp1);
}
else {
len = uffs_read(fd1, buf, sizeof(buf));
}
if (len == 0)
break;
if (len < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "read file %s fail ?", src);
break;
}
if (des_local) {
if ((int)fwrite(buf, 1, len, fp2) != len) {
uffs_Perror(UFFS_ERR_NORMAL, "write file %s fail ? ", des);
break;
}
}
else {
if (uffs_write(fd2, buf, len) != len) {
uffs_Perror(UFFS_ERR_NORMAL, "write file %s fail ? ", des);
break;
}
}
}
fail_ext:
if (fd1 > 0)
uffs_close(fd1);
if (fd2 > 0)
uffs_close(fd2);
if (fp1)
fclose(fp1);
if (fp2)
fclose(fp2);
return TRUE;
}
BOOL cmdCat(const char *tail)
{
int fd;
const char *name;
const char *next;
char buf[100];
int start = 0, size = 0, printed = 0, n, len;
if (!tail)
return FALSE;
name = cli_getparam(tail, &next);
if ((fd = uffs_open(name, UO_RDONLY)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s", name);
goto fail;
}
if (next) {
start = strtol(next, (char **) &next, 10);
if (next) size = strtol(next, NULL, 10);
}
if (start >= 0)
uffs_seek(fd, start, USEEK_SET);
else
uffs_seek(fd, -start, USEEK_END);
while (uffs_eof(fd) == 0) {
len = uffs_read(fd, buf, sizeof(buf) - 1);
if (len == 0)
break;
if (len > 0) {
if (size == 0 || printed < size) {
n = (size == 0 ? len : (size - printed > len ? len : size - printed));
buf[n] = 0;
uffs_PerrorRaw(UFFS_ERR_NORMAL, "%s", buf);
printed += n;
}
else {
break;
}
}
}
uffs_PerrorRaw(UFFS_ERR_NORMAL, TENDSTR);
uffs_close(fd);
fail:
return TRUE;
}
static URET test_verify_file(const char *file_name)
{
int fd;
int ret = U_FAIL;
unsigned char buf[100];
int i, pos, len;
if ((fd = uffs_open(file_name, UO_RDONLY)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open file %s for read.", file_name);
goto test_exit;
}
pos = 0;
while (!uffs_eof(fd)) {
len = uffs_read(fd, buf, sizeof(buf));
if (len <= 0)
goto test_failed;
for (i = 0; i < len; i++) {
if (buf[i] != (pos++ & 0xFF)) {
pos--;
uffs_Perror(UFFS_ERR_NORMAL, "Verify file %s failed at: %d, expect %x but got %x", file_name, pos, pos & 0xFF, buf[i]);
goto test_failed;
}
}
}
if (pos != uffs_seek(fd, 0, USEEK_END)) {
uffs_Perror(UFFS_ERR_NORMAL, "Verify file %s failed. invalid file length.", file_name);
goto test_failed;
}
uffs_Perror(UFFS_ERR_NORMAL, "Verify file %s succ.", file_name);
ret = U_SUCC;
test_failed:
uffs_close(fd);
test_exit:
return ret;
}
static URET do_write_test_file(int fd, int size)
{
long pos;
unsigned char buf[100];
unsigned char data;
int i, len;
while (size > 0) {
pos = uffs_seek(fd, 0, USEEK_CUR);
len = (size > sizeof(buf) ? sizeof(buf) : size);
data = pos & 0xFF;
for (i = 0; i < len; i++, data++) {
buf[i] = data;
}
if (uffs_write(fd, buf, len) != len) {
uffs_Perror(UFFS_ERR_NORMAL, "Write file failed, size %d at %d", len, pos);
return U_FAIL;
}
size -= len;
}
return U_SUCC;
}
static URET test_append_file(const char *file_name, int size)
{
int ret = U_FAIL;
int fd = -1;
if ((fd = uffs_open(file_name, UO_RDWR|UO_APPEND|UO_CREATE)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open file %s for append.", file_name);
goto test_exit;
}
uffs_seek(fd, 0, USEEK_END);
if (do_write_test_file(fd, size) == U_FAIL) {
uffs_Perror(UFFS_ERR_NORMAL, "Write file %s failed.", file_name);
goto test_failed;
}
ret = U_SUCC;
test_failed:
uffs_close(fd);
test_exit:
return ret;
}
static URET test_write_file(const char *file_name, int pos, int size)
{
int ret = U_FAIL;
int fd = -1;
if ((fd = uffs_open(file_name, UO_RDWR|UO_CREATE)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open file %s for write.", file_name);
goto test_exit;
}
if (uffs_seek(fd, pos, USEEK_SET) != pos) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't seek file %s at pos %d", file_name, pos);
goto test_failed;
}
if (do_write_test_file(fd, size) == U_FAIL) {
uffs_Perror(UFFS_ERR_NORMAL, "Write file %s failed.", file_name);
goto test_failed;
}
ret = U_SUCC;
test_failed:
uffs_close(fd);
test_exit:
return ret;
}
static URET DoTest2(void)
{
int fd = -1;
URET ret = U_FAIL;
char buf[100], buf_1[100];
fd = uffs_open("/abc/", UO_RDWR|UO_DIR);
if (fd < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open dir abc, err: %d", uffs_get_error());
uffs_Perror(UFFS_ERR_NORMAL, "Try to create a new one...");
fd = uffs_open("/abc/", UO_RDWR|UO_CREATE|UO_DIR);
if (fd < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't create new dir /abc/");
goto exit_test;
}
else {
uffs_close(fd);
}
}
else {
uffs_close(fd);
}
fd = uffs_open("/abc/test.txt", UO_RDWR|UO_CREATE);
if (fd < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open /abc/test.txt");
goto exit_test;
}
sprintf(buf, "123456789ABCDEF");
ret = uffs_write(fd, buf, strlen(buf));
uffs_Perror(UFFS_ERR_NORMAL, "write %d bytes to file, content: %s", ret, buf);
ret = uffs_seek(fd, 3, USEEK_SET);
uffs_Perror(UFFS_ERR_NORMAL, "new file position: %d", ret);
memset(buf_1, 0, sizeof(buf_1));
ret = uffs_read(fd, buf_1, 5);
uffs_Perror(UFFS_ERR_NORMAL, "read %d bytes, content: %s", ret, buf_1);
if (memcmp(buf + 3, buf_1, 5) != 0) {
ret = U_FAIL;
}
else {
ret = U_SUCC;
}
uffs_close(fd);
exit_test:
return ret;
}
/* test create file, write file and read back */
BOOL cmdTest1(const char *tail)
{
int fd;
URET ret;
char buf[100];
const char *name;
if (!tail) {
return FALSE;
}
name = cli_getparam(tail, NULL);
fd = uffs_open(name, UO_RDWR|UO_CREATE|UO_TRUNC);
if (fd < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s", name);
goto fail;
}
sprintf(buf, "123456789ABCDEF");
ret = uffs_write(fd, buf, strlen(buf));
uffs_Perror(UFFS_ERR_NORMAL, "write %d bytes to file, content: %s", ret, buf);
ret = uffs_seek(fd, 3, USEEK_SET);
uffs_Perror(UFFS_ERR_NORMAL, "new file position: %d", ret);
memset(buf, 0, sizeof(buf));
ret = uffs_read(fd, buf, 5);
uffs_Perror(UFFS_ERR_NORMAL, "read %d bytes, content: %s", ret, buf);
uffs_close(fd);
fail:
return TRUE;
}
BOOL cmdTest2(const char *tail)
{
uffs_Perror(UFFS_ERR_NORMAL, "Test return: %s !", DoTest2() == U_SUCC ? "succ" : "failed");
return TRUE;
}
/* Test file append and 'random' write */
BOOL cmdTest3(const char *tail)
{
const char *name;
int i;
int write_test_seq[] = { 20, 10, 500, 40, 1140, 900, 329, 4560, 352, 1100 };
if (!tail) {
return FALSE;
}
name = cli_getparam(tail, NULL);
uffs_Perror(UFFS_ERR_NORMAL, "Test append file %s ...", name);
for (i = 1; i < 500; i += 29) {
if (test_append_file(name, i) != U_SUCC) {
uffs_Perror(UFFS_ERR_NORMAL, "Append file %s test failed at %d !", name, i);
return TRUE;
}
}
uffs_Perror(UFFS_ERR_NORMAL, "Check file %s ... ", name);
if (test_verify_file(name) != U_SUCC) {
uffs_Perror(UFFS_ERR_NORMAL, "Verify file %s failed.", name);
return TRUE;
}
uffs_Perror(UFFS_ERR_NORMAL, "Test write file ...");
for (i = 0; i < sizeof(write_test_seq) / sizeof(int) - 1; i++) {
if (test_write_file(name, write_test_seq[i], write_test_seq[i+1]) != U_SUCC) {
uffs_Perror(UFFS_ERR_NORMAL, "Test write file failed !");
return TRUE;
}
}
uffs_Perror(UFFS_ERR_NORMAL, "Check file %s ... ", name);
if (test_verify_file(name) != U_SUCC) {
uffs_Perror(UFFS_ERR_NORMAL, "Verify file %s failed.", name);
return TRUE;
}
uffs_Perror(UFFS_ERR_NORMAL, "Test succ !");
return TRUE;
}
/* open two files and test write */
BOOL cmdTest4(const char *tail)
{
int fd1 = -1, fd2 = -1;
uffs_Perror(UFFS_ERR_NORMAL, "open /a ...");
if ((fd1 = uffs_open("/a", UO_RDWR | UO_CREATE)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open /a");
goto fail_exit;
}
uffs_Perror(UFFS_ERR_NORMAL, "open /b ...");
if ((fd2 = uffs_open("/b", UO_RDWR | UO_CREATE)) < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open /b");
uffs_close(fd1);
goto fail_exit;
}
uffs_Perror(UFFS_ERR_NORMAL, "write (1) to /a ...");
uffs_write(fd1, "Hello,", 6);
uffs_Perror(UFFS_ERR_NORMAL, "write (1) to /b ...");
uffs_write(fd2, "Hello,", 6);
uffs_Perror(UFFS_ERR_NORMAL, "write (2) to /a ...");
uffs_write(fd1, "World.", 6);
uffs_Perror(UFFS_ERR_NORMAL, "write (2) to /b ...");
uffs_write(fd2, "World.", 6);
uffs_Perror(UFFS_ERR_NORMAL, "close /a ...");
uffs_close(fd1);
uffs_Perror(UFFS_ERR_NORMAL, "close /b ...");
uffs_close(fd2);
return TRUE;
fail_exit:
return TRUE;
}
/* test appending file */
BOOL cmdTest5(const char *tail)
{
int fd = -1;
URET ret;
char buf[100];
const char *name;
if (!tail) {
return FALSE;
}
name = cli_getparam(tail, NULL);
fd = uffs_open(name, UO_RDWR|UO_APPEND);
if (fd < 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Can't open %s", name);
goto fail;
}
sprintf(buf, "append test...");
ret = uffs_write(fd, buf, strlen(buf));
if (ret != strlen(buf)) {
uffs_Perror(UFFS_ERR_NORMAL, "write file failed, %d/%d", ret, strlen(buf));
}
else {
uffs_Perror(UFFS_ERR_NORMAL, "write %d bytes to file, content: %s", ret, buf);
}
uffs_close(fd);
fail:
return TRUE;
}
BOOL cmdMount(const char *tail)
{
uffs_MountTable *tab = uffs_GetMountTable();
tail = tail;
while (tab) {
uffs_Perror(UFFS_ERR_NORMAL, " %s : (%d) ~ (%d)", tab->mount, tab->start_block, tab->end_block);
tab = tab->next;
}
return TRUE;
}
static struct cli_commandset cmdset[] =
{
{ cmdFormat, "format", "[<mount>]", "Format device" },
{ cmdMkf, "mkfile", "<name>", "create a new file" },
{ cmdMkdir, "mkdir", "<name>", "create a new directory" },
{ cmdRm, "rm", "<name>", "delete file/directory" },
{ cmdRen, "mv|ren", "<old> <new>", "rename file/directory" },
{ cmdLs, "ls", "<dir>", "list dirs and files" },
{ cmdSt, "info|st", "<mount>", "show statistic infomation" },
{ cmdTest1, "t1", "<name>", "test 1" },
{ cmdTest2, "t2", NULL, "test 2" },
{ cmdTest3, "t3", "<name>", "test 3" },
{ cmdTest4, "t4", NULL, "test 4" },
{ cmdTest5, "t5", "<name>", "test 5" },
{ cmdCp, "cp", "<src> <des>", "copy files. the local file name start with '::'" },
{ cmdCat, "cat", "<name>", "show file content" },
{ cmdPwd, "pwd", NULL, "show current dir" },
{ cmdCd, "cd", "<path>", "change current dir" },
{ cmdMount, "mount", NULL, "list mounted file systems" },
{ NULL, NULL, NULL, NULL }
};
struct cli_commandset * get_helper_cmds()
{
return cmdset;
};

View File

@ -0,0 +1,172 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file test_cmds.c
* \brief commands for test uffs
* \author Ricky Zheng
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uffs/uffs_config.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_fs.h"
#include "uffs/uffs_utils.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_mtb.h"
#include "uffs/uffs_find.h"
#include "uffs/uffs_badblock.h"
#include "cmdline.h"
#define PFX "test:"
static BOOL cmdTestPageReadWrite(const char *tail)
{
TreeNode *node;
uffs_Device *dev;
uffs_Tags local_tag;
uffs_Tags *tag = &local_tag;
int ret;
u16 block;
u16 page;
uffs_Buf *buf;
u32 i;
dev = uffs_GetDeviceFromMountPoint("/");
if (!dev)
goto ext;
buf = uffs_BufClone(dev, NULL);
if (!buf)
goto ext;
node = uffs_TreeGetErasedNode(dev);
if (!node) {
uffs_Perror(UFFS_ERR_SERIOUS, "no free block ?");
goto ext;
}
for (i = 0; i < dev->com.pg_data_size; i++) {
buf->data[i] = i & 0xFF;
}
block = node->u.list.block;
page = 1;
TAG_DATA_LEN(tag) = dev->com.pg_data_size;
TAG_TYPE(tag) = UFFS_TYPE_DATA;
TAG_PAGE_ID(tag) = 3;
TAG_PARENT(tag) = 100;
TAG_SERIAL(tag) = 10;
TAG_BLOCK_TS(tag) = 1;
ret = uffs_FlashWritePageCombine(dev, block, page, buf, tag);
if (UFFS_FLASH_HAVE_ERR(ret)) {
uffs_Perror(UFFS_ERR_SERIOUS, "Write page error: %d", ret);
goto ext;
}
ret = uffs_FlashReadPage(dev, block, page, buf);
if (UFFS_FLASH_HAVE_ERR(ret)) {
uffs_Perror(UFFS_ERR_SERIOUS, "Read page error: %d", ret);
goto ext;
}
for (i = 0; i < dev->com.pg_data_size; i++) {
if (buf->data[i] != (i & 0xFF)) {
uffs_Perror(UFFS_ERR_SERIOUS, "Data verify fail at: %d", i);
goto ext;
}
}
ret = uffs_FlashReadPageSpare(dev, block, page, tag, NULL);
if (UFFS_FLASH_HAVE_ERR(ret)) {
uffs_Perror(UFFS_ERR_SERIOUS, "Read tag (page spare) error: %d", ret);
goto ext;
}
// verify tag:
if (!TAG_IS_DIRTY(tag)) {
uffs_Perror(UFFS_ERR_SERIOUS, "not dirty ? Tag verify fail!");
goto ext;
}
if (!TAG_IS_VALID(tag)) {
uffs_Perror(UFFS_ERR_SERIOUS, "not valid ? Tag verify fail!");
goto ext;
}
if (TAG_DATA_LEN(tag) != dev->com.pg_data_size ||
TAG_TYPE(tag) != UFFS_TYPE_DATA ||
TAG_PAGE_ID(tag) != 3 ||
TAG_PARENT(tag) != 100 ||
TAG_SERIAL(tag) != 10 ||
TAG_BLOCK_TS(tag) != 1) {
uffs_Perror(UFFS_ERR_SERIOUS, "Tag verify fail!");
goto ext;
}
uffs_Perror(UFFS_ERR_SERIOUS, "Page read/write test succ.");
ext:
if (node) {
uffs_FlashEraseBlock(dev, node->u.list.block);
if (HAVE_BADBLOCK(dev))
uffs_BadBlockProcess(dev, node);
else
uffs_InsertToErasedListHead(dev, node);
}
if (dev)
uffs_PutDevice(dev);
if (buf)
uffs_BufFreeClone(dev, buf);
return TRUE;
}
static struct cli_commandset cmdset[] =
{
{ cmdTestPageReadWrite, "t_pgrw", NULL, "test page read/write" },
{ NULL, NULL, NULL, NULL }
};
struct cli_commandset * get_test_cmds()
{
return cmdset;
};

View File

@ -0,0 +1,475 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_fileem.c
* \brief emulate uffs file system
* \author Ricky Zheng, created 9th May, 2005
*/
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "uffs/uffs_device.h"
#include "uffs_fileem.h"
#define PFX "femu: "
#define MAXWRITETIME_PAGE 1
#define MAXWRITETIME_SPARE 1
#define FEMU_MAX_SPARE_SIZE UFFS_MAX_SPARE_SIZE
static u8 em_page_buf[UFFS_MAX_PAGE_SIZE + UFFS_MAX_SPARE_SIZE];
static URET emu_initDevice(uffs_Device *dev);
static URET CheckInit(uffs_Device *dev)
{
int i;
int fSize;
int written;
u8 * p = em_page_buf;
uffs_FileEmu *emu;
int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
pg_size = dev->attr->page_data_size + dev->attr->spare_size;
pgd_size = dev->attr->page_data_size;
sp_size = dev->attr->spare_size;
blk_pgs = dev->attr->pages_per_block;
blks = dev->attr->total_blocks;
blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
emu = (uffs_FileEmu *)(dev->attr->_private);
if (emu->initCount > 0) {
emu->initCount++;
return U_SUCC;
}
if (dev->attr->ecc_opt != UFFS_ECC_NONE &&
dev->attr->ecc_opt != UFFS_ECC_SOFT) {
return U_FAIL; //!< file emulator don't support HW ECC.
}
emu->em_monitor_page = (u8 *) malloc(dev->attr->total_blocks * dev->attr->pages_per_block);
if (!emu->em_monitor_page)
return U_FAIL;
emu->em_monitor_spare = (u8 *) malloc(dev->attr->total_blocks * dev->attr->pages_per_block);
if (!emu->em_monitor_spare)
return U_FAIL;
//clear monitor
memset(emu->em_monitor_page, 0, blks * blk_pgs);
memset(emu->em_monitor_spare, 0, blks * blk_pgs);
emu->fp = fopen(emu->emu_filename, "rb");
if (emu->fp == NULL) {
emu->fp = fopen(emu->emu_filename, "ab+");
if (emu->fp == NULL) {
printf(PFX"Failed to create uffs emulation file.");
return U_FAIL;
}
fseek(emu->fp, 0, SEEK_END);
fSize = ftell(emu->fp);
if (fSize < blk_size * blks) {
printf("Creating uffs emulation file\n");
fseek(emu->fp, 0, SEEK_SET);
memset(p, 0xff, pgd_size + sp_size);
for (i = 0; i < blk_pgs * blks; i++) {
written = fwrite(p, 1, pgd_size + sp_size, emu->fp);
if (written != pgd_size + sp_size) {
printf("Write failed\n");
fclose(emu->fp);
emu->fp = NULL;
return U_FAIL;
}
}
}
}
fflush(emu->fp);
fclose(emu->fp);
emu->fp = fopen(emu->emu_filename, "rb+");
if (emu->fp == NULL) {
printf(PFX"Can't open emulation file.\n");
return U_FAIL;
}
emu->initCount++;
return U_SUCC;
}
static int femu_WritePageData(uffs_Device *dev, u32 block, u32 page_num, const u8 *data, int len, u8 *ecc)
{
int written;
int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
uffs_FileEmu *emu;
emu = (uffs_FileEmu *)(dev->attr->_private);
if (!emu || !(emu->fp))
goto err;
pg_size = dev->attr->page_data_size + dev->attr->spare_size;
pgd_size = dev->attr->page_data_size;
sp_size = dev->attr->spare_size;
blk_pgs = dev->attr->pages_per_block;
blks = dev->attr->total_blocks;
blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
if (len > pgd_size) {
printf("femu: write page data out of range!\n");
goto err;
}
emu->em_monitor_page[block * blk_pgs + page_num]++;
if (emu->em_monitor_page[block * blk_pgs + page_num] > MAXWRITETIME_PAGE) {
printf("Warrning: block %d page %d exceed it's maximum write time!\r\n", block, page_num);
goto err;
}
if (data) {
fseek(emu->fp,
(block * blk_pgs + page_num) *
(pgd_size + sp_size), SEEK_SET);
written = fwrite(data, 1, len, emu->fp);
if (written != len) {
printf("femu: write page I/O error ?\n");
goto err;
}
}
dev->st.page_write_count++;
return UFFS_FLASH_NO_ERR;
err:
return UFFS_FLASH_IO_ERR;
}
static int femu_WritePageSpare(uffs_Device *dev, u32 block, u32 page_num, const u8 *spare, int ofs, int len, UBOOL eod)
{
int written;
int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
uffs_FileEmu *emu;
emu = (uffs_FileEmu *)(dev->attr->_private);
if (!emu || !(emu->fp))
goto err;
pg_size = dev->attr->page_data_size + dev->attr->spare_size;
pgd_size = dev->attr->page_data_size;
sp_size = dev->attr->spare_size;
blk_pgs = dev->attr->pages_per_block;
blks = dev->attr->total_blocks;
blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
// printf("WS: %d/%d, size %d\n", block, page_num, len);
if (len > sp_size) {
printf("femu: write page data out of range!\n");
goto err;
}
emu->em_monitor_spare[block*blk_pgs + page_num]++;
if (emu->em_monitor_spare[block*blk_pgs + page_num] > MAXWRITETIME_SPARE) {
printf("Warrning: block %d page %d (spare) exceed it's maximum write time!\r\n", block, page_num);
goto err;
}
if (spare) {
// simulate power lost ! produce an unclean page.
if (0 && block == 3 && page_num == 2) {
fflush(emu->fp);
exit(1);
}
fseek(emu->fp, (block*blk_pgs + page_num) * (pgd_size + sp_size) + dev->attr->page_data_size + ofs, SEEK_SET);
written = fwrite(spare, 1, len, emu->fp);
if (written != len) {
printf("femu: write spare I/O error ?\n");
goto err;
}
}
if (eod == U_TRUE) {
// eod: U_TRUE -- single write cycle
// eod: U_FALSE -- this is the write after page data
}
fflush(emu->fp);
dev->st.spare_write_count++;
return UFFS_FLASH_NO_ERR;
err:
return UFFS_FLASH_IO_ERR;
}
static URET femu_ReadPageData(uffs_Device *dev, u32 block, u32 page_num, u8 *data, int len, u8 *ecc)
{
int nread;
int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
uffs_FileEmu *emu;
emu = (uffs_FileEmu *)(dev->attr->_private);
if (!emu || !(emu->fp))
goto err;
pg_size = dev->attr->page_data_size + dev->attr->spare_size;
pgd_size = dev->attr->page_data_size;
sp_size = dev->attr->spare_size;
blk_pgs = dev->attr->pages_per_block;
blks = dev->attr->total_blocks;
blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
if (len > pgd_size) {
printf("femu: read page data out of range!\n");
goto err;
}
if (data) {
fseek(emu->fp, (block*blk_pgs + page_num) * (pgd_size + sp_size), SEEK_SET);
nread = fread(data, 1, len, emu->fp);
// for ECC testing.
if (1 && block == 2 && page_num == 3 && len > 13) {
printf("--- ECC error inject to block %d page %d ---\n", block, page_num);
data[13] = (data[13] & ~0x40) | (~(data[13] & 0x40) & 0x40) ;
}
if (nread != len) {
printf("femu: read page I/O error ?\n");
goto err;
}
}
dev->st.page_read_count++;
return UFFS_FLASH_NO_ERR;
err:
return UFFS_FLASH_IO_ERR;
}
static URET femu_ReadPageSpare(uffs_Device *dev, u32 block, u32 page_num, u8 *spare, int ofs, int len)
{
int nread;
int pos;
int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
uffs_FileEmu *emu;
emu = (uffs_FileEmu *)(dev->attr->_private);
if (!emu || !(emu->fp))
goto err;
pg_size = dev->attr->page_data_size + dev->attr->spare_size;
pgd_size = dev->attr->page_data_size;
sp_size = dev->attr->spare_size;
blk_pgs = dev->attr->pages_per_block;
blks = dev->attr->total_blocks;
blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
// printf("RS: %d/%d, size %d\n", block, page_num, len);
if (len > sp_size) {
printf("femu: read page spare out of range!\n");
goto err;
}
if (spare) {
pos = (block*blk_pgs + page_num) * (pgd_size + sp_size) + dev->attr->page_data_size + ofs;
if (fseek(emu->fp, pos, SEEK_SET) != 0) {
printf("femu: seek to %d fail!\n", pos);
goto err;
}
nread= fread(spare, 1, len, emu->fp);
if (nread != len) {
printf("femu: read spare I/O error ?\n");
goto err;
}
}
dev->st.spare_read_count++;
return UFFS_FLASH_NO_ERR;
err:
return UFFS_FLASH_IO_ERR;
}
static URET femu_EraseBlock(uffs_Device *dev, u32 blockNumber)
{
int i;
u8 * pg = em_page_buf;
int pg_size, pgd_size, sp_size, blks, blk_pgs, blk_size;
uffs_FileEmu *emu;
emu = (uffs_FileEmu *)(dev->attr->_private);
if (!emu || !(emu->fp))
goto err;
pg_size = dev->attr->page_data_size + dev->attr->spare_size;
pgd_size = dev->attr->page_data_size;
sp_size = dev->attr->spare_size;
blk_pgs = dev->attr->pages_per_block;
blks = dev->attr->total_blocks;
blk_size = dev->attr->page_data_size * dev->attr->pages_per_block;
printf("femu: erase block %d\n", blockNumber);
if ((int)blockNumber >= blks) {
printf("Attempt to erase non-existant block %d\n",blockNumber);
goto err;
}
else {
//clear this block monitors
memset(emu->em_monitor_page + (blockNumber * blk_pgs),
0,
blk_pgs * sizeof(u8));
memset(emu->em_monitor_spare + (blockNumber * blk_pgs),
0,
blk_pgs * sizeof(u8));
if (1 && (blockNumber == 5)) { // simulate bad block
return UFFS_FLASH_BAD_BLK;
}
memset(pg, 0xff, (pgd_size + sp_size));
fseek(emu->fp, blockNumber * blk_pgs * (pgd_size + sp_size), SEEK_SET);
for (i = 0; i < blk_pgs; i++) {
fwrite(pg, 1, (pgd_size + sp_size), emu->fp);
}
fflush(emu->fp);
dev->st.block_erase_count++;
}
return UFFS_FLASH_NO_ERR;
err:
return UFFS_FLASH_IO_ERR;
}
/////////////////////////////////////////////////////////////////////////////////
#if GCC
static uffs_FlashOps emu_flash_ops = {
.ReadPageData = femu_ReadPageData,
.ReadPageSpare = femu_ReadPageSpare,
.ReadPageSpareLayout = NULL,
.WritePageData = femu_WritePageData,
.WritePageSpare = femu_WritePageSpare,
.WritePageSpareLayout = NULL,
.IsBadBlock = NULL,
.MarkBadBlock = NULL,
.EraseBlock = femu_EraseBlock,
};
#else
static uffs_FlashOps emu_flash_ops = {
femu_ReadPageData,
femu_ReadPageSpare,
NULL, //!< ReadPageSpareLayout, let UFFS do layout
femu_WritePageData,
femu_WritePageSpare,
NULL, //!< WritePageSpareLayout, let UFFS do layout
NULL, //!< IsBadBlock(), let UFFS take care of it.
NULL, //!< MarkBadBlock(), let UFFS take care of it.
femu_EraseBlock,
};
#endif
static URET femu_initDevice(uffs_Device *dev)
{
uffs_Perror(UFFS_ERR_NORMAL, "femu device init.");
dev->ops = &emu_flash_ops; /* EMU device operations */
CheckInit(dev);
return U_SUCC;
}
static URET femu_releaseDevice(uffs_Device *dev)
{
uffs_FileEmu *emu;
uffs_Perror(UFFS_ERR_NORMAL, "femu device release.");
emu = (uffs_FileEmu *)(dev->attr->_private);
emu->initCount--;
if (emu->initCount == 0) {
if (emu->fp) {
fclose(emu->fp);
emu->fp = NULL;
}
memset(emu, 0, sizeof(uffs_FileEmu));
if (emu->em_monitor_page)
free(emu->em_monitor_page);
if (emu->em_monitor_spare)
free(emu->em_monitor_spare);
emu->em_monitor_page = NULL;
emu->em_monitor_spare = NULL;
}
return U_SUCC;
}
void uffs_fileem_setup_device(uffs_Device *dev)
{
dev->Init = femu_initDevice;
dev->Release = femu_releaseDevice;
}
/////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,55 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_fileem.h
* \brief Emulate NAND flash with host file.
* \author Ricky Zheng
*/
#ifndef _UFFS_FILEEM_H_
#define _UFFS_FILEEM_H_
#include "uffs/uffs_device.h"
typedef struct uffs_FileEmuSt {
int initCount;
FILE *fp;
u8 *em_monitor_page;
u8 * em_monitor_spare;
const char *emu_filename;
} uffs_FileEmu;
void uffs_fileem_setup_device(uffs_Device *dev);
#endif

View File

@ -0,0 +1,104 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_os_linux.c
* \brief emulation on linux host
* \author Ricky Zheng
*/
#include "uffs/uffs_os.h"
#include "uffs/uffs_public.h"
#include <memory.h>
#include <stdlib.h>
#include <time.h>
#define PFX "linuxemu:"
int uffs_SemCreate(int n)
{
//TODO: ... create semaphore, return semaphore handler (rather then return n) ...
return n;
}
int uffs_SemWait(int sem)
{
if (sem) {
//TODO: ... wait semaphore available ...
}
return 0;
}
int uffs_SemSignal(int sem)
{
if (sem) {
//TODO: ... release semaphore ...
}
return 0;
}
int uffs_SemDelete(int sem)
{
if (sem) {
//TODO: ... delete semaphore ...
}
return 0;
}
int uffs_OSGetTaskId(void)
{
//TODO: ... return current task ID ...
return 0;
}
void uffs_CriticalEnter(void)
{
//TODO: enter critical section (for example, disable IRQ?)
return;
}
void uffs_CriticalExit(void)
{
//TODO: exit from critical section (for example, enable IRQ?)
return;
}
unsigned int uffs_GetCurDateTime(void)
{
// FIXME: return system time, please modify this for your platform !
// or just return 0 if you don't care about file time.
time_t tvalue;
tvalue = time(NULL);
return (unsigned int)tvalue;
}

View File

@ -0,0 +1,12 @@
INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/emu)
LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/emu)
LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/uffs)
SET(static_mem_SRCS static-mem-allocate.c)
SET(flash_if_SRCS flash-interface-example.c)
ADD_EXECUTABLE(static-mem-example ${static_mem_SRCS})
ADD_EXECUTABLE(flash-if-example ${flash_if_SRCS})
TARGET_LINK_LIBRARIES(static-mem-example emu uffs emu)
TARGET_LINK_LIBRARIES(flash-if-example emu uffs emu)

View File

@ -0,0 +1,310 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.my_application_main_entry
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file flash-interface-example.c
* \brief example for using flash driver and multiple partitions, with static memory allocator.
* \author Ricky Zheng, created at 27 Nov, 2007
*/
#include <string.h>
#include "uffs/uffs_device.h"
#include "uffs/uffs_flash.h"
#include "uffs/uffs_mtb.h"
#include "uffs/uffs_fs.h"
#define PFX "nand-drv:"
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR == 0
int main()
{
uffs_Perror(UFFS_ERR_NORMAL, "This example need CONFIG_USE_STATIC_MEMORY_ALLOCATOR = 1");
return 0;
}
#else
#define USE_SINGLE_WRITE_FUN
#ifdef USE_SINGLE_WRITE_FUN
static int nand_write_full_page(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, const u8 *tag, int tag_len, const u8 *ecc);
#else
static int nand_write_page_data(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, u8 *ecc);
static int nand_write_page_spare(uffs_Device *dev, u32 block, u32 pageNum, const u8 *spare, int ofs, int len, UBOOL eod);
#endif
static int nand_read_page_data(uffs_Device *dev, u32 block, u32 pageNum, u8 *page, int len, u8 *ecc);
static int nand_read_page_spare(uffs_Device *dev, u32 block, u32 pageNum, u8 *spare, int ofs, int len);
static int nand_erase_block(uffs_Device *dev, u32 blockNumber);
static URET nand_init_device(uffs_Device *dev);
#ifdef USE_SINGLE_WRITE_FUN
// if you want to optimize nand flash driver, or use special nand hardware controller,
// or use other NAND driver (for example, eCos NAND lib), you shoud do layout in nand driver.
static int nand_write_full_page(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, const u8 *tag, int tag_len, const u8 *ecc)
{
#define SPOOL(dev) &((dev)->mem.spare_pool)
u8 *spare_buf = NULL;
spare_buf = (u8 *) uffs_PoolGet(SPOOL(dev)); // alloc a spare buffer
// ... START WRITE COMMAND ...
// ...
if (page) {
// WRITE page data
// ....
if (dev->attr->ecc_opt == UFFS_ECC_HW) {
// read ECC from hardware controller to ecc buf,
// ...
}
}
if (tag && tag_len > 0) {
// now, you can use UFFS's layout function
uffs_FlashMakeSpare(dev, (uffs_TagStore *)tag, ecc, spare_buf);
// or, do your own layout
// ....
// WRITE spare_buf to page spare ...
// ...
}
// FINISH write command ...
// ...
// read program status ...
// ...
if (page)
dev->st.page_write_count++;
if (tag)
dev->st.spare_write_count++;
if (spare_buf)
uffs_PoolPut(SPOOL(dev), spare_buf); // release spare buffer
return UFFS_FLASH_NO_ERR;
}
#else
static int nand_write_page_data(uffs_Device *dev, u32 block, u32 pageNum, const u8 *page, int len, u8 *ecc)
{
// send WRITE command
// ... transfer data ...
dev->st.page_write_count++;
return UFFS_FLASH_NO_ERR;
}
static int nand_write_page_spare(uffs_Device *dev, u32 block, u32 pageNum, const u8 *spare, int ofs, int len, UBOOL eod)
{
if (eod == U_FALSE) {
// send WRITE command
}
else {
// do not need to send WRITE command if eod == U_FALSE because 'nand_write_page_data' is called before.
}
// ... transfer data ...
// send COMMIT command
// read STATUS
dev->st.spare_write_count++;
return UFFS_FLASH_NO_ERR;
}
#endif
static int nand_read_page_data(uffs_Device *dev, u32 block, u32 pageNum, u8 *page, int len, u8 *ecc)
{
// send READ command
// ... transfer data ...
// read STATUS
dev->st.page_read_count++;
return UFFS_FLASH_NO_ERR;
}
static int nand_read_page_spare(uffs_Device *dev, u32 block, u32 pageNum, u8 *spare, int ofs, int len)
{
// send READ command
// ... transfer data ...
// read STATUS
dev->st.spare_read_count++;
return UFFS_FLASH_NO_ERR;
}
static int nand_erase_block(uffs_Device *dev, u32 blockNumber)
{
// insert your nand driver codes here ...
dev->st.block_erase_count++;
return UFFS_FLASH_NO_ERR;
}
/////////////////////////////////////////////////////////////////////////////////
static struct uffs_FlashOpsSt my_nand_driver_ops = {
nand_read_page_data, //ReadPageData
nand_read_page_spare, //ReadPageSpare
NULL, //ReadPageSpareWithLayout
#ifdef USE_SINGLE_WRITE_FUN
NULL,
NULL,
nand_write_full_page, //WriteFullPages
#else
nand_write_page_data, //WritePageData
nand_write_page_spare, //WritePageSpare
NULL,
#endif
NULL, //IsBadBlock
NULL, //MarkBadBlock
nand_erase_block, //EraseBlock
};
// change these parameters to fit your nand flash specification
#define MAN_ID MAN_ID_SAMSUNG // simulate Samsung's NAND flash
#define TOTAL_BLOCKS 1024
#define PAGE_DATA_SIZE 512
#define PAGE_SPARE_SIZE 16
#define PAGES_PER_BLOCK 32
#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
#define BLOCK_DATA_SIZE (PAGE_DATA_SIZE * PAGES_PER_BLOCK)
#define NR_PARTITION 2 /* total partitions */
#define PAR_1_BLOCKS 100 /* partition 1 */
#define PAR_2_BLOCKS (TOTAL_BLOCKS - PAR_1_BLOCKS) /* partition 2 */
static struct uffs_StorageAttrSt flash_storage = {0};
/* static alloc the memory for each partition */
static int static_buffer_par1[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_1_BLOCKS) / sizeof(int)];
static int static_buffer_par2[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, PAR_2_BLOCKS) / sizeof(int)];;
static void setup_flash_storage(struct uffs_StorageAttrSt *attr)
{
memset(attr, 0, sizeof(struct uffs_StorageAttrSt));
attr->total_blocks = TOTAL_BLOCKS; /* total blocks */
attr->page_data_size = PAGE_DATA_SIZE; /* page data size */
attr->pages_per_block = PAGES_PER_BLOCK; /* pages per block */
attr->spare_size = PAGE_SPARE_SIZE; /* page spare size */
attr->block_status_offs = 4; /* block status offset is 5th byte in spare */
attr->ecc_opt = UFFS_ECC_SOFT; /* ecc option */
attr->layout_opt = UFFS_LAYOUT_UFFS; /* let UFFS do the spare layout */
}
static URET my_initDevice(uffs_Device *dev)
{
dev->ops = &my_nand_driver_ops;
return U_SUCC;
}
static URET my_releaseDevice(uffs_Device *dev)
{
return U_SUCC;
}
/* define mount table */
static uffs_Device demo_device_1 = {0};
static uffs_Device demo_device_2 = {0};
static uffs_MountTable demo_mount_table[] = {
{ &demo_device_1, 0, PAR_1_BLOCKS - 1, "/data/" },
{ &demo_device_2, PAR_1_BLOCKS, PAR_1_BLOCKS + PAR_2_BLOCKS - 1, "/" },
{ NULL, 0, 0, NULL }
};
static int my_init_filesystem(void)
{
uffs_MountTable *mtbl = &(demo_mount_table[0]);
/* setup nand storage attributes */
setup_flash_storage(&flash_storage);
/* setup memory allocator */
uffs_MemSetupStaticAllocator(&demo_device_1.mem, static_buffer_par1, sizeof(static_buffer_par1));
uffs_MemSetupStaticAllocator(&demo_device_2.mem, static_buffer_par2, sizeof(static_buffer_par2));
/* register mount table */
while(mtbl->dev) {
mtbl->dev->Init = my_initDevice;
mtbl->dev->Release = my_releaseDevice;
mtbl->dev->attr = &flash_storage;
uffs_RegisterMountTable(mtbl);
mtbl++;
}
return uffs_InitMountTable() == U_SUCC ? 0 : -1;
}
/* application entry */
int main()
{
my_init_filesystem();
// ... my application codes ....
// read/write/create/delete files ...
uffs_ReleaseMountTable();
return 0;
}
#endif
/////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,161 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file static-mem-allocate.c
* \brief demostrate how to use static memory allocation. This example use
* file emulated NAND flash.
* \author Ricky Zheng
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uffs/uffs_config.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_fs.h"
#include "uffs/uffs_utils.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_mtb.h"
#include "cmdline.h"
#include "uffs_fileem.h"
#define PFX "static-example: "
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR == 0
int main()
{
uffs_Perror(UFFS_ERR_NORMAL, "This example need CONFIG_USE_STATIC_MEMORY_ALLOCATOR = 1");
return 0;
}
#else
extern struct cli_commandset * get_helper_cmds(void);
#define DEFAULT_EMU_FILENAME "uffsemfile.bin"
#define PAGE_DATA_SIZE 512
#define PAGE_SPARE_SIZE 16
#define PAGES_PER_BLOCK 32
#define TOTAL_BLOCKS 128
#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE)
#define BLOCK_DATA_SIZE (PAGES_PER_BLOCK * PAGE_DATA_SIZE)
#define TOTAL_DATA_SIZE (TOTAL_BLOCKS * BLOCK_DATA_SIZE)
#define BLOCK_SIZE (PAGES_PER_BLOCK * PAGE_SIZE)
#define TOTAL_SIZE (BLOCK_SIZE * TOTAL_BLOCKS)
#define MAX_MOUNT_TABLES 10
#define MAX_MOUNT_POINT_NAME 32
static uffs_Device demo_device = {0};
static struct uffs_MountTableEntrySt demo_mount = {
&demo_device,
0, /* start from block 0 */
-1, /* use whole chip */
"/", /* mount point */
NULL
};
static struct uffs_StorageAttrSt emu_storage = {0};
static struct uffs_FileEmuSt emu_private = {0};
/* static alloc the memory */
static int static_buffer_pool[UFFS_STATIC_BUFF_SIZE(PAGES_PER_BLOCK, PAGE_SIZE, TOTAL_BLOCKS) / sizeof(int)];
static void setup_emu_storage(struct uffs_StorageAttrSt *attr)
{
attr->total_blocks = TOTAL_BLOCKS; /* total blocks */
attr->page_data_size = PAGE_DATA_SIZE; /* page data size */
attr->spare_size = PAGE_SPARE_SIZE; /* page spare size */
attr->pages_per_block = PAGES_PER_BLOCK; /* pages per block */
attr->block_status_offs = 4; /* block status offset is 5th byte in spare */
attr->ecc_opt = UFFS_ECC_SOFT; /* ecc option */
attr->layout_opt = UFFS_LAYOUT_UFFS; /* let UFFS do the spare layout */
}
static void setup_emu_private(uffs_FileEmu *emu)
{
memset(emu, 0, sizeof(uffs_FileEmu));
emu->emu_filename = DEFAULT_EMU_FILENAME;
}
static int init_uffs_fs(void)
{
struct uffs_MountTableEntrySt *mtbl = &demo_mount;
/* setup emu storage */
setup_emu_storage(&emu_storage);
setup_emu_private(&emu_private);
emu_storage._private = &emu_private;
mtbl->dev->attr = &emu_storage;
/* setup memory allocator */
uffs_MemSetupStaticAllocator(&mtbl->dev->mem, static_buffer_pool, sizeof(static_buffer_pool));
/* setup device */
uffs_fileem_setup_device(mtbl->dev);
/* register mount table */
uffs_RegisterMountTable(mtbl);
return uffs_InitMountTable() == U_SUCC ? 0 : -1;
}
static int release_uffs_fs(void)
{
return uffs_ReleaseMountTable();
}
int main(int argc, char *argv[])
{
int ret;
ret = init_uffs_fs();
if (ret != 0) {
printf ("Init file system fail: %d\n", ret);
return -1;
}
cli_add_commandset(get_helper_cmds());
cliMain();
release_uffs_fs();
return 0;
}
#endif

View File

@ -0,0 +1,139 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs.h
* \brief uffs basic defines
* \author Ricky Zheng
*/
#ifndef _UFFS_H_
#define _UFFS_H_
#include "uffs/uffs_types.h"
#ifdef __cplusplus
extern "C"{
#endif
#define UO_RDONLY 0x0000 /** read only */
#define UO_WRONLY 0x0001 /** write only */
#define UO_RDWR 0x0002 /** read and write */
#define UO_APPEND 0x0008 /** append */
#define UO_BINARY 0x0000 /** no used in uffs */
#define UO_CREATE 0x0100
#define UO_TRUNC 0x0200
#define UO_EXCL 0x0400
#define UO_DIR 0x1000 /** open a directory */
#define UENOERR 0 /** no error */
#define UEACCES 1 /** Tried to open read-only file
for writing, or files sharing mode
does not allow specified operations,
or given path is directory */
#define UEEXIST 2 /** _O_CREAT and _O_EXCL flags specified,
but filename already exists */
#define UEINVAL 3 /** Invalid oflag or pmode argument */
#define UEMFILE 4 /** No more file handles available
(too many open files) */
#define UENOENT 5 /** file or path not found */
#define UETIME 6 /** can't set file time */
#define UEBADF 9 /** invalid file handle */
#define UENOMEM 10 /** no enough memory */
#define UEIOERR 11 /** I/O error from lower level flash operation */
#define UENOTDIR 12 /** Not a directory */
#define UEISDIR 13 /** Is a directory */
#define UEUNKNOWN 100 /** unknown error */
#define _SEEK_CUR 0 /** seek from current position */
#define _SEEK_SET 1 /** seek from beginning of file */
#define _SEEK_END 2 /** seek from end of file */
#define USEEK_CUR _SEEK_CUR
#define USEEK_SET _SEEK_SET
#define USEEK_END _SEEK_END
/**
* \def MAX_FILENAME_LENGTH
* \note Be careful: it's part of the physical format (see: uffs_FileInfoSt.name)
* !!DO NOT CHANGE IT AFTER FILE SYSTEM IS FORMATED!!
*/
#define MAX_FILENAME_LENGTH 32
/** \note 8-bits attr goes to uffs_dirent::d_type */
#define FILE_ATTR_DIR (1 << 7) //!< attribute for directory
#define FILE_ATTR_WRITE (1 << 0) //!< writable
/**
* \structure uffs_FileInfoSt
* \brief file/dir entry info in physical storage format
*/
struct uffs_FileInfoSt {
u32 attr; //!< file/dir attribute
u32 create_time;
u32 last_modify;
u32 access;
u32 reserved;
u32 name_len; //!< length of file/dir name
char name[MAX_FILENAME_LENGTH];
};
typedef struct uffs_FileInfoSt uffs_FileInfo;
/**
* \struct uffs_ObjectInfoSt
* \brief object info
*/
typedef struct uffs_ObjectInfoSt {
uffs_FileInfo info;
u32 len; //!< length of file
u16 serial; //!< object serial num
} uffs_ObjectInfo;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,70 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_badblock.h
* \brief bad block management
* \author Ricky Zheng
*/
#ifndef _UFFS_BADBLOCK_H_
#define _UFFS_BADBLOCK_H_
#include "uffs/uffs_public.h"
#include "uffs/uffs_device.h"
#include "uffs/uffs_core.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HAVE_BADBLOCK(dev) (dev->bad.block != UFFS_INVALID_BLOCK)
/** initialize bad block management data structures for uffs device */
void uffs_BadBlockInit(uffs_Device *dev);
/** processing bad block: erase bad block, mark it as 'bad' and put it to bad block list */
void uffs_BadBlockProcess(uffs_Device *dev, TreeNode *node);
/** try to recover data from a new discovered bad block */
void uffs_BadBlockRecover(uffs_Device *dev);
/** put a new block to the bad block waiting list */
void uffs_BadBlockAdd(uffs_Device *dev, int block);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,107 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_blockinfo.h
* \brief data structure for operating block information
* \author Ricky Zheng
*/
#ifndef _UFFS_BLOCKINFO_H_
#define _UFFS_BLOCKINFO_H_
#include "uffs/uffs_types.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_core.h"
#ifdef __cplusplus
extern "C"{
#endif
/**
* \struct uffs_PageSpareSt
* \brief this structure is for storing uffs tag and more.
*/
struct uffs_PageSpareSt {
uffs_Tags tag; //!< page tag
u8 expired:1;
};
/**
* \struct uffs_BlockInfoSt
* \brief block information data. Block info is frequently accessed,
UFFS use a cache system to speed up block info access.
*/
struct uffs_BlockInfoSt {
struct uffs_BlockInfoSt *next;
struct uffs_BlockInfoSt *prev;
u16 block; //!< block number
struct uffs_PageSpareSt *spares; //!< page spare info array
int expired_count; //!< how many pages expired in this block ?
int ref_count; //!< reference counter, it's safe to reuse this block memory when the counter is 0.
};
/** get tag from block info */
#define GET_TAG(bc, page) (&(bc)->spares[page].tag)
/** initialize block info caches */
URET uffs_BlockInfoInitCache(uffs_Device *dev, int maxCachedBlocks);
/** release block info caches */
URET uffs_BlockInfoReleaseCache(uffs_Device *dev);
/** load page spare to block info cache */
URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page);
/** find block info cache */
uffs_BlockInfo * uffs_BlockInfoFindInCache(uffs_Device *dev, int block);
/** get block info cache, load it on demand */
uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block);
/** put info cache back to pool, should be called with #uffs_BlockInfoGet in pairs. */
void uffs_BlockInfoPut(uffs_Device *dev, uffs_BlockInfo *p);
/** explicitly expire a block info cache */
void uffs_BlockInfoExpire(uffs_Device *dev, uffs_BlockInfo *p, int page);
/** no one hold any block info cache ? safe to release block info caches */
UBOOL uffs_BlockInfoIsAllFree(uffs_Device *dev);
/** explicitly expire all block info caches */
void uffs_BlockInfoExpireAll(uffs_Device *dev);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,174 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_buf.h
* \brief page buffers
* \author Ricky Zheng
*/
#ifndef UFFS_BUF_H
#define UFFS_BUF_H
#include "uffs/uffs_types.h"
#include "uffs/uffs_device.h"
#include "uffs/uffs_tree.h"
#include "uffs/uffs_core.h"
#ifdef __cplusplus
extern "C"{
#endif
#define CLONE_BUF_MARK 0xffff //!< set uffs_BufSt::ref_count to this for a 'cloned' buffer
/** for uffs_BufSt::mark */
#define UFFS_BUF_EMPTY 0 //!< buffer is empty
#define UFFS_BUF_VALID 1 //!< buffer is holding valid data
#define UFFS_BUF_DIRTY 2 //!< buffer data is modified
/** for uffs_BufSt::ext_mark */
#define UFFS_BUF_EXT_MARK_TRUNC_TAIL 1 //!<
/** uffs page buffer */
struct uffs_BufSt{
struct uffs_BufSt *next; //!< link to next buffer
struct uffs_BufSt *prev; //!< link to previous buffer
struct uffs_BufSt *next_dirty; //!< link to next dirty buffer
struct uffs_BufSt *prev_dirty; //!< link to previous dirty buffer
u8 type; //!< #UFFS_TYPE_DIR or #UFFS_TYPE_FILE or #UFFS_TYPE_DATA
u16 parent; //!< parent serial
u16 serial; //!< serial
u16 page_id; //!< page id
u16 mark; //!< #UFFS_BUF_EMPTY or #UFFS_BUF_VALID, or #UFFS_BUF_DIRTY ?
u16 ref_count; //!< reference counter, or #CLONE_BUF_MARK for a cloned buffer
u16 data_len; //!< length of data
u16 check_sum; //!< checksum field
u8 * data; //!< data buffer
u8 * header; //!< header
int ext_mark; //!< extension mark.
};
#define uffs_BufIsFree(buf) (buf->ref_count == 0 ? U_TRUE : U_FALSE)
/** initialize page buffers */
URET uffs_BufInit(struct uffs_DeviceSt *dev, int buf_max, int dirty_buf_max);
/** release page buffers */
URET uffs_BufReleaseAll(struct uffs_DeviceSt *dev);
/** find the page buffer, move to link list head if found */
uffs_Buf * uffs_BufGet(struct uffs_DeviceSt *dev, u16 parent, u16 serial, u16 page_id);
uffs_Buf *uffs_BufGetEx(struct uffs_DeviceSt *dev, u8 type, TreeNode *node, u16 page_id);
/** alloc a new page buffer */
uffs_Buf *uffs_BufNew(struct uffs_DeviceSt *dev, u8 type, u16 parent, u16 serial, u16 page_id);
/** find the page buffer (not affect the reference counter) */
uffs_Buf * uffs_BufFind(uffs_Device *dev, u16 parent, u16 serial, u16 page_id);
/** put page buffer back to pool, called in pair with #uffs_Get,#uffs_GetEx or #uffs_BufNew */
URET uffs_BufPut(uffs_Device *dev, uffs_Buf *buf);
/** increase buffer references */
void uffs_BufIncRef(uffs_Buf *buf);
/** decrease buffer references */
void uffs_BufDecRef(uffs_Buf *buf);
/** write data to a page buffer */
URET uffs_BufWrite(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len);
/** read data from a page buffer */
URET uffs_BufRead(struct uffs_DeviceSt *dev, uffs_Buf *buf, void *data, u32 ofs, u32 len);
/** mark buffer as #UFFS_BUF_EMPTY if ref_count == 0, and discard all data it holds */
void uffs_BufMarkEmpty(uffs_Device *dev, uffs_Buf *buf);
/** if there is no free dirty group slot, flush the most dirty group */
URET uffs_BufFlush(struct uffs_DeviceSt *dev);
URET uffs_BufFlushEx(struct uffs_DeviceSt *dev, UBOOL force_block_recover);
/** flush dirty group */
URET uffs_BufFlushGroup(struct uffs_DeviceSt *dev, u16 parent, u16 serial);
URET uffs_BufFlushGroupEx(struct uffs_DeviceSt *dev, u16 parent, u16 serial, UBOOL force_block_recover);
/** find free dirty group slot */
int uffs_BufFindFreeGroupSlot(struct uffs_DeviceSt *dev);
/** find the dirty group slot */
int uffs_BufFindGroupSlot(struct uffs_DeviceSt *dev, u16 parent, u16 serial);
/** lock dirty group */
URET uffs_BufLockGroup(struct uffs_DeviceSt *dev, int slot);
/** unlock dirty group */
URET uffs_BufUnLockGroup(struct uffs_DeviceSt *dev, int slot);
/** flush most dirty group */
URET uffs_BufFlushMostDirtyGroup(struct uffs_DeviceSt *dev);
/** flush all groups under the same parent number */
URET uffs_BufFlushGroupMatchParent(struct uffs_DeviceSt *dev, u16 parent);
/** flush all page buffers */
URET uffs_BufFlushAll(struct uffs_DeviceSt *dev);
/** no one holding any page buffer ? safe to release page buffers */
UBOOL uffs_BufIsAllFree(struct uffs_DeviceSt *dev);
/** are all page buffer marked with #UFFS_BUF_EMPTY ? */
UBOOL uffs_BufIsAllEmpty(struct uffs_DeviceSt *dev);
/** mark all page buffer as #UFFS_BUF_EMPTY */
URET uffs_BufSetAllEmpty(struct uffs_DeviceSt *dev);
/** clone a page buffer */
uffs_Buf * uffs_BufClone(struct uffs_DeviceSt *dev, uffs_Buf *buf);
/** release a cloned page buffer, call in pair with #uffs_BufClone */
URET uffs_BufFreeClone(uffs_Device *dev, uffs_Buf *buf);
/** load physical storage data to page buffer */
URET uffs_BufLoadPhyData(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page);
/** load physical storage data to page buffer withouth checking ECC */
URET uffs_LoadPhyDataToBufEccUnCare(uffs_Device *dev, uffs_Buf *buf, u32 block, u32 page);
/** showing page buffers info, for debug only */
void uffs_BufInspect(uffs_Device *dev);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,277 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_config.h
* \brief basic configuration of uffs
* \author Ricky Zheng
*/
#ifndef _UFFS_CONFIG_H_
#define _UFFS_CONFIG_H_
/**
* \def UFFS_MAX_PAGE_SIZE
* \note maximum page size UFFS support
*/
#define UFFS_MAX_PAGE_SIZE 2048
/**
* \def UFFS_MAX_SPARE_SIZE
*/
#define UFFS_MAX_SPARE_SIZE ((UFFS_MAX_PAGE_SIZE / 256) * 8)
/**
* \def MAX_CACHED_BLOCK_INFO
* \note uffs cache the block info for opened directories and files,
* a practical value is 5 ~ MAX_OBJECT_HANDLE
*/
#define MAX_CACHED_BLOCK_INFO 10
/**
* \def MAX_PAGE_BUFFERS
* \note the bigger value will bring better read/write performance.
* but few writing performance will be improved when this
* value is become larger than 'max pages per block'
*/
#define MAX_PAGE_BUFFERS 10
/**
* \def CLONE_BUFFER_THRESHOLD
* \note reserve buffers for clone. 1 or 2 should be enough.
*/
#define CLONE_BUFFERS_THRESHOLD 2
/**
* \def MAX_SPARE_BUFFERS
* \note spare buffers are used for lower level flash operations, 5 should be enough.
*/
#define MAX_SPARE_BUFFERS 5
/**
* \def MAX_DIRTY_PAGES_IN_A_BLOCK
* \note this value should be between '2' and the lesser of 'max pages per block' and (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD - 1).
* the smaller the value the frequently the buffer will be flushed.
*/
#define MAX_DIRTY_PAGES_IN_A_BLOCK 7
/**
* \def MAX_DIRTY_BUF_GROUPS
*/
#define MAX_DIRTY_BUF_GROUPS 3
/**
* \def CONFIG_USE_STATIC_MEMORY_ALLOCATOR
* \note uffs will use static memory allocator if this is defined.
* to use static memory allocator, you need to provide memory
* buffer when creating uffs_Device.
*
* use UFFS_STATIC_BUFF_SIZE() to calculate memory buffer size.
*/
#define CONFIG_USE_STATIC_MEMORY_ALLOCATOR 0
/**
* \def CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
* \note the native memory allocator should only be used for
* tracking memory leak bugs or tracking memory consuming.
* In your final product, you either disable the native memory
* allocator or use the system heap as the memory pool for the
* native memory allocator.
*/
#define CONFIG_USE_NATIVE_MEMORY_ALLOCATOR 0
/**
* \def CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR
* \note using system platform's 'malloc' and 'free'.
*/
#define CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR 1
/**
* \def CONFIG_FLUSH_BUF_AFTER_WRITE
* \note UFFS will write all data directly into flash in
* each 'write' call if you enable this option.
* (which means lesser data lost when power failue but
* pooer writing performance).
* It's not recommented to open this define for normal applications.
*/
//#define CONFIG_FLUSH_BUF_AFTER_WRITE
/**
* \def CONFIG_TREE_NODE_USE_DOUBLE_LINK
* \note: enable double link tree node will speed up insert/delete operation,
*/
#define CONFIG_TREE_NODE_USE_DOUBLE_LINK
/**
* \def MAX_OBJECT_HANDLE
* maximum number of object handle
*/
#define MAX_OBJECT_HANDLE 10
/**
* \def MAX_DIR_HANDLE
* maximum number of uffs_DIR
*/
#define MAX_DIR_HANDLE 5
/**
* \def MINIMUN_ERASED_BLOCK
* UFFS will not allow appending or creating new files when the free/erased block
* is lower then MINIMUN_ERASED_BLOCK.
*/
#define MINIMUN_ERASED_BLOCK 2
/**
* \def CONFIG_CHANGE_MODIFY_TIME
* \note If defined, closing a file which is opened for writing/appending will
* update the file's modify time as well. Disable this feature will save a
* lot of writing activities if you frequently open files for write and close it.
*/
//#define CONFIG_CHANGE_MODIFY_TIME
/**
* \def CONFIG_ENABLE_BAD_BLOCK_VERIFY
* \note allow erase and verify block marked as 'bad' when format UFFS partition.
* it's not recommented for most NAND flash.
*/
#define CONFIG_ENABLE_BAD_BLOCK_VERIFY
/**
* \def CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
* \note erase block again before mark bad block
*/
#define CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
/**
* \def CONFIG_PAGE_WRITE_VERIFY
* \note verify page data after write, for extra safe data storage.
*/
#define CONFIG_PAGE_WRITE_VERIFY
/**
* \def CONFIG_BAD_BLOCK_POLICY_STRICT
* \note If this is enabled, UFFS will report the block as 'bad' if any bit-flips found;
* otherwise, UFFS report bad block only when ECC failed or reported by low level flash driver.
*
* \note Enable this will ensure your data always be stored on completly good blocks.
*/
#define CONFIG_BAD_BLOCK_POLICY_STRICT
/** micros for calculating buffer sizes */
/**
* \def UFFS_BLOCK_INFO_BUFFER_SIZE
* \brief calculate memory bytes for block info caches
*/
#define UFFS_BLOCK_INFO_BUFFER_SIZE(n_pages_per_block) \
( \
( \
sizeof(uffs_BlockInfo) + \
sizeof(uffs_PageSpare) * n_pages_per_block \
) * MAX_CACHED_BLOCK_INFO \
)
/**
* \def UFFS_PAGE_BUFFER_SIZE
* \brief calculate memory bytes for page buffers
*/
#define UFFS_PAGE_BUFFER_SIZE(n_page_size) \
( \
( \
sizeof(uffs_Buf) + n_page_size \
) * MAX_PAGE_BUFFERS \
)
/**
* \def UFFS_TREE_BUFFER_SIZE
* \brief calculate memory bytes for tree nodes
*/
#define UFFS_TREE_BUFFER_SIZE(n_blocks) (sizeof(TreeNode) * n_blocks)
#define UFFS_SPARE_BUFFER_SIZE (MAX_SPARE_BUFFERS * UFFS_MAX_SPARE_SIZE)
/**
* \def UFFS_STATIC_BUFF_SIZE
* \brief calculate total memory usage of uffs system
*/
#define UFFS_STATIC_BUFF_SIZE(n_pages_per_block, n_page_size, n_blocks) \
( \
UFFS_BLOCK_INFO_BUFFER_SIZE(n_pages_per_block) + \
UFFS_PAGE_BUFFER_SIZE(n_page_size) + \
UFFS_TREE_BUFFER_SIZE(n_blocks) + \
UFFS_SPARE_BUFFER_SIZE \
)
/* config check */
#if (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD) < 3
#error "MAX_PAGE_BUFFERS is too small"
#endif
#if (MAX_DIRTY_PAGES_IN_A_BLOCK < 2)
#error "MAX_DIRTY_PAGES_IN_A_BLOCK should >= 2"
#endif
#if (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD - 1 < MAX_DIRTY_PAGES_IN_A_BLOCK)
#error "MAX_DIRTY_PAGES_IN_A_BLOCK should < (MAX_PAGE_BUFFERS - CLONE_BUFFERS_THRESHOLD)"
#endif
#if defined(CONFIG_PAGE_WRITE_VERIFY) && (CLONE_BUFFERS_THRESHOLD < 2)
#error "CLONE_BUFFERS_THRESHOLD should >= 2 when CONFIG_PAGE_WRITE_VERIFY is enabled."
#endif
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR + CONFIG_USE_NATIVE_MEMORY_ALLOCATOR + CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 1
#error "Please enable ONLY one memory allocator"
#endif
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR + CONFIG_USE_NATIVE_MEMORY_ALLOCATOR + CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR == 0
#error "Please enable ONE of memory allocators"
#endif
#ifdef WIN32
# pragma warning(disable : 4996)
#endif
#endif

View File

@ -0,0 +1,59 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef _UFFS_CORE_H_
#define _UFFS_CORE_H_
#ifdef __cplusplus
extern "C"{
#endif
/** \typedef uffs_Device */
typedef struct uffs_DeviceSt uffs_Device;
/** \typedef uffs_FlashOps */
typedef struct uffs_FlashOpsSt uffs_FlashOps;
typedef struct uffs_BlockInfoSt uffs_BlockInfo;
typedef struct uffs_PageSpareSt uffs_PageSpare;
typedef struct uffs_TagsSt uffs_Tags; //!< UFFS page tags
typedef struct uffs_TagStoreSt uffs_TagStore; //!< UFFS page tags physical store structure
typedef struct uffs_BufSt uffs_Buf;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,191 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_device.h
* \brief uffs device structures definition
* \author Ricky Zheng
*/
#ifndef UFFS_DEVICE_H
#define UFFS_DEVICE_H
#include "uffs/uffs_types.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_buf.h"
#include "uffs/uffs_blockinfo.h"
#include "uffs/uffs_pool.h"
#include "uffs/uffs_tree.h"
#include "uffs/uffs_mem.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_flash.h"
#ifdef __cplusplus
extern "C"{
#endif
/**
* \struct uffs_BlockInfoCacheSt
* \brief block information structure, used to manager block information caches
*/
struct uffs_BlockInfoCacheSt {
uffs_BlockInfo *head; //!< buffer head of block info(spares)
uffs_BlockInfo *tail; //!< buffer tail
void *mem_pool; //!< internal memory pool, used for release whole buffer
};
/**
* \struct uffs_PartitionSt
* \brief partition basic information
*/
struct uffs_PartitionSt {
u16 start; //!< start block number of partition
u16 end; //!< end block number of partiton
};
/**
* \struct uffs_LockSt
* \brief lock stuffs
*/
struct uffs_LockSt {
int sem;
int task_id;
int counter;
};
/**
* \struct uffs_DirtyGroupSt
* \brief manager dirty page buffers
*/
struct uffs_DirtyGroupSt {
int count; //!< dirty buffers count
int lock; //!< dirty group lock (0: unlocked, >0: locked)
uffs_Buf *dirty; //!< dirty buffer list
};
/**
* \struct uffs_PageBufDescSt
* \brief uffs page buffers descriptor
*/
struct uffs_PageBufDescSt {
uffs_Buf *head; //!< head of buffers
uffs_Buf *tail; //!< tail of buffers
struct uffs_DirtyGroupSt dirtyGroup[MAX_DIRTY_BUF_GROUPS]; //!< dirty buffer groups
int buf_max; //!< maximum buffers
int dirty_buf_max; //!< maximum dirty buffer allowed
void *pool; //!< memory pool for buffers
};
/**
* \struct uffs_PageCommInfoSt
* \brief common data for device, should be initialized at early
* \note it is possible that pg_size is smaller than physical page size, but normally they are the same.
* \note page data layout: [HEADER] + [DATA]
*/
struct uffs_PageCommInfoSt {
u16 pg_data_size; //!< page data size
u16 header_size; //!< header size
u16 pg_size; //!< page size
};
/**
* \struct uffs_NewBadBlockSt
* \brief holding new discovered bad block
*/
struct uffs_NewBadBlockSt {
u16 block; //!< bad block, FIX ME to process more than one bad block
};
/**
* \struct uffs_FlashStatSt
* \typedef uffs_FlashStat
* \brief statistic data of flash read/write/erase activities
*/
typedef struct uffs_FlashStatSt {
int block_erase_count;
int page_write_count;
int page_read_count;
int page_header_read_count;
int spare_write_count;
int spare_read_count;
} uffs_FlashStat;
/**
* \struct uffs_DeviceSt
* \brief The core data structure of UFFS, all information needed by manipulate UFFS object
* \note one partition corresponding one uffs device.
*/
struct uffs_DeviceSt {
URET (*Init)(uffs_Device *dev); //!< low level initialization
URET (*Release)(uffs_Device *dev); //!< low level release
void *_private; //!< private data for device
struct uffs_StorageAttrSt *attr; //!< storage attribute
struct uffs_PartitionSt par; //!< partition information
struct uffs_FlashOpsSt *ops; //!< flash operations
struct uffs_BlockInfoCacheSt bc; //!< block info cache
struct uffs_LockSt lock; //!< lock data structure
struct uffs_PageBufDescSt buf; //!< page buffers
struct uffs_PageCommInfoSt com; //!< common information
struct uffs_TreeSt tree; //!< tree list of block
struct uffs_NewBadBlockSt bad; //!< new discovered bad block
struct uffs_FlashStatSt st; //!< statistic (counters)
struct uffs_memAllocatorSt mem; //!< uffs native memory allocator
u32 ref_count; //!< device reference count
int dev_num; //!< device number (partition number)
};
/** create the lock for uffs device */
URET uffs_DeviceInitLock(uffs_Device *dev);
/** delete the lock of uffs device */
URET uffs_DeviceReleaseLock(uffs_Device *dev);
/** lock uffs device */
URET uffs_DeviceLock(uffs_Device *dev);
/** unlock uffs device */
URET uffs_DeviceUnLock(uffs_Device *dev);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,90 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_ecc.h
* \brief file handle operations
* \author Ricky Zheng, created 8th Jun, 2005
*/
#ifndef _UFFS_ECC_H_
#define _UFFS_ECC_H_
#include <string.h>
#include "uffs/uffs_fs.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_core.h"
#ifdef __cplusplus
extern "C"{
#endif
#define MAX_ECC_LENGTH 24 //!< 2K page ecc length is 24 bytes.
/**
* calculate ECC
* \return length of generated ECC. (3 bytes ECC per 256 data)
*/
int uffs_EccMake(void *data, int data_len, void *ecc);
/**
* correct data by ECC.
*
* return: 0 -- no error
* -1 -- can not be corrected
* >0 -- how many bits are corrected
*/
int uffs_EccCorrect(void *data, int data_len, void *read_ecc, const void *test_ecc);
/**
* generate 12 bit ecc for maximum 8 bytes data
*/
u16 uffs_EccMake8(void *data, int data_len);
/**
* correct maximum 8 bytes data from 12 bits ECC
*
* return: 0 -- no error
* -1 -- can not be corrected
* >0 -- how many bits are corrected
*/
int uffs_EccCorrect8(void *data, u16 read_ecc, u16 test_ecc, int errtop);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,150 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_fd.h
* \brief PISIX like file operations
* \author Ricky Zheng, created 8th Jun, 2005
*/
#include "uffs/uffs_config.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_fs.h"
#include "uffs/uffs.h"
#include "uffs/uffs_find.h"
#include <string.h>
/**
* \brief definitions for uffs_stat::st_mode
*/
#define US_IFMT 0xF000 /* file type make */
#define US_IFREG 0x8000 /* regular */
#define US_IFLNK 0xA000 /* symbolic link */
#define US_IFDIR 0x4000 /* directory */
#define US_IREAD 00400 /* read permission */
#define US_IWRITE 00200 /* write permission */
#define US_IRWXU 00700 /* RWX owner */
#define US_IRUSR 00400 /* R owner */
#define US_IWUSR 00200 /* W owner */
#define US_IXUSR 00100 /* X owner */
#define US_IRWXG 00070 /* RWX group */
#define US_IRGRP 00040 /* R group */
#define US_IWGRP 00020 /* W group */
#define US_IXGRP 00010 /* X group */
#define US_IRWXO 00007 /* RWX other */
#define US_IROTH 00004 /* R other */
#define US_IWOTH 00002 /* W other */
#define US_IXOTH 00001 /* X other */
/**
* \brief POSIX dirent
*/
struct uffs_dirent {
int d_ino; /* inode number (serial number or this record) */
char d_name[MAX_FILENAME_LENGTH]; /* name of this record */
int d_off; /* offset to this dirent */
unsigned short int d_reclen; /* length of this uffs_dirent */
unsigned short int d_namelen; /* length of this d_name */
unsigned char d_type; /* type of this record */
};
/**
* \brief POSIX DIR
*/
typedef struct uffs_dirSt {
struct uffs_ObjectSt *obj; /* dir object */
struct uffs_FindInfoSt f; /* find info */
struct uffs_ObjectInfoSt info; /* object info */
struct uffs_dirent dirent; /* dir entry */
} uffs_DIR;
/**
* \brief POSIX stat
*/
struct uffs_stat {
int st_dev; /* ID of device containing file */
int st_ino; /* inode number */
int st_mode; /* protection */
int st_nlink; /* number of hard links */
int st_uid; /* user ID of owner */
int st_gid; /* group ID of owner */
int st_rdev; /* device ID (if special file) */
long st_size; /* total size, in bytes */
int st_blksize; /* blocksize for filesystem I/O */
int st_blocks; /* number of blocks allocated */
u32 st_atime; /* time of last access */
u32 st_mtime; /* time of last modification */
u32 st_ctime; /* time of last status change */
};
URET uffs_InitDirEntryBuf(void);
URET uffs_ReleaseDirEntryBuf(void);
uffs_Pool * uffs_GetDirEntryBufPool(void);
/* POSIX compliant file system APIs */
int uffs_open(const char *name, int oflag, ...);
int uffs_close(int fd);
int uffs_read(int fd, void *data, int len);
int uffs_write(int fd, void *data, int len);
long uffs_seek(int fd, long offset, int origin);
long uffs_tell(int fd);
int uffs_eof(int fd);
int uffs_flush(int fd);
int uffs_rename(const char *old_name, const char *new_name);
int uffs_remove(const char *name);
int uffs_truncate(int fd, long remain);
int uffs_mkdir(const char *name, ...);
int uffs_rmdir(const char *name);
int uffs_stat(const char *name, struct uffs_stat *buf);
int uffs_lstat(const char *name, struct uffs_stat *buf);
int uffs_fstat(int fd, struct uffs_stat *buf);
int uffs_closedir(uffs_DIR *dirp);
uffs_DIR * uffs_opendir(const char *path);
struct uffs_dirent * uffs_readdir(uffs_DIR *dirp);
void uffs_rewinddir(uffs_DIR *dirp);
#if 0
void uffs_seekdir(uffs_DIR *dirp, long loc);
long uffs_telldir(uffs_DIR *dirp);
#endif
int uffs_get_error(void);
int uffs_set_error(int err);

View File

@ -0,0 +1,74 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_find.h
* \brief find objects under dir
* \author Ricky Zheng
*/
#ifndef _UFFS_FIND_H_
#define _UFFS_FIND_H_
#include "uffs/uffs_fs.h"
#ifdef __cplusplus
extern "C"{
#endif
typedef struct uffs_FindInfoSt {
uffs_Device *dev; //!< the device to be searched
u16 serial; //!< the dir serial number
int step; //!< step: 0 - working on dir entries, 1 - working on file entries, 2 - stoped.
int hash; //!< hash entry, internal used
TreeNode *work; //!< working node, internal used.
int pos; //!< current position
} uffs_FindInfo;
URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info, int *err);
URET uffs_FindObjectOpen(uffs_FindInfo *find_handle, uffs_Object *dir);
URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir);
URET uffs_FindObjectFirst(uffs_ObjectInfo *info, uffs_FindInfo *find_handle);
URET uffs_FindObjectNext(uffs_ObjectInfo *info, uffs_FindInfo *find_handle);
URET uffs_FindObjectRewind(uffs_FindInfo *find_handle);
URET uffs_FindObjectClose(uffs_FindInfo * find_handle);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,274 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_public.h
* \brief flash interface for UFFS
* \author Ricky Zheng
*/
#ifndef _UFFS_FLASH_H_
#define _UFFS_FLASH_H_
#include "uffs/uffs_types.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_device.h"
#ifdef __cplusplus
extern "C"{
#endif
/** ECC options (uffs_StorageAttrSt.ecc_opt) */
#define UFFS_ECC_NONE 0 //!< do not use ECC
#define UFFS_ECC_SOFT 1 //!< UFFS calculate the ECC
#define UFFS_ECC_HW 2 //!< Flash driver(or by hardware) calculate the ECC
#define UFFS_ECC_HW_AUTO 3 //!< Hardware calculate the ECC and automatically write to spare.
/** spare layout options (uffs_StorageAttrSt.layout_opt) */
#define UFFS_LAYOUT_UFFS 0 //!< do layout by dev->attr information
#define UFFS_LAYOUT_FLASH 1 //!< flash driver do the layout
#define UFFS_SPARE_LAYOUT_SIZE 6 //!< maximum spare layout array size, 2 segments
/** flash operation return code */
#define UFFS_FLASH_NO_ERR 0 //!< no error
#define UFFS_FLASH_ECC_OK 1 //!< bit-flip found, but corrected by ECC
#define UFFS_FLASH_IO_ERR -1 //!< I/O error
#define UFFS_FLASH_ECC_FAIL -2 //!< ECC failed
#define UFFS_FLASH_BAD_BLK -3 //!< bad block
#define UFFS_FLASH_UNKNOWN_ERR -100 //!< unkown error?
#define UFFS_FLASH_HAVE_ERR(e) ((e) < 0)
#if defined(CONFIG_BAD_BLOCK_POLICY_STRICT)
# define UFFS_FLASH_IS_BAD_BLOCK(e) ((e) == UFFS_FLASH_ECC_FAIL || (e) == UFFS_FLASH_ECC_OK || (e) == UFFS_FLASH_BAD_BLK)
#else
# define UFFS_FLASH_IS_BAD_BLOCK(e) ((e) == UFFS_FLASH_ECC_FAIL || (e) == UFFS_FLASH_BAD_BLK)
#endif
/** defines for page info (data length and data sum) */
#define UFFS_PAGE_INFO_CLEAN 0xFFFFFFFF
#define UFFS_PAGE_INFO_IOERR 0xDEADFFFF
#define UFFS_PAGE_GET_LEN(info) (info & 0xFFFF)
#define UFFS_PAGE_GET_DSUM(info) (info >> 16)
#define UFFS_PAGE_MAKE_INFO(d_len, d_sum) ((d_sum << 16) | d_len)
/**
* \struct uffs_StorageAttrSt
* \brief uffs device storage attribute, provide by nand specific file
*/
struct uffs_StorageAttrSt {
u32 total_blocks; //!< total blocks in this chip
u16 page_data_size; //!< page data size (physical page data size, e.g. 512)
u16 pages_per_block; //!< pages per block
u8 spare_size; //!< page spare size (physical page spare size, e.g. 16)
u8 block_status_offs; //!< block status byte offset in spare
int ecc_opt; //!< ecc option ( #UFFS_ECC_[NONE|SOFT|HW|HW_AUTO] )
int layout_opt; //!< layout option (#UFFS_LAYOUT_UFFS or #UFFS_LAYOUT_FLASH)
const u8 *ecc_layout; //!< page data ECC layout: [ofs1, size1, ofs2, size2, ..., 0xFF, 0]
const u8 *data_layout; //!< spare data layout: [ofs1, size1, ofs2, size2, ..., 0xFF, 0]
u8 _uffs_ecc_layout[UFFS_SPARE_LAYOUT_SIZE]; //!< uffs spare ecc layout
u8 _uffs_data_layout[UFFS_SPARE_LAYOUT_SIZE]; //!< uffs spare data layout
void *_private; //!< private data for storage attribute
};
/**
* \struct uffs_FlashOpsSt
* \brief low level flash operations, should be implement in flash driver
*/
struct uffs_FlashOpsSt {
/**
* Read page data.
*
* if ecc_opt is UFFS_ECC_HW, flash driver must calculate and return ecc (if ecc != NULL).
*
* if ecc_opt is UFFS_ECC_HW_AUTO, flash driver do ecc correction aganist ecc in spare area.
*
* \return #UFFS_FLASH_NO_ERR: success and/or has no flip bits.
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_ECC_FAIL: page data has flip bits and ecc correct failed.
* #UFFS_FLASH_ECC_OK: page data has flip bits and corrected by ecc.
*
* \note pad 0xFF for calculating ECC if len < page_data_size
*/
int (*ReadPageData)(uffs_Device *dev, u32 block, u32 page, u8 *data, int len, u8 *ecc);
/**
* Read page spare [len] bytes from [ofs].
*
* \note flash driver must privide this function.
*
* \return #UFFS_FLASH_NO_ERR: success
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
*
* \note flash driver DO NOT need to do ecc correction for spare data,
* UFFS will take care of spare data ecc.
*/
int (*ReadPageSpare)(uffs_Device *dev, u32 block, u32 page, u8 *spare, int ofs, int len);
/**
* Read page spare, unload to tag and ecc.
*
* \note flash driver must provide this function if layout_opt is UFFS_LAYOUT_FLASH.
* UFFS will use this function (if exist) prio to 'ReadPageSpare()'
*
* \return #UFFS_FLASH_NO_ERR: success
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
*
* \note flash driver DO NOT need to do ecc correction for spare data,
* UFFS will take care of spare data ecc.
*/
int (*ReadPageSpareWithLayout)(uffs_Device *dev, u32 block, u32 page, u8 *tag, int len, u8 *ecc);
/**
* Write page data.
*
* if ecc_opt is UFFS_ECC_HW, flash driver must calculate and return the ecc.
* if ecc_opt is UFFS_ECC_HW_AUTO, do not need to return ecc.
*
* \return #UFFS_FLASH_NO_ERR: success
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_BAD_BLK: a bad block detected.
*
* \note pad 0xFF for calculating ECC if len < page_data_size
*/
int (*WritePageData)(uffs_Device *dev, u32 block, u32 page, const u8 *data, int len, u8 *ecc);
/**
* Write [len] bytes to page spare from [ofs].
*
* \note flash driver must privide this function.
*
* \return #UFFS_FLASH_NO_ERR: success
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_BAD_BLK: a bad block detected.
*/
int (*WritePageSpare)(uffs_Device *dev, u32 block, u32 page, const u8 *spare, int ofs, int len, UBOOL eod);
/**
* Write full page, include page data and spare.
*
* you need to pack spare within nand driver.
*
* \note if layout_opt is UFFS_LAYOUT_FLASH, flash driver must implement this function.
* UFFS will use this function (if provided) prio to 'WritePageData() + WritePageSpare()'
*
* \return #UFFS_FLASH_NO_ERR: success
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_BAD_BLK: a bad block detected.
*/
int (*WriteFullPage)(uffs_Device *dev, u32 block, u32 page, const u8* data, int len, const u8 *ts, int ts_len, const u8 *ecc);
/**
* check block status.
*
* \note flash driver may maintain a bad block table to speed up bad block checking or
* it will require one or two read spare I/O to check block status.
*
* \note if this function is not provided, UFFS check the block_status byte in spare.
*
* \return 1 if it's a bad block, 0 if it's not.
*/
int (*IsBadBlock)(uffs_Device *dev, u32 block);
/**
* Mark a new bad block.
*
* \return 0 if success, otherwise return -1.
*/
int (*MarkBadBlock)(uffs_Device *dev, u32 block);
/**
* Erase a block.
*
* \return #UFFS_FLASH_NO_ERR: success
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_BAD_BLK: a bad block detected.
*/
int (*EraseBlock)(uffs_Device *dev, u32 block);
};
/** make spare from tag store and ecc */
void uffs_FlashMakeSpare(uffs_Device *dev, uffs_TagStore *ts, const u8 *ecc, u8* spare);
/** read page spare, fill tag and ECC */
int uffs_FlashReadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag, u8 *ecc);
/** read page data to page buf and do ECC correct */
int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf);
/** write page data and spare */
int uffs_FlashWritePageCombine(uffs_Device *dev, int block, int page, uffs_Buf *buf, uffs_Tags *tag);
/** Mark this block as bad block */
int uffs_FlashMarkBadBlock(uffs_Device *dev, int block);
/** Is this block a bad block ? */
UBOOL uffs_FlashIsBadBlock(uffs_Device *dev, int block);
/** Erase flash block */
int uffs_FlashEraseBlock(uffs_Device *dev, int block);
/* mark a clean page as 'dirty' (and 'invalid') */
int uffs_FlashMarkDirtyPage(uffs_Device *dev, int block, int page);
/**
* get page head info
*
* \return #UFFS_PAGE_INFO_IOERR if I/O error, otherwise return page info
*/
u32 uffs_FlashGetPageInfo(uffs_Device *dev, int block, int page);
/** load uffs_FileInfo from flash storage */
URET uffs_FlashReadFileinfoPhy(uffs_Device *dev, int block, int page, uffs_FileInfo *info);
/**
* Initialize UFFS flash interface
*/
URET uffs_FlashInterfaceInit(uffs_Device *dev);
/**
* Release UFFS flash interface
*/
URET uffs_FlashInterfaceRelease(uffs_Device *dev);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,137 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_fs.h
* \brief uffs basic file operations
* \author Ricky Zheng
*/
#ifndef _UFFS_FS_H_
#define _UFFS_FS_H_
#include "uffs/uffs_types.h"
#include "uffs/uffs.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_core.h"
#ifdef __cplusplus
extern "C"{
#endif
/** file object */
struct uffs_ObjectSt {
/******* objects manager ********/
int dev_lock_count;
int dev_get_count;
/******** init level 0 ********/
const char * name; //!< pointer to the start of name, for open or create
u32 name_len; //!< name length
u16 sum; //!< sum of name
uffs_Device *dev; //!< uffs device
u32 oflag;
u8 type;
u16 head_pages; //!< data pages on file head block
u16 parent;
/******* init level 1 ********/
TreeNode *node; //!< file entry node in tree
u16 serial;
/******* output ******/
int err; //!< error number
/******* current *******/
u32 pos; //!< current position in file
/***** others *******/
UBOOL attr_loaded; //!< attributes loaded ?
UBOOL open_succ; //!< U_TRUE or U_FALSE
};
typedef struct uffs_ObjectSt uffs_Object;
#define uffs_GetObjectErr(obj) ((obj)->err)
#define uffs_ClearObjectErr(obj) do { (obj)->err = UENOERR; } while (0)
uffs_Pool * uffs_GetObjectPool(void);
URET uffs_InitObjectBuf(void);
URET uffs_ReleaseObjectBuf(void);
uffs_Object * uffs_GetObject(void);
void uffs_PutObject(uffs_Object *obj);
int uffs_GetObjectIndex(uffs_Object *obj);
uffs_Object * uffs_GetObjectByIndex(int idx);
/**
* Re-initialize an object.
* should call this function if you want to re-use an object.
*/
URET uffs_ReInitObject(uffs_Object *obj);
URET uffs_ParseObject(uffs_Object *obj, const char *name);
URET uffs_CreateObjectEx(uffs_Object *obj, uffs_Device *dev,
int dir, const char *name, int name_len, int oflag);
URET uffs_OpenObjectEx(uffs_Object *obj, uffs_Device *dev,
int dir, const char *name, int name_len, int oflag);
URET uffs_OpenObject(uffs_Object *obj, const char *fullname, int oflag);
URET uffs_TruncateObject(uffs_Object *obj, u32 remain);
URET uffs_CreateObject(uffs_Object *obj, const char *fullname, int oflag);
URET uffs_CloseObject(uffs_Object *obj);
int uffs_WriteObject(uffs_Object *obj, const void *data, int len);
int uffs_ReadObject(uffs_Object *obj, void *data, int len);
long uffs_SeekObject(uffs_Object *obj, long offset, int origin);
int uffs_GetCurOffset(uffs_Object *obj);
int uffs_EndOfFile(uffs_Object *obj);
URET uffs_FlushObject(uffs_Object *obj);
URET uffs_RenameObject(const char *old_name, const char *new_name, int *err);
URET uffs_DeleteObject(const char * name, int *err);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,130 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef UFFS_MEM_H
#define UFFS_MEM_H
#include "uffs/uffs_device.h"
#ifdef __cplusplus
extern "C"{
#endif
#define MAX_ECC_SIZE (3 * UFFS_MAX_PAGE_SIZE / 256)
#define MAX_SPARE_SIZE (8 * UFFS_MAX_PAGE_SIZE / 256)
#define MAX_SPARE_BUF 10
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
#define HEAP_HASH_BIT 6 /* hash table bit */
#define HEAP_HASH_SIZE (1 << (HEAP_HASH_BIT - 1)) /* hash table size */
#define HEAP_HASH_MASK (HEAP_HASH_SIZE - 1) /* hash table mask */
#define GET_HASH_INDEX(p) ((((unsigned long)(p)) >> 2) & HEAP_HASH_MASK)
/* memory alloc node */
typedef struct HeapManagementNodeSt{
int task_id; /* who alloc this block? it's the caller's task id */
struct HeapManagementNodeSt * next; /* point to next node */
void *p; /* point to allocated block */
int size; /* block size */
} HeapMm;
typedef HeapMm* HeapHashTable;
/** \note: uffs_MemInitHeap should be called before using native memory allocator on each device */
void uffs_MemInitHeap(void *addr, int size);
URET uffs_MemInitNativeAllocator(uffs_Device *dev);
int uffs_MemReleaseNativeAllocator(uffs_Device *dev);
#endif //CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
/** uffs native memory allocator */
typedef struct uffs_memAllocatorSt {
URET (*init)(struct uffs_DeviceSt *dev); /* init memory allocator, setup buffer sizes */
URET (*release)(struct uffs_DeviceSt *dev); /* release memory allocator (for dynamic memory allocation) */
void * (*malloc)(struct uffs_DeviceSt *dev, unsigned int size); /* allocate memory (for dynamic memory allocation) */
URET (*free)(struct uffs_DeviceSt *dev, void *p); /* free memory (for dynamic memory allocation) */
void * blockinfo_pool_buf; //!< block info cache buffers
void * pagebuf_pool_buf; //!< page buffers
void * tree_nodes_pool_buf; //!< tree nodes buffer
void * spare_pool_buf; //!< spare buffers
int blockinfo_pool_size; //!< block info cache buffers size
int pagebuf_pool_size; //!< page buffers size
int tree_nodes_pool_size; //!< tree nodes buffer size
int spare_pool_size; //!< spare buffer pool size
uffs_Pool tree_pool;
uffs_Pool spare_pool;
int spare_data_size; //!< spare data size, calculated by UFFS.
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
HeapHashTable tbl[HEAP_HASH_SIZE];
int count;
int maxused;
#endif
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
char *buf_start;
int buf_size;
int pos;
#endif
} uffs_MemAllocator;
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
void uffs_MemSetupNativeAllocator(uffs_MemAllocator *allocator);
#endif
#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
void uffs_MemSetupSystemAllocator(uffs_MemAllocator *allocator);
#endif
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
void uffs_MemSetupStaticAllocator(uffs_MemAllocator *allocator, void *pool, int size);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,90 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_mtb.h
* \brief mount table related stuff
* \author Ricky Zheng
*/
#ifndef UFFS_MTB_H
#define UFFS_MTB_H
#include "uffs/uffs_types.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs.h"
#ifdef __cplusplus
extern "C"{
#endif
typedef struct uffs_MountTableEntrySt {
uffs_Device *dev;
int start_block;
int end_block;
const char *mount;
struct uffs_MountTableEntrySt *next;
} uffs_MountTable;
/** initialize registered mount table */
URET uffs_InitMountTable(void);
/** release registered mount table */
URET uffs_ReleaseMountTable(void);
/** get registered mount table */
uffs_MountTable * uffs_GetMountTable(void);
/** register mount table */
int uffs_RegisterMountTable(uffs_MountTable *mtab);
/** get matched mount point from absolute path */
int uffs_GetMatchedMountPointSize(const char *path);
/** get uffs device from mount point */
uffs_Device * uffs_GetDeviceFromMountPoint(const char *mount);
/** get uffs device from mount point */
uffs_Device * uffs_GetDeviceFromMountPointEx(const char *mount, int len);
/** get mount point name from uffs device */
const char * uffs_GetDeviceMountPoint(uffs_Device *dev);
/** down crease uffs device references by uffs_GetDeviceXXX() */
void uffs_PutDevice(uffs_Device *dev);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,65 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef UFFS_OS_H
#define UFFS_OS_H
#ifdef __cplusplus
extern "C"{
#endif
#include "uffs/uffs_device.h"
#include "uffs/uffs_core.h"
#define UFFS_TASK_ID_NOT_EXIST -1
typedef int OSSEM;
/* OS specific functions */
int uffs_SemCreate(int n);
int uffs_SemWait(int sem);
int uffs_SemSignal(int sem);
int uffs_SemDelete(int sem);
void uffs_CriticalEnter(void);
void uffs_CriticalExit(void);
int uffs_OSGetTaskId(void); //get current task id
unsigned int uffs_GetCurDateTime(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,92 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_pool.h
* \brief Fast fixed size memory pool management.
* \author Ricky Zheng, Simon Kallweit
*/
#ifndef _UFFS_POOL_H_
#define _UFFS_POOL_H_
#include "uffs/uffs_types.h"
#ifdef __cplusplus
extern "C"{
#endif
/**
* \struct uffs_PoolEntrySt
* \brief Helper type for free buffer entries.
*/
typedef struct uffs_PoolEntrySt {
struct uffs_PoolEntrySt *next;
} uffs_PoolEntry;
/**
* \struct uffs_PoolSt
* \brief Memory pool.
*/
typedef struct uffs_PoolSt {
u8 *mem; //!< memory pool
u32 buf_size; //!< size of a buffer
u32 num_bufs; //!< number of buffers in the pool
uffs_PoolEntry *free_list; //!< linked list of free buffers
int sem; //!< buffer lock
} uffs_Pool;
URET uffs_PoolInit(uffs_Pool *pool, void *mem, u32 mem_size, u32 buf_size, u32 num_bufs);
URET uffs_PoolRelease(uffs_Pool *pool);
UBOOL uffs_PoolVerify(uffs_Pool *pool, void *p);
void *uffs_PoolGet(uffs_Pool *pool);
void *uffs_PoolGetLocked(uffs_Pool *pool);
int uffs_PoolPut(uffs_Pool *pool, void *p);
int uffs_PoolPutLocked(uffs_Pool *pool, void *p);
void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index);
u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p);
UBOOL uffs_PoolCheckFreeList(uffs_Pool *pool, void *p);
void * uffs_PoolFindNextAllocated(uffs_Pool *pool, void *from);
int uffs_PoolGetFreeCount(uffs_Pool *pool);
#ifdef __cplusplus
}
#endif
#endif // _UFFS_POOL_H_

View File

@ -0,0 +1,243 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_public.h
* \brief public data structures for uffs
* \author Ricky Zheng
*/
#ifndef _UFFS_PUBLIC_H_
#define _UFFS_PUBLIC_H_
#include "uffs/uffs_types.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs.h"
#ifdef __cplusplus
extern "C"{
#endif
/**
* \struct uffs_TagStoreSt
* \brief uffs tag, 8 bytes, will be store in page spare area.
*/
struct uffs_TagStoreSt {
u32 dirty:1; //!< 0: dirty, 1: clear
u32 valid:1; //!< 0: valid, 1: invalid
u32 type:2; //!< block type: #UFFS_TYPE_DIR, #UFFS_TYPE_FILE, #UFFS_TYPE_DATA
u32 block_ts:2; //!< time stamp of block;
u32 data_len:12; //!< length of page data
u32 serial:14; //!< serial number
u32 parent:10; //!< parent's serial number
u32 page_id:6; //!< page id
u32 reserved:4; //!< reserved, for UFFS2
u32 tag_ecc:12; //!< tag ECC
};
#define TAG_ECC_DEFAULT (0xFFF) //!< 12-bit '1'
/**
* \struct uffs_TagStoreSt_8
* \brief this data structure describes the page status, for 8 bytes page spare.
* \note there is no tag ecc for this !
*/
struct uffs_TagStoreSt_8 {
u32 dirty:1; //!< 0: dirty, 1: clear
u32 valid:1; //!< 0: valid, 1: invalid
u32 type:2; //!< block type: #UFFS_TYPE_DIR, #UFFS_TYPE_FILE, #UFFS_TYPE_DATA
u32 block_ts:2; //!< time stamp of block;
u32 page_id:5; //!< page id
u32 parent:7; //!< parent's serial number
u32 serial:8; //!< serial number
u32 data_len:8; //!< length of page data
};
/**
* \struct uffs_TagsSt
*/
struct uffs_TagsSt {
struct uffs_TagStoreSt s; /* store must be the first member */
/** data_sum for file or dir name */
u16 data_sum;
/**
* block_status is not covered by tag_ecc.
* it's loaded from flash but not directly write to flash.
*/
u8 block_status;
/** internal used */
u8 _dirty:1; //!< raw data, before doing ecc correction
u8 _valid:1; //!< raw data, before doing ecc correction
};
/**
* \struct uffs_MiniHeaderSt
* \brief the mini header resides on the head of page data
*/
struct uffs_MiniHeaderSt {
u8 status;
u8 reserved;
u16 crc;
};
/** uffs_TagsSt.dirty */
#define TAG_VALID 0
#define TAG_INVALID 1
/** uffs_TagsSt.valid */
#define TAG_DIRTY 0
#define TAG_CLEAR 1
#define TAG_IS_DIRTY(tag) ((tag)->s.dirty == TAG_DIRTY)
#define TAG_IS_VALID(tag) ((tag)->s.valid == TAG_VALID)
#define TAG_SERIAL(tag) (tag)->s.serial
#define TAG_PARENT(tag) (tag)->s.parent
#define TAG_PAGE_ID(tag) (tag)->s.page_id
#define TAG_DATA_LEN(tag) (tag)->s.data_len
#define TAG_TYPE(tag) (tag)->s.type
#define TAG_BLOCK_TS(tag) (tag)->s.block_ts
int uffs_GetFirstBlockTimeStamp(void);
int uffs_GetNextBlockTimeStamp(int prev);
UBOOL uffs_IsSrcNewerThanObj(int src, int obj);
#include "uffs_device.h"
/********************************** debug & error *************************************/
#define UFFS_ERR_NOISY -1
#define UFFS_ERR_NORMAL 0
#define UFFS_ERR_SERIOUS 1
#define UFFS_ERR_DEAD 2
#define TENDSTR "\n"
//#define UFFS_DBG_LEVEL UFFS_ERR_NORMAL
#define UFFS_DBG_LEVEL UFFS_ERR_NOISY
void uffs_DebugMessage(int level, const char *prefix, const char *suffix, const char *errFmt, ...);
#define uffs_Perror(level, fmt, ... ) \
uffs_DebugMessage(level, PFX, TENDSTR, fmt, ## __VA_ARGS__)
#define uffs_PerrorRaw(level, fmt, ... ) \
uffs_DebugMessage(level, NULL, NULL, fmt, ## __VA_ARGS__)
void uffs_AssertCall(const char *file, int line, const char *msg);
#define uffs_Assert(expr, msg) \
do { \
if (!(expr)) \
uffs_AssertCall(__FILE__, __LINE__, msg); \
} while(0)
/********************************** NAND **********************************************/
//NAND flash specific file must implement these interface
URET uffs_LoadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag);
URET uffs_WritePageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag);
URET uffs_MakePageValid(uffs_Device *dev, int block, int page, uffs_Tags *tag);
UBOOL uffs_IsBlockBad(uffs_Device *dev, uffs_BlockInfo *bc);
/********************************** Public defines *****************************/
/**
* \def UFFS_ALL_PAGES
* \brief UFFS_ALL_PAGES if this value presented, that means the objects are all pages in the block
*/
#define UFFS_ALL_PAGES (0xffff)
/**
* \def UFFS_INVALID_PAGE
* \brief macro for invalid page number
*/
#define UFFS_INVALID_PAGE (0xfffe)
#define UFFS_INVALID_BLOCK (0xfffe)
URET uffs_NewBlock(uffs_Device *dev, u16 block, uffs_Tags *tag, uffs_Buf *buf);
URET uffs_BlockRecover(uffs_Device *dev, uffs_BlockInfo *old, u16 newBlock);
URET uffs_PageRecover(uffs_Device *dev,
uffs_BlockInfo *bc,
u16 oldPage,
u16 newPage,
uffs_Buf *buf);
int uffs_FindFreePageInBlock(uffs_Device *dev, uffs_BlockInfo *bc);
u16 uffs_FindBestPageInBlock(uffs_Device *dev, uffs_BlockInfo *bc, u16 page);
u16 uffs_FindFirstValidPage(uffs_Device *dev, uffs_BlockInfo *bc);
u16 uffs_FindFirstFreePage(uffs_Device *dev, uffs_BlockInfo *bc, u16 pageFrom);
u16 uffs_FindPageInBlockWithPageId(uffs_Device *dev, uffs_BlockInfo *bc, u16 page_id);
u8 uffs_MakeSum8(const void *p, int len);
u16 uffs_MakeSum16(const void *p, int len);
URET uffs_CreateNewFile(uffs_Device *dev, u16 parent, u16 serial, uffs_BlockInfo *bc, uffs_FileInfo *fi);
int uffs_GetBlockFileDataLength(uffs_Device *dev, uffs_BlockInfo *bc, u8 type);
UBOOL uffs_IsPageErased(uffs_Device *dev, uffs_BlockInfo *bc, u16 page);
int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc);
UBOOL uffs_IsDataBlockReguFull(uffs_Device *dev, uffs_BlockInfo *bc);
int uffs_GetBlockTimeStamp(uffs_Device *dev, uffs_BlockInfo *bc);
int uffs_GetDeviceUsed(uffs_Device *dev);
int uffs_GetDeviceFree(uffs_Device *dev);
int uffs_GetDeviceTotal(uffs_Device *dev);
URET uffs_LoadMiniHeader(uffs_Device *dev, int block, u16 page, struct uffs_MiniHeaderSt *header);
/************************************************************************/
/* init functions */
/************************************************************************/
URET uffs_InitDevice(uffs_Device *dev);
URET uffs_ReleaseDevice(uffs_Device *dev);
URET uffs_InitFlashClass(uffs_Device *dev);
#ifdef __cplusplus
}
#endif
#endif // _UFFS_PUBLIC_H_

View File

@ -0,0 +1,221 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef _UFFS_TREE_H_
#define _UFFS_TREE_H_
#include "uffs/uffs_types.h"
#include "uffs/uffs_pool.h"
#include "uffs/uffs_device.h"
#include "uffs/uffs_core.h"
#ifdef __cplusplus
extern "C"{
#endif
#define UFFS_TYPE_DIR 0
#define UFFS_TYPE_FILE 1
#define UFFS_TYPE_DATA 2
#define UFFS_TYPE_RESV 3
#define UFFS_TYPE_INVALID 0xFF
struct BlockListSt { /* 10 bytes */
struct uffs_TreeNodeSt * next;
struct uffs_TreeNodeSt * prev;
u16 block;
};
struct DirhSt { /* 8 bytes */
u16 checksum; /* check sum of dir name */
u16 block;
u16 parent;
u16 serial;
};
struct FilehSt { /* 12 bytes */
u16 block;
u16 checksum; /* check sum of file name */
u16 parent;
u16 serial;
u32 len; /* file length total */
};
struct FdataSt { /* 10 bytes */
u16 block;
u16 parent;
u32 len; /* file data length on this block */
u16 serial;
};
//UFFS TreeNode (14 or 16 bytes)
typedef struct uffs_TreeNodeSt {
union {
struct BlockListSt list;
struct DirhSt dir;
struct FilehSt file;
struct FdataSt data;
} u;
u16 hash_next;
#ifdef CONFIG_TREE_NODE_USE_DOUBLE_LINK
u16 hash_prev;
#endif
} TreeNode;
//TODO: UFFS2 Tree structures
/*
struct FdataSt {
u32 len;
};
struct filebSt {
u16 bls; //how many blocks this file contents ...
u8 offs; //the offset of this file header on FILE block
u8 sum; //short sum of file name
};
//Extra data structure for storing file length information
struct FilehSt {
u32 len;
};
//UFFS2 TreeNode (12 bytes)
typedef struct uffs_TreeNodeSt {
u16 nextIdx;
u16 block;
u16 parent;
u16 serial;
union {
struct FilehSt h;
struct filedSt file;
struct data;
} u;
} TreeNode;
*/
#define EMPTY_NODE 0xffff //!< special index num of empty node.
#define ROOT_DIR_SERIAL 0 //!< serial num of root dir
#define MAX_UFFS_FSN 0x3ff //!< maximum dir|file serial number (uffs_TagStore#parent: 10 bits)
#define MAX_UFFS_FDN 0x3fff //!< maximum file data block serial numbers (uffs_TagStore#serial: 14 bits)
#define PARENT_OF_ROOT 0xfffd //!< parent of ROOT ? kidding me ...
#define INVALID_UFFS_SERIAL 0xffff //!< invalid serial num
#define DIR_NODE_HASH_MASK 0x1f
#define DIR_NODE_ENTRY_LEN (DIR_NODE_HASH_MASK + 1)
#define FILE_NODE_HASH_MASK 0x3f
#define FILE_NODE_ENTRY_LEN (FILE_NODE_HASH_MASK + 1)
#define DATA_NODE_HASH_MASK 0x1ff
#define DATA_NODE_ENTRY_LEN (DATA_NODE_HASH_MASK + 1)
#define FROM_IDX(idx, pool) ((TreeNode *)uffs_PoolGetBufByIndex(pool, idx))
#define TO_IDX(p, pool) ((u16)uffs_PoolGetIndex(pool, (void *) p))
#define GET_FILE_HASH(serial) (serial & FILE_NODE_HASH_MASK)
#define GET_DIR_HASH(serial) (serial & DIR_NODE_HASH_MASK)
#define GET_DATA_HASH(parent, serial) ((parent + serial) & DATA_NODE_HASH_MASK)
struct uffs_TreeSt {
TreeNode *erased; //!< erased block list head
TreeNode *erased_tail; //!< erased block list tail
int erased_count; //!< erased block counter
TreeNode *bad; //!< bad block list
int bad_count; //!< bad block count
u16 dir_entry[DIR_NODE_ENTRY_LEN];
u16 file_entry[FILE_NODE_ENTRY_LEN];
u16 data_entry[DATA_NODE_ENTRY_LEN];
u16 max_serial;
};
URET uffs_TreeInit(uffs_Device *dev);
URET uffs_TreeRelease(uffs_Device *dev);
URET uffs_BuildTree(uffs_Device *dev);
u16 uffs_FindFreeFsnSerial(uffs_Device *dev);
TreeNode * uffs_TreeFindFileNode(uffs_Device *dev, u16 serial);
TreeNode * uffs_TreeFindFileNodeWithParent(uffs_Device *dev, u16 parent);
TreeNode * uffs_TreeFindDirNode(uffs_Device *dev, u16 serial);
TreeNode * uffs_TreeFindDirNodeWithParent(uffs_Device *dev, u16 parent);
TreeNode * uffs_TreeFindFileNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent);
TreeNode * uffs_TreeFindDirNodeByName(uffs_Device *dev, const char *name, u32 len, u16 sum, u16 parent);
TreeNode * uffs_TreeFindDataNode(uffs_Device *dev, u16 parent, u16 serial);
TreeNode * uffs_TreeFindDirNodeByBlock(uffs_Device *dev, u16 block);
TreeNode * uffs_TreeFindFileNodeByBlock(uffs_Device *dev, u16 block);
TreeNode * uffs_TreeFindDataNodeByBlock(uffs_Device *dev, u16 block);
TreeNode * uffs_TreeFindErasedNodeByBlock(uffs_Device *dev, u16 block);
TreeNode * uffs_TreeFindBadNodeByBlock(uffs_Device *dev, u16 block);
#define SEARCH_REGION_DIR 1
#define SEARCH_REGION_FILE 2
#define SEARCH_REGION_DATA 4
#define SEARCH_REGION_BAD 8
#define SEARCH_REGION_ERASED 16
TreeNode * uffs_TreeFindNodeByBlock(uffs_Device *dev, u16 block, int *region);
UBOOL uffs_TreeCompareFileName(uffs_Device *dev, const char *name, u32 len, u16 sum, TreeNode *node, int type);
TreeNode * uffs_TreeGetErasedNode(uffs_Device *dev);
void uffs_InsertNodeToTree(uffs_Device *dev, u8 type, TreeNode *node);
void uffs_InsertToErasedListHead(uffs_Device *dev, TreeNode *node);
void uffs_TreeInsertToErasedListTail(uffs_Device *dev, TreeNode *node);
void uffs_TreeInsertToBadBlockList(uffs_Device *dev, TreeNode *node);
void uffs_BreakFromEntry(uffs_Device *dev, u8 type, TreeNode *node);
void uffs_TreeSetNodeBlock(u8 type, TreeNode *node, u16 block);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,156 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef UFFS_TYPES_H
#define UFFS_TYPES_H
#ifdef __cplusplus
extern "C"{
#endif
#ifdef _UBASE_
#include <sys/utypes.h>
#endif
/**
* \file uffs_types.h
* \brief basic types used on uffs
* \author Ricky Zheng
*/
/* basic types */
/** \typedef i8
* \brief 8 bit integer
*/
typedef char i8;
/** \typedef u8
* \brief 8 bit unsigned integer
*/
typedef unsigned char u8;
/** \typedef i16
* \brief 16 bit integer
*/
typedef short int i16;
/** \typedef u16
* \brief 16 bit unsigned integer
*/
typedef unsigned short int u16;
/** \typedef i32
* \brief 32 bit integer
*/
typedef int i32;
/** \typedef u32
* \brief 32 bit unsigned integer
*/
typedef unsigned int u32;
#ifndef _UBASE_
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* boolean type */
/** \typedef UBOOL
* \brief boolean type for uffs, the value would be: #U_TRUE or #U_FALSE
*/
typedef int UBOOL;
/** \def U_TRUE
* \brief boolean true for uffs
*/
#define U_TRUE (TRUE)
/** \def U_FALSE
* \brief boolean false for uffs
*/
#define U_FALSE (FALSE)
/** \typedef URET
* \brief return type for uffs, should be #U_FAIL or #U_SUCC
*/
typedef int URET;
/** \def U_FAIL
* \brief indicator of fail
*/
#define U_FAIL -1
/** \def U_SUCC
* \brief indicator of successful
*/
#define U_SUCC 0
/** \def IS_SUCC(ret)
* \brief is it successful ?
*/
#define IS_SUCC(ret) (ret >= 0 ? U_TRUE : U_FALSE)
/** \def IS_FAIL(ret)
* \brief is it fail ?
*/
#define IS_FAIL(ret) (ret < 0 ? U_TRUE : U_FALSE)
#ifndef NULL
/** \def NULL
* \brief zero for pointer
*/
#define NULL 0
#endif
#endif // _UBASE_
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,85 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef UFFS_UTILS_H
#define UFFS_UTILS_H
#include "uffs/uffs_types.h"
#include "uffs/uffs_device.h"
#include "uffs/uffs_core.h"
#ifdef __cplusplus
extern "C"{
#endif
//begin method
#define PARTITION_FOLLOW_PRIVATE 0
#define PARTITION_BEGIN_ABSOLUTE 1
//alloc method
#define ALLOC_BY_SIZE 0
#define ALLOC_BY_ABSOLUTE 1
#define ALLOC_USE_FREE 2
//struct uffs_PartitionMakeInfoSt {
// u32 begin_method;
// u32 alloc_method;
// union{
// u32 begin_block;
// u32 begin_offset;
// };
// union{
// u32 end_block;
// u32 size;
// u32 remain_size;
// };
// u32 access;
//};
//
//
//URET uffs_MakePartition(struct uffs_DeviceSt *dev, struct uffs_PartitionMakeInfoSt *pi, int nums);
//
//void uffs_ListPartition(struct uffs_DeviceSt *dev);
//get UFFS disk version, if fail, return 0
int uffs_GetUFFSVersion(struct uffs_DeviceSt *dev);
URET uffs_FormatDevice(uffs_Device *dev);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,54 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
#ifndef UFFS_VERSION_H
#define UFFS_VERSION_H
#ifdef __cplusplus
extern "C"{
#endif
#define UFFS_VERSION 0x01030000 //"01.03.0000"
const char * uffs_Version2Str(int ver);
int uffs_GetVersion(void);
int uffs_GetMainVersion(int ver);
int uffs_GetMinorVersion(int ver);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,49 @@
SET (libuffs_SRCS
uffs_badblock.c
uffs_blockinfo.c
uffs_buf.c
uffs_debug.c
uffs_device.c
uffs_ecc.c
uffs_fd.c
uffs_fs.c
uffs_init.c
uffs_mem.c
uffs_pool.c
uffs_public.c
uffs_tree.c
uffs_utils.c
uffs_mtb.c
uffs_find.c
uffs_flash.c
uffs_version.c
)
SET (HDR ${uffs_SOURCE_DIR}/src/inc/uffs)
SET (libuffs_HEADS
${HDR}/uffs.h
${HDR}/uffs_badblock.h
${HDR}/uffs_blockinfo.h
${HDR}/uffs_buf.h
${HDR}/uffs_config.h
${HDR}/uffs_core.h
${HDR}/uffs_device.h
${HDR}/uffs_ecc.h
${HDR}/uffs_fd.h
${HDR}/uffs_fs.h
${HDR}/uffs_mem.h
${HDR}/uffs_os.h
${HDR}/uffs_pool.h
${HDR}/uffs_public.h
${HDR}/uffs_tree.h
${HDR}/uffs_types.h
${HDR}/uffs_utils.h
${HDR}/uffs_mtb.h
${HDR}/uffs_find.h
${HDR}/uffs_flash.h
${HDR}/uffs_version.h
)
INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
ADD_LIBRARY( uffs STATIC ${libuffs_SRCS} ${libuffs_HEADS} )

View File

@ -0,0 +1,216 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_badblock.c
* \brief bad block checking and recovering
* \author Ricky Zheng, created in 13th Jun, 2005
*/
#include "uffs/uffs_fs.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_ecc.h"
#include "uffs/uffs_badblock.h"
#include <string.h>
#define PFX "bbl: "
void uffs_BadBlockInit(uffs_Device *dev)
{
dev->bad.block = UFFS_INVALID_BLOCK;
}
/**
* \brief process bad block: erase bad block, mark it as 'bad' and put the node to bad block list.
* \param[in] dev uffs device
* \param[in] node bad block tree node (before the block turn 'bad', it must belong to something ...)
*/
void uffs_BadBlockProcess(uffs_Device *dev, TreeNode *node)
{
if (HAVE_BADBLOCK(dev)) {
// mark the bad block
uffs_FlashMarkBadBlock(dev, dev->bad.block);
// and put it into bad block list
if (node != NULL)
uffs_TreeInsertToBadBlockList(dev, node);
//clear bad block mark.
dev->bad.block = UFFS_INVALID_BLOCK;
}
}
/**
* \brief recover bad block
* \param[in] dev uffs device
*/
void uffs_BadBlockRecover(uffs_Device *dev)
{
TreeNode *good, *bad;
uffs_Buf *buf;
u16 i;
u16 page;
uffs_BlockInfo *bc = NULL;
uffs_Tags *tag;
uffs_Tags newTag;
UBOOL succRecov;
UBOOL goodBlockIsDirty = U_FALSE;
int ret;
int region;
u8 type;
if (dev->bad.block == UFFS_INVALID_BLOCK)
return;
// pick up an erased good block
good = uffs_TreeGetErasedNode(dev);
if (good == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, "no free block to replace bad block!");
return;
}
//recover block
bc = uffs_BlockInfoGet(dev, dev->bad.block);
if (bc == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, "can't get bad block info");
return;
}
succRecov = U_TRUE;
for (i = 0; i < dev->attr->pages_per_block; i++) {
page = uffs_FindPageInBlockWithPageId(dev, bc, i);
if(page == UFFS_INVALID_PAGE) {
break; //end of last valid page, normal break
}
page = uffs_FindBestPageInBlock(dev, bc, page);
tag = GET_TAG(bc, page);
buf = uffs_BufClone(dev, NULL);
if (buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, "Can't clone a new buf!");
succRecov = U_FALSE;
break;
}
//NOTE: since this is a bad block, we can't guarantee the data is ECC ok, so just load data even ECC is not OK.
ret = uffs_LoadPhyDataToBufEccUnCare(dev, buf, bc->block, page);
if (ret == U_FAIL) {
uffs_Perror(UFFS_ERR_SERIOUS, "I/O error ?");
uffs_BufFreeClone(dev, buf);
succRecov = U_FALSE;
break;
}
buf->data_len = TAG_DATA_LEN(tag);
if (buf->data_len > dev->com.pg_data_size) {
uffs_Perror(UFFS_ERR_NOISY, "data length over flow!!!");
buf->data_len = dev->com.pg_data_size;
}
buf->parent = TAG_PARENT(tag);
buf->serial = TAG_SERIAL(tag);
buf->type = TAG_TYPE(tag);
buf->page_id = TAG_PAGE_ID(tag);
newTag = *tag;
TAG_BLOCK_TS(&newTag) = uffs_GetNextBlockTimeStamp(TAG_BLOCK_TS(tag));
ret = uffs_FlashWritePageCombine(dev, good->u.list.block, i, buf, &newTag);
goodBlockIsDirty = U_TRUE;
uffs_BufFreeClone(dev, buf);
if (ret == UFFS_FLASH_IO_ERR) {
uffs_Perror(UFFS_ERR_NORMAL, "I/O error ?");
succRecov = U_FALSE;
break;
}
}
if (succRecov == U_TRUE) {
//successful recover bad block, so need to mark bad block, and replace with good one
region = SEARCH_REGION_DIR|SEARCH_REGION_FILE|SEARCH_REGION_DATA;
bad = uffs_TreeFindNodeByBlock(dev, dev->bad.block, &region);
if (bad != NULL) {
switch (region) {
case SEARCH_REGION_DIR:
bad->u.dir.block = good->u.list.block;
type = UFFS_TYPE_DIR;
break;
case SEARCH_REGION_FILE:
bad->u.file.block = good->u.list.block;
type = UFFS_TYPE_FILE;
break;
case SEARCH_REGION_DATA:
bad->u.data.block = good->u.list.block;
type = UFFS_TYPE_DATA;
}
//from now, the 'bad' is actually good block :)))
uffs_Perror(UFFS_ERR_NOISY, "new bad block %d found, and replaced by %d!", dev->bad.block, good->u.list.block);
uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
//we reuse the 'good' node as bad block node, and process the bad block.
good->u.list.block = dev->bad.block;
uffs_BadBlockProcess(dev, good);
}
else {
uffs_Perror(UFFS_ERR_SERIOUS, "can't find the reported bad block(%d) in the tree???", dev->bad.block);
if (goodBlockIsDirty == U_TRUE)
dev->ops->EraseBlock(dev, good->u.list.block);
uffs_TreeInsertToErasedListTail(dev, good);
}
}
else {
if (goodBlockIsDirty == U_TRUE)
dev->ops->EraseBlock(dev, good->u.list.block);
uffs_TreeInsertToErasedListTail(dev, good); //put back to erased list
}
uffs_BlockInfoPut(dev, bc);
}
/** put a new block to the bad block waiting list */
void uffs_BadBlockAdd(uffs_Device *dev, int block)
{
if (dev->bad.block == block)
return;
if (dev->bad.block != UFFS_INVALID_BLOCK)
uffs_Perror(UFFS_ERR_SERIOUS, "Can't add more then one bad block !");
else
dev->bad.block = block;
}

View File

@ -0,0 +1,387 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_blockinfo.c
* \brief block information cache system manipulations
* \author Ricky Zheng, created 10th May, 2005
*/
#include "uffs/uffs_blockinfo.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_os.h"
#include <string.h>
#define PFX "bc : "
#define UFFS_CLONE_BLOCK_INFO_NEXT ((uffs_BlockInfo *)(-2))
/**
* \brief before block info cache is enable, this function should be called to initialize it
*
* \param[in] dev uffs device
* \param[in] maxCachedBlocks maximum cache buffers to be allocated
* \return result of initialization
* \retval U_SUCC successful
* \retval U_FAIL failed
*/
URET uffs_BlockInfoInitCache(uffs_Device *dev, int maxCachedBlocks)
{
uffs_BlockInfo * blockInfos = NULL;
uffs_PageSpare * pageSpares = NULL;
void * buf = NULL;
uffs_BlockInfo *work = NULL;
int size, i, j;
if (dev->bc.head != NULL) {
uffs_Perror(UFFS_ERR_NOISY, "block info cache has been inited already, now release it first.");
uffs_BlockInfoReleaseCache(dev);
}
size = (
sizeof(uffs_BlockInfo) +
sizeof(uffs_PageSpare) * dev->attr->pages_per_block
) * maxCachedBlocks;
if (dev->mem.blockinfo_pool_size == 0) {
if (dev->mem.malloc) {
dev->mem.blockinfo_pool_buf = dev->mem.malloc(dev, size);
if (dev->mem.blockinfo_pool_buf) dev->mem.blockinfo_pool_size = size;
}
}
if (size > dev->mem.blockinfo_pool_size) {
uffs_Perror(UFFS_ERR_DEAD, "Block cache buffer require %d but only %d available.", size, dev->mem.blockinfo_pool_size);
return U_FAIL;
}
uffs_Perror(UFFS_ERR_NOISY, "alloc info cache %d bytes.", size);
buf = dev->mem.blockinfo_pool_buf;
memset(buf, 0, size);
dev->bc.mem_pool = buf;
size = 0;
blockInfos = (uffs_BlockInfo *)buf;
size += sizeof(uffs_BlockInfo) * maxCachedBlocks;
pageSpares = (uffs_PageSpare *)((char *)buf + size);
//initialize block info
work = &(blockInfos[0]);
dev->bc.head = work;
work->ref_count = 0;
work->prev = NULL;
work->next = &(blockInfos[1]);
work->block = UFFS_INVALID_BLOCK;
for (i = 0; i < maxCachedBlocks - 2; i++) {
work = &(blockInfos[i+1]);
work->prev = &(blockInfos[i]);
work->next = &(blockInfos[i+2]);
work->ref_count = 0;
work->block = UFFS_INVALID_BLOCK;
}
//the last node
work = &(blockInfos[i+1]);
work->prev = &(blockInfos[i]);
work->next = NULL;
work->block = UFFS_INVALID_BLOCK;
work->ref_count = 0;
dev->bc.tail = work;
//initialize spares
work = dev->bc.head;
for (i = 0; i < maxCachedBlocks; i++) {
work->spares = &(pageSpares[i*dev->attr->pages_per_block]);
for (j = 0; j < dev->attr->pages_per_block; j++) {
work->spares[j].expired = 1;
}
work->expired_count = dev->attr->pages_per_block;
work = work->next;
}
return U_SUCC;
}
/**
* \brief release all allocated memory of block info cache,
* this function should be called when unmount file system
* \param[in] dev uffs device
*/
URET uffs_BlockInfoReleaseCache(uffs_Device *dev)
{
uffs_BlockInfo *work;
if (dev->bc.head) {
for (work = dev->bc.head; work != NULL; work = work->next) {
if (work->ref_count != 0) {
uffs_Perror(UFFS_ERR_SERIOUS, "There have refed block info cache, release cache fail.");
return U_FAIL;
}
}
if (dev->mem.free) {
dev->mem.free(dev, dev->bc.mem_pool);
}
}
dev->bc.head = dev->bc.tail = NULL;
dev->bc.mem_pool = NULL;
return U_SUCC;
}
static void _BreakBcFromList(uffs_Device *dev, uffs_BlockInfo *bc)
{
if (bc->prev)
bc->prev->next = bc->next;
if (bc->next)
bc->next->prev = bc->prev;
if (dev->bc.head == bc)
dev->bc.head = bc->next;
if (dev->bc.tail == bc)
dev->bc.tail = bc->prev;
}
static void _InsertToBcListTail(uffs_Device *dev, uffs_BlockInfo *bc)
{
bc->next = NULL;
bc->prev = dev->bc.tail;
bc->prev->next = bc;
dev->bc.tail = bc;
}
static void _MoveBcToTail(uffs_Device *dev, uffs_BlockInfo *bc)
{
_BreakBcFromList(dev, bc);
_InsertToBcListTail(dev, bc);
}
/**
* \brief load page spare data to given block info structure with given page number
* \param[in] dev uffs device
* \param[in] work given block info to be filled with
* \param[in] page given page number to be read from, if #UFFS_ALL_PAGES is presented, it will read
* all pages, otherwise it will read only one given page.
* \return load result
* \retval U_SUCC successful
* \retval U_FAIL fail to load
* \note work->block must be set before load block info
*/
URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page)
{
int i, ret;
uffs_PageSpare *spare;
if (page == UFFS_ALL_PAGES) {
for (i = 0; i < dev->attr->pages_per_block; i++) {
spare = &(work->spares[i]);
if (spare->expired == 0)
continue;
ret = uffs_FlashReadPageSpare(dev, work->block, i, &(spare->tag), NULL);
if (UFFS_FLASH_HAVE_ERR(ret)) {
uffs_Perror(UFFS_ERR_SERIOUS, "load block %d page %d spare fail.", work->block, i);
return U_FAIL;
}
spare->expired = 0;
work->expired_count--;
}
}
else {
if (page < 0 || page >= dev->attr->pages_per_block) {
uffs_Perror(UFFS_ERR_SERIOUS, "page out of range !");
return U_FAIL;
}
spare = &(work->spares[page]);
if (spare->expired != 0) {
ret = uffs_FlashReadPageSpare(dev, work->block, page, &(spare->tag), NULL);
if (UFFS_FLASH_HAVE_ERR(ret)) {
uffs_Perror(UFFS_ERR_SERIOUS, "load block %d page %d spare fail.", work->block, page);
return U_FAIL;
}
spare->expired = 0;
work->expired_count--;
}
}
return U_SUCC;
}
/**
* \brief find a block cache with given block number
* \param[in] dev uffs device
* \param[in] block block number
* \return found block cache
* \retval NULL cache not found
* \retval non-NULL found cache pointer
*/
uffs_BlockInfo * uffs_BlockInfoFindInCache(uffs_Device *dev, int block)
{
uffs_BlockInfo *work;
//search cached block
for (work = dev->bc.head; work != NULL; work = work->next) {
if (work->block == block) {
work->ref_count++;
return work;
}
}
return NULL;
}
/**
* \brief Find a cached block in cache pool, if the cached block exist then return the pointer,
* if the block does not cached already, find a non-used cache. if all of cached are
* used out, return NULL.
* \param[in] dev uffs device
* \param[in] block block number to be found
* \return found block cache buffer
* \retval NULL caches used out
* \retval non-NULL buffer pointer of given block
*/
uffs_BlockInfo * uffs_BlockInfoGet(uffs_Device *dev, int block)
{
uffs_BlockInfo *work;
int i;
//search cached block
if ((work = uffs_BlockInfoFindInCache(dev, block)) != NULL) {
_MoveBcToTail(dev, work);
return work;
}
//can't find block from cache, need to find a free(unlocked) cache
for (work = dev->bc.head; work != NULL; work = work->next) {
if(work->ref_count == 0) break;
}
if (work == NULL) {
//caches used out !
uffs_Perror(UFFS_ERR_SERIOUS, "insufficient block info cache");
return NULL;
}
work->block = block;
work->expired_count = dev->attr->pages_per_block;
for (i = 0; i < dev->attr->pages_per_block; i++) {
work->spares[i].expired = 1;
}
work->ref_count = 1;
_MoveBcToTail(dev, work);
return work;
}
/**
* \brief put block info buffer back to pool, should be called with #uffs_BlockInfoGet in pairs.
* \param[in] dev uffs device
* \param[in] p pointer of block info buffer
*/
void uffs_BlockInfoPut(uffs_Device *dev, uffs_BlockInfo *p)
{
dev = dev;
if (p->ref_count == 0) {
uffs_Perror(UFFS_ERR_SERIOUS, "Put an unused block info cache back ?");
}
else {
p->ref_count--;
}
}
/**
* \brief make the given pages expired in given block info buffer
* \param[in] dev uffs device
* \param[in] p pointer of block info buffer
* \param[in] page given page number. if #UFFS_ALL_PAGES presented, all pages in the block should be made expired.
*/
void uffs_BlockInfoExpire(uffs_Device *dev, uffs_BlockInfo *p, int page)
{
int i;
uffs_PageSpare *spare;
if (page == UFFS_ALL_PAGES) {
for (i = 0; i < dev->attr->pages_per_block; i++) {
spare = &(p->spares[i]);
if (spare->expired == 0) {
spare->expired = 1;
p->expired_count++;
}
}
}
else {
if (page >= 0 && page < dev->attr->pages_per_block) {
spare = &(p->spares[page]);
if (spare->expired == 0) {
spare->expired = 1;
p->expired_count++;
}
}
}
}
/**
* Is all blcok info cache free (not referenced) ?
*/
UBOOL uffs_BlockInfoIsAllFree(uffs_Device *dev)
{
uffs_BlockInfo *work;
work = dev->bc.head;
while (work) {
if (work->ref_count != 0)
return U_FALSE;
work = work->next;
}
return U_TRUE;
}
void uffs_BlockInfoExpireAll(uffs_Device *dev)
{
uffs_BlockInfo *bc;
bc = dev->bc.head;
while (bc) {
uffs_BlockInfoExpire(dev, bc, UFFS_ALL_PAGES);
bc = bc->next;
}
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_debug.c
* \brief output debug messages
* \author Ricky Zheng, created 10th May, 2005
*/
#include "uffs/uffs_public.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#if !defined(_UBASE_)
#define ENABLE_DEBUG
//#define OUTPUT_TOFILE
#endif
#if !defined(_UBASE_)
#ifdef OUTPUT_TOFILE
#define DEBUG_LOGFILE "log.txt"
#endif
void uffs_DebugMessage(int level, const char *prefix, const char *suffix, const char *errFmt, ...)
{
#ifdef ENABLE_DEBUG
if (level >= UFFS_DBG_LEVEL) {
char buf[1024] = {0};
char *p;
#ifdef OUTPUT_TOFILE
FILE *fp = NULL;
#endif
va_list arg;
if (strlen(errFmt) > 800) {
// dangerous!!
printf("uffs_Perror buffer is not enough !");
return;
}
p = buf;
if (prefix) {
strcpy(p, prefix);
p += strlen(prefix);
}
va_start(arg, errFmt);
vsprintf(p, errFmt, arg);
va_end(arg);
if (suffix)
strcat(p, suffix);
#ifdef OUTPUT_TOFILE
fp = fopen(DEBUG_LOGFILE, "a+b");
if (fp) {
fwrite(buf, 1, strlen(buf), fp);
fclose(fp);
}
#else
printf("%s", buf);
#endif
}
#endif //ENABLE_DEBUG
}
#else
#define ENABLE_DEBUG
#include <uBase.h>
#include <sys/debug.h>
void uffs_Perror( int level, const char *errFmt, ...)
{
#ifdef ENABLE_DEBUG
va_list args;
if (level >= UFFS_DBG_LEVEL) {
va_start(args, errFmt);
//uffs_vTrace(errFmt, args);
dbg_simple_vprintf(errFmt, args);
va_end(args);
}
dbg_simple_raw(TENDSTR);
#else
level = level;
errFmt = errFmt;
#endif //ENABLE_DEBUG
}
#endif
/**
* \brief Called when an assert occurred.
* This method is called when an assert occurred and should stop the
* application from running, as this there is a severe error condition.
* \param[in] file Source filename
* \param[in] line Source line of code
* \param[in] msg Assert message
*/
void uffs_AssertCall(const char *file, int line, const char *msg)
{
printf("ASSERT %s:%d - msg:%s\n", file, line, msg);
while (1);
}

View File

@ -0,0 +1,94 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_device.c
* \brief uffs device operation
* \author Ricky Zheng, created 10th May, 2005
*/
#include "uffs/uffs_device.h"
#include "uffs/uffs_os.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_mtb.h"
#include <string.h>
#define PFX "dev: "
URET uffs_DeviceInitLock(uffs_Device *dev)
{
dev->lock.sem = uffs_SemCreate(1);
dev->lock.task_id = UFFS_TASK_ID_NOT_EXIST;
dev->lock.counter = 0;
return U_SUCC;
}
URET uffs_DeviceReleaseLock(uffs_Device *dev)
{
if (dev->lock.sem) {
uffs_SemDelete(dev->lock.sem);
dev->lock.sem = 0;
}
return U_SUCC;
}
URET uffs_DeviceLock(uffs_Device *dev)
{
uffs_SemWait(dev->lock.sem);
if (dev->lock.counter != 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Lock device, counter %d NOT zero?!", dev->lock.counter);
}
dev->lock.counter++;
return U_SUCC;
}
URET uffs_DeviceUnLock(uffs_Device *dev)
{
dev->lock.counter--;
if (dev->lock.counter != 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Unlock device, counter %d NOT zero?!", dev->lock.counter);
}
uffs_SemSignal(dev->lock.sem);
return U_SUCC;
}

View File

@ -0,0 +1,357 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_ecc.c
* \brief ecc maker and correct
* \author Ricky Zheng, created in 12th Jun, 2005
*/
#include "uffs/uffs_fs.h"
#include "uffs/uffs_config.h"
#include <string.h>
#define PFX "ecc: "
static const u8 bits_tbl[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,
};
static const u8 line_parity_tbl[16] = {
0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a, 0x80, 0x82, 0x88, 0x8a, 0xa0, 0xa2, 0xa8, 0xaa
};
static const u8 line_parity_prime_tbl[16] = {
0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55
};
static const u8 column_parity_tbl[256] = {
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,
};
/**
* calculate 3 bytes ECC for 256 bytes data.
*
* \param[in] data input data
* \param[out] ecc output ecc
* \param[in] length of data in bytes
*/
static void uffs_EccMakeChunk256(void *data, void *ecc, u16 len)
{
u8 *pecc = (u8 *)ecc;
u8 *p = (u8 *)data;
u8 b, col_parity = 0, line_parity = 0, line_parity_prime = 0;
u16 i;
for (i = 0; i < len; i++) {
b = column_parity_tbl[*p++];
col_parity ^= b;
if (b & 0x01) { // odd number of bits in the byte
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
// ECC layout:
// Byte[0] P64 | P64' | P32 | P32' | P16 | P16' | P8 | P8'
// Byte[1] P1024 | P1024' | P512 | P512' | P256 | P256' | P128 | P128'
// Byte[2] P4 | P4' | P2 | P2' | P1 | P1' | 1 | 1
pecc[0] = ~(line_parity_tbl[line_parity & 0xf] | line_parity_prime_tbl[line_parity_prime & 0xf]);
pecc[1] = ~(line_parity_tbl[line_parity >> 4] | line_parity_prime_tbl[line_parity_prime >> 4]);
pecc[2] = (~col_parity) | 0x03;
}
/**
* calculate ECC. (3 bytes ECC per 256 data)
*
* \param[in] data input data
* \param[in] data_len length of data in byte
* \param[out] ecc output ecc
*
* \return length of ECC in byte. (3 bytes ECC per 256 data)
*/
int uffs_EccMake(void *data, int data_len, void *ecc)
{
u8 *p_data = (u8 *)data, *p_ecc = (u8 *)ecc;
int len;
if (data == NULL || ecc == NULL)
return 0;
while (data_len > 0) {
len = data_len > 256 ? 256 : data_len;
uffs_EccMakeChunk256(p_data, p_ecc, len);
data_len -= len;
p_data += len;
p_ecc += 3;
}
return p_ecc - (u8 *)ecc;
}
/**
* perform ECC error correct for 256 bytes data chunk.
*
* \param[in|out] data input data to be corrected
* \param[in] read_ecc 3 bytes ECC read from storage
* \param[in] test_ecc 3 bytes ECC calculated from data
* \param[in] errtop top position of error
*
* \return: 0 -- no error
* -1 -- can not be corrected
* >0 -- how many bits corrected
*/
static int uffs_EccCorrectChunk256(void *data, void *read_ecc, const void *test_ecc, int errtop)
{
u8 d0, d1, d2; /* deltas */
u8 *p = (u8 *)data;
u8 *pread_ecc = (u8 *)read_ecc, *ptest_ecc = (u8 *)test_ecc;
d0 = pread_ecc[0] ^ ptest_ecc[0];
d1 = pread_ecc[1] ^ ptest_ecc[1];
d2 = pread_ecc[2] ^ ptest_ecc[2];
if ((d0 | d1 | d2) == 0)
return 0;
if( ((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
((d2 ^ (d2 >> 1)) & 0x54) == 0x54)
{
// Single bit (recoverable) error in data
u8 b;
u8 bit;
bit = b = 0;
if(d1 & 0x80) b |= 0x80;
if(d1 & 0x20) b |= 0x40;
if(d1 & 0x08) b |= 0x20;
if(d1 & 0x02) b |= 0x10;
if(d0 & 0x80) b |= 0x08;
if(d0 & 0x20) b |= 0x04;
if(d0 & 0x08) b |= 0x02;
if(d0 & 0x02) b |= 0x01;
if(d2 & 0x80) bit |= 0x04;
if(d2 & 0x20) bit |= 0x02;
if(d2 & 0x08) bit |= 0x01;
if (b >= errtop) return -1;
p[b] ^= (1 << bit);
return 1;
}
if ((bits_tbl[d0] + bits_tbl[d1] + bits_tbl[d2]) == 1) {
// error in ecc, no action need
return 1;
}
// Unrecoverable error
return -1;
}
/**
* perform ECC error correct
*
* \param[in|out] data input data to be corrected
* \param[in] data_len length of data in byte
* \param[in] read_ecc ECC read from storage
* \param[in] test_ecc ECC calculated from data
*
* \return: 0 -- no error
* -1 -- can not be corrected
* >0 -- how many bits corrected
*/
int uffs_EccCorrect(void *data, int data_len, void *read_ecc, const void *test_ecc)
{
u8 *p_data = (u8 *)data, *p_read_ecc = (u8 *)read_ecc, *p_test_ecc = (u8 *)test_ecc;
int total = 0, ret, len;
if (data == NULL || read_ecc == NULL || test_ecc == NULL)
return -1;
while (data_len > 0) {
len = (data_len > 256 ? 256 : data_len);
ret = uffs_EccCorrectChunk256(p_data, p_read_ecc, p_test_ecc, len);
if (ret < 0) {
total = ret;
break;
}
else
total += ret;
p_data += len;
p_read_ecc += 3;
p_test_ecc += 3;
data_len -= len;
}
return total;
}
/**
* generate 12 bit ecc for 8 bytes data.
* (use 0xFF padding if the data length is less then 8 bytes)
*
* \param[in] data input data
* \param[in] data_len length of data in byte
*
* \return 12 bits ECC data (lower 12 bits).
*/
u16 uffs_EccMake8(void *data, int data_len)
{
u8 *p = (u8 *)data;
u8 b, col_parity = 0, line_parity = 0, line_parity_prime = 0;
u8 i;
u16 ecc = 0;
data_len = (data_len > 8 ? 8 : data_len);
for (i = 0; i < data_len; i++) {
b = column_parity_tbl[*p++];
col_parity ^= b;
if (b & 0x01) { // odd number of bits in the byte
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
// ECC layout:
// row: (1) | (1) | P32 | P32' | P16 | P16' | P8 | P8'
// column: P4 | P4' | P2 | P2' | P1 | P1' | (1) | (1)
// 12-bit ecc: P32 | P32' | P16 | P16' | P8 | P8' | P4 | P4' | P2 | P2' | P1 | P1' |
ecc = (~(line_parity_tbl[line_parity & 0xf] | line_parity_prime_tbl[line_parity_prime & 0xf])) << 6;
ecc |= (((~col_parity) >> 2) & 0x3f);
return ecc & 0xfff;
}
/**
* correct 8 bytes data from 12 bits ECC
*
* \param[in|out] data input data
* \param[in] read_ecc ecc read from storage
* \param[in] test_ecc ecc calculated from data
* \param[in] errtop top position of error.
*
* \return: 0 -- no error
* -1 -- can not be corrected
* >0 -- how many bits corrected
*/
int uffs_EccCorrect8(void *data, u16 read_ecc, u16 test_ecc, int errtop)
{
u8 d0, d1; /* deltas */
u8 *p = (u8 *)data;
read_ecc &= 0xfff;
test_ecc &= 0xfff;
d0 = (read_ecc >> 6) ^ (test_ecc >> 6);
d1 = (read_ecc & 0x3f) ^ (test_ecc & 0x3f);
if ((d0 | d1) == 0)
return 0;
if( ((d0 ^ (d0 >> 1)) & 0x15) == 0x15 &&
((d1 ^ (d1 >> 1)) & 0x15) == 0x15)
{
// Single bit (recoverable) error in data
u8 b;
u8 bit;
bit = b = 0;
if(d0 & 0x20) b |= 0x04;
if(d0 & 0x08) b |= 0x02;
if(d0 & 0x02) b |= 0x01;
if(d1 & 0x20) bit |= 0x04;
if(d1 & 0x08) bit |= 0x02;
if(d1 & 0x02) bit |= 0x01;
if (b >= (u8)errtop) return -1;
if (bit >= 8) return -1;
p[b] ^= (1 << bit);
return 1;
}
if ((bits_tbl[d0] + bits_tbl[d1]) == 1) {
// error in ecc, no action need
return 1;
}
// Unrecoverable error
return -1;
}

View File

@ -0,0 +1,532 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_fd.c
* \brief POSIX like, hight level file operations
* \author Ricky Zheng, created 8th Jun, 2005
*/
#include <string.h>
#include "uffs/uffs_config.h"
#include "uffs/uffs_fs.h"
#include "uffs/uffs_fd.h"
#define PFX "fd: "
#define FD_OFFSET 3 //!< just make file handler more like POSIX (0, 1, 2 for stdin/stdout/stderr)
#define FD2OBJ(fd) (((fd) >= FD_OFFSET && (fd) < MAX_DIR_HANDLE + FD_OFFSET) ? \
(uffs_Object *)uffs_PoolGetBufByIndex(uffs_GetObjectPool(), (fd) - FD_OFFSET) : NULL )
#define OBJ2FD(obj) (uffs_PoolGetIndex(uffs_GetObjectPool(), obj) + FD_OFFSET)
#define CHK_OBJ(obj, ret) do { \
if (uffs_PoolVerify(uffs_GetObjectPool(), (obj)) == U_FALSE || \
uffs_PoolCheckFreeList(uffs_GetObjectPool(), (obj)) == U_TRUE) { \
uffs_set_error(-UEBADF); \
return (ret); \
} \
} while(0)
#define CHK_DIR(dirp, ret) do { \
if (uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
uffs_set_error(-UEBADF); \
return (ret); \
} \
} while(0)
#define CHK_DIR_VOID(dirp) do { \
if (uffs_PoolVerify(&_dir_pool, (dirp)) == U_FALSE || \
uffs_PoolCheckFreeList(&_dir_pool, (dirp)) == U_TRUE) { \
uffs_set_error(-UEBADF); \
return; \
} \
} while(0)
static int _dir_pool_data[sizeof(uffs_DIR) * MAX_DIR_HANDLE / sizeof(int)];
static uffs_Pool _dir_pool;
static int _uffs_errno = 0;
/**
* initialise uffs_DIR buffers, called by UFFS internal
*/
URET uffs_InitDirEntryBuf(void)
{
return uffs_PoolInit(&_dir_pool, _dir_pool_data, sizeof(_dir_pool_data),
sizeof(uffs_DIR), MAX_DIR_HANDLE);
}
/**
* Release uffs_DIR buffers, called by UFFS internal
*/
URET uffs_ReleaseDirEntryBuf(void)
{
return uffs_PoolRelease(&_dir_pool);
}
uffs_Pool * uffs_GetDirEntryBufPool(void)
{
return &_dir_pool;
}
static uffs_DIR * GetDirEntry(void)
{
uffs_DIR *dirp = (uffs_DIR *) uffs_PoolGet(&_dir_pool);
if (dirp)
memset(dirp, 0, sizeof(uffs_DIR));
return dirp;
}
static void PutDirEntry(uffs_DIR *p)
{
uffs_PoolPut(&_dir_pool, p);
}
/** get global errno
*/
int uffs_get_error(void)
{
return _uffs_errno;
}
/** set global errno
*/
int uffs_set_error(int err)
{
return (_uffs_errno = err);
}
/* POSIX compliant file system APIs */
int uffs_open(const char *name, int oflag, ...)
{
uffs_Object *obj;
int ret = 0;
obj = uffs_GetObject();
if (obj == NULL) {
uffs_set_error(-UEMFILE);
ret = -1;
}
else {
if (uffs_OpenObject(obj, name, oflag) == U_FAIL) {
uffs_set_error(-uffs_GetObjectErr(obj));
uffs_PutObject(obj);
ret = -1;
}
else {
ret = OBJ2FD(obj);
}
}
return ret;
}
int uffs_close(int fd)
{
int ret = 0;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
if (uffs_CloseObject(obj) == U_FAIL) {
uffs_set_error(-uffs_GetObjectErr(obj));
ret = -1;
}
else {
uffs_PutObject(obj);
ret = 0;
}
return ret;
}
int uffs_read(int fd, void *data, int len)
{
int ret;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
ret = uffs_ReadObject(obj, data, len);
uffs_set_error(-uffs_GetObjectErr(obj));
return ret;
}
int uffs_write(int fd, void *data, int len)
{
int ret;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
ret = uffs_WriteObject(obj, data, len);
uffs_set_error(-uffs_GetObjectErr(obj));
return ret;
}
long uffs_seek(int fd, long offset, int origin)
{
int ret;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
ret = uffs_SeekObject(obj, offset, origin);
uffs_set_error(-uffs_GetObjectErr(obj));
return ret;
}
long uffs_tell(int fd)
{
long ret;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
ret = (long) uffs_GetCurOffset(obj);
uffs_set_error(-uffs_GetObjectErr(obj));
return ret;
}
int uffs_eof(int fd)
{
int ret;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
ret = uffs_EndOfFile(obj);
uffs_set_error(-uffs_GetObjectErr(obj));
return ret;
}
int uffs_flush(int fd)
{
int ret;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
ret = (uffs_FlushObject(obj) == U_SUCC) ? 0 : -1;
uffs_set_error(-uffs_GetObjectErr(obj));
return ret;
}
int uffs_rename(const char *old_name, const char *new_name)
{
int err = 0;
int ret = 0;
ret = (uffs_RenameObject(old_name, new_name, &err) == U_SUCC) ? 0 : -1;
uffs_set_error(-err);
return ret;
}
int uffs_remove(const char *name)
{
int err = 0;
int ret = 0;
struct uffs_stat st;
if (uffs_stat(name, &st) < 0) {
err = UENOENT;
ret = -1;
}
else if (st.st_mode & US_IFDIR) {
err = UEISDIR;
ret = -1;
}
else if (uffs_DeleteObject(name, &err) == U_SUCC) {
ret = 0;
}
else {
ret = -1;
}
uffs_set_error(-err);
return ret;
}
int uffs_truncate(int fd, long remain)
{
int ret;
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
uffs_ClearObjectErr(obj);
ret = (uffs_TruncateObject(obj, remain) == U_SUCC) ? 0 : -1;
uffs_set_error(-uffs_GetObjectErr(obj));
return ret;
}
static int do_stat(uffs_Object *obj, struct uffs_stat *buf)
{
uffs_ObjectInfo info;
int ret = 0;
int err = 0;
if (uffs_GetObjectInfo(obj, &info, &err) == U_FAIL) {
ret = -1;
}
else {
buf->st_dev = obj->dev->dev_num;
buf->st_ino = info.serial;
buf->st_nlink = 0;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_rdev = 0;
buf->st_size = info.len;
buf->st_blksize = obj->dev->com.pg_data_size;
buf->st_blocks = 0;
buf->st_atime = info.info.last_modify;
buf->st_mtime = info.info.last_modify;
buf->st_ctime = info.info.create_time;
buf->st_mode = (info.info.attr & FILE_ATTR_DIR ? US_IFDIR : US_IFREG);
if (info.info.attr & FILE_ATTR_WRITE)
buf->st_mode |= US_IRWXU;
}
uffs_set_error(-err);
return ret;
}
int uffs_stat(const char *name, struct uffs_stat *buf)
{
uffs_Object *obj;
int ret = 0;
int err = 0;
URET result;
obj = uffs_GetObject();
if (obj) {
if (*name && name[strlen(name) - 1] == '/') {
result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR);
}
else {
if ((result = uffs_OpenObject(obj, name, UO_RDONLY)) != U_SUCC) // try file
result = uffs_OpenObject(obj, name, UO_RDONLY | UO_DIR); // then try dir
}
if (result == U_SUCC) {
ret = do_stat(obj, buf);
uffs_CloseObject(obj);
}
else {
err = uffs_GetObjectErr(obj);
ret = -1;
}
uffs_PutObject(obj);
}
else {
err = UENOMEM;
ret = -1;
}
uffs_set_error(-err);
return ret;
}
int uffs_lstat(const char *name, struct uffs_stat *buf)
{
return uffs_stat(name, buf);
}
int uffs_fstat(int fd, struct uffs_stat *buf)
{
uffs_Object *obj = FD2OBJ(fd);
CHK_OBJ(obj, -1);
return do_stat(obj, buf);
}
int uffs_closedir(uffs_DIR *dirp)
{
CHK_DIR(dirp, -1);
uffs_FindObjectClose(&dirp->f);
if (dirp->obj) {
uffs_CloseObject(dirp->obj);
uffs_PutObject(dirp->obj);
}
PutDirEntry(dirp);
return 0;
}
uffs_DIR * uffs_opendir(const char *path)
{
int err = 0;
uffs_DIR *ret = NULL;
uffs_DIR *dirp = GetDirEntry();
if (dirp) {
dirp->obj = uffs_GetObject();
if (dirp->obj) {
if (uffs_OpenObject(dirp->obj, path, UO_RDONLY | UO_DIR) == U_SUCC) {
if (uffs_FindObjectOpen(&dirp->f, dirp->obj) == U_SUCC) {
ret = dirp;
goto ext;
}
else {
uffs_CloseObject(dirp->obj);
}
}
else {
err = uffs_GetObjectErr(dirp->obj);
}
uffs_PutObject(dirp->obj);
dirp->obj = NULL;
}
else {
err = UEMFILE;
}
PutDirEntry(dirp);
}
else {
err = UEMFILE;
}
ext:
uffs_set_error(-err);
return ret;
}
struct uffs_dirent * uffs_readdir(uffs_DIR *dirp)
{
struct uffs_dirent *ent;
CHK_DIR(dirp, NULL);
if (uffs_FindObjectNext(&dirp->info, &dirp->f) == U_SUCC) {
ent = &dirp->dirent;
ent->d_ino = dirp->info.serial;
ent->d_namelen = dirp->info.info.name_len;
memcpy(ent->d_name, dirp->info.info.name, ent->d_namelen);
ent->d_name[ent->d_namelen] = 0;
ent->d_off = dirp->f.pos;
ent->d_reclen = sizeof(struct uffs_dirent);
ent->d_type = dirp->info.info.attr;
return ent;
}
else
return NULL;
}
void uffs_rewinddir(uffs_DIR *dirp)
{
CHK_DIR_VOID(dirp);
uffs_FindObjectRewind(&dirp->f);
}
int uffs_mkdir(const char *name, ...)
{
uffs_Object *obj;
int ret = 0;
int err = 0;
obj = uffs_GetObject();
if (obj) {
if (uffs_CreateObject(obj, name, UO_CREATE|UO_DIR) != U_SUCC) {
err = obj->err;
ret = -1;
}
else {
uffs_CloseObject(obj);
ret = 0;
}
uffs_PutObject(obj);
}
else {
err = UEMFILE;
ret = -1;
}
uffs_set_error(-err);
return ret;
}
int uffs_rmdir(const char *name)
{
int err = 0;
int ret = 0;
struct uffs_stat st;
if (uffs_stat(name, &st) < 0) {
err = UENOENT;
ret = -1;
}
else if ((st.st_mode & US_IFDIR) == 0) {
err = UENOTDIR;
ret = -1;
}
else if (uffs_DeleteObject(name, &err) == U_SUCC) {
ret = 0;
}
else {
ret = -1;
}
uffs_set_error(-err);
return ret;
}
#if 0
void uffs_seekdir(uffs_DIR *dirp, long loc)
{
return ;
}
long uffs_telldir(uffs_DIR *dirp)
{
return 0;
}
#endif

View File

@ -0,0 +1,360 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_find.c
* \brief find objects under dir
* \author Ricky Zheng, created 13th July, 2009
*/
#include <string.h>
#include <stdio.h>
#include "uffs/uffs_find.h"
#define TPOOL(dev) &((dev)->mem.tree_pool)
static void ResetFindInfo(uffs_FindInfo *f)
{
f->hash = 0;
f->work = NULL;
f->step = 0;
f->pos = 0;
}
static URET _LoadObjectInfo(uffs_Device *dev, TreeNode *node, uffs_ObjectInfo *info, int type, int *err)
{
uffs_Buf *buf;
buf = uffs_BufGetEx(dev, (u8)type, node, 0);
if (buf == NULL) {
if (err)
*err = UENOMEM;
return U_FAIL;
}
memcpy(&(info->info), buf->data, sizeof(uffs_FileInfo));
if (type == UFFS_TYPE_DIR) {
info->len = 0;
info->serial = node->u.dir.serial;
}
else {
info->len = node->u.file.len;
info->serial = node->u.file.serial;
}
uffs_BufPut(dev, buf);
return U_SUCC;
}
/**
* get object information
*
* \param[in] obj the object to be revealed
* \param[out] info object information will be loaded to info
* \param[out] err return error code if failed
*
* \return U_SUCC or U_FAIL
*
* \node the obj should be openned before call this function.
*/
URET uffs_GetObjectInfo(uffs_Object *obj, uffs_ObjectInfo *info, int *err)
{
uffs_Device *dev = obj->dev;
URET ret = U_FAIL;
uffs_DeviceLock(dev);
if (obj && dev && info) {
ret = _LoadObjectInfo(dev, obj->node, info, obj->type, err);
}
else {
if (err)
*err = UEINVAL;
}
uffs_DeviceUnLock(dev);
return ret;
}
/**
* Open a FindInfo for finding objects under dir
*
* \param[out] f uffs_FindInfo structure
* \param[in] dir an openned dir object (openned by uffs_OpenObject() ).
*
* \return U_SUCC if success, U_FAIL if invalid param or the dir
* is not been openned.
*/
URET uffs_FindObjectOpen(uffs_FindInfo *f, uffs_Object *dir)
{
if (f == NULL || dir == NULL || dir->dev == NULL || dir->open_succ != U_TRUE)
return U_FAIL;
f->dev = dir->dev;
f->serial = dir->serial;
ResetFindInfo(f);
return U_SUCC;
}
/**
* Open a FindInfo for finding objects under dir
*
* \param[out] f uffs_FindInfo structure
* \param[in] dev uffs device
* \param[in] dir serial number of the dir to be searched
*
* \return U_SUCC if success, U_FAIL if invalid param or the dir
* serial number is not valid.
*/
URET uffs_FindObjectOpenEx(uffs_FindInfo *f, uffs_Device *dev, int dir)
{
TreeNode *node;
if (f == NULL || dev == NULL)
return U_FAIL;
node = uffs_TreeFindDirNode(dev, dir);
if (node == NULL)
return U_FAIL;
f->serial = dir;
f->dev = dev;
ResetFindInfo(f);
return U_SUCC;
}
static URET do_FindObject(uffs_FindInfo *f, uffs_ObjectInfo *info, u16 x)
{
URET ret = U_SUCC;
TreeNode *node;
uffs_Device *dev = f->dev;
if (f->step == 0) { //!< working on dirs
while (x != EMPTY_NODE) {
node = FROM_IDX(x, TPOOL(dev));
if (node->u.dir.parent == f->serial) {
f->work = node;
f->pos++;
if (info)
ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
goto ext;
}
x = node->hash_next;
}
f->hash++; //come to next hash entry
for (; f->hash < DIR_NODE_ENTRY_LEN; f->hash++) {
x = dev->tree.dir_entry[f->hash];
while (x != EMPTY_NODE) {
node = FROM_IDX(x, TPOOL(dev));
if (node->u.dir.parent == f->serial) {
f->work = node;
f->pos++;
if (info)
ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_DIR, NULL);
goto ext;
}
x = node->hash_next;
}
}
//no subdirs, then lookup files ..
f->step++;
f->hash = 0;
x = EMPTY_NODE;
}
if (f->step == 1) {
while (x != EMPTY_NODE) {
node = FROM_IDX(x, TPOOL(dev));
if (node->u.file.parent == f->serial) {
f->work = node;
f->pos++;
if (info)
ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
goto ext;
}
x = node->hash_next;
}
f->hash++; //come to next hash entry
for (; f->hash < FILE_NODE_ENTRY_LEN; f->hash++) {
x = dev->tree.file_entry[f->hash];
while (x != EMPTY_NODE) {
node = FROM_IDX(x, TPOOL(dev));
if (node->u.file.parent == f->serial) {
f->work = node;
f->pos++;
if (info)
ret = _LoadObjectInfo(dev, node, info, UFFS_TYPE_FILE, NULL);
goto ext;
}
x = node->hash_next;
}
}
//no any files, stopped.
f->step++;
}
ret = U_FAIL;
ext:
return ret;
}
/**
* Find the first object
*
* \param[out] info the object information will be filled to info.
* if info is NULL, then skip this object.
* \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
*
* \return U_SUCC if an object is found, U_FAIL if no object is found.
*/
URET uffs_FindObjectFirst(uffs_ObjectInfo * info, uffs_FindInfo * f)
{
uffs_Device *dev = f->dev;
URET ret = U_SUCC;
uffs_DeviceLock(dev);
ResetFindInfo(f);
ret = do_FindObject(f, info, dev->tree.dir_entry[0]);
uffs_DeviceUnLock(dev);
return ret;
}
/**
* Find the next object.
*
* \param[out] info the object information will be filled to info.
* if info is NULL, then skip this object.
* \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
*
* \return U_SUCC if an object is found, U_FAIL if no object is found.
*
* \note uffs_FindObjectFirst() should be called before uffs_FindObjectNext().
*/
URET uffs_FindObjectNext(uffs_ObjectInfo *info, uffs_FindInfo * f)
{
uffs_Device *dev = f->dev;
URET ret = U_SUCC;
if (f->dev == NULL || f->step > 1)
return U_FAIL;
if (f->work == NULL)
return uffs_FindObjectFirst(info, f);
uffs_DeviceLock(dev);
ret = do_FindObject(f, info, f->work->hash_next);
uffs_DeviceUnLock(dev);
return ret;
}
/**
* Rewind a find object process.
*
* \note After rewind, you can call uffs_FindObjectFirst() to start find object process.
*/
URET uffs_FindObjectRewind(uffs_FindInfo *f)
{
if (f == NULL)
return U_FAIL;
ResetFindInfo(f);
return U_SUCC;
}
/**
* Close Find Object.
*
* \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
*
* \return U_SUCC if success, U_FAIL if invalid param.
*/
URET uffs_FindObjectClose(uffs_FindInfo * f)
{
if (f == NULL)
return U_FAIL;
f->dev = NULL;
ResetFindInfo(f);
return U_SUCC;
}
/**
* Count objects
*
* \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
*
* \return object counts
* \note after call this function, you need to call uffs_FindObjectRewind() to start finding process.
*/
int uffs_FindObjectCount(uffs_FindInfo *f)
{
if (uffs_FindObjectFirst(NULL, f) == U_SUCC) {
while (uffs_FindObjectNext(NULL, f) == U_SUCC) { };
}
return f->pos;
}
/**
* Return current finding position
*
* \param[in] f uffs_FindInfo structure, openned by uffs_FindObjectOpen().
*
* \return current finding position
*/
int uffs_FindObjectTell(uffs_FindInfo *f)
{
return f->pos;
}

View File

@ -0,0 +1,674 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_flash.c
* \brief UFFS flash interface
* \author Ricky Zheng, created 17th July, 2009
*/
#include "uffs/uffs_config.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_ecc.h"
#include "uffs/uffs_flash.h"
#include "uffs/uffs_device.h"
#include "uffs/uffs_badblock.h"
#include <string.h>
#define PFX "Flash: "
#define SPOOL(dev) &((dev)->mem.spare_pool)
#define HEADER(buf) ((struct uffs_MiniHeaderSt *)(buf)->header)
#define ECC_SIZE(dev) (3 * (dev)->attr->page_data_size / 256)
#define TAG_STORE_SIZE (sizeof(struct uffs_TagStoreSt))
static void TagMakeEcc(struct uffs_TagStoreSt *ts)
{
ts->tag_ecc = 0xFFF;
ts->tag_ecc = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
}
static int TagEccCorrect(struct uffs_TagStoreSt *ts)
{
u16 ecc_store, ecc_read;
int ret;
ecc_store = ts->tag_ecc;
ts->tag_ecc = 0xFFF;
ecc_read = uffs_EccMake8(ts, sizeof(struct uffs_TagStoreSt));
ret = uffs_EccCorrect8(ts, ecc_read, ecc_store, sizeof(struct uffs_TagStoreSt));
ts->tag_ecc = ecc_store; // restore tag ecc
return ret;
}
/** setup UFFS spare data & ecc layout */
static void InitSpareLayout(uffs_Device *dev)
{
u8 s; // status byte offset
u8 *p;
s = dev->attr->block_status_offs;
if (s < TAG_STORE_SIZE) { /* status byte is within 0 ~ TAG_STORE_SIZE-1 */
/* spare data layout */
p = dev->attr->_uffs_data_layout;
if (s > 0) {
*p++ = 0;
*p++ = s;
}
*p++ = s + 1;
*p++ = TAG_STORE_SIZE - s;
*p++ = 0xFF;
*p++ = 0;
/* spare ecc layout */
p = dev->attr->_uffs_ecc_layout;
*p++ = TAG_STORE_SIZE + 1;
*p++ = ECC_SIZE(dev);
*p++ = 0xFF;
*p++ = 0;
}
else { /* status byte > TAG_STORE_SIZE-1 */
/* spare data layout */
p = dev->attr->_uffs_data_layout;
*p++ = 0;
*p++ = TAG_STORE_SIZE;
*p++ = 0xFF;
*p++ = 0;
/* spare ecc layout */
p = dev->attr->_uffs_ecc_layout;
if (s < TAG_STORE_SIZE + ECC_SIZE(dev)) {
if (s > TAG_STORE_SIZE) {
*p++ = TAG_STORE_SIZE;
*p++ = s - TAG_STORE_SIZE;
}
*p++ = s + 1;
*p++ = TAG_STORE_SIZE + ECC_SIZE(dev) - s;
}
else {
*p++ = TAG_STORE_SIZE;
*p++ = ECC_SIZE(dev);
}
*p++ = 0xFF;
*p++ = 0;
}
dev->attr->data_layout = dev->attr->_uffs_data_layout;
dev->attr->ecc_layout = dev->attr->_uffs_ecc_layout;
}
static int CalculateSpareDataSize(uffs_Device *dev)
{
const u8 *p;
int ecc_last = 0, tag_last = 0;
int ecc_size, tag_size;
int n;
ecc_size = ECC_SIZE(dev);
p = dev->attr->ecc_layout;
if (p) {
while (*p != 0xFF && ecc_size > 0) {
n = (p[1] > ecc_size ? ecc_size : p[1]);
ecc_last = p[0] + n;
ecc_size -= n;
p += 2;
}
}
tag_size = TAG_STORE_SIZE;
p = dev->attr->data_layout;
if (p) {
while (*p != 0xFF && tag_size > 0) {
n = (p[1] > tag_size ? tag_size : p[1]);
tag_last = p[0] + n;
tag_size -= n;
p += 2;
}
}
n = (ecc_last > tag_last ? ecc_last : tag_last);
n = (n > dev->attr->block_status_offs + 1 ? n : dev->attr->block_status_offs + 1);
return n;
}
/**
* Initialize UFFS flash interface
*/
URET uffs_FlashInterfaceInit(uffs_Device *dev)
{
struct uffs_StorageAttrSt *attr = dev->attr;
uffs_Pool *pool = SPOOL(dev);
if (!dev->ops->IsBadBlock && !dev->ops->ReadPageSpare) {
uffs_Perror(UFFS_ERR_SERIOUS, "flash driver must provide 'IsBadBlock' or 'ReadPageSpare' function!");
return U_FAIL;
}
if (!dev->ops->MarkBadBlock && !dev->ops->WritePageSpare && !dev->ops->WriteFullPage) {
uffs_Perror(UFFS_ERR_SERIOUS, "flash driver must provide 'MarkBadBlock' or 'WritePageSpare' or 'WriteFullPage' function!");
return U_FAIL;
}
if (dev->mem.spare_pool_size == 0) {
if (dev->mem.malloc) {
dev->mem.spare_pool_buf = dev->mem.malloc(dev, UFFS_SPARE_BUFFER_SIZE);
if (dev->mem.spare_pool_buf)
dev->mem.spare_pool_size = UFFS_SPARE_BUFFER_SIZE;
}
}
if (UFFS_SPARE_BUFFER_SIZE > dev->mem.spare_pool_size) {
uffs_Perror(UFFS_ERR_DEAD, "Spare buffer require %d but only %d available.", UFFS_SPARE_BUFFER_SIZE, dev->mem.spare_pool_size);
memset(pool, 0, sizeof(uffs_Pool));
return U_FAIL;
}
uffs_Perror(UFFS_ERR_NOISY, "alloc spare buffers %d bytes.", UFFS_SPARE_BUFFER_SIZE);
uffs_PoolInit(pool, dev->mem.spare_pool_buf, dev->mem.spare_pool_size, UFFS_MAX_SPARE_SIZE, MAX_SPARE_BUFFERS);
if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
/* sanity check */
if ((dev->attr->data_layout && !dev->attr->ecc_layout) ||
(!dev->attr->data_layout && dev->attr->ecc_layout)) {
uffs_Perror(UFFS_ERR_SERIOUS, "Please setup data_layout and ecc_layout, or leave them all NULL !");
return U_FAIL;
}
if (!attr->data_layout && !attr->ecc_layout)
InitSpareLayout(dev);
}
dev->mem.spare_data_size = CalculateSpareDataSize(dev);
return U_SUCC;
}
/**
* Release UFFS flash interface
*/
URET uffs_FlashInterfaceRelease(uffs_Device *dev)
{
uffs_Pool *pool;
pool = SPOOL(dev);
if (pool->mem && dev->mem.free) {
dev->mem.free(dev, pool->mem);
pool->mem = NULL;
dev->mem.spare_pool_size = 0;
}
uffs_PoolRelease(pool);
memset(pool, 0, sizeof(uffs_Pool));
return U_SUCC;
}
/**
* unload spare to tag and ecc.
*/
static void UnloadSpare(uffs_Device *dev, const u8 *spare, uffs_Tags *tag, u8 *ecc)
{
u8 *p_tag = (u8 *)&tag->s;
int tag_size = TAG_STORE_SIZE;
int ecc_size = ECC_SIZE(dev);
int n;
const u8 *p;
// unload ecc
p = dev->attr->ecc_layout;
if (p && ecc) {
while (*p != 0xFF && ecc_size > 0) {
n = (p[1] > ecc_size ? ecc_size : p[1]);
memcpy(ecc, spare + p[0], n);
ecc_size -= n;
ecc += n;
p += 2;
}
}
// unload tag
if (tag) {
p = dev->attr->data_layout;
while (*p != 0xFF && tag_size > 0) {
n = (p[1] > tag_size ? tag_size : p[1]);
memcpy(p_tag, spare + p[0], n);
tag_size -= n;
p_tag += n;
p += 2;
}
tag->block_status = spare[dev->attr->block_status_offs];
}
}
/**
* Read tag and ecc from page spare
*
* \param[in] dev uffs device
* \param[in] block flash block num
* \param[in] page flash page num
* \param[out] tag tag to be filled
* \param[out] ecc ecc to be filled
*
* \return #UFFS_FLASH_NO_ERR: success and/or has no flip bits.
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
* #UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
*/
int uffs_FlashReadPageSpare(uffs_Device *dev, int block, int page, uffs_Tags *tag, u8 *ecc)
{
uffs_FlashOps *ops = dev->ops;
struct uffs_StorageAttrSt *attr = dev->attr;
u8 * spare_buf;
int ret = UFFS_FLASH_UNKNOWN_ERR;
UBOOL is_bad = U_FALSE;
spare_buf = (u8 *) uffs_PoolGet(SPOOL(dev));
if (spare_buf == NULL)
goto ext;
if (ops->ReadPageSpareWithLayout)
ret = ops->ReadPageSpareWithLayout(dev, block, page, (u8 *)&tag->s, tag ? TAG_STORE_SIZE : 0, ecc);
else
ret = ops->ReadPageSpare(dev, block, page, spare_buf, 0, dev->mem.spare_data_size);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
if (!ops->ReadPageSpareWithLayout)
UnloadSpare(dev, spare_buf, tag, ecc);
// copy some raw data
if (tag) {
tag->_dirty = tag->s.dirty;
tag->_valid = tag->s.valid;
}
if (UFFS_FLASH_HAVE_ERR(ret))
goto ext;
if (tag) {
if (tag->_valid == 1) //it's not a valid page ? don't need go further
goto ext;
// do tag ecc correction
if (dev->attr->ecc_opt != UFFS_ECC_NONE) {
ret = TagEccCorrect(&tag->s);
ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
if (UFFS_FLASH_HAVE_ERR(ret))
goto ext;
}
}
ext:
if (is_bad) {
uffs_BadBlockAdd(dev, block);
uffs_Perror(UFFS_ERR_NORMAL, "A new bad block (%d) is detected.", block);
}
if (spare_buf)
uffs_PoolPut(SPOOL(dev), spare_buf);
return ret;
}
/**
* Read page data to page buf and calculate ecc.
* \param[in] dev uffs device
* \param[in] block flash block num
* \param[in] page flash page num of the block
* \param[out] buf holding the read out data
*
* \return #UFFS_FLASH_NO_ERR: success and/or has no flip bits.
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
* #UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
*/
int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf)
{
uffs_FlashOps *ops = dev->ops;
int size = dev->com.pg_size;
u8 ecc_buf[MAX_ECC_SIZE];
u8 ecc_store[MAX_ECC_SIZE];
UBOOL is_bad = U_FALSE;
int ret;
// if ecc_opt is UFFS_ECC_HW, flash driver return ecc,
// if ecc_opt is UFFS_ECC_HW_AUTO, flash driver should do ecc correction.
ret = ops->ReadPageData(dev, block, page, buf->header, size, ecc_buf);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
if (UFFS_FLASH_HAVE_ERR(ret))
goto ext;
if (dev->attr->ecc_opt == UFFS_ECC_SOFT || dev->attr->ecc_opt == UFFS_ECC_HW) {
if (dev->attr->ecc_opt == UFFS_ECC_SOFT)
uffs_EccMake(buf->header, size, ecc_buf);
// will auto select ops->ReadPageSpareWithLayout() or ops->ReadPageSpare()
ret = uffs_FlashReadPageSpare(dev, block, page, NULL, ecc_store);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
if (UFFS_FLASH_HAVE_ERR(ret))
goto ext;
ret = uffs_EccCorrect(buf->header, size, ecc_store, ecc_buf);
ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
if (UFFS_FLASH_HAVE_ERR(ret))
goto ext;
}
ext:
if (is_bad) {
uffs_BadBlockAdd(dev, block);
}
return ret;
}
/**
* make spare from tag and ecc
*
* \param[in] dev uffs dev
* \param[in] ts uffs tag store, NULL if don't pack tag store
* \param[in] ecc ecc of data, NULL if don't pack ecc
* \param[out] spare output buffer
* \note spare buffer size: dev->mem.spare_data_size, all unpacked bytes will be inited 0xFF
*/
void uffs_FlashMakeSpare(uffs_Device *dev, uffs_TagStore *ts, const u8 *ecc, u8* spare)
{
u8 *p_ts = (u8 *)ts;
int ts_size = TAG_STORE_SIZE;
int ecc_size = ECC_SIZE(dev);
int n;
const u8 *p;
memset(spare, 0xFF, dev->mem.spare_data_size); // initialize as 0xFF.
// load ecc
p = dev->attr->ecc_layout;
if (p && ecc) {
while (*p != 0xFF && ecc_size > 0) {
n = (p[1] > ecc_size ? ecc_size : p[1]);
memcpy(spare + p[0], ecc, n);
ecc_size -= n;
ecc += n;
p += 2;
}
}
p = dev->attr->data_layout;
while (*p != 0xFF && ts_size > 0) {
n = (p[1] > ts_size ? ts_size : p[1]);
memcpy(spare + p[0], p_ts, n);
ts_size -= n;
p_ts += n;
p += 2;
}
}
/**
* write the whole page, include data and tag
*
* \param[in] dev uffs device
* \param[in] block
* \param[in] page
* \param[in] buf contains data to be wrote
* \param[in] tag tag to be wrote
*
* \return #UFFS_FLASH_NO_ERR: success.
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_BAD_BLK: a new bad block detected.
*/
int uffs_FlashWritePageCombine(uffs_Device *dev, int block, int page, uffs_Buf *buf, uffs_Tags *tag)
{
uffs_FlashOps *ops = dev->ops;
int size = dev->com.pg_size;
u8 ecc_buf[MAX_ECC_SIZE];
u8 *spare;
struct uffs_MiniHeaderSt *header;
int ret = UFFS_FLASH_UNKNOWN_ERR;
UBOOL is_bad = U_FALSE;
uffs_Buf *verify_buf;
spare = (u8 *) uffs_PoolGet(SPOOL(dev));
if (spare == NULL)
goto ext;
// setup header
header = HEADER(buf);
memset(header, 0xFF, sizeof(struct uffs_MiniHeaderSt));
header->status = 0;
// setup tag
tag->s.dirty = TAG_DIRTY; //!< set dirty bit
tag->s.valid = TAG_VALID; //!< set valid bit
if (dev->attr->ecc_opt != UFFS_ECC_NONE)
TagMakeEcc(&tag->s);
else
tag->s.tag_ecc = TAG_ECC_DEFAULT;
if (dev->attr->ecc_opt == UFFS_ECC_SOFT)
uffs_EccMake(buf->header, size, ecc_buf);
if (ops->WriteFullPage) {
ret = ops->WriteFullPage(dev, block, page, buf->header, size, (u8 *)&(tag->s), TAG_STORE_SIZE, ecc_buf);
}
else {
ret = ops->WritePageData(dev, block, page, buf->header, size, ecc_buf);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
if (UFFS_FLASH_HAVE_ERR(ret))
goto ext;
if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
if (dev->attr->ecc_opt == UFFS_ECC_SOFT ||
dev->attr->ecc_opt == UFFS_ECC_HW) {
uffs_FlashMakeSpare(dev, &tag->s, ecc_buf, spare);
}
else
uffs_FlashMakeSpare(dev, &tag->s, NULL, spare);
ret = ops->WritePageSpare(dev, block, page, spare, 0, dev->mem.spare_data_size, U_TRUE);
}
else {
uffs_Assert(dev->attr->layout_opt == UFFS_LAYOUT_FLASH && ops->WriteFullPage != NULL,
"Flash driver MUST provide 'WriteFullPage()' for UFFS_LAYOUT_FLASH\n");
}
}
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
#ifdef CONFIG_PAGE_WRITE_VERIFY
if (!UFFS_FLASH_HAVE_ERR(ret)) {
verify_buf = uffs_BufClone(dev, NULL);
if (verify_buf) {
ret = uffs_FlashReadPage(dev, block, page, verify_buf);
if (!UFFS_FLASH_HAVE_ERR(ret)) {
if (memcmp(buf->header, verify_buf->header, size) != 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Page write verify fail (block %d page %d)", block, page);
ret = UFFS_FLASH_BAD_BLK;
}
}
uffs_BufFreeClone(dev, verify_buf);
}
}
#endif
ext:
if (is_bad)
uffs_BadBlockAdd(dev, block);
if (spare)
uffs_PoolPut(SPOOL(dev), spare);
return ret;
}
/**
* mark a clean page as 'dirty' (and 'invalid')
*
* \param[in] dev uffs device
* \param[in] block
* \param[in] page
*
* \return #UFFS_FLASH_NO_ERR: success.
* #UFFS_FLASH_IO_ERR: I/O error, expect retry ?
* #UFFS_FLASH_BAD_BLK: a new bad block detected.
*/
int uffs_FlashMarkDirtyPage(uffs_Device *dev, int block, int page)
{
u8 *spare;
struct uffs_TagStoreSt s;
uffs_FlashOps *ops = dev->ops;
UBOOL is_bad = U_FALSE;
int ret = UFFS_FLASH_UNKNOWN_ERR;
spare = (u8 *) uffs_PoolGet(SPOOL(dev));
if (spare == NULL)
goto ext;
memset(&s, 0xFF, sizeof(s));
s.dirty = TAG_DIRTY; // set only 'dirty' bit
if (dev->attr->ecc_opt != UFFS_ECC_NONE)
TagMakeEcc(&s);
if (dev->attr->layout_opt == UFFS_LAYOUT_UFFS) {
uffs_FlashMakeSpare(dev, &s, NULL, spare);
ret = ops->WritePageSpare(dev, block, page, spare, 0, dev->mem.spare_data_size, U_FALSE);
}
else {
uffs_Assert(ops->WriteFullPage, "Flash driver MUST provide 'WriteFullPage()' for UFFS_LAYOUT_FLASH\n");
ret = ops->WriteFullPage(dev, block, page, NULL, 0, (u8 *)&s, TAG_STORE_SIZE, NULL);
}
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
is_bad = U_TRUE;
ext:
if (is_bad)
uffs_BadBlockAdd(dev, block);
if (spare)
uffs_PoolPut(SPOOL(dev), spare);
return ret;
}
/** Mark this block as bad block */
URET uffs_FlashMarkBadBlock(uffs_Device *dev, int block)
{
u8 status = 0;
int ret;
uffs_Perror(UFFS_ERR_NORMAL, "Mark bad block: %d", block);
if (dev->ops->MarkBadBlock)
return dev->ops->MarkBadBlock(dev, block) == 0 ? U_SUCC : U_FAIL;
#ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
ret = dev->ops->EraseBlock(dev, block);
if (ret != UFFS_FLASH_IO_ERR) { // note: event EraseBlock return UFFS_FLASH_BAD_BLK, we still process it ...
#endif
ret = dev->ops->WritePageSpare(dev, block, 0, &status, dev->attr->block_status_offs, 1, U_FALSE);
#ifdef CONFIG_ERASE_BLOCK_BEFORE_MARK_BAD
}
#endif
return ret == UFFS_FLASH_NO_ERR ? U_SUCC : U_FAIL;
}
/** Is this block a bad block ? */
UBOOL uffs_FlashIsBadBlock(uffs_Device *dev, int block)
{
u8 status = 0xFF;
if (dev->ops->IsBadBlock) /* if flash driver provide 'IsBadBlock' function, then use it. */
return dev->ops->IsBadBlock(dev, block) == 0 ? U_FALSE : U_TRUE;
/* otherwise we check the 'status' byte of spare */
/* check the first page */
dev->ops->ReadPageSpare(dev, block, 0, &status, dev->attr->block_status_offs, 1);
if (status == 0xFF) {
/* check the second page */
dev->ops->ReadPageSpare(dev, block, 1, &status, dev->attr->block_status_offs, 1);
if (status == 0xFF)
return U_FALSE;
}
return U_TRUE;
}
/** Erase flash block */
URET uffs_FlashEraseBlock(uffs_Device *dev, int block)
{
int ret;
ret = dev->ops->EraseBlock(dev, block);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
uffs_BadBlockAdd(dev, block);
return UFFS_FLASH_HAVE_ERR(ret) ? U_FAIL : U_SUCC;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_init.c
* \brief initialize uffs file system device
* \author Ricky Zheng, created 12th May, 2005
*/
#include "uffs/uffs_types.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_tree.h"
#include "uffs/uffs_fs.h"
#include "uffs/uffs_badblock.h"
#include <string.h>
#define PFX "init: "
URET uffs_InitDevice(uffs_Device *dev)
{
URET ret;
if (dev->mem.init) {
if (dev->mem.init(dev) != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "Init memory allocator fail.");
return U_FAIL;
}
}
memset(&(dev->st), 0, sizeof(uffs_FlashStat));
uffs_DeviceInitLock(dev);
uffs_BadBlockInit(dev);
if (uffs_FlashInterfaceInit(dev) != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "Can't initialize flash interface !");
goto fail;
}
uffs_Perror(UFFS_ERR_NOISY, "init page buf");
ret = uffs_BufInit(dev, MAX_PAGE_BUFFERS, MAX_DIRTY_PAGES_IN_A_BLOCK);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_DEAD, "Initialize page buffers fail");
goto fail;
}
uffs_Perror(UFFS_ERR_NOISY, "init block info cache");
ret = uffs_BlockInfoInitCache(dev, MAX_CACHED_BLOCK_INFO);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_DEAD, "Initialize block info fail");
goto fail;
}
ret = uffs_TreeInit(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "fail to init tree buffers");
goto fail;
}
ret = uffs_BuildTree(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "fail to build tree");
goto fail;
}
return U_SUCC;
fail:
uffs_DeviceReleaseLock(dev);
return U_FAIL;
}
URET uffs_ReleaseDevice(uffs_Device *dev)
{
URET ret;
ret = uffs_BlockInfoReleaseCache(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "fail to release block info.");
goto ext;
}
ret = uffs_BufReleaseAll(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "fail to release page buffers");
goto ext;
}
ret = uffs_TreeRelease(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "fail to release tree buffers!");
goto ext;
}
ret = uffs_FlashInterfaceRelease(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "fail to release tree buffers!");
goto ext;
}
if (dev->mem.release)
ret = dev->mem.release(dev);
if (ret != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "fail to release memory allocator!");
}
uffs_DeviceReleaseLock(dev);
ext:
return ret;
}

View File

@ -0,0 +1,902 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_mem.c
* \brief uffs native memory allocator
* \author Ricky Zheng, created 23th Feb, 2007
*/
#include <string.h>
#include "uffs/uffs_types.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_os.h"
#include "uffs/uffs_mem.h"
#define PFX "mem: "
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
#define HEAP_MAGIC_SIZE 8 /* heap magic size, this block is for memory protection */
/* the 'BEST FIT' arithmetic,
if not defined, the arithmetic
will be the 'FIRST FIT' */
#define K_HEAP_ALLOCK_BEST_FIT
/* page size may be: 16,32,64,128... */
#define ALLOC_PAGE_BIT_OFFSET 5
#define ALLOC_PAGE_SIZE (1 << ALLOC_PAGE_BIT_OFFSET)
#define ALLOC_PAGE_MASK (ALLOC_PAGE_SIZE - 1)
#define ALLOC_THRESHOLD (ALLOC_PAGE_SIZE * 1)
/* magic mummbers */
#define HEAP_NODE_FREE 0x123455aa
#define HEAP_NODE_ALLOCED 0xaa551234
#define ALLOC_OFFSET (sizeof(int) + sizeof(int) + sizeof(void *))
/* Heap memory node type. */
typedef struct HeapNodeSt {
int mark; /* alloc mark */
int size; /* Size of this node */
struct HeapNodeSt *prev_node; /* private node */
struct HeapNodeSt *prev_free; /* Link to prev free node */
struct HeapNodeSt *next_free; /* Link to next free node */
} HeapNode;
/*
p1 |-----------|
|prev_node | NULL
|mark | HEAP_NODE_ALLOCED
|size | p2 - p1
|prev_free | alloc to user
|next_free | not used.
| |
| |
p2 |-----------|
|prev_node | p1
|mark | HEAP_NODE_FREE
|size | p3 - p2
|prev_free | NULL
|next_free | p5
| |
| |
p3 |-----------|
|prev_node | p2
|mark | HEAP_NODE_ALLOCED
|size | p4 - p3
|prev_free | alloc to user
|next_free | not used.
| |
| |
p4 |-----------|
|prev_node | p3
|mark | HEAP_NODE_ALLOCED
|size | p5 - p4
|prev_free | alloc to user
|next_free | not used.
| |
| |
p5 |-----------|
|prev_node | p4
|mark | HEAP_NODE_FREE
|size | p6 - p5
|prev_free | p2
|next_free | NULL
| |
| |
p6 |-----------|
*/
static HeapNode* volatile m_heapFreeList = NULL;
static HeapNode * m_heapTail = NULL;
static u32 m_heap_available = 0;
static u32 m_min_heap_avaiable = 0x0fffffff;
static u32 m_kernel_heap_total = 0;
static void HeapDeleteFromFreeList(HeapNode *node);
static void HeapChainToFreeList(HeapNode *node);
static void *_k_allock_node(HeapNode *node, int size);
//static void * _kmalloc_clear(int size);
static int _kfree(void *block);
/*
* Delete one node from free list
*
*/
static void HeapDeleteFromFreeList(HeapNode *node)
{
if(node->next_free)
node->next_free->prev_free = node->prev_free;
if(node->prev_free)
node->prev_free->next_free = node->next_free;
if(node == m_heapFreeList)
m_heapFreeList = node->next_free;
}
/*
* Chain the node to free list
*/
static void HeapChainToFreeList(HeapNode *node)
{
node->next_free = NULL;
node->prev_free = NULL;
if(m_heapFreeList == NULL){
m_heapFreeList = node;
return;
}
else{
m_heapFreeList->prev_free = node;
node->next_free = m_heapFreeList;
m_heapFreeList = node;
}
}
/*
* Alloc a block with given node
* If the node is larger than the
* required space plus the space needed for
* a new node plus a defined threshold, then
* we split it. The unused portion is put back into
* the free-list.
*
* Attention: Irq is locked when call this routin,
* so we must unlock irq when return
*/
static void *_k_allock_node(HeapNode *node, int size)
{
HeapNode *newNode;
if(node->size >= size + ALLOC_THRESHOLD){
/*
* we need to split it
*/
newNode = (HeapNode *)((char *)node + size);
newNode->size = node->size - size;
newNode->mark = HEAP_NODE_FREE;
newNode->prev_node = node;
node->size = size;
/*
* chain the newNode to free list
*/
HeapChainToFreeList(newNode);
/*
* fix the next node
*/
((HeapNode *)((char *)newNode + newNode->size))->prev_node = newNode;
}
/*
* allock this block
*/
node->mark = HEAP_NODE_ALLOCED;
/*
* delete the node from free list
*/
HeapDeleteFromFreeList(node);
m_heap_available -= node->size;
if(m_min_heap_avaiable > m_heap_available)
m_min_heap_avaiable = m_heap_available;
uffs_CriticalExit(); /* exit critical */
return (void *)((char *)node + ALLOC_OFFSET);
}
/*
* Allocate a block from heap memory.
*
* This functions allocates a memory block of the specified
* size and returns a pointer to that block.
*
* The actual size of the allocated block is larger than the
* requested size because of space required for maintenance
* information. This additional information is invisible to
* the application.
*
* The routine looks for the smallest block that will meet
* the required size and releases it to the caller. If the
* block being requested is usefully smaller than the smallest
* free block then the block from which the request is being
* met is split in two. The unused portion is put back into
* the free-list.
*
* The contents of the allocated block is unspecified.
* To allocate a block with all bytes set to zero use
* KHeapAllocClear().
*
* \note Interrupts are automatically enabled, when this
* function returns.
*
* \param size Size of the requested memory block.
*
* \return Pointer to the allocated memory block if the
* function is successful or NULL if the requested
* amount of memory is not m_heap_available.
*/
static void *_kmalloc(int size)
{
HeapNode *node;
#if defined(K_HEAP_ALLOCK_BEST_FIT)
HeapNode *fit;
#endif
if(size <= 0)
return NULL; /* size is not fit */
/*
* adjust size
*/
size += ALLOC_OFFSET;
if(size & ALLOC_PAGE_MASK){
size += ALLOC_PAGE_SIZE;
size &= ~ALLOC_PAGE_MASK;
}
uffs_CriticalEnter(); /* enter critical */
node = m_heapFreeList;
#if defined(K_HEAP_ALLOCK_BEST_FIT)
/*
* Walk through the linked list of free nodes and find the best fit.
*/
fit = NULL;
while(node){
/*
* Found a note that fits?
*/
if(node->size >= size){
/*
* If it's an exact match, we don't
* search any further.
*/
if(node->size == size){
fit = node;
break;
}
/*
* We search most fit one
*/
if(fit){
if(node->size < fit->size)
fit = node;
}
else
fit = node;
}
node = node->next_free;
}
if(fit){
if(fit->size >= size)
return _k_allock_node(fit, size);
}
#else
while(node){
if(node->size >= size)
return _k_allock_node(node, size);
node = node->next_free;
}
#endif
uffs_CriticalExit(); /* exit critical */
return NULL; /* not found available block */
}
#if 0
/* Allocates an array in memory with elements initialized to 0 */
static void *_kcalloc(int num, int size)
{
return _kmalloc_clear(num * size);
}
#endif
/* Realloc memory.
* if the size of memblock is small then the new required size,
* alloc a new block memory, and copy the contents from the old one,
* and free the old block.
* if the size is zero, free the old block, and return NULL. <2004.5.8>
* if the size of origin block is larger then the new required size,
* then:
* if the gap is larger then ALLOC_PAGE_SIZE, split the node, and return
* the leav memory back to free list.
* if the gap is less then ALLOC_PAGE_SIZE, just return current block.
* If the given block parameter is NULL, _krealloc behaves the same as _kmalloc.
*/
static void *_krealloc(void *block, int size)
{
HeapNode *node;
HeapNode *newNode;
void *p; /* return pointer */
int old_data_size; /* old block data size */
if(block == NULL){
return _kmalloc(size);
}
if(size == 0) {
_kfree(block);
return NULL;
}
uffs_CriticalEnter(); /* enter critical */
node = (HeapNode *)((char *)block - ALLOC_OFFSET);
old_data_size = node->size - ALLOC_OFFSET;
if(node->mark != (int)HEAP_NODE_ALLOCED || old_data_size <= 0) {
uffs_CriticalExit(); /* exit critical */
return NULL; /*!!!! at this moment, the heap
managment info must be damaged !!!!!*/
}
if(old_data_size < size) {
/* new size is larger then origin block, so need alloc new block */
p = _kmalloc(size);
if(!p) {
uffs_CriticalExit(); /* exit critical */
return NULL; /* can't alloc a new block memory, fail... */
}
/* alloc a new block, and copy contents from origin block,
* and free it finally.
*/
memcpy(p, block, old_data_size);
_kfree(block);
uffs_CriticalExit(); /* exit critical */
return p;
}
else {
/* adjust size */
size += ALLOC_OFFSET;
if(size & ALLOC_PAGE_MASK) {
size += ALLOC_PAGE_SIZE;
size &= ~ALLOC_PAGE_MASK;
}
if(node->size - size < ALLOC_PAGE_SIZE) {
/* the remain memory is too small, so just skip it */
uffs_CriticalExit(); /* exit critical */
return block;
}
else {
/* the remain memory is large enough to be splited */
/* we generate a new 'alloced' node there */
newNode = (HeapNode *)((char *)node + size);
newNode->prev_node = node;
newNode->mark = HEAP_NODE_ALLOCED;
newNode->size = node->size - size;
/* split into two node now */
((HeapNode *)((char *)node + node->size))->prev_node = newNode;
node->size = size;
/* put the newNode into free list */
_kfree((void *)((char *)newNode + ALLOC_OFFSET));
uffs_CriticalExit(); /* exit critical */
return block;
}
}
}
#if 0
static void * _kmalloc_clear(int size)
{
void *p;
p = _kmalloc(size);
if(p)
memset(p, 0, size);
return p;
}
#endif
/*!
* \brief Return a block to heap memory.
*
* An application calls this function, when a previously
* allocated memory block is no longer needed.
*
* The heap manager checks, if the released block adjoins any
* other free regions. If it does, then the adjacent free regions
* are joined together to form one larger region.
*
* \note Interrupts are automatically enabled, when this
* function returns.
*
* \param block Points to a memory block previously allocated
* through a call to _kmalloc().
*
* \return 0 on success, -1 if the caller tried to free
* a block which had been previously released.
*/
static int _kfree(void *block)
{
HeapNode *node;
HeapNode *prev;
HeapNode *next;
if (block == NULL) {
return -1; //the pointer of the memory is invalid.
}
uffs_CriticalEnter(); /* enter critical */
node = (HeapNode *)((char *)block - ALLOC_OFFSET);
if(node->mark != (int)HEAP_NODE_ALLOCED || node->size <= ALLOC_OFFSET) {
uffs_CriticalExit();/* exit critical */
return -1; /*!!!! at this point, the heap
management info must be damaged !!!!!*/
}
m_heap_available += node->size;
prev = node->prev_node;
next = (HeapNode *)((char *)node + node->size);
if(prev->mark == HEAP_NODE_FREE){
/*
* If there' s a free node in front of us, merge it.
*/
prev->size += node->size;
next->prev_node = prev;
HeapDeleteFromFreeList(prev);
node = prev;
}
if(next->mark == HEAP_NODE_FREE){
/*
* If there' s a free node following us, merge it.
*/
node->size += next->size;
((HeapNode *)((char *)next + next->size))->prev_node = node;
HeapDeleteFromFreeList(next);
}
/*
* now, we just chain the node to free list head.
*/
node->mark = HEAP_NODE_FREE;
HeapChainToFreeList(node);
uffs_CriticalExit(); /* exit critical */
return 0;
}
/*!
* \brief
* Add a new memory region to the free heap.
*
* This function is called during
* initialization.
*
* Applications typically do not call this function.
*
* \param addr Start address of the memory region.
* \param size Number of bytes of the memory region.
*/
void uffs_MemInitHeap(void *addr, int size)
{
HeapNode *np;
if(!((long)addr & 3)){
addr = (void *)(((char *)addr) + 4);
addr = (void *)(((long)addr) & ~3);
}
size &= ~ALLOC_PAGE_MASK;
if(size < ALLOC_PAGE_SIZE * 3) return;
uffs_CriticalEnter();
/* pre alloc header node, size is ALLOC_PAGE_SIZE */
np = (HeapNode *)addr;
np->size = ALLOC_PAGE_SIZE;
np->mark = HEAP_NODE_ALLOCED;
np->prev_node = NULL;
/* pre alloc tail node, size is -1 */
np = (HeapNode *)((char *)addr + size - ALLOC_PAGE_SIZE);
np->mark = HEAP_NODE_ALLOCED;
np->size = -1;
np->prev_node = (HeapNode *)((char *)addr + ALLOC_PAGE_SIZE);
m_heapTail = np;
/* Free list head */
np = (HeapNode *)((char *)addr + ALLOC_PAGE_SIZE);
np->mark = HEAP_NODE_FREE;
np->prev_node = (HeapNode *)addr;
np->size = size - 2 * ALLOC_PAGE_SIZE;
np->next_free = NULL;
np->prev_free = NULL;
m_heapFreeList = np;
m_heap_available = np->size;
m_min_heap_avaiable = m_heap_available;
m_kernel_heap_total += size;
uffs_CriticalExit();
}
/******************************************************************************************/
static void *__umalloc(uffs_MemAllocator *mem, unsigned int size, HeapHashTable * hash_tbl);
static void *__ucalloc(uffs_MemAllocator *mem, unsigned int num, unsigned int size, HeapHashTable *hash_tbl);
static void *__urealloc(uffs_MemAllocator *mem, void *block, unsigned int size, HeapHashTable *hash_tbl);
static int __ufree(uffs_MemAllocator *mem, void *p, HeapHashTable * hash_tbl);
/* release all alloced memory from hash table,
* return alloced pointer nummber.
*/
static int ReleaseHeap(uffs_MemAllocator *mem, HeapHashTable *hash_tbl)
{
int i;
int count = 0;
HeapMm volatile * node;
if (hash_tbl == NULL)
return -1;
for (i = 0; i < HEAP_HASH_SIZE; i++){
while ((node = hash_tbl[i]) != NULL){
__ufree(mem, node->p, hash_tbl);
count++;
}
}
_kfree(hash_tbl);
return count;
}
static void *uffs_malloc(struct uffs_DeviceSt *dev, unsigned int size)
{
HeapHashTable * hash_tbl;
if ((int)size < 0)
return NULL;
hash_tbl = dev->mem.tbl;
if (hash_tbl) {
return __umalloc(&dev->mem, size, hash_tbl);
}
else{
return NULL;
}
}
/* alloc one block with given size, return the block pointer */
static void *__umalloc(uffs_MemAllocator *mem, unsigned int size, HeapHashTable *hash_tbl)
{
void *p;
HeapMm *node;
int idx;
/* calling kernel routin allocate bigger size memory block */
p = _kmalloc(HEAP_MAGIC_SIZE + size + HEAP_MAGIC_SIZE);
if (p) {
node = (HeapMm *)_kmalloc(sizeof(HeapMm));
if (node == NULL) {
_kfree(p);
return NULL;
}
p = (void *)((char *)p + HEAP_MAGIC_SIZE); /* adjust pointer first */
node->p = p;
node->size = size;
mem->count += size;
if (mem->maxused < mem->count)
mem->maxused = mem->count;
node->task_id = uffs_OSGetTaskId(); /* get task id */
uffs_CriticalEnter();
/* insert node to hash table */
idx = GET_HASH_INDEX(p);
node->next = hash_tbl[idx];
hash_tbl[idx] = node;
uffs_CriticalExit();
return p; /* ok, return the pointer */
}
return NULL;
}
/* Allocates an array in memory with elements initialized to 0 */
static void *__ucalloc(uffs_MemAllocator *mem, unsigned int num, unsigned int size, HeapHashTable *hash_tbl)
{
return __umalloc(mem, num * size, hash_tbl);
}
/* realloc one block with given size, return the block pointer */
static void *__urealloc(uffs_MemAllocator *mem, void *block, unsigned int size, HeapHashTable *hash_tbl)
{
void *p, *pNew;
HeapMm *prev, *node;
int idx;
if (block == NULL) {
return __umalloc(mem, size, hash_tbl);
}
if (size == 0) {
__ufree(mem, block, hash_tbl);
return NULL;
}
/* calculate hash idx */
idx = GET_HASH_INDEX(block);
/* check whether block pointer is alloc from this heap... */
uffs_CriticalEnter();
node = hash_tbl[idx];
prev = NULL;
while (node){
if (node->p == block) {
break; /* got it! */
}
prev = node;
node = node->next; /* search for next node */
}
if (!node) {
/* not my duty :-) */
uffs_CriticalExit();
return NULL;
}
/* ok, begin call kernel API to realloc memory */
p = (void *)((char *)block - HEAP_MAGIC_SIZE); /* get real pointer which kernel need */
pNew = _krealloc(p, HEAP_MAGIC_SIZE + size + HEAP_MAGIC_SIZE);
if (pNew == NULL) { /* realloc fail */
uffs_CriticalExit();
return NULL;
}
if (pNew == p) {
/* new block is the same as the old block */
uffs_CriticalExit();
return block;
}
/* new block is difference with old block, we need to change hash table ... */
if (prev){
/* prev is not the first */
prev->next = node->next;
}
else{
/* this node is the first, so.. */
hash_tbl[idx] = node->next;
}
uffs_CriticalExit();
node->p = (void *)((char *)pNew + HEAP_MAGIC_SIZE);
node->size = size;
node->task_id = uffs_OSGetTaskId();
/* insert node into hash table */
idx = GET_HASH_INDEX(node->p);
uffs_CriticalEnter();
node->next = hash_tbl[idx];
hash_tbl[idx] = node;
uffs_CriticalExit();
return node->p;
}
/* free the block, if the pointer(parameter 'p') is
* not valid(allocated by this allocate system) or error occur, return -1,
* else return 0
*/
static int __ufree(uffs_MemAllocator *mem, void *p, HeapHashTable *hash_tbl)
{
HeapMm *node, *prev;
if (p) { /* check the pointer */
uffs_CriticalEnter();
node = hash_tbl[GET_HASH_INDEX(p)];
prev = NULL;
while (node) {
if (node->p == p) {
/* we find the node, so begin to release */
if (prev) {
/* this node is not the first */
prev->next = node->next;
}
else {
/* this node is the first node of hash channel */
hash_tbl[GET_HASH_INDEX(p)] = node->next;
}
mem->count -= node->size;
uffs_CriticalExit();
if (_kfree(node) == -1) /* calling kernel routine release node */
return -1; /* fail, return -1 */
/* calling kernel routine and return */
return _kfree((void *)((char *)p - HEAP_MAGIC_SIZE));
}
prev = node;
node = node->next; /* search for next node */
}
uffs_CriticalExit();
}
return -1;
}
static URET uffs_free(struct uffs_DeviceSt *dev, void *block)
{
HeapHashTable *hash_tbl;
hash_tbl = dev->mem.tbl;
if (hash_tbl) {
if (__ufree(&dev->mem, block, hash_tbl) < 0) {
uffs_Perror(UFFS_ERR_SERIOUS, "Try to free unmanaged memory ?");
return U_FAIL;
}
}
return U_SUCC;
}
URET uffs_MemInitNativeAllocator(uffs_Device *dev)
{
uffs_MemAllocator *mem = &dev->mem;
memset(mem->tbl, 0, sizeof(mem->tbl));
mem->malloc = uffs_malloc;
mem->free = uffs_free;
mem->blockinfo_pool_size = 0;
mem->pagebuf_pool_size = 0;
mem->tree_nodes_pool_size = 0;
return U_SUCC;
}
URET uffs_MemReleaseNativeAllocator(uffs_Device *dev)
{
int count;
URET ret = U_SUCC;
if (dev) {
count = ReleaseHeap(&dev->mem, dev->mem.tbl);
if (count < 0) {
uffs_Perror(UFFS_ERR_SERIOUS, "Release native memory allocator fail!");
ret = U_FAIL;
}
else if (count > 0) {
uffs_Perror(UFFS_ERR_NORMAL, "Find %d block memory leak!", count);
}
}
return ret;
}
/**
* \brief Setup the memory allocator to native memory allocator
*
* \param allocator memory allocator to be setup
*/
void uffs_MemSetupNativeAllocator(uffs_MemAllocator *allocator)
{
memset(allocator, 0, sizeof(uffs_MemAllocator));
allocator->init = uffs_MemInitNativeAllocator;
allocator->release = uffs_MemReleaseNativeAllocator;
}
#endif //CONFIG_USE_NATIVE_MEMORY_ALLOCATOR
#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
#include <malloc.h>
static void * sys_malloc(struct uffs_DeviceSt *dev, unsigned int size)
{
uffs_Perror(UFFS_ERR_NORMAL, "system memory alloc %d bytes", size);
return malloc(size);
}
static URET sys_free(struct uffs_DeviceSt *dev, void *p)
{
free(p);
return U_SUCC;
}
void uffs_MemSetupSystemAllocator(uffs_MemAllocator *allocator)
{
allocator->malloc = sys_malloc;
allocator->free = sys_free;
}
#endif //CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
static void * static_malloc(struct uffs_DeviceSt *dev, unsigned int size)
{
struct uffs_memAllocatorSt *mem = &dev->mem;
void *p = NULL;
size += (size % sizeof(long) ? sizeof(long) - (size % sizeof(long)) : 0);
if (mem->buf_size - mem->pos < (int)size) {
uffs_Perror(UFFS_ERR_SERIOUS, "Memory alloc failed! (alloc %d, free %d)", size, mem->buf_size - mem->pos);
}
else {
p = mem->buf_start + mem->pos;
mem->pos += size;
uffs_Perror(UFFS_ERR_NOISY, "0x%p: Allocated %d, free %d", p, size, mem->buf_size - mem->pos);
}
return p;
}
void uffs_MemSetupStaticAllocator(uffs_MemAllocator *allocator, void *pool, int size)
{
allocator->buf_start = (unsigned char *)pool;
allocator->buf_size = size;
allocator->pos = 0;
allocator->malloc = static_malloc;
allocator->free = NULL; //never free memory for static memory allocator
uffs_Perror(UFFS_ERR_NOISY, "System static memory: %d bytes", allocator->buf_size);
}
#endif

View File

@ -0,0 +1,247 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_mtb.c
* \brief mount table operations
* \author Ricky Zheng, created 11th July, 2009
*/
#include "uffs/uffs_types.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_tree.h"
#include "uffs/uffs_mtb.h"
#include "uffs/uffs_fd.h"
#include <string.h>
#define PFX "mtb: "
static struct uffs_MountTableEntrySt *g_mtb_head = NULL;
uffs_MountTable * uffs_GetMountTable(void)
{
return g_mtb_head;
}
int uffs_RegisterMountTable(uffs_MountTable *mtab)
{
uffs_MountTable *work = g_mtb_head;
if (mtab == NULL)
return -1;
if (work == NULL) {
g_mtb_head = mtab;
return 0;
}
while (work) {
if (mtab == work) {
/* already registered */
return 0;
}
if (work->next == NULL) {
work->next = mtab;
mtab->next = NULL;
return 0;
}
work = work->next;
}
return -1;
}
URET uffs_InitMountTable(void)
{
struct uffs_MountTableEntrySt *tbl = uffs_GetMountTable();
struct uffs_MountTableEntrySt *work;
int dev_num = 0;
for (work = tbl; work; work = work->next) {
uffs_Perror(UFFS_ERR_NOISY, "init device for mount point %s ...", work->mount);
if (work->dev->Init(work->dev) == U_FAIL) {
uffs_Perror(UFFS_ERR_SERIOUS, "init device for mount point %s fail", work->mount);
return U_FAIL;
}
work->dev->par.start = work->start_block;
if (work->end_block < 0) {
work->dev->par.end = work->dev->attr->total_blocks + work->end_block;
}
else {
work->dev->par.end = work->end_block;
}
uffs_Perror(UFFS_ERR_NOISY, "mount partiton: %d,%d",
work->dev->par.start, work->dev->par.end);
if (uffs_InitDevice(work->dev) != U_SUCC) {
uffs_Perror(UFFS_ERR_SERIOUS, "init device fail !");
return U_FAIL;
}
work->dev->dev_num = dev_num++;
}
if (uffs_InitObjectBuf() == U_SUCC) {
if (uffs_InitDirEntryBuf() == U_SUCC) {
return U_SUCC;
}
}
return U_FAIL;
}
URET uffs_ReleaseMountTable(void)
{
struct uffs_MountTableEntrySt *tbl = uffs_GetMountTable();
struct uffs_MountTableEntrySt *work;
for (work = tbl; work; work = work->next) {
uffs_ReleaseDevice(work->dev);
work->dev->Release(work->dev);
}
if (uffs_ReleaseObjectBuf() == U_SUCC) {
if (uffs_ReleaseDirEntryBuf() == U_SUCC) {
return U_SUCC;
}
}
return U_FAIL;
}
/**
* find the matched mount point from a given full absolute path.
*
* \param[in] path full path
* \return the length of mount point.
*/
int uffs_GetMatchedMountPointSize(const char *path)
{
int pos;
uffs_Device *dev;
if (path[0] != '/')
return 0;
pos = strlen(path);
while (pos > 0) {
if ((dev = uffs_GetDeviceFromMountPointEx(path, pos)) != NULL ) {
uffs_PutDevice(dev);
return pos;
}
else {
if (path[pos-1] == '/')
pos--;
//back forward search the next '/'
for (; pos > 0 && path[pos-1] != '/'; pos--)
;
}
}
return pos;
}
/**
* get device from mount point.
*
* \param[in] mount mount point name.
* \return NULL if mount point is not found.
*/
uffs_Device * uffs_GetDeviceFromMountPoint(const char *mount)
{
struct uffs_MountTableEntrySt *devTab = uffs_GetMountTable();
while (devTab) {
if (strcmp(mount, devTab->mount) == 0) {
devTab->dev->ref_count++;
return devTab->dev;
}
devTab = devTab->next;
}
return NULL;
}
/**
* get device from mount point.
*
* \param[in] mount mount point name.
* \param[in] len mount point name length.
* \return NULL if mount point is not found.
*/
uffs_Device * uffs_GetDeviceFromMountPointEx(const char *mount, int len)
{
struct uffs_MountTableEntrySt *devTab = uffs_GetMountTable();
while (devTab) {
if (strlen(devTab->mount) == len && strncmp(mount, devTab->mount, len) == 0) {
devTab->dev->ref_count++;
return devTab->dev;
}
devTab = devTab->next;
}
return NULL;
}
/**
* return mount point from device
*
* \param[in] dev uffs device
* \return NULL if mount point is not found, otherwise return mount point name in mount table.
*/
const char * uffs_GetDeviceMountPoint(uffs_Device *dev)
{
struct uffs_MountTableEntrySt * devTab = uffs_GetMountTable();
while (devTab) {
if (devTab->dev == dev) {
return devTab->mount;
}
devTab = devTab->next;
}
return NULL;
}
void uffs_PutDevice(uffs_Device *dev)
{
dev->ref_count--;
}

View File

@ -0,0 +1,343 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_pool.c
* \brief Fast fixed size memory pool management.
* \author Ricky Zheng, Simon Kallweit
*/
#include "uffs/uffs_types.h"
#include "uffs/uffs_os.h"
#include "uffs/uffs_pool.h"
/*
usage:
#define BUF_SIZE 32
#define NUM_BUFS 1024
static int pool_mem[NUM_BUFS * BUF_SIZE / sizeof(int)];
static uffs_Pool pool;
uffs_PoolInit(&pool, pool_mem, sizeof(pool_mem), BUF_SIZE, NUM_BUFS);
void * p;
p = uffs_PoolGet(&pool);
...
uffs_PoolPut(p, &pool);
notice:
uffs_PoolInit will assert when NUM_BUFS is not at least 1, or BUF_SIZE is
not aligned to the platforms pointer size.
*/
/**
* \brief Initializes the memory pool.
* \param[in] pool memory pool
* \param[in] mem pool memory
* \param[in] mem_size size of pool memory
* \param[in] buf_size size of a single buffer
* \param[in] num_bufs number of buffers
* \return Returns U_SUCC if successful.
*/
URET uffs_PoolInit(uffs_Pool *pool, void *mem, u32 mem_size, u32 buf_size, u32 num_bufs)
{
unsigned int i;
uffs_PoolEntry *e1, *e2;
uffs_Assert(pool, "pool missing");
uffs_Assert(mem, "pool memory missing");
uffs_Assert(num_bufs > 0, "not enough buffers");
uffs_Assert(buf_size % sizeof(void *) == 0, "buffer size not aligned to pointer size");
uffs_Assert(mem_size == num_bufs * buf_size, "pool memory size is wrong");
pool->mem = (u8 *)mem;
pool->buf_size = buf_size;
pool->num_bufs = num_bufs;
pool->sem = uffs_SemCreate(1);
uffs_SemWait(pool->sem);
// Initialize the free_list
e1 = e2 = pool->free_list = (uffs_PoolEntry *) pool->mem;
for (i = 1; i < pool->num_bufs; i++) {
e2 = (uffs_PoolEntry *) (pool->mem + i * pool->buf_size);
e1->next = e2;
e1 = e2;
}
e2->next = NULL;
uffs_SemSignal(pool->sem);
return U_SUCC;
}
/**
* \brief verify pointer validity aganist memory pool
* \return U_TRUE if valid, U_FALSE if invalid.
*/
UBOOL uffs_PoolVerify(uffs_Pool *pool, void *p)
{
return p &&
(u8 *)p >= pool->mem &&
(u8 *)p < pool->mem + (pool->buf_size * pool->num_bufs) &&
(((u8 *)p - pool->mem) % pool->buf_size) == 0 ? U_TRUE : U_FALSE;
}
/**
* \brief Releases the memory pool.
* \param[in] pool memory pool
* \return Returns U_SUCC if successful.
*/
URET uffs_PoolRelease(uffs_Pool *pool)
{
uffs_Assert(pool, "pool missing");
uffs_SemDelete(pool->sem);
pool->sem = 0;
return U_SUCC;
}
/**
* \brief Get a buffer from the memory pool.
* \param[in] pool memory pool
* \return Returns a pointer to the buffer or NULL if none is available.
*/
void *uffs_PoolGet(uffs_Pool *pool)
{
uffs_PoolEntry *e;
uffs_Assert(pool, "pool missing");
e = pool->free_list;
if (e)
pool->free_list = e->next;
return e;
}
/**
* \brief Get a buffer from the memory pool.
* This version is locked and should be used when multiple threads access the
* same memory pool.
* \param[in] pool memory pool
* \return Returns a pointer to the buffer or NULL if none is available.
*/
void *uffs_PoolGetLocked(uffs_Pool *pool)
{
uffs_PoolEntry *e;
uffs_Assert(pool, "pool missing");
uffs_SemWait(pool->sem);
e = pool->free_list;
if (e)
pool->free_list = e->next;
uffs_SemSignal(pool->sem);
return e;
}
/**
* \brief Puts a buffer back to the memory pool.
* \param[in] pool memory pool
* \param[in] p buffer to put back
* \return Returns 0 if successful.
*/
int uffs_PoolPut(uffs_Pool *pool, void *p)
{
uffs_PoolEntry *e = (uffs_PoolEntry *)p;
uffs_Assert(pool, "pool missing");
if (e) {
e->next = pool->free_list;
pool->free_list = e;
return 0;
}
return -1;
}
/**
* \brief Puts a buffer back to the memory pool.
* This version is locked and should be used when multiple threads access the
* same memory pool.
* \param[in] pool memory pool
* \param[in] p buffer to put back
* \return Returns 0 if successful.
*/
int uffs_PoolPutLocked(uffs_Pool *pool, void *p)
{
uffs_PoolEntry *e = (uffs_PoolEntry *)p;
uffs_Assert(pool, "pool missing");
if (e) {
uffs_SemWait(pool->sem);
e->next = pool->free_list;
pool->free_list = e;
uffs_SemSignal(pool->sem);
return 0;
}
return -1;
}
/**
* \brief Gets a buffer by index (offset).
* This method returns a buffer from the memory pool by index.
* \param[in] pool memory pool
* \param[in] index index
* \return Returns a pointer to the buffer.
*/
void *uffs_PoolGetBufByIndex(uffs_Pool *pool, u32 index)
{
uffs_Assert(pool, "pool missing");
uffs_Assert(index >= 0 && index < pool->num_bufs, "index out of range");
return (u8 *) pool->mem + index * pool->buf_size;
}
/**
* \brief Gets the index (offset) of a buffer.
* This method returns the index of a buffer from the memory pool.
* \param[in] pool memory pool
* \param[in] p buffer to get index from
* \return Returns the index of the buffer.
*/
u32 uffs_PoolGetIndex(uffs_Pool *pool, void *p)
{
uffs_Assert(pool, "pool missing");
uffs_Assert(p >= (void *) pool->mem &&
p < (void *) (pool->mem + pool->num_bufs * pool->buf_size),
"pointer out of range");
return ((u8 *) p - pool->mem) / pool->buf_size;
}
/**
* \brief Check given buffer in free list
* \return U_TRUE if it's in free list, U_FALSE if not.
*/
UBOOL uffs_PoolCheckFreeList(uffs_Pool *pool, void *p)
{
uffs_PoolEntry *e;
for (e = pool->free_list; e; e = e->next) {
if ((void *)e == p)
return U_TRUE;
}
return U_FALSE;
}
/**
* \brief this is more efficient version for small nodes number memory pool (< 32)
*/
static void * FindNextAllocatedInSmallPool(uffs_Pool *pool, void *from)
{
u32 map = 0;
uffs_PoolEntry *e;
u32 i;
for (e = pool->free_list; e; e = e->next)
map |= (1 << uffs_PoolGetIndex(pool, e));
for (i = uffs_PoolGetIndex(pool, from); (map & (1 << i)) && i < 32; i++);
return i < 32 ? uffs_PoolGetBufByIndex(pool, i) : NULL;
}
/**
* \brief Find next allocated memory block
*
* \param[in] pool memory pool
* \param[in] from search start address, if NULL, from pool->mem
*
* \return next allocated memory block, NULL if not found.
*
* \note This is NOT efficient, don't do it on a pool with large free nodes !
*/
void * uffs_PoolFindNextAllocated(uffs_Pool *pool, void *from)
{
uffs_PoolEntry *e = NULL;
u8 *p = (u8 *)from;
if (p == NULL)
p = pool->mem;
else
p += pool->buf_size;
if (pool->num_bufs < 32)
return FindNextAllocatedInSmallPool(pool, p);
// work through the free list, stop if not in free list,
// otherwise move to next entry and search free list again.
if (pool->free_list) {
while (e == NULL && uffs_PoolVerify(pool, p)) {
e = pool->free_list;
while (e) {
if (p == (u8 *)e) {
p += pool->buf_size; // in free list, move to next entry
break;
}
e = e->next;
}
}
}
return uffs_PoolVerify(pool, p) ? p : NULL ;
}
/**
* \brief get free memory block count
*/
int uffs_PoolGetFreeCount(uffs_Pool *pool)
{
int count = 0;
uffs_PoolEntry *e;
e = pool->free_list;
while (e) {
count++;
e = e->next;
}
return count;
}

View File

@ -0,0 +1,533 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_public.c
* \brief public and miscellaneous functions
* \author Ricky Zheng, created 10th May, 2005
*/
#include "uffs/uffs_types.h"
#include "uffs/uffs_config.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_device.h"
#include "uffs/uffs_os.h"
#include <string.h>
#define PFX "pub: "
int uffs_GetFirstBlockTimeStamp(void)
{
return 0;
}
int uffs_GetNextBlockTimeStamp(int prev)
{
return (prev + 1) % 3;
}
UBOOL uffs_IsSrcNewerThanObj(int src, int obj)
{
switch (src - obj) {
case 0:
uffs_Perror(UFFS_ERR_SERIOUS, "the two block have the same time stamp ?");
break;
case 1:
case -2:
return U_TRUE;
case -1:
case 2:
return U_FALSE;
default:
uffs_Perror(UFFS_ERR_SERIOUS, "time stamp out of range !");
break;
}
return U_FALSE;
}
/**
* \brief given a page, search the block to find a better page with the same page id
*
* \param[in] dev uffs device
* \param[in] bc block info
* \param[in] page page number to be compared with
*
* \return the better page number, could be the same with the given page
*/
u16 uffs_FindBestPageInBlock(uffs_Device *dev, uffs_BlockInfo *bc, u16 page)
{
int i;
int best;
uffs_Tags *tag, *tag_old;
if (page == dev->attr->pages_per_block - 1)
return page;
uffs_BlockInfoLoad(dev, bc, page); //load old page
tag_old = GET_TAG(bc, page);
for (i = dev->attr->pages_per_block - 1; i > page; i--) {
uffs_BlockInfoLoad(dev, bc, i);
tag = GET_TAG(bc, i);
if (TAG_PAGE_ID(tag) == TAG_PAGE_ID(tag_old)) {
if (TAG_PARENT(tag) == TAG_PARENT(tag_old) &&
TAG_SERIAL(tag) == TAG_SERIAL(tag_old) &&
TAG_IS_DIRTY(tag) && //0: dirty, 1:clear
TAG_IS_VALID(tag_old)) { //0: valid, 1:invalid
break;
}
}
}
best = i;
#if 0
if (TAG_PAGE_ID(tag_old) == page) {
//well, try to speed up by probing the last page ....
uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
if (TAG_IS_VALID(tag) &&
TAG_IS_DIRTY(tag) &&
TAG_PAGE_ID(tag) == dev->attr->pages_per_block - 1) {
return page;
}
}
uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
best = page;
//the better page must be ahead of page, so ...i = page + 1; i < ...
for (i = page + 1; i < dev->attr->pages_per_block; i++) {
tag = GET_TAG(bc, i);
if (TAG_PAGE_ID(tag) == TAG_PAGE_ID(tag_old)) {
if (TAG_PARENT(tag) == TAG_PARENT(tag_old) &&
TAG_SERIAL(tag) == TAG_SERIAL(tag_old) &&
TAG_IS_DIRTY(tag) && //0: dirty, 1:clear
TAG_IS_VALID(tag_old)) { //0: valid, 1:invalid
if (i > best)
best = i;
}
}
}
#endif
return best;
}
/**
* \brief find a valid page with given page_id
* \param[in] dev uffs device
* \param[in] bc block info
* \param[in] page_id page_id to be find
* \return the valid page number which has given page_id
* \retval >=0 page number
* \retval UFFS_INVALID_PAGE page not found
*/
u16 uffs_FindPageInBlockWithPageId(uffs_Device *dev, uffs_BlockInfo *bc, u16 page_id)
{
u16 page;
uffs_Tags *tag;
//Indeed, the page which has page_id, should ahead of page_id ...
for (page = page_id; page < dev->attr->pages_per_block; page++) {
uffs_BlockInfoLoad(dev, bc, page);
tag = &(bc->spares[page].tag);
if (TAG_PAGE_ID(tag) == page_id)
return page;
}
return UFFS_INVALID_PAGE;
}
/**
* Are all the pages in the block used ?
*/
UBOOL uffs_IsBlockPagesFullUsed(uffs_Device *dev, uffs_BlockInfo *bc)
{
uffs_Tags *tag;
// if the last page is dirty, then the whole block is full
uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
return TAG_IS_DIRTY(tag) ? U_TRUE : U_FALSE;
}
/**
* Is this block used ?
* \param[in] dev uffs device
* \param[in] bc block info
* \retval U_TRUE block is used
* \retval U_FALSE block is free
*/
UBOOL uffs_IsThisBlockUsed(uffs_Device *dev, uffs_BlockInfo *bc)
{
uffs_Tags *tag;
// if the first page is dirty, then this block is used.
uffs_BlockInfoLoad(dev, bc, 0);
tag = GET_TAG(bc, 0);
return TAG_IS_DIRTY(tag) ? U_TRUE : U_FALSE;
}
/**
* get block time stamp from a exist block
* \param[in] dev uffs device
* \param[in] bc block info
*/
int uffs_GetBlockTimeStamp(uffs_Device *dev, uffs_BlockInfo *bc)
{
if(uffs_IsThisBlockUsed(dev, bc) == U_FALSE)
return uffs_GetFirstBlockTimeStamp();
else{
uffs_BlockInfoLoad(dev, bc, 0);
return TAG_BLOCK_TS(GET_TAG(bc, 0));
}
}
/**
* find first free page from 'pageFrom'
* \param[in] dev uffs device
* \param[in] bc block info
* \param[in] pageFrom search from this page
* \return return first free page number from 'pageFrom'
* \retval UFFS_INVALID_PAGE no free page found
* \retval >=0 the first free page number
*/
u16 uffs_FindFirstFreePage(uffs_Device *dev, uffs_BlockInfo *bc, u16 pageFrom)
{
u16 i;
for (i = pageFrom; i < dev->attr->pages_per_block; i++) {
uffs_BlockInfoLoad(dev, bc, i);
if (uffs_IsPageErased(dev, bc, i) == U_TRUE)
return i;
}
return UFFS_INVALID_PAGE; //free page not found
}
/**
* Find first valid page from a block, just used in mounting a partition
*/
u16 uffs_FindFirstValidPage(uffs_Device *dev, uffs_BlockInfo *bc)
{
u16 i;
for (i = 0; i < dev->attr->pages_per_block; i++) {
if (uffs_BlockInfoLoad(dev, bc, i) == U_SUCC)
return i;
}
return UFFS_INVALID_PAGE;
}
/**
* calculate sum of data, 8bit version
* \param[in] p data pointer
* \param[in] len length of data
* \return return sum of data, 8bit
*/
u8 uffs_MakeSum8(const void *p, int len)
{
u8 ret = 0;
const u8 *data = (const u8 *)p;
if (!p)
return 0;
while (len > 0) {
ret += *data++;
len--;
}
return ret;
}
/**
* calculate sum of datam, 16bit version
* \param[in] p data pointer
* \param[in] len length of data
* \return return sum of data, 16bit
*/
u16 uffs_MakeSum16(const void *p, int len)
{
u8 ret_lo = 0;
u8 ret_hi = 0;
const u8 *data = (const u8 *)p;
if (!p)
return 0;
while (len > 0) {
ret_lo += *data;
ret_hi ^= *data;
data++;
len--;
}
return (ret_hi << 8) | ret_lo;
}
/**
* create a new file on a free block
* \param[in] dev uffs device
* \param[in] parent parent dir serial num
* \param[in] serial serial num of this new file
* \param[in] bc block information
* \param[in] fi file information
* \note parent, serial, bc must be provided before, and all information in fi should be filled well before.
*/
URET uffs_CreateNewFile(uffs_Device *dev, u16 parent, u16 serial, uffs_BlockInfo *bc, uffs_FileInfo *fi)
{
uffs_Tags *tag;
uffs_Buf *buf;
uffs_BlockInfoLoad(dev, bc, 0);
tag = GET_TAG(bc, 0);
TAG_PARENT(tag) = parent;
TAG_SERIAL(tag) = serial;
TAG_DATA_LEN(tag) = sizeof(uffs_FileInfo);
//tag->data_sum = uffs_MakeSum16(fi->name, fi->name_len);
buf = uffs_BufGet(dev, parent, serial, 0);
if (buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, "get buf fail.");
return U_FAIL;
}
memcpy(buf->data, fi, TAG_DATA_LEN(tag));
buf->data_len = TAG_DATA_LEN(tag);
return uffs_BufPut(dev, buf);
}
/**
* \brief calculate data length of a file block
* \param[in] dev uffs device
* \param[in] bc block info
*/
int uffs_GetBlockFileDataLength(uffs_Device *dev, uffs_BlockInfo *bc, u8 type)
{
u16 page_id;
u16 i;
uffs_Tags *tag;
int size = 0;
u16 page;
u16 lastPage = dev->attr->pages_per_block - 1;
// TODO: Need to speed up this procedure!
// First try the last page. will hit it if it's the full loaded file/data block.
uffs_BlockInfoLoad(dev, bc, lastPage);
tag = GET_TAG(bc, lastPage);
if (type == UFFS_TYPE_FILE) {
if(TAG_PAGE_ID(tag) == (lastPage - 1) &&
TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
size = dev->com.pg_data_size * (dev->attr->pages_per_block - 1);
return size;
}
}
if (type == UFFS_TYPE_DATA) {
if(TAG_PAGE_ID(tag) == lastPage &&
TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
size = dev->com.pg_data_size * dev->attr->pages_per_block;
return size;
}
}
// ok, it's not the full loaded file/data block, need to read all spares....
uffs_BlockInfoLoad(dev, bc, UFFS_ALL_PAGES);
tag = GET_TAG(bc, 0);
if (TAG_TYPE(tag) == UFFS_TYPE_FILE) {
page_id = 1; //In file header block, file data page_id from 1
i = 1; //search from page 1
}
else {
page_id = 0; //in normal file data block, page_id from 0
i = 0; //in normal file data block, search from page 0
}
for (; i < dev->attr->pages_per_block; i++) {
tag = GET_TAG(bc, i);
if (page_id == TAG_PAGE_ID(tag)) {
page = uffs_FindBestPageInBlock(dev, bc, i);
size += TAG_DATA_LEN(GET_TAG(bc, page));
page_id++;
}
}
return size;
}
/**
* get free pages number
* \param[in] dev uffs device
* \param[in] bc block info
*/
int uffs_GetFreePagesCount(uffs_Device *dev, uffs_BlockInfo *bc)
{
int count = 0;
int i;
for (i = dev->attr->pages_per_block - 1; i >= 0; i--) {
uffs_BlockInfoLoad(dev, bc, i);
if (uffs_IsPageErased(dev, bc, (u16)i) == U_TRUE) {
count++;
}
else break;
}
return count;
}
/**
* \brief Is the block erased ?
* \param[in] dev uffs device
* \param[in] bc block info
* \param[in] page page number to be check
* \retval U_TRUE block is erased, ready to use
* \retval U_FALSE block is dirty, maybe use by file
*/
UBOOL uffs_IsPageErased(uffs_Device *dev, uffs_BlockInfo *bc, u16 page)
{
uffs_Tags *tag;
uffs_BlockInfoLoad(dev, bc, page);
tag = GET_TAG(bc, page);
if (!TAG_IS_DIRTY(tag) &&
!TAG_IS_VALID(tag)) {
return U_TRUE;
}
return U_FALSE;
}
/**
* \brief Is this block the last block of file ? (no free pages, and full filled with full page_id)
*/
UBOOL uffs_IsDataBlockReguFull(uffs_Device *dev, uffs_BlockInfo *bc)
{
uffs_Tags *tag;
uffs_BlockInfoLoad(dev, bc, dev->attr->pages_per_block - 1);
tag = GET_TAG(bc, dev->attr->pages_per_block - 1);
if (TAG_PAGE_ID(tag) == (dev->attr->pages_per_block - 1) &&
TAG_DATA_LEN(tag) == dev->com.pg_data_size) {
return U_TRUE;
}
return U_FALSE;
}
/**
* get partition used (bytes)
*/
int uffs_GetDeviceUsed(uffs_Device *dev)
{
return (dev->par.end - dev->par.start + 1 - dev->tree.bad_count
- dev->tree.erased_count) * dev->attr->page_data_size * dev->attr->pages_per_block;
}
/**
* get partition free (bytes)
*/
int uffs_GetDeviceFree(uffs_Device *dev)
{
return dev->tree.erased_count * dev->attr->page_data_size * dev->attr->pages_per_block;
}
/**
* get partition total size (bytes)
*/
int uffs_GetDeviceTotal(uffs_Device *dev)
{
return (dev->par.end - dev->par.start + 1) * dev->attr->page_data_size * dev->attr->pages_per_block;
}
/**
* load mini hader from flash
*/
URET uffs_LoadMiniHeader(uffs_Device *dev, int block, u16 page, struct uffs_MiniHeaderSt *header)
{
int ret = dev->ops->ReadPageData(dev, block, page, (u8 *)header, sizeof(struct uffs_MiniHeaderSt), NULL);
dev->st.page_header_read_count++;
return UFFS_FLASH_HAVE_ERR(ret) ? U_FAIL : U_SUCC;
}
#if 0
/** \brief transfer the standard uffs_Tags to uffs_Tags_8
* \param[in] tag standard uffs_Tags
* \param[out] tag_8 small tag to fit into 8 bytes spare space
*/
void uffs_TransferToTag8(uffs_Tags *tag, uffs_Tags_8 *tag_8)
{
tag_8->dirty = tag->dirty;
tag_8->valid = tag->valid;
tag_8->type = tag->type;
tag_8->block_ts = tag->block_ts;
tag_8->page_id = tag->page_id;
tag_8->parent = tag->parent & 0xFF;
tag_8->serial = tag->serial & 0xFF;
tag_8->data_len = tag->data_len & 0xFF;
tag_8->data_sum = tag->data_sum;
tag_8->block_status = tag->block_status;
}
/** \brief transfer the small uffs_Tags_8 to standard uffs_Tags
* \param[out] tag standard uffs_Tags
* \param[in] tag_8 small tag to fit into 8 bytes spare space
*/
void uffs_TransferFromTag8(uffs_Tags *tag, uffs_Tags_8 *tag_8)
{
tag->dirty = tag_8->dirty;
tag->valid = tag_8->valid;
tag->type = tag_8->type;
tag->block_ts = tag_8->block_ts;
tag->page_id = tag_8->page_id;
tag->parent = tag_8->parent;
tag->serial = tag_8->serial;
tag->data_len = tag_8->data_len;
tag->data_sum = tag_8->data_sum;
tag->block_status = tag_8->block_status;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,195 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_utils.c
* \brief utilities of uffs
* \author Ricky Zheng, created 12th May, 2005
*/
#include "uffs/uffs_device.h"
#include "uffs/uffs_utils.h"
#include "uffs/uffs_os.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_version.h"
#include "uffs/uffs_badblock.h"
#include <stdio.h>
#include <string.h>
#define PFX "util: "
#ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY
static void _ForceFormatAndCheckBlock(uffs_Device *dev, int block)
{
u8 *pageBuf;
int pageSize;
int i, j;
uffs_Buf *buf;
UBOOL bad = U_TRUE;
int ret;
buf = uffs_BufClone(dev, NULL);
if (buf == NULL) {
uffs_Perror(UFFS_ERR_SERIOUS, "Alloc page buffer fail ! Format stoped.");
goto ext;
}
pageSize = dev->com.pg_data_size;
pageBuf = buf->data;
//step 1: Erase, fully fill with 0x0, and check
ret = dev->ops->EraseBlock(dev, block);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
goto bad_out;
memset(pageBuf, 0, pageSize);
for (i = 0; i < dev->attr->pages_per_block; i++) {
ret = dev->ops->WritePageData(dev, block, i, pageBuf, pageSize, NULL);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
goto bad_out;
ret = dev->ops->WritePageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size, U_TRUE);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
goto bad_out;
}
for (i = 0; i < dev->attr->pages_per_block; i++) {
memset(pageBuf, 0xFF, pageSize);
dev->ops->ReadPageData(dev, block, i, pageBuf, pageSize, NULL);
for (j = 0; j < pageSize; j++) {
if(pageBuf[j] != 0)
goto bad_out;
}
memset(pageBuf, 0xFF, dev->attr->spare_size);
dev->ops->ReadPageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size);
for (j = 0; j < dev->attr->spare_size; j++) {
if(pageBuf[j] != 0)
goto bad_out;
}
}
//step 2: Erase, and check
ret = dev->ops->EraseBlock(dev, block);
if (UFFS_FLASH_IS_BAD_BLOCK(ret))
goto bad_out;
for (i = 0; i < dev->attr->pages_per_block; i++) {
memset(pageBuf, 0, pageSize);
dev->ops->ReadPageData(dev, block, i, pageBuf, pageSize, NULL);
for (j = 0; j < pageSize; j++) {
if(pageBuf[j] != 0xFF)
goto bad_out;
}
memset(pageBuf, 0, dev->attr->spare_size);
dev->ops->ReadPageSpare(dev, block, i, pageBuf, 0, dev->attr->spare_size);
for (j = 0; j < dev->attr->spare_size; j++) {
if(pageBuf[j] != 0xFF)
goto bad_out;
}
}
// format succ
bad = U_FALSE;
bad_out:
if (bad == U_TRUE)
uffs_FlashMarkBadBlock(dev, block);
ext:
if (buf)
uffs_BufFreeClone(dev, buf);
return;
}
#endif
URET uffs_FormatDevice(uffs_Device *dev)
{
u16 i, slot;
if (dev == NULL)
return U_FAIL;
if (dev->ops == NULL)
return U_FAIL;
if (uffs_BufIsAllFree(dev) == U_FALSE) {
uffs_Perror(UFFS_ERR_NORMAL, "some page still in used!");
return U_FAIL;
}
for (slot = 0; slot < MAX_DIRTY_BUF_GROUPS; slot++) {
if (dev->buf.dirtyGroup[slot].count > 0) {
uffs_Perror(UFFS_ERR_SERIOUS, "there still have dirty pages!");
return U_FAIL;
}
}
uffs_BufSetAllEmpty(dev);
if (uffs_BlockInfoIsAllFree(dev) == U_FALSE) {
uffs_Perror(UFFS_ERR_NORMAL, "there still have block info cache ? fail to format");
return U_FAIL;
}
uffs_BlockInfoExpireAll(dev);
for (i = dev->par.start; i <= dev->par.end; i++) {
if (uffs_FlashIsBadBlock(dev, i) == U_FALSE) {
uffs_FlashEraseBlock(dev, i);
if (HAVE_BADBLOCK(dev))
uffs_BadBlockProcess(dev, NULL);
}
else {
#ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY
_ForceFormatAndCheckBlock(dev, i);
#endif
}
}
if (uffs_TreeRelease(dev) == U_FAIL) {
return U_FAIL;
}
if (uffs_TreeInit(dev) == U_FAIL) {
return U_FAIL;
}
if (uffs_BuildTree(dev) == U_FAIL) {
return U_FAIL;
}
return U_SUCC;
}

View File

@ -0,0 +1,67 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_version.c
* \brief uffs version information
* \author Ricky Zheng, created 8th May, 2005
*/
#include "uffs/uffs_version.h"
#include "uffs/uffs_config.h"
#include <stdio.h>
#define PFX "ver: "
static char version_buf[8];
const char * uffs_Version2Str(int ver)
{
sprintf(version_buf, "%1d.%02d.%04d", (ver&0xff000000) >> 24, (ver&0xff0000) >> 16, (ver&0xffff));
return version_buf;
}
int uffs_GetVersion(void)
{
return UFFS_VERSION;
}
int uffs_GetMainVersion(int ver)
{
return (ver&0xff000000) >> 24;
}
int uffs_GetMinorVersion(int ver)
{
return (ver&0xff0000) >> 16;
}

View File

@ -0,0 +1,10 @@
INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/inc)
INCLUDE_DIRECTORIES(${uffs_SOURCE_DIR}/src/emu)
LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/emu)
LINK_DIRECTORIES(${uffs_BINARY_DIR}/src/uffs)
SET(mkuffs_SRCS mkuffs.c)
ADD_EXECUTABLE(mkuffs ${mkuffs_SRCS})
TARGET_LINK_LIBRARIES(mkuffs emu uffs emu)

View File

@ -0,0 +1,497 @@
/*
This file is part of UFFS, the Ultra-low-cost Flash File System.
Copyright (C) 2005-2009 Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
UFFS is free software; you can redistribute it and/or modify it under
the GNU Library General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any
later version.
UFFS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
or GNU Library General Public License, as applicable, for more details.
You should have received a copy of the GNU General Public License
and GNU Library General Public License along with UFFS; if not, write
to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
As a special exception, if other files instantiate templates or use
macros or inline functions from this file, or you compile this file
and link it with other works to produce a work based on this file,
this file does not by itself cause the resulting work to be covered
by the GNU General Public License. However the source code for this
file must still be made available in accordance with section (3) of
the GNU General Public License v2.
This exception does not invalidate any other reasons why a work based
on this file might be covered by the GNU General Public License.
*/
/**
* \file uffs_test.c
* \brief uffs test main entry
* \author Ricky Zheng
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uffs/uffs_config.h"
#include "uffs/uffs_public.h"
#include "uffs/uffs_fs.h"
#include "uffs/uffs_utils.h"
#include "uffs/uffs_core.h"
#include "uffs/uffs_mtb.h"
#include "cmdline.h"
#include "uffs_fileem.h"
#if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
int main()
{
printf("Static memory allocator is not supported.\n");
return 0;
}
#else
extern struct cli_commandset * get_helper_cmds(void);
extern struct cli_commandset * get_test_cmds(void);
extern void femu_init_uffs_device(uffs_Device *dev);
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
static int conf_memory_pool_size_kb = 800; /* default allocate 100k memory. */
static void *memory_pool = NULL;
#endif
static int conf_command_line_mode = 0;
static int conf_verbose_mode = 0;
static int conf_exec_script = 0;
static char script_file_name[256];
#define DEFAULT_EMU_FILENAME "uffsemfile.bin"
const char * conf_emu_filename = DEFAULT_EMU_FILENAME;
/* default basic parameters of the NAND device */
int conf_pages_per_block = 32;
int conf_pages_data_size = 512;
int conf_pages_spare_size = 16;
int conf_status_byte_offset = 5;
int conf_total_blocks = 128;
#define PAGE_SIZE (conf_pages_data_size + conf_pages_spare_size)
#define BLOCK_DATA_SIZE (conf_pages_per_block * conf_pages_data_size)
#define TOTAL_DATA_SIZE (conf_total_blocks * BLOCK_DATA_SIZE)
#define BLOCK_SIZE (conf_pages_per_block * PAGE_SIZE)
#define TOTAL_SIZE (BLOCK_SIZE * conf_total_blocks)
#define MAX_MOUNT_TABLES 10
#define MAX_MOUNT_POINT_NAME 32
static struct uffs_MountTableEntrySt conf_mounts[MAX_MOUNT_TABLES] = {0};
static uffs_Device conf_devices[MAX_MOUNT_TABLES] = {0};
static char mount_point_name[MAX_MOUNT_TABLES][MAX_MOUNT_POINT_NAME] = {0};
static struct uffs_StorageAttrSt emu_storage = {0};
static struct uffs_FileEmuSt emu_private = {0};
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
BOOL cmdMeminfo(const char *tail)
{
const char *mount = "/";
int i;
HeapMm *mm;
int count = 0;
int blocks = 0;
uffs_Device *dev;
if (tail)
mount = cli_getparam(tail, NULL);
dev = uffs_GetDeviceFromMountPoint(mount);
if (!dev) {
printf("can't get device from mount point %s\n", mount);
return TRUE;
}
for (i = 0; i < HEAP_HASH_SIZE; i++) {
mm = dev->mem.tbl[i];
while (mm) {
printf("%d, ", mm->size);
count += mm->size;
blocks++;
mm = mm->next;
}
}
printf("\n>>> total allocated %d blocks (%d bytes), max %d bytes. <<<\n", blocks, count, dev->mem.maxused);
uffs_PutDevice(dev);
return TRUE;
}
#endif
static struct cli_commandset basic_cmdset[] =
{
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
{ cmdMeminfo, "mem", "<mount>", "show native memory allocator infomation" },
#endif
{ NULL, NULL, NULL, NULL }
};
static void setup_emu_storage(struct uffs_StorageAttrSt *attr)
{
attr->total_blocks = conf_total_blocks; /* total blocks */
attr->page_data_size = conf_pages_data_size; /* page data size */
attr->spare_size = conf_pages_spare_size; /* page spare size */
attr->pages_per_block = conf_pages_per_block; /* pages per block */
attr->block_status_offs = conf_status_byte_offset; /* block status offset is 5th byte in spare */
attr->ecc_opt = UFFS_ECC_SOFT; /* let UFFS handle the ECC */
attr->layout_opt = UFFS_LAYOUT_UFFS; /* let UFFS handle layout */
}
static void setup_emu_private(uffs_FileEmu *emu)
{
memset(emu, 0, sizeof(uffs_FileEmu));
emu->emu_filename = conf_emu_filename;
}
static int init_uffs_fs(void)
{
static int bIsFileSystemInited = 0;
struct uffs_MountTableEntrySt *mtbl = &(conf_mounts[0]);
if(bIsFileSystemInited) return -4;
bIsFileSystemInited = 1;
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
// init protected heap for native memory allocator
memory_pool = malloc(conf_memory_pool_size_kb * 1024);
if (memory_pool)
uffs_MemInitHeap(memory_pool, conf_memory_pool_size_kb * 1024);
else {
uffs_Perror(UFFS_ERR_SERIOUS, "Can't alloc memory (size = %dKB) for uffs.", conf_memory_pool_size_kb);
return -1;
}
#endif
setup_emu_storage(&emu_storage);
setup_emu_private(&emu_private);
emu_storage._private = &emu_private;
while (mtbl->dev) {
mtbl->dev->attr = &emu_storage;
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
uffs_MemSetupNativeAllocator(&mtbl->dev->mem);
#endif
#if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
uffs_MemSetupSystemAllocator(&mtbl->dev->mem);
#endif
uffs_fileem_setup_device(mtbl->dev);
uffs_RegisterMountTable(mtbl);
mtbl++;
}
return uffs_InitMountTable() == U_SUCC ? 0 : -1;
}
static int release_uffs_fs(void)
{
int ret;
ret = uffs_ReleaseMountTable();
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
if (memory_pool) {
free(memory_pool);
memory_pool = NULL;
}
#endif
return ret;
}
/* mount point arg: /sys/,100,-1 */
static int parse_mount_point(char *arg, int m_idx)
{
int start = 0, end = -1;
char *p = arg;
struct uffs_MountTableEntrySt *mtbl = &(conf_mounts[m_idx]);
while(*p && *p != ',' && *p != ' ' && *p != '\t')
p++;
if (*p == 0 || p == arg)
return -1;
mtbl->mount = &(mount_point_name[m_idx][0]);
memcpy((char *)mtbl->mount, arg, p - arg);
((char *)(mtbl->mount))[p - arg] = 0;
p++;
arg = p;
while(*p && *p != ',' && *p != ' ' && *p != '\t')
p++;
if (p != arg) {
if (sscanf(arg, "%i", &start) < 1)
return -1;
p++;
arg = p;
while(*p && *p != ',' && *p != ' ' && *p != '\t')
p++;
if (p != arg) {
if (sscanf(arg, "%i", &end) < 1)
return -1;
}
}
mtbl->start_block = start;
mtbl->end_block = end;
mtbl->dev = &(conf_devices[m_idx]);
return 0;
}
static int parse_options(int argc, char *argv[])
{
int iarg;
int usage = 0;
int m_idx = 0;
static char em_file[128];
for (iarg = 1; iarg < argc && !usage; iarg++) {
const char *arg = argv[iarg];
if (arg[0] == '-') {
if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
usage++;
}
else if (!strcmp(arg, "-f") || !strcmp(arg, "--file")) {
if (++iarg >= argc)
usage++;
else {
strcpy(em_file, argv[iarg]);
conf_emu_filename = (const char *)em_file;
}
}
else if (!strcmp(arg, "-c") || !strcmp(arg, "--command-line")) {
conf_command_line_mode = 1;
}
else if (!strcmp(arg, "-p") || !strcmp(arg, "--page-size")) {
if (++iarg >= argc)
usage++;
else if (sscanf(argv[iarg], "%i", &conf_pages_data_size) < 1)
usage++;
if (conf_pages_data_size <= 0 || (conf_pages_data_size % 512))
usage++;
}
else if (!strcmp(arg, "-s") || !strcmp(arg, "--spare-size")) {
if (++iarg >= argc)
usage++;
else if (sscanf(argv[iarg], "%i", &conf_pages_spare_size) < 1)
usage++;
if (conf_pages_spare_size < 16 || (conf_pages_spare_size % 4))
usage++;
}
else if (!strcmp(arg, "-o") || !strcmp(arg, "--status-offset")) {
if (++iarg >= argc)
usage++;
else if (sscanf(argv[iarg], "%i", &conf_status_byte_offset) < 1)
usage++;
if (conf_status_byte_offset < 0)
usage++;
}
else if (!strcmp(arg, "-b") || !strcmp(arg, "--block-pages")) {
if (++iarg >= argc)
usage++;
else if (sscanf(argv[iarg], "%i", &conf_pages_per_block) < 1)
usage++;
if (conf_pages_per_block < 2)
usage++;
}
else if (!strcmp(arg, "-t") || !strcmp(arg, "--total-blocks")) {
if (++iarg >= argc)
usage++;
else if (sscanf(argv[iarg], "%i", &conf_total_blocks) < 1)
usage++;
if (conf_total_blocks < 2)
usage++;
}
else if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
conf_verbose_mode = 1;
}
else if (!strcmp(arg, "-m") || !strcmp(arg, "--mount")) {
if (++iarg > argc)
usage++;
else if (parse_mount_point(argv[iarg], m_idx) < 0)
usage++;
m_idx++;
}
else if (!strcmp(arg, "-e") || !strcmp(arg, "--exec")) {
if (++iarg > argc)
usage++;
else {
strcpy(script_file_name, argv[iarg]);
conf_exec_script = 1;
}
}
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
else if (!strcmp(arg, "-a") || !strcmp(arg, "--alloc")) {
if (++iarg > argc)
usage++;
else if (sscanf(argv[iarg], "%d", &conf_memory_pool_size_kb) < 1)
usage++;
if (conf_memory_pool_size_kb <= 0)
usage++;
}
#endif
else {
printf("Unknown option: %s, try %s --help\n", arg, argv[0]);
return -1;
}
}
else {
printf("Unexpected parameter: %s, try %s --help\n", arg, argv[0]);
return -1;
}
}
if (usage) {
printf("Usage: %s [options]\n", argv[0]);
printf(" -h --help show usage\n");
printf(" -c --command-line command line mode\n");
printf(" -v --verbose verbose mode\n");
printf(" -f --file <file> uffs image file\n");
printf(" -p --page-size <n> page data size, default=512\n");
printf(" -s --spare-size <n> page spare size, default=16\n");
printf(" -o --status-offset <n> status byte offset, default=5\n");
printf(" -b --block-pages <n> pages per block\n");
printf(" -t --total-blocks <n> total blocks\n");
printf(" -m --mount <mount_point,start,end> , for example: -m /,0,-1\n");
printf(" -i --id-man <id> set manufacture ID, default=0xEC\n");
printf(" -e --exec <file> execute a script file\n");
#if CONFIG_USE_NATIVE_MEMORY_ALLOCATOR > 0
printf(" -a --alloc <size> allocate size(KB) of memory for uffs, default 100\n");
#endif
printf("\n");
return -1;
}
if (m_idx == 0) {
parse_mount_point("/,0,-1", 0);
}
return 0;
}
static void print_mount_points(void)
{
struct uffs_MountTableEntrySt *m;
m = &(conf_mounts[0]);
while (m->dev) {
printf ("Mount point: %s, start: %d, end: %d\n", m->mount, m->start_block, m->end_block);
m++;
}
}
static void print_params(void)
{
printf("uffs image file: %s\n", conf_emu_filename);
printf("page size: %d\n", conf_pages_data_size);
printf("page spare size: %d\n", conf_pages_spare_size);
printf("pages per block: %d\n", conf_pages_per_block);
printf("total blocks: %d\n", conf_total_blocks);
}
static void exec_script()
{
char line_buf[256];
char *p;
FILE *fp;
fp = fopen(script_file_name, "r");
if (fp) {
memset(line_buf, 0, sizeof(line_buf));
while (fgets(line_buf, sizeof(line_buf) - 1, fp)) {
p = line_buf + sizeof(line_buf) - 1;
while (*p == 0 && p > line_buf)
p--;
while ((*p == '\r' || *p == '\n') && p > line_buf) {
*p-- = 0;
}
if (conf_verbose_mode)
printf("%s\r\n", line_buf);
cliInterpret(line_buf);
memset(line_buf, 0, sizeof(line_buf));
}
fclose(fp);
}
}
int main(int argc, char *argv[])
{
int ret;
if (parse_options(argc, argv) < 0) {
return -1;
}
if (conf_verbose_mode) {
print_mount_points();
print_params();
#if 0
printf("TreeNode size: %d\n", sizeof(TreeNode));
printf("struct BlockListSt: %d\n", sizeof(struct BlockListSt));
printf("struct DirhSt: %d\n", sizeof(struct DirhSt));
printf("struct FilehSt: %d\n", sizeof(struct FilehSt));
printf("struct FdataSt: %d\n", sizeof(struct FdataSt));
#endif
}
ret = init_uffs_fs();
if (ret != 0) {
printf ("Init file system fail: %d\n", ret);
return -1;
}
cli_add_commandset(get_helper_cmds());
cli_add_commandset(get_test_cmds());
cli_add_commandset(basic_cmdset);
if (conf_command_line_mode) {
if (conf_exec_script) {
exec_script();
}
cliMain();
}
else {
if (conf_exec_script) {
exec_script();
}
else {
cliMain();
}
}
release_uffs_fs();
return 0;
}
#endif

View File

@ -0,0 +1,25 @@
#usage:
# find . -name "*.c" | xargs /usr/bin/ruby path/to/chomp_uffs_perror.rb
#
ARGV.each do |file|
lines = []
count = 0
File.open(file).each_line do |line|
if line =~ /^(.*uffs_Perror.+)PFX(\s*".+)$/
lines << ($1 + $2)
count += 1
#puts ($1 + $2)
else
lines << line
end
end
if count > 0
f = File.open(file, "w")
lines.each do |s|
f.puts s
end
f.close
puts "Fix file #{file}, modified lines: #{count}"
end
end

View File

@ -0,0 +1,24 @@
#usage:
# find . -name "*.c" | xargs /usr/bin/ruby path/to/format_code.rb
#
ARGV.each do |file|
lines = []
count = 0
File.open(file).each_line do |line|
if line =~ /^(.*)\s$/
lines << $1.dup
count += 1
else
lines << line
end
end
if count > 0
f = File.open(file, "w")
lines.each do |s|
f.puts s
end
f.close
puts "Fix file #{file}, modified lines: #{count}"
end
end

View File