add UFFS 1.3.2-4 (http://sourceforge.net/projects/uffs)
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@888 bbd45198-f89e-11dd-88c7-29a3b14d5316
This commit is contained in:
parent
a3ca8e33db
commit
7b76fb6ecd
|
@ -0,0 +1 @@
|
|||
Ricky Zheng <ricky_gz_zheng@yahoo.co.nz>
|
|
@ -0,0 +1,3 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6 )
|
||||
PROJECT( uffs )
|
||||
ADD_SUBDIRECTORY( src )
|
|
@ -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.
|
|
@ -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
|
|
@ -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>
|
|
@ -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.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
|
@ -0,0 +1,4 @@
|
|||
ADD_SUBDIRECTORY(emu)
|
||||
ADD_SUBDIRECTORY(uffs)
|
||||
ADD_SUBDIRECTORY(utils)
|
||||
ADD_SUBDIRECTORY(example)
|
|
@ -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} )
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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_
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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} )
|
|
@ -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, ®ion);
|
||||
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;
|
||||
}
|
||||
|
|
@ -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
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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--;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue