diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c6e7d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*.o +.deps/ +.libs/ +Makefile +Makefile.in +/aclocal.m4 +/autom4te.cache +/build-aux +/config.* +/configure +/libtool +/stamp-h1 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..84bba36 --- /dev/null +++ b/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..23bce08 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,78 @@ +EXTRA_DIST = +CLEANFILES = +ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} +AM_MAKEFLAGS = --no-print-directory + +AM_CPPFLAGS = \ + -include $(top_builddir)/config.h \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -I${top_srcdir}/src/dt \ + -I${top_srcdir}/src + +AM_CFLAGS = ${my_CFLAGS} \ + -fvisibility=hidden \ + -ffunction-sections \ + -fdata-sections + +AM_LDFLAGS = \ + -Wl,--gc-sections \ + -Wl,--as-needed + +SED_PROCESS = \ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \ + -e 's,@VERSION\@,$(VERSION),g' \ + -e 's,@prefix\@,$(prefix),g' \ + -e 's,@exec_prefix\@,$(exec_prefix),g' \ + -e 's,@libdir\@,$(libdir),g' \ + -e 's,@includedir\@,$(includedir),g' \ + < $< > $@ || rm $@ + +%.pc: %.pc.in Makefile + $(SED_PROCESS) + +LIBDT_CURRENT=2 +LIBDT_REVISION=0 +LIBDT_AGE=2 + +pkginclude_HEADERS =\ + src/dt/dt.h \ + src/dt/fdt.h \ + src/dt/list.h +lib_LTLIBRARIES = src/libdt.la + +bin_PROGRAMS = state fdtdump +state_SOURCES = src/state.c +state_CFLAGS = $(LIBDT_CFLAGS) +state_LDADD = src/libdt.la + +fdtdump_SOURCES = src/fdtdump.c +fdtdump_CFLAGS = $(LIBDT_CFLAGS) +fdtdump_LDADD = src/libdt.la + +src_libdt_la_SOURCES =\ + src/crc32.c \ + src/libdt-private.h \ + src/libdt.c \ + src/fdt.c + +src_libdt_la_CFLAGS = $(UDEV_CFLAGS) +src_libdt_la_LIBADD = $(UDEV_LIBS) + +EXTRA_DIST += src/libdt.sym + +src_libdt_la_LDFLAGS = $(AM_LDFLAGS) \ + -version-info $(LIBDT_CURRENT):$(LIBDT_REVISION):$(LIBDT_AGE) \ + -Wl,--version-script=$(top_srcdir)/src/libdt.sym +src_libdt_la_DEPENDENCIES = ${top_srcdir}/src/libdt.sym + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = src/libdt.pc +EXTRA_DIST += src/libdt.pc.in +CLEANFILES += src/libdt.pc + +TESTS = src/test-libdt + +check_PROGRAMS = src/test-libdt +src_test_libdt_SOURCES = src/test-libdt.c +src_test_libdt_LDADD = src/libdt.la diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..f4db347 --- /dev/null +++ b/NEWS @@ -0,0 +1,17 @@ +libabc 4 +======== +Use separate include directory: /usr/include/libabc/libabc.h. + +Create .xz tarball. + +libabc 3 +======== +Add functionality. Export symbols for 'thing'. + +libabc 2 +======== +Add support for 'thing'. + +libabc 1 +======== +Initial release. diff --git a/README b/README new file mode 100644 index 0000000..bb06cad --- /dev/null +++ b/README @@ -0,0 +1,262 @@ +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + Unless you really want to, do not even mention that the copied content + originates from this skeleton library. Its sole purpose is to be copied + into other projects. + + The above statements apply to all content in this skeleton library, even + when the COPYING files, or the headers in the files state otherwise, + they are just common examples. +*/ + +Questions, feedback, patches please email: + linux-hotplug@vger.kernel.org +or: + Kay Sievers + Lennart Poettering + +Why bother? + - To make things easy for library users, distribution packagers and + developers of library bindings for other programming languages. If + you want your stuff to be used and commonly available, try to play + nice, and give them what they are used to. It makes their life a + lot easier. + +use autotools + - Every custom config/makefile/build system is worse for everybody + than autotools is. + - We are all used to autotools, it works, nobody cares. + - It's only two simple files to edit and include in git, which are + well understood by many many people, not just you. + - Ignore all crap autotools create in the source tree. never check + the created files into git. + - Never, ever, install config.h. That's internal to your sources + and is nothing to install. + - And really, anything but autotools is realy an option. Just get + over it. Everything else is an experiment, and it will come back + to you sooner or later. Why? think cross compilation, installation/ + uninstallation, build root integration, separate object trees, + standard adherence, tarball handling, make distcheck, testing, + portability between distros, ... + +If you use the GPL, always use the GPL's "(or later)" clause + - Developers are not lawyers, libraries should be able to be linked + to any version of the GPL. Remember that GPL2-only is incompatible + with LGPL3! + +Use LGPL (for the shared libraries) if you don't care about politics + - It protects the code, but does not restrict its use. Low-level + library interfaces are mostly used like kernel syscall or proc/sysfs + interfaces, which are usually without any restrictions. + +Zero global state -- Make your library threads-aware, but *not* thread-safe! + - An app can use liba and libb. libb internally can also use liba -- + without you knowing. Both you and libb can run liba code at the + very same time in different threads and operate at the same global + variables, without telling you about that. Loadable modules make + this problem even more prominent, since the libraries they pull in + are generally completely unknown by the main application. And + *every* program has loadable modules, think NSS! + - Avoid locking and mutexes, they are very unlikely to work correctly, + and incredibly hard to get right. + - Always use a library context object. every thread should then + operate on its own context. Do not imply context objects via TLS. It + won't work. TLS inheritance to new threads will get in your way. TLS + is a problem in itself, not a solution. + - Do not use gcc constructors, or destructors, you can only loose if + you do. Do not use _fini() or _ini(), don't even use your own + explicit library initializer/destructor functions. It just won't + work if your library is pulled in indirectly from another library + or even a shared module (i.e. dlopen()) + - Always use O_CLOEXEC, SOCK_CLOEXEC and friends. It's not an + option, it's a must. + - Don't use global variables (it includes static variables defined + inside functions). Ever. And under no circumstances export global + variables. It's madness. + +Use a common prefix for _all_ exported symbols + - Avoids namespace clashes + - Also, hacking is not a contest of finding the shortest possible + function name. And nobody cares about your 80ch line limit! + - If you use a drop-in library in your own library make sure to hide its + symbols with symbol versioning. Don't forget to hide *all* symbols, and + don't install the header file of the used drop-in library. + +Do not expose any complex structures in your API + - Use get() and set() instead. + - All objects should be opaque. + - Exporting structs in headers is OK in very few cases only: usually + those where you define standard binary formats (think: file + formats, datagram headers, ...) or where you define well-known + primitive types (think struct timeval, struct iovec, uuid + type). + - Why bother? Because struct stat, struct dirent and friends are + disasters. Particularly horrible are structs with fixed-size + strings. + +Use the de-facto standardized function names + - It's abc_new(), abc_free(), abc_ref(), abc_unref(). Don't invent + your own names, and don't use the confusing kernel-style ref + counting. Function names: _get() is for accessing properties of + objects, not for refcounting. + +Stick to kernel coding style + - Just because you are otherwise not bound by the kernel guidelines + when your write userspace libraries doesn't mean you have to give + up the good things it defines. + +Avoid callbacks in your API + - Language bindings want iterators. + - Programmers want iterators too. + +Never call exit(), abort(), be very careful with assert() + - Always return error codes. + - Libraries need to be safe for usage in critical processes that + need to recover from errors instead of getting killed (think PID 1!). + +Avoid thinking about main loops/event dispatchers. + - Get your stuff right in the kernel: fds are awesome, expose them + in userspace and in the library, because people can easily integrate + them with their own poll() loops of whatever kind they have. + - Don't hide file descriptors away in your headers. + - Never add blocking kernel syscalls, and never add blocking library + calls either (with very few exceptions). Userspace code is primarily + asynchronous around event loops, and blocking calls are generally + incompatible with that. + - Corollary of that: always O_NONBLOCK! + +Functions should return int and negative errors instead of NULL + - Return NULL in malloc() is fine, return NULL in fopen() is not! + - Pass allocated objects as parameter (yes, ctx_t** is OK!) + - Returning kernel style negative error codes is cool in + userspace too. Do it! + +Provide pkgconfig files + - Apps want to add a single line to their configure file, + they do not want to fiddle with the parameters, dependencies + to setup and link your library. + - It's just how we do these things today on Linux, and everything + else is just horribly messy. + +Avoid *hidden* fork()/exec() in libraries + - Apps generally do not expect signals and react allergic to them. + - Mutexes, locks, threads of the app might get confused. Mixing + mutexes and fork() equals failure. It just can't work, and + pthread_atfork() is not a solution for that, because it's broken + (even POSIX acknowledges that, just read the POSIX man + pages!). fork() safety for mutex-ridden code is not an + afterthought, it's a broken right from the beginning. + +Make your code safe for unexpected termination and any point: + - Do not leave files dirty or temporary files around. + - This is a tricky, since you need to design your stuff like this + from the beginning, it's not an afterthought, since you generally + do not have a place to clean up your stuff on exit. gcc + destructors are NOT the answer. + +Use symbol versioning + - Only with that, RPM can handle dependencies for added symbols + - Hide all internal symbols! *This is important!* + +Always provide logging/debugging, but do not clutter stderr + - Allow the app to hook the libs logging into its logging facility. + - Use conditional logging, do not filter too late. + - Do not burn cycles with printf() to /dev/null. + - By default: do not generate any output on stdout/stderr. + +Always use 'make distcheck' to create tarballs + - Never release anything that does not pass distcheck. It will + likely be broken for others too + +Use ./autogen.sh to bootstrap the git repo + - Always test bootstrapping with 'git clean -x -f -d' before + release (careful, it force-deletes all uncommitted files). + +Avoid any spec files or debian/ subdirs in git trees + - Distribution specific things do not belong in upstream trees, + but into distro packages + +Update NEWS to let developers know what has changed + - It's the history of the project, stuff that packagers need to know + when putting a new version in the distro. The interesting changes + or added/removed functionality from version to version. This is + not a commit changelog. + - If you want to provide ChangeLog, use the one generated + by git, do not maintain your own. + +use standard types + - The kernel's u8, u16, ... correspond to uint8_t, uint16_t in + userspace from . Don't define your own typedefs + for that, don't include the kernel types in common headers. + - Use enums, not #define for constants, wherever possible. In + userspace you have debuggers, and they are much nicer to use if + you have proper enum identifiers instead of macro definitions, + because the debugger can translate binary values back to enum + identifiers, but not macros. However, be careful with enums in + function prototypes: they might change the int type they are + resolved to as you add new enum values. + +Always guard for multiple inclusions of headers + - You must place '#ifndef libabc, #define libabc, #endif' in your + header files. There is no way around that. + +Be careful with variadic functions + - It's great if you provide them, but you must accompany them with + "v" variants (i.e. functions taking a va_arg object), and provide + non-variadic variants as well. This is important to get language + wrappers right. + +Don't put "extern" in front of your function prototypes in headers + - It has no effect, no effect at all. + +Never use sysv IPC, always use POSIX IPC + - Shmops and semops are horrors. Don't use them, ever. POSIX IPC is + much much much nicer. + +Avoid multiplexed functions ala ioctl()/prctl() style variadic functions + - Type-safety is awesome! + +Executing out-of-process tools and parsing their output is usually +not acceptable in libraries + - Tools should be built on top of their own lib. + - Always separate 'mechanism' from 'policy'. Make access to functionality + simple, but do not try to hide things that need to be decided by the + caller. Keep automagic at its minimum. Don't do hidden fork() do not + implicitly maintain cache files, ... + +Function calls with 15 arguments are a bad idea. If you have tons of +booleans in a function call, then replace them by a flag argument! + - Think about the invocation! foo(0, 1, 0, 1, 0, 0, 0, 1) is unreadable! + foo(FOO_QUUX|FOO_BAR|FOO_WALDO) much nicer. + +Don't be afraid of C99. Use it. + - It's 12 years old. And it's nice. + +Never expose fixed size strings in your API + - Pass malloc()ed strings out, or ask the caller to provide you with + a buffer, and return ENOSPC if too short. + +Glibc has byteswapping calls, don't invent your own: + - le32toh(), htole32() all those are documented in endian(3) + - bswap_32(), bswap_16(), bswap_64(). #include + - Don't use the versions provided by the linux kernel headers cpu_to_*() , *_to_cpu. + stick to the glibc API. + +Don't typedef pointers to structs! + +Don't write your own LISP interpreter and do not include it in your +library. :) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..0d60b0a --- /dev/null +++ b/autogen.sh @@ -0,0 +1,25 @@ +#!/bin/sh -e + +if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then + cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ + chmod +x .git/hooks/pre-commit && \ + echo "Activated pre-commit hook." +fi + +autoreconf --install --symlink + +libdir() { + echo $(cd $1/$(gcc -print-multi-os-directory); pwd) +} + +args="--prefix=/usr \ +--sysconfdir=/etc \ +--libdir=$(libdir /usr/lib)" + +echo +echo "----------------------------------------------------------------" +echo "Initialized build system. For a common configuration please run:" +echo "----------------------------------------------------------------" +echo +echo "./configure CFLAGS='-g -O0' $args" +echo diff --git a/common.h b/common.h deleted file mode 100644 index 4ccec88..0000000 --- a/common.h +++ /dev/null @@ -1,108 +0,0 @@ - -#include - -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -#ifdef DEBUG -#define pr_debug(fmt, arg...) printf(fmt, ##arg) -#else -#define pr_debug(fmt, arg...) -#endif - -#define pr_err(fmt, arg...) printf(fmt, ##arg) - -static inline void *xzalloc(size_t size) -{ - return calloc(1, size); -} - -typedef _Bool bool; - -enum { - false = 0, - true = 1 -}; - -/* - * Kernel pointers have redundant information, so we can use a - * scheme where we can return either an error code or a dentry - * pointer with the same return value. - * - * This should be a per-architecture thing, to allow different - * error and pointer decisions. - */ -#define MAX_ERRNO 4095 - -#ifndef __ASSEMBLY__ - -#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) - -static inline void *ERR_PTR(long error) -{ - return (void *) error; -} - -static inline long PTR_ERR(const void *ptr) -{ - return (long) ptr; -} - -static inline long IS_ERR(const void *ptr) -{ - return IS_ERR_VALUE((unsigned long)ptr); -} - -static inline long IS_ERR_OR_NULL(const void *ptr) -{ - return !ptr || IS_ERR_VALUE((unsigned long)ptr); -} - -/** - * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type - * @ptr: The pointer to cast. - * - * Explicitly cast an error-valued pointer to another pointer type in such a - * way as to make it clear that's what's going on. - */ -static inline void *ERR_CAST(const void *ptr) -{ - /* cast away the const */ - return (void *) ptr; -} - -/** - * strlcpy - Copy a %NUL terminated string into a sized buffer - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @size: size of destination buffer - * - * Compatible with *BSD: the result is always a valid - * NUL-terminated string that fits in the buffer (unless, - * of course, the buffer size is zero). It does not pad - * out the result like strncpy() does. - */ -static inline size_t strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - return ret; -} - -#endif diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..f1d4bbe --- /dev/null +++ b/configure.ac @@ -0,0 +1,68 @@ +AC_PREREQ(2.60) +AC_INIT([dt], + [4], + [s.hauer@pengutronix.de], + [dt], + [http://www.pengutronix.de/dt/]) +AC_CONFIG_SRCDIR([src/libdt.c]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([check-news foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects]) +AC_PROG_CC_STDC +AC_USE_SYSTEM_EXTENSIONS +AC_SYS_LARGEFILE +AC_CONFIG_MACRO_DIR([m4]) +AM_SILENT_RULES([yes]) +LT_INIT([disable-static pic-only]) +AC_PREFIX_DEFAULT([/usr]) + +AC_PROG_SED +AC_PROG_MKDIR_P + +AC_ARG_ENABLE([logging], + AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]), + [], enable_logging=yes) +AS_IF([test "x$enable_logging" = "xyes"], [ + AC_DEFINE(ENABLE_LOGGING, [1], [System logging.]) +]) + +AC_ARG_ENABLE([debug], + AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]), + [], [enable_debug=no]) +AS_IF([test "x$enable_debug" = "xyes"], [ + AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.]) +]) + +AC_CHECK_FUNCS([__secure_getenv secure_getenv]) + +my_CFLAGS="-Wall \ +-Wmissing-declarations -Wmissing-prototypes \ +-Wnested-externs -Wpointer-arith \ +-Wpointer-arith -Wsign-compare -Wchar-subscripts \ +-Wstrict-prototypes -Wshadow \ +-Wformat-security -Wtype-limits" +AC_SUBST([my_CFLAGS]) + +PKG_CHECK_MODULES(UDEV, [libudev]) + +AC_CONFIG_HEADERS(config.h) +AC_CONFIG_FILES([ + Makefile +]) + +AC_OUTPUT +AC_MSG_RESULT([ + $PACKAGE $VERSION + ===== + + prefix: ${prefix} + sysconfdir: ${sysconfdir} + libdir: ${libdir} + includedir: ${includedir} + + compiler: ${CC} + cflags: ${CFLAGS} + ldflags: ${LDFLAGS} + + logging: ${enable_logging} + debug: ${enable_debug} +]) diff --git a/list.h b/list.h deleted file mode 100644 index c17b5d4..0000000 --- a/list.h +++ /dev/null @@ -1,627 +0,0 @@ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#include "common.h" - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) -static inline void prefetch(const void *x) {;} - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} -#else -extern void list_add(struct list_head *new, struct list_head *head); -#endif - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -#else -extern void list_del(struct list_head *entry); -#endif - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_last_entry - get the last element from a list - * @head: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_last_entry(head, type, member) \ - list_entry((head)->prev, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; prefetch(pos->next), pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - prefetch(pos->member.prev), &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; prefetch(pos->member.next), &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -/** - * list_add_sort - add a new entry to a sorted list - * @new: new entry to be added - * @head: list head to add it in - * @compare: Compare function to compare two list entries - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_sort(struct list_head *new, struct list_head *head, - int (*compare)(struct list_head *a, struct list_head *b)) -{ - struct list_head *pos, *insert = head; - - list_for_each(pos, head) { - if (compare(pos, new) < 0) - continue; - insert = pos; - break; - } - - list_add_tail(new, insert); -} - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..8bab51c --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,6 @@ +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 + diff --git a/of.c b/of.c deleted file mode 100644 index 4e5e6c6..0000000 --- a/of.c +++ /dev/null @@ -1,2206 +0,0 @@ -/* - * base.c - basic devicetree functions - * - * Copyright (c) 2012 Sascha Hauer , Pengutronix - * - * based on Linux devicetree support - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This 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. - */ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "of.h" - -static int is_printable_string(const void *data, int len) -{ - const char *s = data; - - /* zero length is not */ - if (len == 0) - return 0; - - /* must terminate with zero */ - if (s[len - 1] != '\0') - return 0; - - /* printable or a null byte (concatenated strings) */ - while (((*s == '\0') || isprint(*s)) && (len > 0)) { - /* - * If we see a null, there are three possibilities: - * 1) If len == 1, it is the end of the string, printable - * 2) Next character also a null, not printable. - * 3) Next character not a null, continue to check. - */ - if (s[0] == '\0') { - if (len == 1) - return 1; - if (s[1] == '\0') - return 0; - } - s++; - len--; - } - - /* Not the null termination, or not done yet: not printable */ - if (*s != '\0' || (len != 0)) - return 0; - - return 1; -} - -/* - * Print the property in the best format, a heuristic guess. Print as - * a string, concatenated strings, a byte, word, double word, or (if all - * else fails) it is printed as a stream of bytes. - */ -void of_print_property(const void *data, int len) -{ - int j; - - /* no data, don't print */ - if (len == 0) - return; - - /* - * It is a string, but it may have multiple strings (embedded '\0's). - */ - if (is_printable_string(data, len)) { - printf("\""); - j = 0; - while (j < len) { - if (j > 0) - printf("\", \""); - printf(data); - j += strlen(data) + 1; - data += strlen(data) + 1; - } - printf("\""); - return; - } - - if ((len % 4) == 0) { - const uint32_t *p; - - printf("<"); - for (j = 0, p = data; j < len/4; j ++) - printf("0x%x%s", __be32_to_cpu(p[j]), j < (len/4 - 1) ? " " : ""); - printf(">"); - } else { /* anything else... hexdump */ - const uint8_t *s; - - printf("["); - for (j = 0, s = data; j < len; j++) - printf("%02x%s", s[j], j < len - 1 ? " " : ""); - printf("]"); - } -} - -/* - * Iterate over all nodes of a tree. As a devicetree does not - * have a dedicated list head, the start node (usually the root - * node) will not be iterated over. - */ -static inline struct device_node *of_next_node(struct device_node *node) -{ - struct device_node *next; - - next = list_first_entry(&node->list, struct device_node, list); - - return next->parent ? next : NULL; -} - -#define of_tree_for_each_node_from(node, from) \ - for (node = of_next_node(from); node; node = of_next_node(node)) - -/** - * struct alias_prop - Alias property in 'aliases' node - * @link: List node to link the structure in aliases_lookup list - * @alias: Alias property name - * @np: Pointer to device_node that the alias stands for - * @id: Index value from end of alias name - * @stem: Alias string without the index - * - * The structure represents one alias property of 'aliases' node as - * an entry in aliases_lookup list. - */ -struct alias_prop { - struct list_head link; - const char *alias; - struct device_node *np; - int id; - char stem[0]; -}; - -static LIST_HEAD(aliases_lookup); - -struct device_node *root_node; - -struct device_node *of_aliases; - -#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 -#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 - -int of_n_addr_cells(struct device_node *np) -{ - const __be32 *ip; - - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#address-cells", NULL); - if (ip) - return __be32_to_cpup(ip); - } while (np->parent); - /* No #address-cells property for the root node */ - return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; -} - -int of_n_size_cells(struct device_node *np) -{ - const __be32 *ip; - - do { - if (np->parent) - np = np->parent; - ip = of_get_property(np, "#size-cells", NULL); - if (ip) - return __be32_to_cpup(ip); - } while (np->parent); - /* No #size-cells property for the root node */ - return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; -} - -struct property *of_find_property(const struct device_node *np, - const char *name, int *lenp) -{ - struct property *pp; - - if (!np) - return NULL; - - list_for_each_entry(pp, &np->properties, list) - if (of_prop_cmp(pp->name, name) == 0) { - if (lenp) - *lenp = pp->length; - return pp; - } - - return NULL; -} - -static void of_alias_add(struct alias_prop *ap, struct device_node *np, - int id, const char *stem, int stem_len) -{ - ap->np = np; - ap->id = id; - strncpy(ap->stem, stem, stem_len); - ap->stem[stem_len] = 0; - list_add_tail(&ap->link, &aliases_lookup); - pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n", - ap->alias, ap->stem, ap->id, np->full_name); -} - -/** - * of_alias_scan - Scan all properties of 'aliases' node - * - * The function scans all the properties of 'aliases' node and populates - * the global lookup table with the properties. It returns the - * number of alias_prop found, or error code in error case. - */ -void of_alias_scan(void) -{ - struct property *pp; - struct alias_prop *app, *tmp; - - list_for_each_entry_safe(app, tmp, &aliases_lookup, link) - free(app); - - INIT_LIST_HEAD(&aliases_lookup); - - if (!root_node) - return; - - of_aliases = of_find_node_by_path("/aliases"); - if (!of_aliases) - return; - - list_for_each_entry(pp, &of_aliases->properties, list) { - const char *start = pp->name; - const char *end = start + strlen(start); - struct device_node *np; - struct alias_prop *ap; - int id, len; - - /* Skip those we do not want to proceed */ - if (!of_prop_cmp(pp->name, "name") || - !of_prop_cmp(pp->name, "phandle") || - !of_prop_cmp(pp->name, "linux,phandle")) - continue; - - np = of_find_node_by_path(pp->value); - if (!np) - continue; - - /* walk the alias backwards to extract the id and work out - * the 'stem' string */ - while (isdigit(*(end-1)) && end > start) - end--; - len = end - start; - - id = strtol(end, 0, 10); - if (id < 0) - continue; - - /* Allocate an alias_prop with enough space for the stem */ - ap = xzalloc(sizeof(*ap) + len + 1); - if (!ap) - continue; - ap->alias = start; - of_alias_add(ap, np, id, start, len); - } -} - -/** - * of_alias_get_id - Get alias id for the given device_node - * @np: Pointer to the given device_node - * @stem: Alias stem of the given device_node - * - * The function travels the lookup table to get alias id for the given - * device_node and alias stem. It returns the alias id if find it. - */ -int of_alias_get_id(struct device_node *np, const char *stem) -{ - struct alias_prop *app; - int id = -ENODEV; - - list_for_each_entry(app, &aliases_lookup, link) { - if (of_node_cmp(app->stem, stem) != 0) - continue; - - if (np == app->np) { - id = app->id; - break; - } - } - - return id; -} - -const char *of_alias_get(struct device_node *np) -{ - struct property *pp; - - list_for_each_entry(pp, &of_aliases->properties, list) { - if (!of_node_cmp(np->full_name, pp->value)) - return pp->name; - } - - return NULL; -} - -/* - * of_find_node_by_alias - Find a node given an alias name - * @root: the root node of the tree. If NULL, use internal tree - * @alias: the alias name to find - */ -struct device_node *of_find_node_by_alias(struct device_node *root, const char *alias) -{ - struct device_node *aliasnp; - int ret; - const char *path; - - if (!root) - root = root_node; - - aliasnp = of_find_node_by_path_from(root, "/aliases"); - if (!aliasnp) - return NULL; - - ret = of_property_read_string(aliasnp, alias, &path); - if (ret) - return NULL; - - return of_find_node_by_path_from(root, path); -} - -/* - * of_find_node_by_phandle - Find a node given a phandle - * @handle: phandle of the node to find - */ -struct device_node *of_find_node_by_phandle(phandle phandle) -{ - struct device_node *node; - - of_tree_for_each_node_from(node, root_node) - if (node->phandle == phandle) - return node; - - return NULL; -} - -/* - * of_get_tree_max_phandle - Find the maximum phandle of a tree - * @root: root node of the tree to search in. If NULL use the - * internal tree. - */ -phandle of_get_tree_max_phandle(struct device_node *root) -{ - struct device_node *n; - phandle max; - - if (!root) - root = root_node; - - if (!root) - return 0; - - max = root->phandle; - - of_tree_for_each_node_from(n, root) { - if (n->phandle > max) - max = n->phandle; - } - - return max; -} - -/* - * of_node_create_phandle - create a phandle for a node - * @node: The node to create a phandle in - * - * returns the new phandle or the existing phandle if the node - * already has a phandle. - */ -phandle of_node_create_phandle(struct device_node *node) -{ - phandle p; - struct device_node *root; - - if (node->phandle) - return node->phandle; - - root = of_find_root_node(node); - - p = of_get_tree_max_phandle(root) + 1; - - node->phandle = p; - - p = __cpu_to_be32(p); - - of_set_property(node, "phandle", &p, sizeof(p), 1); - - return node->phandle; -} - -/* - * Find a property with a given name for a given node - * and return the value. - */ -const void *of_get_property(const struct device_node *np, const char *name, - int *lenp) -{ - struct property *pp = of_find_property(np, name, lenp); - - return pp ? pp->value : NULL; -} - -/** Checks if the given "compat" string matches one of the strings in - * the device's "compatible" property - */ -int of_device_is_compatible(const struct device_node *device, - const char *compat) -{ - const char *cp; - int cplen, l; - - cp = of_get_property(device, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; -} - -/** - * of_find_node_by_name - Find a node by its "name" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. - * @name: The name string to match against - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_node_by_name(struct device_node *from, - const char *name) -{ - struct device_node *np; - - if (!from) - from = root_node; - - of_tree_for_each_node_from(np, from) - if (np->name && !of_node_cmp(np->name, name)) - return np; - - return NULL; -} - -/** - * of_find_node_by_type - Find a node by its "device_type" property - * @from: The node to start searching from, or NULL to start searching - * the entire device tree. The node you pass will not be - * searched, only the next one will; typically, you pass - * what the previous call returned. - * @type: The type string to match against. - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_node_by_type(struct device_node *from, - const char *type) -{ - struct device_node *np; - const char *device_type; - int ret; - - if (!from) - from = root_node; - - of_tree_for_each_node_from(np, from) { - ret = of_property_read_string(np, "device_type", &device_type); - if (!ret && !of_node_cmp(device_type, type)) - return np; - } - return NULL; -} - -/** - * of_find_compatible_node - Find a node based on type and one of the - * tokens in its "compatible" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. - * @type: The type string to match "device_type" or NULL to ignore - * (currently always ignored in barebox) - * @compatible: The string to match to one of the tokens in the device - * "compatible" list. - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_compatible_node(struct device_node *from, - const char *type, const char *compatible) -{ - struct device_node *np; - - if (!from) - from = root_node; - - of_tree_for_each_node_from(np, from) - if (of_device_is_compatible(np, compatible)) - return np; - - return NULL; -} - -/** - * of_find_node_with_property - Find a node which has a property with - * the given name. - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. - * @prop_name: The name of the property to look for. - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_node_with_property(struct device_node *from, - const char *prop_name) -{ - struct device_node *np; - - if (!from) - from = root_node; - - of_tree_for_each_node_from(np, from) { - struct property *pp = of_find_property(np, prop_name, NULL); - if (pp) - return np; - } - - return NULL; -} - -/** - * of_match_node - Tell if an device_node has a matching of_match structure - * @matches: array of of device match structures to search in - * @node: the of device structure to match against - * - * Low level utility function used by device matching. - */ -const struct of_device_id *of_match_node(const struct of_device_id *matches, - const struct device_node *node) -{ - if (!matches || !node) - return NULL; - - while (matches->compatible) { - if (of_device_is_compatible(node, matches->compatible) == 1) - return matches; - matches++; - } - - return NULL; -} - -/** - * of_find_matching_node_and_match - Find a node based on an of_device_id - * match table. - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. - * @matches: array of of device match structures to search in - * @match Updated to point at the matches entry which matched - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_matching_node_and_match(struct device_node *from, - const struct of_device_id *matches, - const struct of_device_id **match) -{ - struct device_node *np; - - if (match) - *match = NULL; - - if (!from) - from = root_node; - - of_tree_for_each_node_from(np, from) { - const struct of_device_id *m = of_match_node(matches, np); - if (m) { - if (match) - *match = m; - return np; - } - } - - return NULL; -} - -/** - * of_find_property_value_of_size - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @len: requested length of property value - * - * Search for a property in a device node and valid the requested size. - * Returns the property value on success, -EINVAL if the property does not - * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - */ -static void *of_find_property_value_of_size(const struct device_node *np, - const char *propname, uint32_t len) -{ - struct property *prop = of_find_property(np, propname, NULL); - - if (!prop) - return ERR_PTR(-EINVAL); - if (!prop->value) - return ERR_PTR(-ENODATA); - if (len > prop->length) - return ERR_PTR(-EOVERFLOW); - - return prop->value; -} - -/** - * of_property_read_u32_index - Find and read a uint32_t from a multi-value property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @index: index of the uint32_t in the list of values - * @out_value: pointer to return value, modified only if no error. - * - * Search for a property in a device node and read nth 32-bit value from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * The out_value is modified only if a valid uint32_t value can be decoded. - */ -int of_property_read_u32_index(const struct device_node *np, - const char *propname, - uint32_t index, uint32_t *out_value) -{ - const uint32_t *val = of_find_property_value_of_size(np, propname, - ((index + 1) * sizeof(*out_value))); - - if (IS_ERR(val)) - return PTR_ERR(val); - - *out_value = __be32_to_cpup(((__be32 *)val) + index); - return 0; -} - -/** - * of_property_read_u8_array - Find and read an array of uint8_t from a property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_value: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read - * - * Search for a property in a device node and read 8-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * dts entry of array should be like: - * property = /bits/ 8 <0x50 0x60 0x70>; - * - * The out_value is modified only if a valid uint8_t value can be decoded. - */ -int of_property_read_u8_array(const struct device_node *np, - const char *propname, uint8_t *out_values, size_t sz) -{ - const uint8_t *val = of_find_property_value_of_size(np, propname, - (sz * sizeof(*out_values))); - - if (IS_ERR(val)) - return PTR_ERR(val); - - while (sz--) - *out_values++ = *val++; - return 0; -} - -/** - * of_property_read_u16_array - Find and read an array of uint16_t from a property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_value: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read - * - * Search for a property in a device node and read 16-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * dts entry of array should be like: - * property = /bits/ 16 <0x5000 0x6000 0x7000>; - * - * The out_value is modified only if a valid uint16_t value can be decoded. - */ -int of_property_read_u16_array(const struct device_node *np, - const char *propname, uint16_t *out_values, size_t sz) -{ - const __be16 *val = of_find_property_value_of_size(np, propname, - (sz * sizeof(*out_values))); - - if (IS_ERR(val)) - return PTR_ERR(val); - - while (sz--) - *out_values++ = __be16_to_cpup(val++); - return 0; -} - -/** - * of_property_read_u32_array - Find and read an array of 32 bit integers - * from a property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_value: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read - * - * Search for a property in a device node and read 32-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * The out_value is modified only if a valid uint32_t value can be decoded. - */ -int of_property_read_u32_array(const struct device_node *np, - const char *propname, uint32_t *out_values, - size_t sz) -{ - const __be32 *val = of_find_property_value_of_size(np, propname, - (sz * sizeof(*out_values))); - - if (IS_ERR(val)) - return PTR_ERR(val); - - while (sz--) - *out_values++ = __be32_to_cpup(val++); - return 0; -} - -/** - * of_property_read_u64 - Find and read a 64 bit integer from a property - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_value: pointer to return value, modified only if return value is 0. - * - * Search for a property in a device node and read a 64-bit value from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * The out_value is modified only if a valid uint64_t value can be decoded. - */ -int of_property_read_u64(const struct device_node *np, const char *propname, - uint64_t *out_value) -{ - const __be32 *val = of_find_property_value_of_size(np, propname, - sizeof(*out_value)); - - if (IS_ERR(val)) - return PTR_ERR(val); - - *out_value = of_read_number(val, 2); - return 0; -} - -/** - * of_property_read_string - Find and read a string from a property - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_string: pointer to null terminated return string, modified only if - * return value is 0. - * - * Search for a property in a device tree node and retrieve a null - * terminated string value (pointer to data, not a copy). Returns 0 on - * success, -EINVAL if the property does not exist, -ENODATA if property - * does not have a value, and -EILSEQ if the string is not null-terminated - * within the length of the property data. - * - * The out_string pointer is modified only if a valid string can be decoded. - */ -int of_property_read_string(struct device_node *np, const char *propname, - const char **out_string) -{ - struct property *prop = of_find_property(np, propname, NULL); - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if (strnlen(prop->value, prop->length) >= prop->length) - return -EILSEQ; - *out_string = prop->value; - return 0; -} - -/** - * of_property_read_string_index - Find and read a string from a multiple - * strings property. - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @index: index of the string in the list of strings - * @out_string: pointer to null terminated return string, modified only if - * return value is 0. - * - * Search for a property in a device tree node and retrieve a null - * terminated string value (pointer to data, not a copy) in the list of strings - * contained in that property. - * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if - * property does not have a value, and -EILSEQ if the string is not - * null-terminated within the length of the property data. - * - * The out_string pointer is modified only if a valid string can be decoded. - */ -int of_property_read_string_index(struct device_node *np, const char *propname, - int index, const char **output) -{ - struct property *prop = of_find_property(np, propname, NULL); - int i = 0; - size_t l = 0, total = 0; - const char *p; - - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if (strnlen(prop->value, prop->length) >= prop->length) - return -EILSEQ; - - p = prop->value; - - for (i = 0; total < prop->length; total += l, p += l) { - l = strlen(p) + 1; - if (i++ == index) { - *output = p; - return 0; - } - } - return -ENODATA; -} - -/** - * of_property_match_string() - Find string in a list and return index - * @np: pointer to node containing string list property - * @propname: string list property name - * @string: pointer to string to search for in string list - * - * This function searches a string list property and returns the index - * of a specific string value. - */ -int of_property_match_string(struct device_node *np, const char *propname, - const char *string) -{ - struct property *prop = of_find_property(np, propname, NULL); - size_t l; - int i; - const char *p, *end; - - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - - p = prop->value; - end = p + prop->length; - - for (i = 0; p < end; i++, p += l) { - l = strlen(p) + 1; - if (p + l > end) - return -EILSEQ; - pr_debug("comparing %s with %s\n", string, p); - if (strcmp(string, p) == 0) - return i; /* Found it; return index */ - } - return -ENODATA; -} - -/** - * of_property_count_strings - Find and return the number of strings from a - * multiple strings property. - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device tree node and retrieve the number of null - * terminated string contain in it. Returns the number of strings on - * success, -EINVAL if the property does not exist, -ENODATA if property - * does not have a value, and -EILSEQ if the string is not null-terminated - * within the length of the property data. - */ -int of_property_count_strings(struct device_node *np, const char *propname) -{ - struct property *prop = of_find_property(np, propname, NULL); - int i = 0; - size_t l = 0, total = 0; - const char *p; - - if (!prop) - return -EINVAL; - if (!prop->value) - return -ENODATA; - if (strnlen(prop->value, prop->length) >= prop->length) - return -EILSEQ; - - p = prop->value; - - for (i = 0; total < prop->length; total += l, p += l, i++) - l = strlen(p) + 1; - - return i; -} - -const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, - uint32_t *pu) -{ - const void *curv = cur; - - if (!prop) - return NULL; - - if (!cur) { - curv = prop->value; - goto out_val; - } - - curv += sizeof(*cur); - if (curv >= prop->value + prop->length) - return NULL; - -out_val: - *pu = __be32_to_cpup(curv); - return curv; -} - -const char *of_prop_next_string(struct property *prop, const char *cur) -{ - const void *curv = cur; - - if (!prop) - return NULL; - - if (!cur) - return prop->value; - - curv += strlen(cur) + 1; - if (curv >= prop->value + prop->length) - return NULL; - - return curv; -} - -/** - * of_property_write_bool - Create/Delete empty (bool) property. - * - * @np: device node from which the property is to be set. - * @propname: name of the property to be set. - * - * Search for a property in a device node and create or delete the property. - * If the property already exists and write value is false, the property is - * deleted. If write value is true and the property does not exist, it is - * created. Returns 0 on success, -ENOMEM if the property or array - * of elements cannot be created. - */ -int of_property_write_bool(struct device_node *np, const char *propname, - const bool value) -{ - struct property *prop = of_find_property(np, propname, NULL); - - if (!value) { - if (prop) - of_delete_property(prop); - return 0; - } - - if (!prop) - prop = of_new_property(np, propname, NULL, 0); - if (!prop) - return -ENOMEM; - - return 0; -} - -/** - * of_property_write_u8_array - Write an array of uint8_t to a property. If - * the property does not exist, it will be created and appended to the given - * device node. - * - * @np: device node to which the property value is to be written. - * @propname: name of the property to be written. - * @values: pointer to array elements to write. - * @sz: number of array elements to write. - * - * Search for a property in a device node and write 8-bit value(s) to - * it. If the property does not exist, it will be created and appended to - * the device node. Returns 0 on success, -ENOMEM if the property or array - * of elements cannot be created. - */ -int of_property_write_u8_array(struct device_node *np, - const char *propname, const uint8_t *values, - size_t sz) -{ - struct property *prop = of_find_property(np, propname, NULL); - uint8_t *val; - - if (prop) - of_delete_property(prop); - - prop = of_new_property(np, propname, NULL, sizeof(*val) * sz); - if (!prop) - return -ENOMEM; - - val = prop->value; - while (sz--) - *val++ = *values++; - - return 0; -} - -/** - * of_property_write_u16_array - Write an array of uint16_t to a property. If - * the property does not exist, it will be created and appended to the given - * device node. - * - * @np: device node to which the property value is to be written. - * @propname: name of the property to be written. - * @values: pointer to array elements to write. - * @sz: number of array elements to write. - * - * Search for a property in a device node and write 16-bit value(s) to - * it. If the property does not exist, it will be created and appended to - * the device node. Returns 0 on success, -ENOMEM if the property or array - * of elements cannot be created. - */ -int of_property_write_u16_array(struct device_node *np, - const char *propname, const uint16_t *values, - size_t sz) -{ - struct property *prop = of_find_property(np, propname, NULL); - __be16 *val; - - if (prop) - of_delete_property(prop); - - prop = of_new_property(np, propname, NULL, sizeof(*val) * sz); - if (!prop) - return -ENOMEM; - - val = prop->value; - while (sz--) - *val++ = __cpu_to_be16(*values++); - - return 0; -} - -/** - * of_property_write_u32_array - Write an array of uint32_t to a property. If - * the property does not exist, it will be created and appended to the given - * device node. - * - * @np: device node to which the property value is to be written. - * @propname: name of the property to be written. - * @values: pointer to array elements to write. - * @sz: number of array elements to write. - * - * Search for a property in a device node and write 32-bit value(s) to - * it. If the property does not exist, it will be created and appended to - * the device node. Returns 0 on success, -ENOMEM if the property or array - * of elements cannot be created. - */ -int of_property_write_u32_array(struct device_node *np, - const char *propname, const uint32_t *values, - size_t sz) -{ - struct property *prop = of_find_property(np, propname, NULL); - __be32 *val; - - if (prop) - of_delete_property(prop); - - prop = of_new_property(np, propname, NULL, sizeof(*val) * sz); - if (!prop) - return -ENOMEM; - - val = prop->value; - while (sz--) - *val++ = __cpu_to_be32(*values++); - - return 0; -} - -/** - * of_property_write_u64_array - Write an array of uint64_t to a property. If - * the property does not exist, it will be created and appended to the given - * device node. - * - * @np: device node to which the property value is to be written. - * @propname: name of the property to be written. - * @values: pointer to array elements to write. - * @sz: number of array elements to write. - * - * Search for a property in a device node and write 64-bit value(s) to - * it. If the property does not exist, it will be created and appended to - * the device node. Returns 0 on success, -ENOMEM if the property or array - * of elements cannot be created. - */ -int of_property_write_u64_array(struct device_node *np, - const char *propname, const uint64_t *values, - size_t sz) -{ - struct property *prop = of_find_property(np, propname, NULL); - __be32 *val; - - if (prop) - of_delete_property(prop); - - prop = of_new_property(np, propname, NULL, 2 * sizeof(*val) * sz); - if (!prop) - return -ENOMEM; - - val = prop->value; - while (sz--) { - of_write_number(val, *values++, 2); - val += 2; - } - - return 0; -} - -/** - * of_parse_phandle - Resolve a phandle property to a device_node pointer - * @np: Pointer to device node holding phandle property - * @phandle_name: Name of property holding a phandle value - * @index: For properties holding a table of phandles, this is the index into - * the table - * - * Returns the device_node pointer found or NULL. - */ -struct device_node *of_parse_phandle(const struct device_node *np, - const char *phandle_name, int index) -{ - const __be32 *phandle; - int size; - - phandle = of_get_property(np, phandle_name, &size); - if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) - return NULL; - - return of_find_node_by_phandle(__be32_to_cpup(phandle + index)); -} - -/** - * of_parse_phandle_with_args() - Find a node pointed by phandle in a list - * @np: pointer to a device tree node containing a list - * @list_name: property name that contains a list - * @cells_name: property name that specifies phandles' arguments count - * @index: index of a phandle to parse out - * @out_args: optional pointer to output arguments structure (will be filled) - * - * This function is useful to parse lists of phandles and their arguments. - * Returns 0 on success and fills out_args, on error returns appropriate - * errno value. - * - * Example: - * - * phandle1: node1 { - * #list-cells = <2>; - * } - * - * phandle2: node2 { - * #list-cells = <1>; - * } - * - * node3 { - * list = <&phandle1 1 2 &phandle2 3>; - * } - * - * To get a device_node of the `node2' node you may call this: - * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); - */ -static int __of_parse_phandle_with_args(const struct device_node *np, - const char *list_name, - const char *cells_name, int index, - struct of_phandle_args *out_args) -{ - const __be32 *list, *list_end; - int rc = 0, size, cur_index = 0; - uint32_t count = 0; - struct device_node *node = NULL; - phandle phandle; - - /* Retrieve the phandle list property */ - list = of_get_property(np, list_name, &size); - if (!list) - return -ENOENT; - list_end = list + size / sizeof(*list); - - /* Loop over the phandles until all the requested entry is found */ - while (list < list_end) { - rc = -EINVAL; - count = 0; - - /* - * If phandle is 0, then it is an empty entry with no - * arguments. Skip forward to the next entry. - */ - phandle = __be32_to_cpup(list++); - if (phandle) { - /* - * Find the provider node and parse the #*-cells - * property to determine the argument length - */ - node = of_find_node_by_phandle(phandle); - if (!node) { - pr_err("%s: could not find phandle\n", - np->full_name); - goto err; - } - if (of_property_read_u32(node, cells_name, &count)) { - pr_err("%s: could not get %s for %s\n", - np->full_name, cells_name, - node->full_name); - goto err; - } - - /* - * Make sure that the arguments actually fit in the - * remaining property data length - */ - if (list + count > list_end) { - pr_err("%s: arguments longer than property\n", - np->full_name); - goto err; - } - } - - /* - * All of the error cases above bail out of the loop, so at - * this point, the parsing is successful. If the requested - * index matches, then fill the out_args structure and return, - * or return -ENOENT for an empty entry. - */ - rc = -ENOENT; - if (cur_index == index) { - if (!phandle) - goto err; - - if (out_args) { - int i; - if (count > MAX_PHANDLE_ARGS) - count = MAX_PHANDLE_ARGS; - out_args->np = node; - out_args->args_count = count; - for (i = 0; i < count; i++) - out_args->args[i] = - __be32_to_cpup(list++); - } - - /* Found it! return success */ - return 0; - } - - node = NULL; - list += count; - cur_index++; - } - - /* - * Unlock node before returning result; will be one of: - * -ENOENT : index is for empty phandle - * -EINVAL : parsing error on data - * [1..n] : Number of phandle (count mode; when index = -1) - */ - rc = index < 0 ? cur_index : -ENOENT; - err: - return rc; -} - -int of_parse_phandle_with_args(const struct device_node *np, - const char *list_name, const char *cells_name, int index, - struct of_phandle_args *out_args) -{ - if (index < 0) - return -EINVAL; - return __of_parse_phandle_with_args(np, list_name, cells_name, - index, out_args); -} - -/** - * of_count_phandle_with_args() - Find the number of phandles references in a property - * @np: pointer to a device tree node containing a list - * @list_name: property name that contains a list - * @cells_name: property name that specifies phandles' arguments count - * - * Returns the number of phandle + argument tuples within a property. It - * is a typical pattern to encode a list of phandle and variable - * arguments into a single property. The number of arguments is encoded - * by a property in the phandle-target node. For example, a gpios - * property would contain a list of GPIO specifies consisting of a - * phandle and 1 or more arguments. The number of arguments are - * determined by the #gpio-cells property in the node pointed to by the - * phandle. - */ -int of_count_phandle_with_args(const struct device_node *np, - const char *list_name, const char *cells_name) -{ - return __of_parse_phandle_with_args(np, list_name, cells_name, - -1, NULL); -} - -/** - * of_machine_is_compatible - Test root of device tree for a given compatible value - * @compat: compatible string to look for in root node's compatible property. - * - * Returns true if the root node has the given value in its - * compatible property. - */ -int of_machine_is_compatible(const char *compat) -{ - if (!root_node) - return 0; - - return of_device_is_compatible(root_node, compat); -} - -/** - * of_find_node_by_path_from - Find a node matching a full OF path - * relative to a given root node. - * @path: The full path to match - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_node_by_path_from(struct device_node *from, - const char *path) -{ - char *slash, *p, *freep; - - if (!from) - from = root_node; - - if (!from || !path || *path != '/') - return NULL; - - path++; - - freep = p = strdup(path); - - while (1) { - if (!*p) - goto out; - - slash = strchr(p, '/'); - if (slash) - *slash = 0; - - from = of_get_child_by_name(from, p); - if (!from) - goto out; - - if (!slash) - goto out; - - p = slash + 1; - } -out: - free(freep); - - return from; -} - -/** - * of_find_node_by_path - Find a node matching a full OF path - * @path: The full path to match - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_node_by_path(const char *path) -{ - return of_find_node_by_path_from(root_node, path); -} - -/** - * of_find_node_by_path_or_alias - Find a node matching a full OF path - * or an alias - * @root: The root node. If NULL the internal tree is used - * @str: the full path or alias - * - * Returns a pointer to the node found or NULL. - */ -struct device_node *of_find_node_by_path_or_alias(struct device_node *root, - const char *str) -{ - if (*str == '/') - return of_find_node_by_path_from(root, str); - else - return of_find_node_by_alias(root, str); - -} - -/** - * of_modalias_node - Lookup appropriate modalias for a device node - * @node: pointer to a device tree node - * @modalias: Pointer to buffer that modalias value will be copied into - * @len: Length of modalias value - * - * Based on the value of the compatible property, this routine will attempt - * to choose an appropriate modalias value for a particular device tree node. - * It does this by stripping the manufacturer prefix (as delimited by a ',') - * from the first entry in the compatible list property. - * - * This routine returns 0 on success, <0 on failure. - */ -int of_modalias_node(struct device_node *node, char *modalias, int len) -{ - const char *compatible, *p; - int cplen; - - compatible = of_get_property(node, "compatible", &cplen); - if (!compatible || strlen(compatible) > cplen) - return -ENODEV; - p = strchr(compatible, ','); - strlcpy(modalias, p ? p + 1 : compatible, len); - return 0; -} - -struct device_node *of_get_root_node(void) -{ - return root_node; -} - -int of_set_root_node(struct device_node *node) -{ - if (node && root_node) - return -EBUSY; - - root_node = node; - - of_alias_scan(); - - return 0; -} - -/** - * of_device_is_available - check if a device is available for use - * - * @device: Node to check for availability - * - * Returns 1 if the status property is absent or set to "okay" or "ok", - * 0 otherwise - */ -int of_device_is_available(const struct device_node *device) -{ - const char *status; - int statlen; - - status = of_get_property(device, "status", &statlen); - if (status == NULL) - return 1; - - if (statlen > 0) { - if (!strcmp(status, "okay") || !strcmp(status, "ok")) - return 1; - } - - return 0; -} - -/** - * of_get_parent - Get a node's parent if any - * @node: Node to get parent - * - * Returns a pointer to the parent node or NULL if already at root. - */ -struct device_node *of_get_parent(const struct device_node *node) -{ - return (!node) ? NULL : node->parent; -} - -/** - * of_get_next_available_child - Find the next available child node - * @node: parent node - * @prev: previous child of the parent node, or NULL to get first - * - * This function is like of_get_next_child(), except that it - * automatically skips any disabled nodes (i.e. status = "disabled"). - */ -struct device_node *of_get_next_available_child(const struct device_node *node, - struct device_node *prev) -{ - prev = list_prepare_entry(prev, &node->children, parent_list); - list_for_each_entry_continue(prev, &node->children, parent_list) - if (of_device_is_available(prev)) - return prev; - return NULL; -} - -/** - * of_get_child_count - Count child nodes of given parent node - * @parent: parent node - * - * Returns the number of child nodes or -EINVAL on NULL parent node. - */ -int of_get_child_count(const struct device_node *parent) -{ - struct device_node *child; - int num = 0; - - if (!parent) - return -EINVAL; - - for_each_child_of_node(parent, child) - num++; - - return num; -} - -/** - * of_get_available_child_count - Count available child nodes of given - * parent node - * @parent: parent node - * - * Returns the number of available child nodes or -EINVAL on NULL parent - * node. - */ -int of_get_available_child_count(const struct device_node *parent) -{ - struct device_node *child; - int num = 0; - - if (!parent) - return -EINVAL; - - for_each_child_of_node(parent, child) - if (of_device_is_available(child)) - num++; - - return num; -} - -/** - * of_get_child_by_name - Find the child node by name for a given parent - * @node: parent node - * @name: child name to look for. - * - * This function looks for child node for given matching name - * - * Returns a node pointer if found or NULL. - */ -struct device_node *of_get_child_by_name(const struct device_node *node, - const char *name) -{ - struct device_node *child; - - for_each_child_of_node(node, child) - if (child->name && (of_node_cmp(child->name, name) == 0)) - return child; - - return NULL; -} - -void of_print_nodes(struct device_node *node, int indent) -{ - struct device_node *n; - struct property *p; - int i; - - if (!node) - return; - - for (i = 0; i < indent; i++) - printf("\t"); - - printf("%s%s\n", node->name, node->name ? " {" : "{"); - - list_for_each_entry(p, &node->properties, list) { - for (i = 0; i < indent + 1; i++) - printf("\t"); - printf("%s", p->name); - if (p->length) { - printf(" = "); - of_print_property(p->value, p->length); - } - printf(";\n"); - } - - list_for_each_entry(n, &node->children, parent_list) { - of_print_nodes(n, indent + 1); - } - - for (i = 0; i < indent; i++) - printf("\t"); - printf("};\n"); -} - -struct device_node *of_new_node(struct device_node *parent, const char *name) -{ - struct device_node *node; - int ret; - - node = xzalloc(sizeof(*node)); - node->parent = parent; - if (parent) - list_add_tail(&node->parent_list, &parent->children); - - INIT_LIST_HEAD(&node->children); - INIT_LIST_HEAD(&node->properties); - - if (parent) { - node->name = strdup(name); - ret = asprintf(&node->full_name, "%s/%s", node->parent->full_name, name); - if (ret < 0) - return NULL; - list_add(&node->list, &parent->list); - } else { - node->name = strdup(""); - node->full_name = strdup(""); - INIT_LIST_HEAD(&node->list); - } - - return node; -} - -struct property *of_new_property(struct device_node *node, const char *name, - const void *data, int len) -{ - struct property *prop; - - prop = xzalloc(sizeof(*prop)); - prop->name = strdup(name); - if (!prop->name) { - free(prop); - return NULL; - } - - prop->length = len; - prop->value = xzalloc(len); - - if (data) - memcpy(prop->value, data, len); - - list_add_tail(&prop->list, &node->properties); - - return prop; -} - -void of_delete_property(struct property *pp) -{ - if (!pp) - return; - - list_del(&pp->list); - - free(pp->name); - free(pp->value); - free(pp); -} - -/** - * of_set_property - create a property for a given node - * @node - the node - * @name - the name of the property - * @val - the value for the property - * @len - the length of the properties value - * @create - if true, the property is created if not existing already - */ -int of_set_property(struct device_node *np, const char *name, const void *val, int len, - int create) -{ - struct property *pp = of_find_property(np, name, NULL); - - if (!np) - return -ENOENT; - - if (!pp && !create) - return -ENOENT; - - of_delete_property(pp); - - pp = of_new_property(np, name, val, len); - if (!pp) - return -ENOMEM; - - return 0; -} - -struct device_node *of_chosen; -const char *of_model; - -const char *of_get_model(void) -{ - return of_model; -} - -const struct of_device_id of_default_bus_match_table[] = { - { - .compatible = "simple-bus", - }, { - /* sentinel */ - } -}; - -/** - * of_create_node - create a new node including its parents - * @path - the nodepath to create - */ -struct device_node *of_create_node(struct device_node *root, const char *path) -{ - char *slash, *p, *freep; - struct device_node *tmp, *dn = root; - - if (*path != '/') - return NULL; - - path++; - - p = freep = strdup(path); - - while (1) { - if (!*p) - goto out; - - slash = strchr(p, '/'); - if (slash) - *slash = 0; - - tmp = of_get_child_by_name(dn, p); - if (tmp) - dn = tmp; - else - dn = of_new_node(dn, p); - - if (!dn) - goto out; - - if (!slash) - goto out; - - p = slash + 1; - } -out: - free(freep); - - return dn; -} - -void of_delete_node(struct device_node *node) -{ - struct device_node *n, *nt; - struct property *p, *pt; - - if (!node) - return; - - list_for_each_entry_safe(p, pt, &node->properties, list) - of_delete_property(p); - - list_for_each_entry_safe(n, nt, &node->children, parent_list) - of_delete_node(n); - - if (node->parent) { - list_del(&node->parent_list); - list_del(&node->list); - } - - free(node->name); - free(node->full_name); - free(node); - - if (node == root_node) - of_set_root_node(NULL); -} - -/** - * of_device_enable - enable a devicenode device - * @node - the node to enable - * - * This deletes the status property of a devicenode effectively - * enabling the device. - */ -int of_device_enable(struct device_node *node) -{ - struct property *pp; - - pp = of_find_property(node, "status", NULL); - if (!pp) - return 0; - - of_delete_property(pp); - - return 0; -} - -/** - * of_device_enable_path - enable a devicenode - * @path - the nodepath to enable - * - * wrapper around of_device_enable taking the nodepath as argument - */ -int of_device_enable_path(const char *path) -{ - struct device_node *node; - - node = of_find_node_by_path(path); - if (!node) - return -ENODEV; - - return of_device_enable(node); -} - -/** - * of_device_enable - disable a devicenode device - * @node - the node to disable - * - * This sets the status of a devicenode to "disabled" - */ -int of_device_disable(struct device_node *node) -{ - return of_set_property(node, "status", "disabled", sizeof("disabled"), 1); -} - -/** - * of_device_disable_path - disable a devicenode - * @path - the nodepath to disable - * - * wrapper around of_device_disable taking the nodepath as argument - */ -int of_device_disable_path(const char *path) -{ - struct device_node *node; - - node = of_find_node_by_path(path); - if (!node) - return -ENODEV; - - return of_device_disable(node); -} - -int scan_proc_dir(struct device_node *node, const char *path) -{ - DIR *dir; - struct dirent *dirent; - struct stat s; - int ret; - void *buf; - - dir = opendir(path); - if (!dir) - return -errno; - - while (1) { - char *cur; - - dirent = readdir(dir); - if (!dirent) - break; - - if (dirent->d_name[0] == '.') - continue; - - asprintf(&cur, "%s/%s", path, dirent->d_name); - ret = stat(cur, &s); - if (ret) - return ret; - - if (S_ISREG(s.st_mode)) { - int fd; - - fd = open(cur, O_RDONLY); - if (fd < 0) - return -errno; - - buf = xzalloc(s.st_size); - ret = read(fd, buf, s.st_size); - if (ret < 0) - return ret; - close(fd); - - of_new_property(node, dirent->d_name, buf, s.st_size); - } - - if (S_ISDIR(s.st_mode)) { - struct device_node *new; - new = of_new_node(node, dirent->d_name); - scan_proc_dir(new, cur); - } - - free(cur); - } - - closedir(dir); - - return 0; -} - -struct device_node *of_read_proc_devicetree(void) -{ - struct device_node *root; - int ret; - - root = of_new_node(NULL, NULL); - - ret = scan_proc_dir(root, "/proc/device-tree"); - if (ret) { - of_delete_node(root); - return NULL; - } - - return root; -} - -struct udev_device *of_find_device_by_node_path(const char *of_full_path) -{ - struct udev *udev; - struct udev_enumerate *enumerate; - struct udev_list_entry *devices, *dev_list_entry; - struct udev_device *dev; - - udev = udev_new(); - if (!udev) { - printf("Can't create udev\n"); - exit(1); - } - - enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_property(enumerate, "OF_FULLNAME", of_full_path); - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - udev_list_entry_foreach(dev_list_entry, devices) { - const char *path; - - /* Get the filename of the /sys entry for the device - and create a udev_device object (dev) representing it */ - path = udev_list_entry_get_name(dev_list_entry); - dev = udev_device_new_from_syspath(udev, path); - - goto out; - } - - dev = NULL; -out: - udev_enumerate_unref(enumerate); - udev_unref(udev); - - return dev; -} - -struct udev_device *device_find_partition(struct udev_device *dev, const char *name) -{ - struct udev *udev; - struct udev_enumerate *enumerate; - struct udev_list_entry *devices, *dev_list_entry; - struct udev_device *part; - - /* Create the udev object */ - udev = udev_new(); - if (!udev) { - printf("Can't create udev\n"); - exit(1); - } - - enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_parent(enumerate, dev); - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - udev_list_entry_foreach(dev_list_entry, devices) { - const char *path, *partname; - path = udev_list_entry_get_name(dev_list_entry); - part = udev_device_new_from_syspath(udev, path); - partname = udev_device_get_sysattr_value(part, "name"); - if (!partname) - continue; - if (!strcmp(partname, name)) - return part; - } - - udev_enumerate_unref(enumerate); - udev_unref(udev); - - return NULL; -} - -struct of_path { - char *devpath; - off_t offset; - size_t size; - struct udev_device *dev; - struct device_node *node; -}; - -struct of_path_type { - const char *name; - int (*parse)(struct of_path *op, const char *str); -}; - -/** - * of_path_type_partname - find a partition based on physical device and - * partition name - * @op: of_path context - * @name: the partition name to find - */ -static int of_path_type_partname(struct of_path *op, const char *name) -{ - struct udev_device *part; - struct stat s; - int ret; - struct device_node *node; - - if (!op->dev) - return -EINVAL; - - part = device_find_partition(op->dev, name); - if (part) { - op->devpath = strdup(udev_device_get_devnode(part)); - pr_debug("%s: found part '%s'\n", __func__, name); - return 0; - } - - asprintf(&op->devpath, "%s/eeprom", udev_device_get_syspath(op->dev)); - ret = stat(op->devpath, &s); - if (ret) - return ret; - - for_each_child_of_node(op->node, node) { - const char *partname; - int len; - - partname = of_get_property(node, "label", &len); - if (!strcmp(partname, name)) { - const __be32 *reg; - int a_cells, s_cells; - - reg = of_get_property(node, "reg", &len); - if (!reg) - continue; - - a_cells = of_n_addr_cells(node); - s_cells = of_n_size_cells(node); - op->offset = of_read_number(reg, a_cells);; - op->size = of_read_number(reg + a_cells, s_cells);; - break; - } - } - - return 0; -} - -static struct of_path_type of_path_types[] = { - { - .name = "partname", - .parse = of_path_type_partname, - }, -}; -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -static int of_path_parse_one(struct of_path *op, const char *str) -{ - int i, ret; - char *name, *desc; - - pr_debug("parsing: %s\n", str); - - name = strdup(str); - desc = strchr(name, ':'); - if (!desc) { - free(name); - return -EINVAL; - } - - *desc = 0; - desc++; - - for (i = 0; i < ARRAY_SIZE(of_path_types); i++) { - if (!strcmp(of_path_types[i].name, name)) { - ret = of_path_types[i].parse(op, desc); - goto out; - } - } - - ret = -EINVAL; -out: - free(name); - - return ret; -} - -/** - * of_find_path - translate a path description in the devicetree to a device node - * path - * - * @node: the node containing the property with the path description - * @propname: the property name of the path description - * @outpath: if this function returns 0 outpath will contain the path belonging - * to the input path description. Must be freed with free(). - * - * pathes in the devicetree have the form of a multistring property. The first - * string contains the full path to the physical device containing the path. - * The remaining strings have the form ":". Currently supported - * for are: - * - * partname: - find a partition by its partition name. For mtd - * partitions this is the label. For DOS partitions - * this is the number beginning with 0. - * - * examples: - * - * device-path = &mmc0, "partname:0"; - * device-path = &norflash, "partname:barebox-environment"; - */ -int of_find_path(struct device_node *node, const char *propname, char **outpath) -{ - struct of_path op = {}; - struct device_node *rnode; - const char *path, *str; - int i, len, ret; - - path = of_get_property(node, propname, &len); - if (!path) - return -EINVAL; - - rnode = of_find_node_by_path(path); - if (!rnode) - return -ENODEV; - - op.node = rnode; - - op.dev = of_find_device_by_node_path(rnode->full_name); - if (!op.dev) - return -ENODEV; - - i = 1; - - while (1) { - ret = of_property_read_string_index(node, propname, i++, &str); - if (ret) - break; - - ret = of_path_parse_one(&op, str); - if (ret) - return ret; - } - - if (!op.devpath) - return -ENOENT; - - printf("devpath: %s ofs: 0x%08lx size: 0x%08x\n", op.devpath, op.offset, op.size); - - return 0; -} - -int main(int argc, char *argv[]) -{ - struct device_node *root, *node; - char *devnode; - - root = of_read_proc_devicetree(); - root_node = root; - - node = of_find_node_by_path_or_alias(root, argv[1]); - if (!node) { - printf("no such node: %s\n", argv[1]); - return 1; - } - - of_find_path(node, argv[2], &devnode); - - return 0; - - of_print_nodes(root, 0); - - for_each_compatible_node(node, NULL, "barebox,state") { - of_print_nodes(node, 0); - } - - return 0; -} diff --git a/of.h b/of.h deleted file mode 100644 index a0d613e..0000000 --- a/of.h +++ /dev/null @@ -1,368 +0,0 @@ -#ifndef __OF_H -#define __OF_H - -#include "list.h" - -/* Default string compare functions */ -#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) -#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) -#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) - -#define OF_BAD_ADDR ((uint64_t)-1) - -typedef uint32_t phandle; - -struct property { - char *name; - int length; - void *value; - struct list_head list; -}; - -struct device_node { - char *name; - char *full_name; - - struct list_head properties; - struct device_node *parent; - struct list_head children; - struct list_head parent_list; - struct list_head list; - phandle phandle; -}; - -struct of_device_id { - char *compatible; - unsigned long data; -}; - -#define MAX_PHANDLE_ARGS 8 -struct of_phandle_args { - struct device_node *np; - int args_count; - uint32_t args[MAX_PHANDLE_ARGS]; -}; - -#define OF_MAX_RESERVE_MAP 16 -struct of_reserve_map { - uint64_t start[OF_MAX_RESERVE_MAP]; - uint64_t end[OF_MAX_RESERVE_MAP]; - int num_entries; -}; - -int of_add_reserve_entry(uint64_t start, uint64_t end); -struct of_reserve_map *of_get_reserve_map(void); -void of_clean_reserve_map(void); -void fdt_add_reserve_map(void *fdt); - -struct device_d; -struct driver_d; - -int of_fix_tree(struct device_node *); -int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context); - -int of_match(struct device_d *dev, struct driver_d *drv); - -struct fdt_header *fdt_get_tree(void); - -struct fdt_header *of_get_fixed_tree(struct device_node *node); - -/* Helper to read a big number; size is in cells (not bytes) */ -static inline uint64_t of_read_number(const __be32 *cell, int size) -{ - uint64_t r = 0; - while (size--) - r = (r << 32) | __be32_to_cpu(*(cell++)); - return r; -} - -/* Helper to write a big number; size is in cells (not bytes) */ -static inline void of_write_number(void *__cell, uint64_t val, int size) -{ - __be32 *cell = __cell; - - while (size--) { - cell[size] = __cpu_to_be32(val); - val >>= 32; - } -} - -void of_print_property(const void *data, int len); -void of_print_cmdline(struct device_node *root); - -void of_print_nodes(struct device_node *node, int indent); -int of_probe(void); -int of_parse_dtb(struct fdt_header *fdt); -struct device_node *of_unflatten_dtb(struct device_node *root, void *fdt); - -struct cdev; - -extern int of_n_addr_cells(struct device_node *np); -extern int of_n_size_cells(struct device_node *np); - -extern struct property *of_find_property(const struct device_node *np, - const char *name, int *lenp); -extern const void *of_get_property(const struct device_node *np, - const char *name, int *lenp); - -extern int of_set_property(struct device_node *node, const char *p, - const void *val, int len, int create); -extern struct property *of_new_property(struct device_node *node, - const char *name, const void *data, int len); -extern void of_delete_property(struct property *pp); - -extern struct device_node *of_find_node_by_name(struct device_node *from, - const char *name); -extern struct device_node *of_find_node_by_path_from(struct device_node *from, - const char *path); -extern struct device_node *of_find_node_by_path(const char *path); -extern struct device_node *of_find_node_by_phandle(phandle phandle); -extern struct device_node *of_find_node_by_type(struct device_node *from, - const char *type); -extern struct device_node *of_find_compatible_node(struct device_node *from, - const char *type, const char *compat); -extern const struct of_device_id *of_match_node( - const struct of_device_id *matches, const struct device_node *node); -extern struct device_node *of_find_matching_node_and_match( - struct device_node *from, - const struct of_device_id *matches, - const struct of_device_id **match); -extern struct device_node *of_find_node_with_property( - struct device_node *from, const char *prop_name); - -extern struct device_node *of_new_node(struct device_node *parent, - const char *name); -extern struct device_node *of_create_node(struct device_node *root, - const char *path); -extern void of_delete_node(struct device_node *node); - -extern int of_machine_is_compatible(const char *compat); -extern int of_device_is_compatible(const struct device_node *device, - const char *compat); -extern int of_device_is_available(const struct device_node *device); - -extern struct device_node *of_get_parent(const struct device_node *node); -extern struct device_node *of_get_next_available_child( - const struct device_node *node, struct device_node *prev); -extern int of_get_child_count(const struct device_node *parent); -extern int of_get_available_child_count(const struct device_node *parent); -extern struct device_node *of_get_child_by_name(const struct device_node *node, - const char *name); - -extern int of_property_read_u32_index(const struct device_node *np, - const char *propname, - uint32_t index, uint32_t *out_value); -extern int of_property_read_u8_array(const struct device_node *np, - const char *propname, uint8_t *out_values, size_t sz); -extern int of_property_read_u16_array(const struct device_node *np, - const char *propname, uint16_t *out_values, size_t sz); -extern int of_property_read_u32_array(const struct device_node *np, - const char *propname, - uint32_t *out_values, - size_t sz); -extern int of_property_read_u64(const struct device_node *np, - const char *propname, uint64_t *out_value); - -extern int of_property_read_string(struct device_node *np, - const char *propname, - const char **out_string); -extern int of_property_read_string_index(struct device_node *np, - const char *propname, - int index, const char **output); -extern int of_property_match_string(struct device_node *np, - const char *propname, - const char *string); -extern int of_property_count_strings(struct device_node *np, - const char *propname); - -extern const __be32 *of_prop_next_u32(struct property *prop, - const __be32 *cur, uint32_t *pu); -extern const char *of_prop_next_string(struct property *prop, const char *cur); - -extern int of_property_write_bool(struct device_node *np, - const char *propname, const bool value); -extern int of_property_write_u8_array(struct device_node *np, - const char *propname, const uint8_t *values, - size_t sz); -extern int of_property_write_u16_array(struct device_node *np, - const char *propname, const uint16_t *values, - size_t sz); -extern int of_property_write_u32_array(struct device_node *np, - const char *propname, const uint32_t *values, - size_t sz); -extern int of_property_write_u64_array(struct device_node *np, - const char *propname, const uint64_t *values, - size_t sz); - -extern struct device_node *of_parse_phandle(const struct device_node *np, - const char *phandle_name, - int index); -extern int of_parse_phandle_with_args(const struct device_node *np, - const char *list_name, const char *cells_name, int index, - struct of_phandle_args *out_args); -extern int of_count_phandle_with_args(const struct device_node *np, - const char *list_name, const char *cells_name); - -extern void of_alias_scan(void); -extern int of_alias_get_id(struct device_node *np, const char *stem); -extern const char *of_alias_get(struct device_node *np); -extern int of_modalias_node(struct device_node *node, char *modalias, int len); - -extern struct device_node *of_get_root_node(void); -extern int of_set_root_node(struct device_node *node); - -extern int of_platform_populate(struct device_node *root, - const struct of_device_id *matches, - struct device_d *parent); -extern struct device_d *of_find_device_by_node(struct device_node *np); - -struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node); -int of_parse_partitions(struct cdev *cdev, struct device_node *node); -int of_device_is_stdout_path(struct device_d *dev); -const char *of_get_model(void); -void *of_flatten_dtb(struct device_node *node); -int of_add_memory(struct device_node *node, bool dump); -void of_add_memory_bank(struct device_node *node, bool dump, int r, - uint64_t base, uint64_t size); -int of_find_path(struct device_node *node, const char *propname, char **outpath); - -#define for_each_node_by_name(dn, name) \ - for (dn = of_find_node_by_name(NULL, name); dn; \ - dn = of_find_node_by_name(dn, name)) -#define for_each_compatible_node(dn, type, compatible) \ - for (dn = of_find_compatible_node(NULL, type, compatible); dn; \ - dn = of_find_compatible_node(dn, type, compatible)) -static inline struct device_node *of_find_matching_node( - struct device_node *from, - const struct of_device_id *matches) -{ - return of_find_matching_node_and_match(from, matches, NULL); -} -#define for_each_matching_node(dn, matches) \ - for (dn = of_find_matching_node(NULL, matches); dn; \ - dn = of_find_matching_node(dn, matches)) -#define for_each_matching_node_and_match(dn, matches, match) \ - for (dn = of_find_matching_node_and_match(NULL, matches, match); \ - dn; dn = of_find_matching_node_and_match(dn, matches, match)) -#define for_each_node_with_property(dn, prop_name) \ - for (dn = of_find_node_with_property(NULL, prop_name); dn; \ - dn = of_find_node_with_property(dn, prop_name)) - -#define for_each_child_of_node(parent, child) \ - list_for_each_entry(child, &parent->children, parent_list) -#define for_each_available_child_of_node(parent, child) \ - for (child = of_get_next_available_child(parent, NULL); child != NULL; \ - child = of_get_next_available_child(parent, child)) - -/** - * of_property_read_bool - Findfrom a property - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device node. - * Returns true if the property exist false otherwise. - */ -static inline bool of_property_read_bool(const struct device_node *np, - const char *propname) -{ - struct property *prop = of_find_property(np, propname, NULL); - - return prop ? true : false; -} - -static inline int of_property_read_u8(const struct device_node *np, - const char *propname, - uint8_t *out_value) -{ - return of_property_read_u8_array(np, propname, out_value, 1); -} - -static inline int of_property_read_u16(const struct device_node *np, - const char *propname, - uint16_t *out_value) -{ - return of_property_read_u16_array(np, propname, out_value, 1); -} - -static inline int of_property_read_u32(const struct device_node *np, - const char *propname, - uint32_t *out_value) -{ - return of_property_read_u32_array(np, propname, out_value, 1); -} - -/* - * struct property *prop; - * const __be32 *p; - * uint32_t u; - * - * of_property_for_each_u32(np, "propname", prop, p, u) - * printk("U32 value: %x\n", u); - */ -#define of_property_for_each_u32(np, propname, prop, p, u) \ - for (prop = of_find_property(np, propname, NULL), \ - p = of_prop_next_u32(prop, NULL, &u); \ - p; \ - p = of_prop_next_u32(prop, p, &u)) - -/* - * struct property *prop; - * const char *s; - * - * of_property_for_each_string(np, "propname", prop, s) - * printk("String value: %s\n", s); - */ -#define of_property_for_each_string(np, propname, prop, s) \ - for (prop = of_find_property(np, propname, NULL), \ - s = of_prop_next_string(prop, NULL); \ - s; \ - s = of_prop_next_string(prop, s)) - -static inline int of_property_write_u8(struct device_node *np, - const char *propname, uint8_t value) -{ - return of_property_write_u8_array(np, propname, &value, 1); -} - -static inline int of_property_write_u16(struct device_node *np, - const char *propname, uint16_t value) -{ - return of_property_write_u16_array(np, propname, &value, 1); -} - -static inline int of_property_write_u32(struct device_node *np, - const char *propname, - uint32_t value) -{ - return of_property_write_u32_array(np, propname, &value, 1); -} - -static inline int of_property_write_u64(struct device_node *np, - const char *propname, - uint64_t value) -{ - return of_property_write_u64_array(np, propname, &value, 1); -} - -extern const struct of_device_id of_default_bus_match_table[]; - -int of_device_enable(struct device_node *node); -int of_device_enable_path(const char *path); -int of_device_disable(struct device_node *node); -int of_device_disable_path(const char *path); - -phandle of_get_tree_max_phandle(struct device_node *root); -phandle of_node_create_phandle(struct device_node *node); -struct device_node *of_find_node_by_alias(struct device_node *root, - const char *alias); -struct device_node *of_find_node_by_path_or_alias(struct device_node *root, - const char *str); - -static inline struct device_node *of_find_root_node(struct device_node *node) -{ - while (node->parent) - node = node->parent; - - return node; -} -#endif /* __OF_H */ diff --git a/sizes.h b/sizes.h new file mode 100644 index 0000000..6f91e9b --- /dev/null +++ b/sizes.h @@ -0,0 +1,56 @@ +/* + * 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. + */ +/* Size defintions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_1 0x00000001 +#define SZ_2 0x00000002 +#define SZ_4 0x00000004 +#define SZ_8 0x00000008 +#define SZ_16 0x00000010 +#define SZ_32 0x00000020 +#define SZ_64 0x00000040 +#define SZ_128 0x00000080 +#define SZ_256 0x00000100 +#define SZ_512 0x00000200 + +#define SZ_1K 0x00000400 +#define SZ_2K 0x00000800 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_32K 0x00008000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +#endif /* __sizes_h */ diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..5e25d6d --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,7 @@ +.dirstamp +.deps/ +.libs/ +*.la +*.lo +libabc.pc +test-libabc diff --git a/src/crc32.c b/src/crc32.c new file mode 100644 index 0000000..8d4dddc --- /dev/null +++ b/src/crc32.c @@ -0,0 +1,112 @@ +/* + * This file is derived from crc32.c from the zlib-1.1.3 distribution + * by Jean-loup Gailly and Mark Adler. + */ + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include + +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uint32_t crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len) +{ + const unsigned char *buf = _buf; + + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8(buf); + len -= 8; + } + + if (len) do { + DO1(buf); + } while (--len); + + return crc ^ 0xffffffffL; +} + +/* No ones complement version. JFFS2 (and other things ?) + * don't use ones compliment in their CRC calculations. + */ +uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len) +{ + const unsigned char *buf = _buf; + + while (len >= 8) { + DO8(buf); + len -= 8; + } + + if (len) do { + DO1(buf); + } while (--len); + + return crc; +} diff --git a/src/dt/common.h b/src/dt/common.h new file mode 100644 index 0000000..9668c4e --- /dev/null +++ b/src/dt/common.h @@ -0,0 +1,125 @@ +#ifndef __DT_COMMON_H +#define __DT_COMMON_H + +#include +#include +#include + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#ifdef DEBUG +#define pr_debug(fmt, arg...) printf(fmt, ##arg) +#else +#define pr_debug(fmt, arg...) +#endif + +#define pr_err(fmt, arg...) printf(fmt, ##arg) + +static inline void *xzalloc(size_t size) +{ + return calloc(1, size); +} + +typedef _Bool bool; + +enum { + false = 0, + true = 1 +}; + +/* + * Kernel pointers have redundant information, so we can use a + * scheme where we can return either an error code or a dentry + * pointer with the same return value. + * + * This should be a per-architecture thing, to allow different + * error and pointer decisions. + */ +#define MAX_ERRNO 4095 + +#ifndef __ASSEMBLY__ + +#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) + +static inline void *ERR_PTR(long error) +{ + return (void *) error; +} + +static inline long PTR_ERR(const void *ptr) +{ + return (long) ptr; +} + +static inline long IS_ERR(const void *ptr) +{ + return IS_ERR_VALUE((unsigned long)ptr); +} + +static inline long IS_ERR_OR_NULL(const void *ptr) +{ + return !ptr || IS_ERR_VALUE((unsigned long)ptr); +} + +/** + * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type + * @ptr: The pointer to cast. + * + * Explicitly cast an error-valued pointer to another pointer type in such a + * way as to make it clear that's what's going on. + */ +static inline void *ERR_CAST(const void *ptr) +{ + /* cast away the const */ + return (void *) ptr; +} + +/** + * strlcpy - Copy a %NUL terminated string into a sized buffer + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @size: size of destination buffer + * + * Compatible with *BSD: the result is always a valid + * NUL-terminated string that fits in the buffer (unless, + * of course, the buffer size is zero). It does not pad + * out the result like strncpy() does. + */ +static inline size_t strlcpy(char *dest, const char *src, size_t size) +{ + size_t ret = strlen(src); + + if (size) { + size_t len = (ret >= size) ? size - 1 : ret; + memcpy(dest, src, len); + dest[len] = '\0'; + } + return ret; +} + +#define cpu_to_be32 __cpu_to_be32 +#define be32_to_cpu __be32_to_cpu + +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#endif + +uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len); +uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len); + +#endif /* __DT_COMMON_H */ diff --git a/src/dt/dt.h b/src/dt/dt.h new file mode 100644 index 0000000..086edfe --- /dev/null +++ b/src/dt/dt.h @@ -0,0 +1,383 @@ +#ifndef __DT_DT_H +#define __DT_DT_H + +#include +#include
+#include
+#include + +/* Default string compare functions */ +#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) +#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) +#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) + +#define OF_BAD_ADDR ((uint64_t)-1) + +typedef uint32_t phandle; + +struct property { + char *name; + int length; + void *value; + struct list_head list; +}; + +struct device_node { + char *name; + char *full_name; + + struct list_head properties; + struct device_node *parent; + struct list_head children; + struct list_head parent_list; + struct list_head list; + phandle phandle; +}; + +struct of_device_id { + char *compatible; + unsigned long data; +}; + +#define MAX_PHANDLE_ARGS 8 +struct of_phandle_args { + struct device_node *np; + int args_count; + uint32_t args[MAX_PHANDLE_ARGS]; +}; + +#define OF_MAX_RESERVE_MAP 16 +struct of_reserve_map { + uint64_t start[OF_MAX_RESERVE_MAP]; + uint64_t end[OF_MAX_RESERVE_MAP]; + int num_entries; +}; + +int of_add_reserve_entry(uint64_t start, uint64_t end); +struct of_reserve_map *of_get_reserve_map(void); +void of_clean_reserve_map(void); +void fdt_add_reserve_map(void *fdt); + +struct device_d; +struct driver_d; + +int of_fix_tree(struct device_node *); +int of_register_fixup(int (*fixup)(struct device_node *, void *), void *context); + +int of_match(struct device_d *dev, struct driver_d *drv); + +struct fdt_header *fdt_get_tree(void); + +struct fdt_header *of_get_fixed_tree(struct device_node *node); + +/* Helper to read a big number; size is in cells (not bytes) */ +static inline uint64_t of_read_number(const __be32 *cell, int size) +{ + uint64_t r = 0; + while (size--) + r = (r << 32) | __be32_to_cpu(*(cell++)); + return r; +} + +/* Helper to write a big number; size is in cells (not bytes) */ +static inline void of_write_number(void *__cell, uint64_t val, int size) +{ + __be32 *cell = __cell; + + while (size--) { + cell[size] = __cpu_to_be32(val); + val >>= 32; + } +} + +void of_print_property(const void *data, int len); +void of_print_cmdline(struct device_node *root); + +void of_print_nodes(struct device_node *node, int indent); +int of_probe(void); +int of_parse_dtb(struct fdt_header *fdt); +struct device_node *of_unflatten_dtb(struct device_node *root, void *fdt); + +struct cdev; + +extern int of_n_addr_cells(struct device_node *np); +extern int of_n_size_cells(struct device_node *np); + +extern struct property *of_find_property(const struct device_node *np, + const char *name, int *lenp); +extern const void *of_get_property(const struct device_node *np, + const char *name, int *lenp); + +extern int of_set_property(struct device_node *node, const char *p, + const void *val, int len, int create); +extern struct property *of_new_property(struct device_node *node, + const char *name, const void *data, int len); +extern void of_delete_property(struct property *pp); + +extern struct device_node *of_find_node_by_name(struct device_node *from, + const char *name); +extern struct device_node *of_find_node_by_path_from(struct device_node *from, + const char *path); +extern struct device_node *of_find_node_by_path(const char *path); +extern struct device_node *of_find_node_by_phandle(phandle phandle); +extern struct device_node *of_find_node_by_type(struct device_node *from, + const char *type); +extern struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compat); +extern const struct of_device_id *of_match_node( + const struct of_device_id *matches, const struct device_node *node); +extern struct device_node *of_find_matching_node_and_match( + struct device_node *from, + const struct of_device_id *matches, + const struct of_device_id **match); +extern struct device_node *of_find_node_with_property( + struct device_node *from, const char *prop_name); + +extern struct device_node *of_new_node(struct device_node *parent, + const char *name); +extern struct device_node *of_create_node(struct device_node *root, + const char *path); +extern void of_delete_node(struct device_node *node); + +extern int of_machine_is_compatible(const char *compat); +extern int of_device_is_compatible(const struct device_node *device, + const char *compat); +extern int of_device_is_available(const struct device_node *device); + +extern struct device_node *of_get_parent(const struct device_node *node); +extern struct device_node *of_get_next_available_child( + const struct device_node *node, struct device_node *prev); +extern int of_get_child_count(const struct device_node *parent); +extern int of_get_available_child_count(const struct device_node *parent); +extern struct device_node *of_get_child_by_name(const struct device_node *node, + const char *name); + +extern int of_property_read_u32_index(const struct device_node *np, + const char *propname, + uint32_t index, uint32_t *out_value); +extern int of_property_read_u8_array(const struct device_node *np, + const char *propname, uint8_t *out_values, size_t sz); +extern int of_property_read_u16_array(const struct device_node *np, + const char *propname, uint16_t *out_values, size_t sz); +extern int of_property_read_u32_array(const struct device_node *np, + const char *propname, + uint32_t *out_values, + size_t sz); +extern int of_property_read_u64(const struct device_node *np, + const char *propname, uint64_t *out_value); + +extern int of_property_read_string(struct device_node *np, + const char *propname, + const char **out_string); +extern int of_property_read_string_index(struct device_node *np, + const char *propname, + int index, const char **output); +extern int of_property_match_string(struct device_node *np, + const char *propname, + const char *string); +extern int of_property_count_strings(struct device_node *np, + const char *propname); + +extern const __be32 *of_prop_next_u32(struct property *prop, + const __be32 *cur, uint32_t *pu); +extern const char *of_prop_next_string(struct property *prop, const char *cur); + +extern int of_property_write_bool(struct device_node *np, + const char *propname, const bool value); +extern int of_property_write_u8_array(struct device_node *np, + const char *propname, const uint8_t *values, + size_t sz); +extern int of_property_write_u16_array(struct device_node *np, + const char *propname, const uint16_t *values, + size_t sz); +extern int of_property_write_u32_array(struct device_node *np, + const char *propname, const uint32_t *values, + size_t sz); +extern int of_property_write_u64_array(struct device_node *np, + const char *propname, const uint64_t *values, + size_t sz); + +extern struct device_node *of_parse_phandle(const struct device_node *np, + const char *phandle_name, + int index); +extern int of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name, int index, + struct of_phandle_args *out_args); +extern int of_count_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name); + +extern void of_alias_scan(void); +extern int of_alias_get_id(struct device_node *np, const char *stem); +extern const char *of_alias_get(struct device_node *np); +extern int of_modalias_node(struct device_node *node, char *modalias, int len); + +extern struct device_node *of_get_root_node(void); +extern int of_set_root_node(struct device_node *node); + +extern int of_platform_populate(struct device_node *root, + const struct of_device_id *matches, + struct device_d *parent); +extern struct device_d *of_find_device_by_node(struct device_node *np); + +struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node); +int of_parse_partitions(struct cdev *cdev, struct device_node *node); +int of_device_is_stdout_path(struct device_d *dev); +const char *of_get_model(void); +void *of_flatten_dtb(struct device_node *node); +int of_add_memory(struct device_node *node, bool dump); +void of_add_memory_bank(struct device_node *node, bool dump, int r, + uint64_t base, uint64_t size); + +struct of_path { + char *devpath; + off_t offset; + size_t size; + struct udev_device *dev; + struct device_node *node; +}; + +int of_find_path(struct device_node *node, const char *propname, struct of_path *op); + +#define for_each_node_by_name(dn, name) \ + for (dn = of_find_node_by_name(NULL, name); dn; \ + dn = of_find_node_by_name(dn, name)) +#define for_each_compatible_node(dn, type, compatible) \ + for (dn = of_find_compatible_node(NULL, type, compatible); dn; \ + dn = of_find_compatible_node(dn, type, compatible)) +static inline struct device_node *of_find_matching_node( + struct device_node *from, + const struct of_device_id *matches) +{ + return of_find_matching_node_and_match(from, matches, NULL); +} +#define for_each_matching_node(dn, matches) \ + for (dn = of_find_matching_node(NULL, matches); dn; \ + dn = of_find_matching_node(dn, matches)) +#define for_each_matching_node_and_match(dn, matches, match) \ + for (dn = of_find_matching_node_and_match(NULL, matches, match); \ + dn; dn = of_find_matching_node_and_match(dn, matches, match)) +#define for_each_node_with_property(dn, prop_name) \ + for (dn = of_find_node_with_property(NULL, prop_name); dn; \ + dn = of_find_node_with_property(dn, prop_name)) + +#define for_each_child_of_node(parent, child) \ + list_for_each_entry(child, &parent->children, parent_list) +#define for_each_available_child_of_node(parent, child) \ + for (child = of_get_next_available_child(parent, NULL); child != NULL; \ + child = of_get_next_available_child(parent, child)) + +/** + * of_property_read_bool - Findfrom a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device node. + * Returns true if the property exist false otherwise. + */ +static inline bool of_property_read_bool(const struct device_node *np, + const char *propname) +{ + struct property *prop = of_find_property(np, propname, NULL); + + return prop ? true : false; +} + +static inline int of_property_read_u8(const struct device_node *np, + const char *propname, + uint8_t *out_value) +{ + return of_property_read_u8_array(np, propname, out_value, 1); +} + +static inline int of_property_read_u16(const struct device_node *np, + const char *propname, + uint16_t *out_value) +{ + return of_property_read_u16_array(np, propname, out_value, 1); +} + +static inline int of_property_read_u32(const struct device_node *np, + const char *propname, + uint32_t *out_value) +{ + return of_property_read_u32_array(np, propname, out_value, 1); +} + +/* + * struct property *prop; + * const __be32 *p; + * uint32_t u; + * + * of_property_for_each_u32(np, "propname", prop, p, u) + * printk("U32 value: %x\n", u); + */ +#define of_property_for_each_u32(np, propname, prop, p, u) \ + for (prop = of_find_property(np, propname, NULL), \ + p = of_prop_next_u32(prop, NULL, &u); \ + p; \ + p = of_prop_next_u32(prop, p, &u)) + +/* + * struct property *prop; + * const char *s; + * + * of_property_for_each_string(np, "propname", prop, s) + * printk("String value: %s\n", s); + */ +#define of_property_for_each_string(np, propname, prop, s) \ + for (prop = of_find_property(np, propname, NULL), \ + s = of_prop_next_string(prop, NULL); \ + s; \ + s = of_prop_next_string(prop, s)) + +static inline int of_property_write_u8(struct device_node *np, + const char *propname, uint8_t value) +{ + return of_property_write_u8_array(np, propname, &value, 1); +} + +static inline int of_property_write_u16(struct device_node *np, + const char *propname, uint16_t value) +{ + return of_property_write_u16_array(np, propname, &value, 1); +} + +static inline int of_property_write_u32(struct device_node *np, + const char *propname, + uint32_t value) +{ + return of_property_write_u32_array(np, propname, &value, 1); +} + +static inline int of_property_write_u64(struct device_node *np, + const char *propname, + uint64_t value) +{ + return of_property_write_u64_array(np, propname, &value, 1); +} + +extern const struct of_device_id of_default_bus_match_table[]; + +int of_device_enable(struct device_node *node); +int of_device_enable_path(const char *path); +int of_device_disable(struct device_node *node); +int of_device_disable_path(const char *path); + +phandle of_get_tree_max_phandle(struct device_node *root); +phandle of_node_create_phandle(struct device_node *node); +struct device_node *of_find_node_by_alias(struct device_node *root, + const char *alias); +struct device_node *of_find_node_by_path_or_alias(struct device_node *root, + const char *str); + +static inline struct device_node *of_find_root_node(struct device_node *node) +{ + while (node->parent) + node = node->parent; + + return node; +} + +struct device_node *of_read_proc_devicetree(void); + +#endif /* __DT_DT_H */ diff --git a/src/dt/fdt.h b/src/dt/fdt.h new file mode 100644 index 0000000..35278e3 --- /dev/null +++ b/src/dt/fdt.h @@ -0,0 +1,73 @@ +#ifndef _FDT_H +#define _FDT_H + +#ifndef __ASSEMBLY__ + +#define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) + +#define fdt32_to_cpu(x) be32_to_cpu(x) +#define cpu_to_fdt32(x) cpu_to_be32(x) + +static inline uint64_t fdt64_to_cpu(uint64_t x) +{ + return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) + | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); +} +#define cpu_to_fdt64(x) fdt64_to_cpu(x) +#undef _B + +struct fdt_header { + uint32_t magic; /* magic word FDT_MAGIC */ + uint32_t totalsize; /* total size of DT block */ + uint32_t off_dt_struct; /* offset to structure */ + uint32_t off_dt_strings; /* offset to strings */ + uint32_t off_mem_rsvmap; /* offset to memory reserve map */ + uint32_t version; /* format version */ + uint32_t last_comp_version; /* last compatible version */ + + /* version 2 fields below */ + uint32_t boot_cpuid_phys; /* Which physical CPU id we're + booting on */ + /* version 3 fields below */ + uint32_t size_dt_strings; /* size of the strings block */ + + /* version 17 fields below */ + uint32_t size_dt_struct; /* size of the structure block */ +}; + +struct fdt_reserve_entry { + uint64_t address; + uint64_t size; +}; + +struct fdt_node_header { + uint32_t tag; + char name[0]; +}; + +struct fdt_property { + uint32_t tag; + uint32_t len; + uint32_t nameoff; + char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ +#define FDT_TAGSIZE sizeof(uint32_t) + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, + size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +#define FDT_V1_SIZE (7*sizeof(uint32_t)) +#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) +#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V16_SIZE FDT_V3_SIZE +#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) + +#endif /* _FDT_H */ diff --git a/src/dt/list.h b/src/dt/list.h new file mode 100644 index 0000000..c17b5d4 --- /dev/null +++ b/src/dt/list.h @@ -0,0 +1,627 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +#include "common.h" + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) +static inline void prefetch(const void *x) {;} + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} +#else +extern void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next); +#endif + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +#ifndef CONFIG_DEBUG_LIST +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} +#else +extern void list_add(struct list_head *new, struct list_head *head); +#endif + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +#ifndef CONFIG_DEBUG_LIST +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} +#else +extern void list_del(struct list_head *entry); +#endif + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @head: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(head, type, member) \ + list_entry((head)->prev, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; prefetch(pos->next), pos != (head); \ + pos = pos->next) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ + pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + prefetch(pos->member.prev), &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; prefetch(pos->member.next), &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +/** + * list_add_sort - add a new entry to a sorted list + * @new: new entry to be added + * @head: list head to add it in + * @compare: Compare function to compare two list entries + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_sort(struct list_head *new, struct list_head *head, + int (*compare)(struct list_head *a, struct list_head *b)) +{ + struct list_head *pos, *insert = head; + + list_for_each(pos, head) { + if (compare(pos, new) < 0) + continue; + insert = pos; + break; + } + + list_add_tail(new, insert); +} + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +#endif diff --git a/src/fdt.c b/src/fdt.c new file mode 100644 index 0000000..903ed68 --- /dev/null +++ b/src/fdt.c @@ -0,0 +1,485 @@ +/* + * dtb.c - flat devicetree functions + * + * Copyright (c) 2013 Sascha Hauer , Pengutronix + * + * based on Linux devicetree support + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include
+#include
+ +static inline uint32_t dt_struct_advance(struct fdt_header *f, uint32_t dt, int size) +{ + dt += size; + dt = ALIGN(dt, 4); + + if (dt > f->off_dt_struct + f->size_dt_struct) + return 0; + + return dt; +} + +static inline char *dt_string(struct fdt_header *f, char *strstart, uint32_t ofs) +{ + if (ofs > f->size_dt_strings) + return NULL; + else + return strstart + ofs; +} + +/** + * of_unflatten_dtb - unflatten a dtb binary blob + * @root - node in which the fdt blob should be merged into or NULL + * @infdt - the fdt blob to unflatten + * + * Parse a flat device tree binary blob and return a pointer to the + * unflattened tree. + */ +struct device_node *of_unflatten_dtb(struct device_node *root, void *infdt) +{ + const void *nodep; /* property node pointer */ + uint32_t tag; /* tag */ + int len; /* length of the property */ + const struct fdt_property *fdt_prop; + const char *pathp, *name; + struct device_node *node = NULL; + struct property *p; + uint32_t dt_struct; + struct fdt_node_header *fnh; + void *dt_strings; + struct fdt_header f; + int ret, merge = 0; + unsigned int maxlen; + struct fdt_header *fdt = infdt; + + if (fdt->magic != cpu_to_fdt32(FDT_MAGIC)) { + pr_err("bad magic: 0x%08x\n", fdt32_to_cpu(fdt->magic)); + return ERR_PTR(-EINVAL); + } + + if (fdt->version != cpu_to_fdt32(17)) { + pr_err("bad dt version: 0x%08x\n", fdt32_to_cpu(fdt->version)); + return ERR_PTR(-EINVAL); + } + + f.totalsize = fdt32_to_cpu(fdt->totalsize); + f.off_dt_struct = fdt32_to_cpu(fdt->off_dt_struct); + f.size_dt_struct = fdt32_to_cpu(fdt->size_dt_struct); + f.off_dt_strings = fdt32_to_cpu(fdt->off_dt_strings); + f.size_dt_strings = fdt32_to_cpu(fdt->size_dt_strings); + + if (f.off_dt_struct + f.size_dt_struct > f.totalsize) { + pr_err("unflatten: dt size exceeds total size\n"); + return ERR_PTR(-ESPIPE); + } + + if (f.off_dt_strings + f.size_dt_strings > f.totalsize) { + pr_err("unflatten: string size exceeds total size\n"); + return ERR_PTR(-ESPIPE); + } + + dt_struct = f.off_dt_struct; + dt_strings = (void *)fdt + f.off_dt_strings; + + if (root) { + pr_debug("unflatten: merging into existing tree\n"); + merge = 1; + } else { + root = of_new_node(NULL, NULL); + if (!root) + return ERR_PTR(-ENOMEM); + } + + while (1) { + tag = be32_to_cpu(*(uint32_t *)(infdt + dt_struct)); + + switch (tag) { + case FDT_BEGIN_NODE: + fnh = infdt + dt_struct; + pathp = name = fnh->name; + maxlen = (unsigned long)fdt + f.off_dt_struct + + f.size_dt_struct - (unsigned long)name; + + len = strnlen(name, maxlen + 1); + if (len > maxlen) { + ret = -ESPIPE; + goto err; + } + + dt_struct = dt_struct_advance(&f, dt_struct, + sizeof(struct fdt_node_header) + len + 1); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + if (!node) { + node = root; + } else { + if (merge) + node = of_get_child_by_name(node, + pathp); + if (!merge || !node) + node = of_new_node(node, pathp); + } + + break; + + case FDT_END_NODE: + if (!node) { + pr_err("unflatten: too many end nodes\n"); + ret = -EINVAL; + goto err; + } + + node = node->parent; + + dt_struct = dt_struct_advance(&f, dt_struct, FDT_TAGSIZE); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + break; + + case FDT_PROP: + fdt_prop = infdt + dt_struct; + len = fdt32_to_cpu(fdt_prop->len); + nodep = fdt_prop->data; + + name = dt_string(&f, dt_strings, fdt32_to_cpu(fdt_prop->nameoff)); + if (!name) { + ret = -ESPIPE; + goto err; + } + + dt_struct = dt_struct_advance(&f, dt_struct, + sizeof(struct fdt_property) + len); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + p = NULL; + if (merge) + p = of_find_property(node, name, NULL); + if (merge && p) { + free(p->value); + p->value = xzalloc(len); + p->length = len; + memcpy(p->value, nodep, len); + } else { + p = of_new_property(node, name, nodep, len); + if (!strcmp(name, "phandle") && len == 4) + node->phandle = be32_to_cpu(*(__be32 *)p->value); + } + + break; + + case FDT_NOP: + dt_struct = dt_struct_advance(&f, dt_struct, FDT_TAGSIZE); + if (!dt_struct) { + ret = -ESPIPE; + goto err; + } + + break; + + case FDT_END: + return root; + + default: + pr_err("unflatten: Unknown tag 0x%08X\n", tag); + ret = -EINVAL; + goto err; + } + } +err: + of_delete_node(root); + + return ERR_PTR(ret); +} + +struct fdt { + void *dt; + uint32_t dt_nextofs; + uint32_t dt_size; + char *strings; + uint32_t str_nextofs; + uint32_t str_size; +}; + +static inline uint32_t dt_next_ofs(uint32_t curofs, uint32_t len) +{ + return ALIGN(curofs + len, 4); +} + +static int lstrcpy(char *dest, const char *src) +{ + int len = 0; + int maxlen = 1023; + + while (*src) { + *dest++ = *src++; + len++; + if (!maxlen) + return -ENOSPC; + maxlen--; + } + + return len; +} + +static int fdt_ensure_space(struct fdt *fdt, int dtsize) +{ + /* + * We assume strings and names have a maximum length of 1024 + * whereas properties can be longer. We allocate new memory + * if we have less than 1024 bytes (+ the property size left. + */ + if (fdt->str_size - fdt->str_nextofs < 1024) { + fdt->strings = realloc(fdt->strings, fdt->str_size * 2); + if (!fdt->strings) + return -ENOMEM; + fdt->str_size *= 2; + } + + if (fdt->dt_size - fdt->dt_nextofs < 1024 + dtsize) { + fdt->dt = realloc(fdt->dt, fdt->dt_size * 2); + if (!fdt->dt) + return -ENOMEM; + fdt->dt_size *= 2; + } + + return 0; +} + +static inline int dt_add_string(struct fdt *fdt, const char *str) +{ + uint32_t ret; + int len; + + if (fdt_ensure_space(fdt, 0) < 0) + return -ENOMEM; + + len = lstrcpy(fdt->strings + fdt->str_nextofs, str); + if (len < 0) + return -ENOSPC; + + ret = fdt->str_nextofs; + + fdt->str_nextofs += len + 1; + + return ret; +} + +static int __of_flatten_dtb(struct fdt *fdt, struct device_node *node) +{ + struct property *p; + struct device_node *n; + int ret; + unsigned int len; + struct fdt_node_header *nh; + + if (fdt_ensure_space(fdt, 0) < 0) + return -ENOMEM; + + nh = fdt->dt + fdt->dt_nextofs; + nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); + len = lstrcpy(nh->name, node->name); + fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs, 4 + len + 1); + + list_for_each_entry(p, &node->properties, list) { + struct fdt_property *fp; + + if (fdt_ensure_space(fdt, p->length) < 0) + return -ENOMEM; + + fp = fdt->dt + fdt->dt_nextofs; + + fp->tag = cpu_to_fdt32(FDT_PROP); + fp->len = cpu_to_fdt32(p->length); + fp->nameoff = cpu_to_fdt32(dt_add_string(fdt, p->name)); + memcpy(fp->data, p->value, p->length); + fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs, + sizeof(struct fdt_property) + p->length); + } + + list_for_each_entry(n, &node->children, parent_list) { + ret = __of_flatten_dtb(fdt, n); + if (ret) + return ret; + } + + nh = fdt->dt + fdt->dt_nextofs; + nh->tag = cpu_to_fdt32(FDT_END_NODE); + fdt->dt_nextofs = dt_next_ofs(fdt->dt_nextofs, + sizeof(struct fdt_node_header)); + + if (fdt_ensure_space(fdt, 0) < 0) + return -ENOMEM; + + return 0; +} + +#define BUFSIZE (64 * 1024) + +/** + * of_flatten_dtb - flatten a barebox internal devicetree to a dtb + * @node - the root node of the tree to be unflattened + */ +void *of_flatten_dtb(struct device_node *node) +{ + int ret; + struct fdt_header header = {}; + struct fdt fdt = {}; + uint32_t ofs; + struct fdt_node_header *nh; + + header.magic = cpu_to_fdt32(FDT_MAGIC); + header.version = cpu_to_fdt32(0x11); + header.last_comp_version = cpu_to_fdt32(0x10); + + fdt.dt = xzalloc(BUFSIZE); + fdt.dt_size = BUFSIZE; + + fdt.strings = xzalloc(BUFSIZE); + fdt.str_size = BUFSIZE; + + memset(fdt.dt, 0, BUFSIZE); + + ofs = sizeof(struct fdt_header); + + header.off_mem_rsvmap = cpu_to_fdt32(ofs); + ofs += sizeof(struct fdt_reserve_entry) * OF_MAX_RESERVE_MAP; + + fdt.dt_nextofs = ofs; + + ret = __of_flatten_dtb(&fdt, node); + if (ret) + goto out_free; + nh = fdt.dt + fdt.dt_nextofs; + nh->tag = cpu_to_fdt32(FDT_END); + fdt.dt_nextofs = dt_next_ofs(fdt.dt_nextofs, sizeof(struct fdt_node_header)); + + header.off_dt_struct = cpu_to_fdt32(ofs); + header.size_dt_struct = cpu_to_fdt32(fdt.dt_nextofs - ofs); + + header.off_dt_strings = cpu_to_fdt32(fdt.dt_nextofs); + header.size_dt_strings = cpu_to_fdt32(fdt.str_nextofs); + + if (fdt.dt_size - fdt.dt_nextofs < fdt.str_nextofs) { + fdt.dt = realloc(fdt.dt, fdt.dt_nextofs + fdt.str_nextofs); + if (!fdt.dt) + goto out_free; + } + + memcpy(fdt.dt + fdt.dt_nextofs, fdt.strings, fdt.str_nextofs); + + header.totalsize = cpu_to_fdt32(fdt.dt_nextofs + fdt.str_nextofs); + + memcpy(fdt.dt, &header, sizeof(header)); + + free(fdt.strings); + + return fdt.dt; + +out_free: + free(fdt.strings); + free(fdt.dt); + + return NULL; +} + +/* + * The last entry is the zeroed sentinel, the one before is + * reserved for the reservemap entry for the dtb itself. + */ +#define OF_MAX_FREE_RESERVE_MAP (OF_MAX_RESERVE_MAP - 2) + +static struct of_reserve_map of_reserve_map; + +int of_add_reserve_entry(uint64_t start, uint64_t end) +{ + int e = of_reserve_map.num_entries; + + if (e >= OF_MAX_FREE_RESERVE_MAP) + return -ENOSPC; + + of_reserve_map.start[e] = start; + of_reserve_map.end[e] = end; + of_reserve_map.num_entries++; + + return 0; +} + +struct of_reserve_map *of_get_reserve_map(void) +{ + return &of_reserve_map; +} + +void of_clean_reserve_map(void) +{ + of_reserve_map.num_entries = 0; +} + +/** + * fdt_add_reserve_map - Add reserve map entries to a devicetree binary + * @__fdt: The devicetree blob + * + * This adds the reservemap entries previously colllected in + * of_add_reserve_entry() to a devicetree binary blob. This also + * adds the devicetree itself to the reserved list, so after calling + * this function the tree should not be relocated anymore. + */ +void fdt_add_reserve_map(void *__fdt) +{ + struct fdt_header *fdt = __fdt; + struct of_reserve_map *res = &of_reserve_map; + struct fdt_reserve_entry *fdt_res = + __fdt + be32_to_cpu(fdt->off_mem_rsvmap); + int i; + + for (i = 0; i < res->num_entries; i++) { + of_write_number(&fdt_res->address, res->start[i], 2); + of_write_number(&fdt_res->size, res->end[i] - res->start[i] + 1, + 2); + fdt_res++; + } + + of_write_number(&fdt_res->address, (unsigned long)__fdt, 2); + of_write_number(&fdt_res->size, be32_to_cpu(fdt->totalsize), 2); + fdt_res++; + + of_write_number(&fdt_res->address, 0, 2); + of_write_number(&fdt_res->size, 0, 2); +} diff --git a/src/fdtdump.c b/src/fdtdump.c new file mode 100644 index 0000000..d438a84 --- /dev/null +++ b/src/fdtdump.c @@ -0,0 +1,76 @@ +#include + +#include +#include
+#include +#include +#include +#include +#include + +void *read_file(const char *filename, size_t *size) +{ + int fd; + struct stat s; + void *buf = NULL; + int ret; + + if (stat(filename, &s)) + return NULL; + + buf = xzalloc(s.st_size + 1); + + fd = open(filename, O_RDONLY); + if (fd < 0) + goto err_out; + + if (read(fd, buf, s.st_size) < s.st_size) + goto err_out1; + + close(fd); + + if (size) + *size = s.st_size; + + return buf; + +err_out1: + close(fd); +err_out: + free(buf); + + return NULL; +} + +int main(int argc, char *argv[]) +{ + void *fdt; + struct device_node *root; + const char *dtbfile = NULL; + + if (argc > 1) + dtbfile = argv[1]; + + if (dtbfile) { + fdt = read_file(dtbfile, NULL); + if (!fdt) { + fprintf(stderr, "Could not read %s: %s\n", dtbfile, strerror(errno)); + exit(1); + } + + root = of_unflatten_dtb(NULL, fdt); + } else { + root = of_read_proc_devicetree(); + } + + if (IS_ERR(root)) { + fprintf(stderr, "Could not unflatten dtb: %s\n", strerror(-PTR_ERR(root))); + exit(1); + } + + printf("/dts-v1/;\n/"); + + of_print_nodes(root, 0); + + exit(0); +} diff --git a/src/libdt.c b/src/libdt.c new file mode 100644 index 0000000..4a3ce1e --- /dev/null +++ b/src/libdt.c @@ -0,0 +1,2185 @@ +/* + * of.c - basic devicetree functions + * + * Copyright (c) 2012 Sascha Hauer , Pengutronix + * + * based on Linux devicetree support + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int is_printable_string(const void *data, int len) +{ + const char *s = data; + + /* zero length is not */ + if (len == 0) + return 0; + + /* must terminate with zero */ + if (s[len - 1] != '\0') + return 0; + + /* printable or a null byte (concatenated strings) */ + while (((*s == '\0') || isprint(*s)) && (len > 0)) { + /* + * If we see a null, there are three possibilities: + * 1) If len == 1, it is the end of the string, printable + * 2) Next character also a null, not printable. + * 3) Next character not a null, continue to check. + */ + if (s[0] == '\0') { + if (len == 1) + return 1; + if (s[1] == '\0') + return 0; + } + s++; + len--; + } + + /* Not the null termination, or not done yet: not printable */ + if (*s != '\0' || (len != 0)) + return 0; + + return 1; +} + +/* + * Print the property in the best format, a heuristic guess. Print as + * a string, concatenated strings, a byte, word, double word, or (if all + * else fails) it is printed as a stream of bytes. + */ +void of_print_property(const void *data, int len) +{ + int j; + + /* no data, don't print */ + if (len == 0) + return; + + /* + * It is a string, but it may have multiple strings (embedded '\0's). + */ + if (is_printable_string(data, len)) { + printf("\""); + j = 0; + while (j < len) { + if (j > 0) + printf("\", \""); + printf(data); + j += strlen(data) + 1; + data += strlen(data) + 1; + } + printf("\""); + return; + } + + if ((len % 4) == 0) { + const uint32_t *p; + + printf("<"); + for (j = 0, p = data; j < len/4; j ++) + printf("0x%x%s", __be32_to_cpu(p[j]), j < (len/4 - 1) ? " " : ""); + printf(">"); + } else { /* anything else... hexdump */ + const uint8_t *s; + + printf("["); + for (j = 0, s = data; j < len; j++) + printf("%02x%s", s[j], j < len - 1 ? " " : ""); + printf("]"); + } +} + +/* + * Iterate over all nodes of a tree. As a devicetree does not + * have a dedicated list head, the start node (usually the root + * node) will not be iterated over. + */ +static inline struct device_node *of_next_node(struct device_node *node) +{ + struct device_node *next; + + next = list_first_entry(&node->list, struct device_node, list); + + return next->parent ? next : NULL; +} + +#define of_tree_for_each_node_from(node, from) \ + for (node = of_next_node(from); node; node = of_next_node(node)) + +/** + * struct alias_prop - Alias property in 'aliases' node + * @link: List node to link the structure in aliases_lookup list + * @alias: Alias property name + * @np: Pointer to device_node that the alias stands for + * @id: Index value from end of alias name + * @stem: Alias string without the index + * + * The structure represents one alias property of 'aliases' node as + * an entry in aliases_lookup list. + */ +struct alias_prop { + struct list_head link; + const char *alias; + struct device_node *np; + int id; + char stem[0]; +}; + +static LIST_HEAD(aliases_lookup); + +struct device_node *root_node; + +struct device_node *of_aliases; + +#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 +#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 + +int of_n_addr_cells(struct device_node *np) +{ + const __be32 *ip; + + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#address-cells", NULL); + if (ip) + return __be32_to_cpup(ip); + } while (np->parent); + /* No #address-cells property for the root node */ + return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; +} + +int of_n_size_cells(struct device_node *np) +{ + const __be32 *ip; + + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#size-cells", NULL); + if (ip) + return __be32_to_cpup(ip); + } while (np->parent); + /* No #size-cells property for the root node */ + return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; +} + +struct property *of_find_property(const struct device_node *np, + const char *name, int *lenp) +{ + struct property *pp; + + if (!np) + return NULL; + + list_for_each_entry(pp, &np->properties, list) + if (of_prop_cmp(pp->name, name) == 0) { + if (lenp) + *lenp = pp->length; + return pp; + } + + return NULL; +} + +static void of_alias_add(struct alias_prop *ap, struct device_node *np, + int id, const char *stem, int stem_len) +{ + ap->np = np; + ap->id = id; + strncpy(ap->stem, stem, stem_len); + ap->stem[stem_len] = 0; + list_add_tail(&ap->link, &aliases_lookup); + pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n", + ap->alias, ap->stem, ap->id, np->full_name); +} + +/** + * of_alias_scan - Scan all properties of 'aliases' node + * + * The function scans all the properties of 'aliases' node and populates + * the global lookup table with the properties. It returns the + * number of alias_prop found, or error code in error case. + */ +void of_alias_scan(void) +{ + struct property *pp; + struct alias_prop *app, *tmp; + + list_for_each_entry_safe(app, tmp, &aliases_lookup, link) + free(app); + + INIT_LIST_HEAD(&aliases_lookup); + + if (!root_node) + return; + + of_aliases = of_find_node_by_path("/aliases"); + if (!of_aliases) + return; + + list_for_each_entry(pp, &of_aliases->properties, list) { + const char *start = pp->name; + const char *end = start + strlen(start); + struct device_node *np; + struct alias_prop *ap; + int id, len; + + /* Skip those we do not want to proceed */ + if (!of_prop_cmp(pp->name, "name") || + !of_prop_cmp(pp->name, "phandle") || + !of_prop_cmp(pp->name, "linux,phandle")) + continue; + + np = of_find_node_by_path(pp->value); + if (!np) + continue; + + /* walk the alias backwards to extract the id and work out + * the 'stem' string */ + while (isdigit(*(end-1)) && end > start) + end--; + len = end - start; + + id = strtol(end, 0, 10); + if (id < 0) + continue; + + /* Allocate an alias_prop with enough space for the stem */ + ap = xzalloc(sizeof(*ap) + len + 1); + if (!ap) + continue; + ap->alias = start; + of_alias_add(ap, np, id, start, len); + } +} + +/** + * of_alias_get_id - Get alias id for the given device_node + * @np: Pointer to the given device_node + * @stem: Alias stem of the given device_node + * + * The function travels the lookup table to get alias id for the given + * device_node and alias stem. It returns the alias id if find it. + */ +int of_alias_get_id(struct device_node *np, const char *stem) +{ + struct alias_prop *app; + int id = -ENODEV; + + list_for_each_entry(app, &aliases_lookup, link) { + if (of_node_cmp(app->stem, stem) != 0) + continue; + + if (np == app->np) { + id = app->id; + break; + } + } + + return id; +} + +const char *of_alias_get(struct device_node *np) +{ + struct property *pp; + + list_for_each_entry(pp, &of_aliases->properties, list) { + if (!of_node_cmp(np->full_name, pp->value)) + return pp->name; + } + + return NULL; +} + +/* + * of_find_node_by_alias - Find a node given an alias name + * @root: the root node of the tree. If NULL, use internal tree + * @alias: the alias name to find + */ +struct device_node *of_find_node_by_alias(struct device_node *root, const char *alias) +{ + struct device_node *aliasnp; + int ret; + const char *path; + + if (!root) + root = root_node; + + aliasnp = of_find_node_by_path_from(root, "/aliases"); + if (!aliasnp) + return NULL; + + ret = of_property_read_string(aliasnp, alias, &path); + if (ret) + return NULL; + + return of_find_node_by_path_from(root, path); +} + +/* + * of_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + */ +struct device_node *of_find_node_by_phandle(phandle phandle) +{ + struct device_node *node; + + of_tree_for_each_node_from(node, root_node) + if (node->phandle == phandle) + return node; + + return NULL; +} + +/* + * of_get_tree_max_phandle - Find the maximum phandle of a tree + * @root: root node of the tree to search in. If NULL use the + * internal tree. + */ +phandle of_get_tree_max_phandle(struct device_node *root) +{ + struct device_node *n; + phandle max; + + if (!root) + root = root_node; + + if (!root) + return 0; + + max = root->phandle; + + of_tree_for_each_node_from(n, root) { + if (n->phandle > max) + max = n->phandle; + } + + return max; +} + +/* + * of_node_create_phandle - create a phandle for a node + * @node: The node to create a phandle in + * + * returns the new phandle or the existing phandle if the node + * already has a phandle. + */ +phandle of_node_create_phandle(struct device_node *node) +{ + phandle p; + struct device_node *root; + + if (node->phandle) + return node->phandle; + + root = of_find_root_node(node); + + p = of_get_tree_max_phandle(root) + 1; + + node->phandle = p; + + p = __cpu_to_be32(p); + + of_set_property(node, "phandle", &p, sizeof(p), 1); + + return node->phandle; +} + +/* + * Find a property with a given name for a given node + * and return the value. + */ +const void *of_get_property(const struct device_node *np, const char *name, + int *lenp) +{ + struct property *pp = of_find_property(np, name, lenp); + + return pp ? pp->value : NULL; +} + +/** Checks if the given "compat" string matches one of the strings in + * the device's "compatible" property + */ +int of_device_is_compatible(const struct device_node *device, + const char *compat) +{ + const char *cp; + int cplen, l; + + cp = of_get_property(device, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + +/** + * of_find_node_by_name - Find a node by its "name" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. + * @name: The name string to match against + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_node_by_name(struct device_node *from, + const char *name) +{ + struct device_node *np; + + if (!from) + from = root_node; + + of_tree_for_each_node_from(np, from) + if (np->name && !of_node_cmp(np->name, name)) + return np; + + return NULL; +} + +/** + * of_find_node_by_type - Find a node by its "device_type" property + * @from: The node to start searching from, or NULL to start searching + * the entire device tree. The node you pass will not be + * searched, only the next one will; typically, you pass + * what the previous call returned. + * @type: The type string to match against. + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_node_by_type(struct device_node *from, + const char *type) +{ + struct device_node *np; + const char *device_type; + int ret; + + if (!from) + from = root_node; + + of_tree_for_each_node_from(np, from) { + ret = of_property_read_string(np, "device_type", &device_type); + if (!ret && !of_node_cmp(device_type, type)) + return np; + } + return NULL; +} + +/** + * of_find_compatible_node - Find a node based on type and one of the + * tokens in its "compatible" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. + * @type: The type string to match "device_type" or NULL to ignore + * (currently always ignored in barebox) + * @compatible: The string to match to one of the tokens in the device + * "compatible" list. + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_compatible_node(struct device_node *from, + const char *type, const char *compatible) +{ + struct device_node *np; + + if (!from) + from = root_node; + + of_tree_for_each_node_from(np, from) + if (of_device_is_compatible(np, compatible)) + return np; + + return NULL; +} + +/** + * of_find_node_with_property - Find a node which has a property with + * the given name. + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. + * @prop_name: The name of the property to look for. + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_node_with_property(struct device_node *from, + const char *prop_name) +{ + struct device_node *np; + + if (!from) + from = root_node; + + of_tree_for_each_node_from(np, from) { + struct property *pp = of_find_property(np, prop_name, NULL); + if (pp) + return np; + } + + return NULL; +} + +/** + * of_match_node - Tell if an device_node has a matching of_match structure + * @matches: array of of device match structures to search in + * @node: the of device structure to match against + * + * Low level utility function used by device matching. + */ +const struct of_device_id *of_match_node(const struct of_device_id *matches, + const struct device_node *node) +{ + if (!matches || !node) + return NULL; + + while (matches->compatible) { + if (of_device_is_compatible(node, matches->compatible) == 1) + return matches; + matches++; + } + + return NULL; +} + +/** + * of_find_matching_node_and_match - Find a node based on an of_device_id + * match table. + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. + * @matches: array of of device match structures to search in + * @match Updated to point at the matches entry which matched + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_matching_node_and_match(struct device_node *from, + const struct of_device_id *matches, + const struct of_device_id **match) +{ + struct device_node *np; + + if (match) + *match = NULL; + + if (!from) + from = root_node; + + of_tree_for_each_node_from(np, from) { + const struct of_device_id *m = of_match_node(matches, np); + if (m) { + if (match) + *match = m; + return np; + } + } + + return NULL; +} + +/** + * of_find_property_value_of_size + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @len: requested length of property value + * + * Search for a property in a device node and valid the requested size. + * Returns the property value on success, -EINVAL if the property does not + * exist, -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + */ +static void *of_find_property_value_of_size(const struct device_node *np, + const char *propname, uint32_t len) +{ + struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return ERR_PTR(-EINVAL); + if (!prop->value) + return ERR_PTR(-ENODATA); + if (len > prop->length) + return ERR_PTR(-EOVERFLOW); + + return prop->value; +} + +/** + * of_property_read_u32_index - Find and read a uint32_t from a multi-value property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the uint32_t in the list of values + * @out_value: pointer to return value, modified only if no error. + * + * Search for a property in a device node and read nth 32-bit value from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid uint32_t value can be decoded. + */ +int of_property_read_u32_index(const struct device_node *np, + const char *propname, + uint32_t index, uint32_t *out_value) +{ + const uint32_t *val = of_find_property_value_of_size(np, propname, + ((index + 1) * sizeof(*out_value))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + *out_value = __be32_to_cpup(((__be32 *)val) + index); + return 0; +} + +/** + * of_property_read_u8_array - Find and read an array of uint8_t from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 8-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * dts entry of array should be like: + * property = /bits/ 8 <0x50 0x60 0x70>; + * + * The out_value is modified only if a valid uint8_t value can be decoded. + */ +int of_property_read_u8_array(const struct device_node *np, + const char *propname, uint8_t *out_values, size_t sz) +{ + const uint8_t *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + while (sz--) + *out_values++ = *val++; + return 0; +} + +/** + * of_property_read_u16_array - Find and read an array of uint16_t from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 16-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * dts entry of array should be like: + * property = /bits/ 16 <0x5000 0x6000 0x7000>; + * + * The out_value is modified only if a valid uint16_t value can be decoded. + */ +int of_property_read_u16_array(const struct device_node *np, + const char *propname, uint16_t *out_values, size_t sz) +{ + const __be16 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + while (sz--) + *out_values++ = __be16_to_cpup(val++); + return 0; +} + +/** + * of_property_read_u32_array - Find and read an array of 32 bit integers + * from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 32-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid uint32_t value can be decoded. + */ +int of_property_read_u32_array(const struct device_node *np, + const char *propname, uint32_t *out_values, + size_t sz) +{ + const __be32 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + while (sz--) + *out_values++ = __be32_to_cpup(val++); + return 0; +} + +/** + * of_property_read_u64 - Find and read a 64 bit integer from a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * + * Search for a property in a device node and read a 64-bit value from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * The out_value is modified only if a valid uint64_t value can be decoded. + */ +int of_property_read_u64(const struct device_node *np, const char *propname, + uint64_t *out_value) +{ + const __be32 *val = of_find_property_value_of_size(np, propname, + sizeof(*out_value)); + + if (IS_ERR(val)) + return PTR_ERR(val); + + *out_value = of_read_number(val, 2); + return 0; +} + +/** + * of_property_read_string - Find and read a string from a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * + * Search for a property in a device tree node and retrieve a null + * terminated string value (pointer to data, not a copy). Returns 0 on + * success, -EINVAL if the property does not exist, -ENODATA if property + * does not have a value, and -EILSEQ if the string is not null-terminated + * within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +int of_property_read_string(struct device_node *np, const char *propname, + const char **out_string) +{ + struct property *prop = of_find_property(np, propname, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + *out_string = prop->value; + return 0; +} + +/** + * of_property_read_string_index - Find and read a string from a multiple + * strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @index: index of the string in the list of strings + * @out_string: pointer to null terminated return string, modified only if + * return value is 0. + * + * Search for a property in a device tree node and retrieve a null + * terminated string value (pointer to data, not a copy) in the list of strings + * contained in that property. + * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if + * property does not have a value, and -EILSEQ if the string is not + * null-terminated within the length of the property data. + * + * The out_string pointer is modified only if a valid string can be decoded. + */ +int of_property_read_string_index(struct device_node *np, const char *propname, + int index, const char **output) +{ + struct property *prop = of_find_property(np, propname, NULL); + int i = 0; + size_t l = 0, total = 0; + const char *p; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + + p = prop->value; + + for (i = 0; total < prop->length; total += l, p += l) { + l = strlen(p) + 1; + if (i++ == index) { + *output = p; + return 0; + } + } + return -ENODATA; +} + +/** + * of_property_match_string() - Find string in a list and return index + * @np: pointer to node containing string list property + * @propname: string list property name + * @string: pointer to string to search for in string list + * + * This function searches a string list property and returns the index + * of a specific string value. + */ +int of_property_match_string(struct device_node *np, const char *propname, + const char *string) +{ + struct property *prop = of_find_property(np, propname, NULL); + size_t l; + int i; + const char *p, *end; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + p = prop->value; + end = p + prop->length; + + for (i = 0; p < end; i++, p += l) { + l = strlen(p) + 1; + if (p + l > end) + return -EILSEQ; + pr_debug("comparing %s with %s\n", string, p); + if (strcmp(string, p) == 0) + return i; /* Found it; return index */ + } + return -ENODATA; +} + +/** + * of_property_count_strings - Find and return the number of strings from a + * multiple strings property. + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * + * Search for a property in a device tree node and retrieve the number of null + * terminated string contain in it. Returns the number of strings on + * success, -EINVAL if the property does not exist, -ENODATA if property + * does not have a value, and -EILSEQ if the string is not null-terminated + * within the length of the property data. + */ +int of_property_count_strings(struct device_node *np, const char *propname) +{ + struct property *prop = of_find_property(np, propname, NULL); + int i = 0; + size_t l = 0, total = 0; + const char *p; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if (strnlen(prop->value, prop->length) >= prop->length) + return -EILSEQ; + + p = prop->value; + + for (i = 0; total < prop->length; total += l, p += l, i++) + l = strlen(p) + 1; + + return i; +} + +const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, + uint32_t *pu) +{ + const void *curv = cur; + + if (!prop) + return NULL; + + if (!cur) { + curv = prop->value; + goto out_val; + } + + curv += sizeof(*cur); + if (curv >= prop->value + prop->length) + return NULL; + +out_val: + *pu = __be32_to_cpup(curv); + return curv; +} + +const char *of_prop_next_string(struct property *prop, const char *cur) +{ + const void *curv = cur; + + if (!prop) + return NULL; + + if (!cur) + return prop->value; + + curv += strlen(cur) + 1; + if (curv >= prop->value + prop->length) + return NULL; + + return curv; +} + +/** + * of_property_write_bool - Create/Delete empty (bool) property. + * + * @np: device node from which the property is to be set. + * @propname: name of the property to be set. + * + * Search for a property in a device node and create or delete the property. + * If the property already exists and write value is false, the property is + * deleted. If write value is true and the property does not exist, it is + * created. Returns 0 on success, -ENOMEM if the property or array + * of elements cannot be created. + */ +int of_property_write_bool(struct device_node *np, const char *propname, + const bool value) +{ + struct property *prop = of_find_property(np, propname, NULL); + + if (!value) { + if (prop) + of_delete_property(prop); + return 0; + } + + if (!prop) + prop = of_new_property(np, propname, NULL, 0); + if (!prop) + return -ENOMEM; + + return 0; +} + +/** + * of_property_write_u8_array - Write an array of uint8_t to a property. If + * the property does not exist, it will be created and appended to the given + * device node. + * + * @np: device node to which the property value is to be written. + * @propname: name of the property to be written. + * @values: pointer to array elements to write. + * @sz: number of array elements to write. + * + * Search for a property in a device node and write 8-bit value(s) to + * it. If the property does not exist, it will be created and appended to + * the device node. Returns 0 on success, -ENOMEM if the property or array + * of elements cannot be created. + */ +int of_property_write_u8_array(struct device_node *np, + const char *propname, const uint8_t *values, + size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + uint8_t *val; + + if (prop) + of_delete_property(prop); + + prop = of_new_property(np, propname, NULL, sizeof(*val) * sz); + if (!prop) + return -ENOMEM; + + val = prop->value; + while (sz--) + *val++ = *values++; + + return 0; +} + +/** + * of_property_write_u16_array - Write an array of uint16_t to a property. If + * the property does not exist, it will be created and appended to the given + * device node. + * + * @np: device node to which the property value is to be written. + * @propname: name of the property to be written. + * @values: pointer to array elements to write. + * @sz: number of array elements to write. + * + * Search for a property in a device node and write 16-bit value(s) to + * it. If the property does not exist, it will be created and appended to + * the device node. Returns 0 on success, -ENOMEM if the property or array + * of elements cannot be created. + */ +int of_property_write_u16_array(struct device_node *np, + const char *propname, const uint16_t *values, + size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + __be16 *val; + + if (prop) + of_delete_property(prop); + + prop = of_new_property(np, propname, NULL, sizeof(*val) * sz); + if (!prop) + return -ENOMEM; + + val = prop->value; + while (sz--) + *val++ = __cpu_to_be16(*values++); + + return 0; +} + +/** + * of_property_write_u32_array - Write an array of uint32_t to a property. If + * the property does not exist, it will be created and appended to the given + * device node. + * + * @np: device node to which the property value is to be written. + * @propname: name of the property to be written. + * @values: pointer to array elements to write. + * @sz: number of array elements to write. + * + * Search for a property in a device node and write 32-bit value(s) to + * it. If the property does not exist, it will be created and appended to + * the device node. Returns 0 on success, -ENOMEM if the property or array + * of elements cannot be created. + */ +int of_property_write_u32_array(struct device_node *np, + const char *propname, const uint32_t *values, + size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + __be32 *val; + + if (prop) + of_delete_property(prop); + + prop = of_new_property(np, propname, NULL, sizeof(*val) * sz); + if (!prop) + return -ENOMEM; + + val = prop->value; + while (sz--) + *val++ = __cpu_to_be32(*values++); + + return 0; +} + +/** + * of_property_write_u64_array - Write an array of uint64_t to a property. If + * the property does not exist, it will be created and appended to the given + * device node. + * + * @np: device node to which the property value is to be written. + * @propname: name of the property to be written. + * @values: pointer to array elements to write. + * @sz: number of array elements to write. + * + * Search for a property in a device node and write 64-bit value(s) to + * it. If the property does not exist, it will be created and appended to + * the device node. Returns 0 on success, -ENOMEM if the property or array + * of elements cannot be created. + */ +int of_property_write_u64_array(struct device_node *np, + const char *propname, const uint64_t *values, + size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + __be32 *val; + + if (prop) + of_delete_property(prop); + + prop = of_new_property(np, propname, NULL, 2 * sizeof(*val) * sz); + if (!prop) + return -ENOMEM; + + val = prop->value; + while (sz--) { + of_write_number(val, *values++, 2); + val += 2; + } + + return 0; +} + +/** + * of_parse_phandle - Resolve a phandle property to a device_node pointer + * @np: Pointer to device node holding phandle property + * @phandle_name: Name of property holding a phandle value + * @index: For properties holding a table of phandles, this is the index into + * the table + * + * Returns the device_node pointer found or NULL. + */ +struct device_node *of_parse_phandle(const struct device_node *np, + const char *phandle_name, int index) +{ + const __be32 *phandle; + int size; + + phandle = of_get_property(np, phandle_name, &size); + if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) + return NULL; + + return of_find_node_by_phandle(__be32_to_cpup(phandle + index)); +} + +/** + * of_parse_phandle_with_args() - Find a node pointed by phandle in a list + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate + * errno value. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * node3 { + * list = <&phandle1 1 2 &phandle2 3>; + * } + * + * To get a device_node of the `node2' node you may call this: + * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); + */ +static int __of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, + const char *cells_name, int index, + struct of_phandle_args *out_args) +{ + const __be32 *list, *list_end; + int rc = 0, size, cur_index = 0; + uint32_t count = 0; + struct device_node *node = NULL; + phandle phandle; + + /* Retrieve the phandle list property */ + list = of_get_property(np, list_name, &size); + if (!list) + return -ENOENT; + list_end = list + size / sizeof(*list); + + /* Loop over the phandles until all the requested entry is found */ + while (list < list_end) { + rc = -EINVAL; + count = 0; + + /* + * If phandle is 0, then it is an empty entry with no + * arguments. Skip forward to the next entry. + */ + phandle = __be32_to_cpup(list++); + if (phandle) { + /* + * Find the provider node and parse the #*-cells + * property to determine the argument length + */ + node = of_find_node_by_phandle(phandle); + if (!node) { + pr_err("%s: could not find phandle\n", + np->full_name); + goto err; + } + if (of_property_read_u32(node, cells_name, &count)) { + pr_err("%s: could not get %s for %s\n", + np->full_name, cells_name, + node->full_name); + goto err; + } + + /* + * Make sure that the arguments actually fit in the + * remaining property data length + */ + if (list + count > list_end) { + pr_err("%s: arguments longer than property\n", + np->full_name); + goto err; + } + } + + /* + * All of the error cases above bail out of the loop, so at + * this point, the parsing is successful. If the requested + * index matches, then fill the out_args structure and return, + * or return -ENOENT for an empty entry. + */ + rc = -ENOENT; + if (cur_index == index) { + if (!phandle) + goto err; + + if (out_args) { + int i; + if (count > MAX_PHANDLE_ARGS) + count = MAX_PHANDLE_ARGS; + out_args->np = node; + out_args->args_count = count; + for (i = 0; i < count; i++) + out_args->args[i] = + __be32_to_cpup(list++); + } + + /* Found it! return success */ + return 0; + } + + node = NULL; + list += count; + cur_index++; + } + + /* + * Unlock node before returning result; will be one of: + * -ENOENT : index is for empty phandle + * -EINVAL : parsing error on data + * [1..n] : Number of phandle (count mode; when index = -1) + */ + rc = index < 0 ? cur_index : -ENOENT; + err: + return rc; +} + +int of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name, int index, + struct of_phandle_args *out_args) +{ + if (index < 0) + return -EINVAL; + return __of_parse_phandle_with_args(np, list_name, cells_name, + index, out_args); +} + +/** + * of_count_phandle_with_args() - Find the number of phandles references in a property + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @cells_name: property name that specifies phandles' arguments count + * + * Returns the number of phandle + argument tuples within a property. It + * is a typical pattern to encode a list of phandle and variable + * arguments into a single property. The number of arguments is encoded + * by a property in the phandle-target node. For example, a gpios + * property would contain a list of GPIO specifies consisting of a + * phandle and 1 or more arguments. The number of arguments are + * determined by the #gpio-cells property in the node pointed to by the + * phandle. + */ +int of_count_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name) +{ + return __of_parse_phandle_with_args(np, list_name, cells_name, + -1, NULL); +} + +/** + * of_machine_is_compatible - Test root of device tree for a given compatible value + * @compat: compatible string to look for in root node's compatible property. + * + * Returns true if the root node has the given value in its + * compatible property. + */ +int of_machine_is_compatible(const char *compat) +{ + if (!root_node) + return 0; + + return of_device_is_compatible(root_node, compat); +} + +/** + * of_find_node_by_path_from - Find a node matching a full OF path + * relative to a given root node. + * @path: The full path to match + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_node_by_path_from(struct device_node *from, + const char *path) +{ + char *slash, *p, *freep; + + if (!from) + from = root_node; + + if (!from || !path || *path != '/') + return NULL; + + path++; + + freep = p = strdup(path); + + while (1) { + if (!*p) + goto out; + + slash = strchr(p, '/'); + if (slash) + *slash = 0; + + from = of_get_child_by_name(from, p); + if (!from) + goto out; + + if (!slash) + goto out; + + p = slash + 1; + } +out: + free(freep); + + return from; +} + +/** + * of_find_node_by_path - Find a node matching a full OF path + * @path: The full path to match + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_node_by_path(const char *path) +{ + return of_find_node_by_path_from(root_node, path); +} + +/** + * of_find_node_by_path_or_alias - Find a node matching a full OF path + * or an alias + * @root: The root node. If NULL the internal tree is used + * @str: the full path or alias + * + * Returns a pointer to the node found or NULL. + */ +struct device_node *of_find_node_by_path_or_alias(struct device_node *root, + const char *str) +{ + if (*str == '/') + return of_find_node_by_path_from(root, str); + else + return of_find_node_by_alias(root, str); + +} + +/** + * of_modalias_node - Lookup appropriate modalias for a device node + * @node: pointer to a device tree node + * @modalias: Pointer to buffer that modalias value will be copied into + * @len: Length of modalias value + * + * Based on the value of the compatible property, this routine will attempt + * to choose an appropriate modalias value for a particular device tree node. + * It does this by stripping the manufacturer prefix (as delimited by a ',') + * from the first entry in the compatible list property. + * + * This routine returns 0 on success, <0 on failure. + */ +int of_modalias_node(struct device_node *node, char *modalias, int len) +{ + const char *compatible, *p; + int cplen; + + compatible = of_get_property(node, "compatible", &cplen); + if (!compatible || strlen(compatible) > cplen) + return -ENODEV; + p = strchr(compatible, ','); + strlcpy(modalias, p ? p + 1 : compatible, len); + return 0; +} + +struct device_node *of_get_root_node(void) +{ + return root_node; +} + +int of_set_root_node(struct device_node *node) +{ + if (node && root_node) + return -EBUSY; + + root_node = node; + + of_alias_scan(); + + return 0; +} + +/** + * of_device_is_available - check if a device is available for use + * + * @device: Node to check for availability + * + * Returns 1 if the status property is absent or set to "okay" or "ok", + * 0 otherwise + */ +int of_device_is_available(const struct device_node *device) +{ + const char *status; + int statlen; + + status = of_get_property(device, "status", &statlen); + if (status == NULL) + return 1; + + if (statlen > 0) { + if (!strcmp(status, "okay") || !strcmp(status, "ok")) + return 1; + } + + return 0; +} + +/** + * of_get_parent - Get a node's parent if any + * @node: Node to get parent + * + * Returns a pointer to the parent node or NULL if already at root. + */ +struct device_node *of_get_parent(const struct device_node *node) +{ + return (!node) ? NULL : node->parent; +} + +/** + * of_get_next_available_child - Find the next available child node + * @node: parent node + * @prev: previous child of the parent node, or NULL to get first + * + * This function is like of_get_next_child(), except that it + * automatically skips any disabled nodes (i.e. status = "disabled"). + */ +struct device_node *of_get_next_available_child(const struct device_node *node, + struct device_node *prev) +{ + prev = list_prepare_entry(prev, &node->children, parent_list); + list_for_each_entry_continue(prev, &node->children, parent_list) + if (of_device_is_available(prev)) + return prev; + return NULL; +} + +/** + * of_get_child_count - Count child nodes of given parent node + * @parent: parent node + * + * Returns the number of child nodes or -EINVAL on NULL parent node. + */ +int of_get_child_count(const struct device_node *parent) +{ + struct device_node *child; + int num = 0; + + if (!parent) + return -EINVAL; + + for_each_child_of_node(parent, child) + num++; + + return num; +} + +/** + * of_get_available_child_count - Count available child nodes of given + * parent node + * @parent: parent node + * + * Returns the number of available child nodes or -EINVAL on NULL parent + * node. + */ +int of_get_available_child_count(const struct device_node *parent) +{ + struct device_node *child; + int num = 0; + + if (!parent) + return -EINVAL; + + for_each_child_of_node(parent, child) + if (of_device_is_available(child)) + num++; + + return num; +} + +/** + * of_get_child_by_name - Find the child node by name for a given parent + * @node: parent node + * @name: child name to look for. + * + * This function looks for child node for given matching name + * + * Returns a node pointer if found or NULL. + */ +struct device_node *of_get_child_by_name(const struct device_node *node, + const char *name) +{ + struct device_node *child; + + for_each_child_of_node(node, child) + if (child->name && (of_node_cmp(child->name, name) == 0)) + return child; + + return NULL; +} + +void of_print_nodes(struct device_node *node, int indent) +{ + struct device_node *n; + struct property *p; + int i; + + if (!node) + return; + + for (i = 0; i < indent; i++) + printf("\t"); + + printf("%s%s\n", node->name, node->name ? " {" : "{"); + + list_for_each_entry(p, &node->properties, list) { + for (i = 0; i < indent + 1; i++) + printf("\t"); + printf("%s", p->name); + if (p->length) { + printf(" = "); + of_print_property(p->value, p->length); + } + printf(";\n"); + } + + list_for_each_entry(n, &node->children, parent_list) { + of_print_nodes(n, indent + 1); + } + + for (i = 0; i < indent; i++) + printf("\t"); + printf("};\n"); +} + +struct device_node *of_new_node(struct device_node *parent, const char *name) +{ + struct device_node *node; + int ret; + + node = xzalloc(sizeof(*node)); + node->parent = parent; + if (parent) + list_add_tail(&node->parent_list, &parent->children); + + INIT_LIST_HEAD(&node->children); + INIT_LIST_HEAD(&node->properties); + + if (parent) { + node->name = strdup(name); + ret = asprintf(&node->full_name, "%s/%s", node->parent->full_name, name); + if (ret < 0) + return NULL; + list_add(&node->list, &parent->list); + } else { + node->name = strdup(""); + node->full_name = strdup(""); + INIT_LIST_HEAD(&node->list); + } + + return node; +} + +struct property *of_new_property(struct device_node *node, const char *name, + const void *data, int len) +{ + struct property *prop; + + prop = xzalloc(sizeof(*prop)); + prop->name = strdup(name); + if (!prop->name) { + free(prop); + return NULL; + } + + prop->length = len; + prop->value = xzalloc(len); + + if (data) + memcpy(prop->value, data, len); + + list_add_tail(&prop->list, &node->properties); + + return prop; +} + +void of_delete_property(struct property *pp) +{ + if (!pp) + return; + + list_del(&pp->list); + + free(pp->name); + free(pp->value); + free(pp); +} + +/** + * of_set_property - create a property for a given node + * @node - the node + * @name - the name of the property + * @val - the value for the property + * @len - the length of the properties value + * @create - if true, the property is created if not existing already + */ +int of_set_property(struct device_node *np, const char *name, const void *val, int len, + int create) +{ + struct property *pp = of_find_property(np, name, NULL); + + if (!np) + return -ENOENT; + + if (!pp && !create) + return -ENOENT; + + of_delete_property(pp); + + pp = of_new_property(np, name, val, len); + if (!pp) + return -ENOMEM; + + return 0; +} + +struct device_node *of_chosen; +const char *of_model; + +const char *of_get_model(void) +{ + return of_model; +} + +const struct of_device_id of_default_bus_match_table[] = { + { + .compatible = "simple-bus", + }, { + /* sentinel */ + } +}; + +/** + * of_create_node - create a new node including its parents + * @path - the nodepath to create + */ +struct device_node *of_create_node(struct device_node *root, const char *path) +{ + char *slash, *p, *freep; + struct device_node *tmp, *dn = root; + + if (*path != '/') + return NULL; + + path++; + + p = freep = strdup(path); + + while (1) { + if (!*p) + goto out; + + slash = strchr(p, '/'); + if (slash) + *slash = 0; + + tmp = of_get_child_by_name(dn, p); + if (tmp) + dn = tmp; + else + dn = of_new_node(dn, p); + + if (!dn) + goto out; + + if (!slash) + goto out; + + p = slash + 1; + } +out: + free(freep); + + return dn; +} + +void of_delete_node(struct device_node *node) +{ + struct device_node *n, *nt; + struct property *p, *pt; + + if (!node) + return; + + list_for_each_entry_safe(p, pt, &node->properties, list) + of_delete_property(p); + + list_for_each_entry_safe(n, nt, &node->children, parent_list) + of_delete_node(n); + + if (node->parent) { + list_del(&node->parent_list); + list_del(&node->list); + } + + free(node->name); + free(node->full_name); + free(node); + + if (node == root_node) + of_set_root_node(NULL); +} + +/** + * of_device_enable - enable a devicenode device + * @node - the node to enable + * + * This deletes the status property of a devicenode effectively + * enabling the device. + */ +int of_device_enable(struct device_node *node) +{ + struct property *pp; + + pp = of_find_property(node, "status", NULL); + if (!pp) + return 0; + + of_delete_property(pp); + + return 0; +} + +/** + * of_device_enable_path - enable a devicenode + * @path - the nodepath to enable + * + * wrapper around of_device_enable taking the nodepath as argument + */ +int of_device_enable_path(const char *path) +{ + struct device_node *node; + + node = of_find_node_by_path(path); + if (!node) + return -ENODEV; + + return of_device_enable(node); +} + +/** + * of_device_enable - disable a devicenode device + * @node - the node to disable + * + * This sets the status of a devicenode to "disabled" + */ +int of_device_disable(struct device_node *node) +{ + return of_set_property(node, "status", "disabled", sizeof("disabled"), 1); +} + +/** + * of_device_disable_path - disable a devicenode + * @path - the nodepath to disable + * + * wrapper around of_device_disable taking the nodepath as argument + */ +int of_device_disable_path(const char *path) +{ + struct device_node *node; + + node = of_find_node_by_path(path); + if (!node) + return -ENODEV; + + return of_device_disable(node); +} + +int scan_proc_dir(struct device_node *node, const char *path) +{ + DIR *dir; + struct dirent *dirent; + struct stat s; + int ret; + void *buf; + + dir = opendir(path); + if (!dir) + return -errno; + + while (1) { + char *cur; + + dirent = readdir(dir); + if (!dirent) + break; + + if (dirent->d_name[0] == '.') + continue; + + ret = asprintf(&cur, "%s/%s", path, dirent->d_name); + if (ret < 0) + return -ENOMEM; + + ret = stat(cur, &s); + if (ret) + return -errno; + + if (S_ISREG(s.st_mode)) { + int fd; + + fd = open(cur, O_RDONLY); + if (fd < 0) + return -errno; + + buf = xzalloc(s.st_size); + ret = read(fd, buf, s.st_size); + if (ret < 0) + return -errno; + close(fd); + + of_new_property(node, dirent->d_name, buf, s.st_size); + } + + if (S_ISDIR(s.st_mode)) { + struct device_node *new; + new = of_new_node(node, dirent->d_name); + scan_proc_dir(new, cur); + } + + free(cur); + } + + closedir(dir); + + return 0; +} + +struct device_node *of_read_proc_devicetree(void) +{ + struct device_node *root; + int ret; + + root = of_new_node(NULL, NULL); + + ret = scan_proc_dir(root, "/sys/firmware/devicetree/base"); + if (!ret) + return root; + + ret = scan_proc_dir(root, "/proc/device-tree"); + if (!ret) + return root; + + of_delete_node(root); + return ERR_PTR(ret); +} + +struct udev_device *of_find_device_by_node_path(const char *of_full_path) +{ + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *dev; + + udev = udev_new(); + if (!udev) { + fprintf(stderr, "Can't create udev\n"); + return NULL; + } + + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_property(enumerate, "OF_FULLNAME", of_full_path); + udev_enumerate_scan_devices(enumerate); + devices = udev_enumerate_get_list_entry(enumerate); + + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path; + + /* + * Get the filename of the /sys entry for the device + * and create a udev_device object (dev) representing it + */ + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + + goto out; + } + + dev = NULL; +out: + udev_enumerate_unref(enumerate); + udev_unref(udev); + + return dev; +} + +struct udev_device *device_find_partition(struct udev_device *dev, const char *name) +{ + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *part; + + udev = udev_new(); + if (!udev) { + fprintf(stderr, "Can't create udev\n"); + return NULL; + } + + enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_parent(enumerate, dev); + udev_enumerate_scan_devices(enumerate); + devices = udev_enumerate_get_list_entry(enumerate); + udev_list_entry_foreach(dev_list_entry, devices) { + const char *path, *partname; + path = udev_list_entry_get_name(dev_list_entry); + part = udev_device_new_from_syspath(udev, path); + partname = udev_device_get_sysattr_value(part, "name"); + if (!partname) + continue; + if (!strcmp(partname, name)) + return part; + } + + udev_enumerate_unref(enumerate); + udev_unref(udev); + + return NULL; +} + +struct of_path_type { + const char *name; + int (*parse)(struct of_path *op, const char *str); +}; + +/** + * of_path_type_partname - find a partition based on physical device and + * partition name + * @op: of_path context + * @name: the partition name to find + */ +static int of_path_type_partname(struct of_path *op, const char *name) +{ + struct udev_device *part; + struct stat s; + int ret; + struct device_node *node; + + if (!op->dev) + return -EINVAL; + + part = device_find_partition(op->dev, name); + if (part) { + op->devpath = strdup(udev_device_get_devnode(part)); + pr_debug("%s: found part '%s'\n", __func__, name); + return 0; + } + + ret = asprintf(&op->devpath, "%s/eeprom", udev_device_get_syspath(op->dev)); + if (ret < 0) + return -ENOMEM; + + ret = stat(op->devpath, &s); + if (ret) + return -errno; + + for_each_child_of_node(op->node, node) { + const char *partname; + int len; + + partname = of_get_property(node, "label", &len); + if (!strcmp(partname, name)) { + const __be32 *reg; + int a_cells, s_cells; + + reg = of_get_property(node, "reg", &len); + if (!reg) + continue; + + a_cells = of_n_addr_cells(node); + s_cells = of_n_size_cells(node); + + op->offset = of_read_number(reg, a_cells); + op->size = of_read_number(reg + a_cells, s_cells); + + break; + } + } + + return 0; +} + +static struct of_path_type of_path_types[] = { + { + .name = "partname", + .parse = of_path_type_partname, + }, +}; +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +static int of_path_parse_one(struct of_path *op, const char *str) +{ + int i, ret; + char *name, *desc; + + pr_debug("parsing: %s\n", str); + + name = strdup(str); + desc = strchr(name, ':'); + if (!desc) { + free(name); + return -EINVAL; + } + + *desc = 0; + desc++; + + for (i = 0; i < ARRAY_SIZE(of_path_types); i++) { + if (!strcmp(of_path_types[i].name, name)) { + ret = of_path_types[i].parse(op, desc); + goto out; + } + } + + ret = -EINVAL; +out: + free(name); + + return ret; +} + +/** + * of_find_path - translate a path description in the devicetree to a device node + * path + * + * @node: the node containing the property with the path description + * @propname: the property name of the path description + * @outpath: if this function returns 0 outpath will contain the path belonging + * to the input path description. Must be freed with free(). + * + * pathes in the devicetree have the form of a multistring property. The first + * string contains the full path to the physical device containing the path. + * The remaining strings have the form ":". Currently supported + * for are: + * + * partname: - find a partition by its partition name. For mtd + * partitions this is the label. For DOS partitions + * this is the number beginning with 0. + * + * examples: + * + * device-path = &mmc0, "partname:0"; + * device-path = &norflash, "partname:barebox-environment"; + */ +int of_find_path(struct device_node *node, const char *propname, struct of_path *op) +{ + struct device_node *rnode; + const char *path, *str; + int i, len, ret; + + memset(op, 0, sizeof(*op)); + + path = of_get_property(node, propname, &len); + if (!path) + return -EINVAL; + + rnode = of_find_node_by_path(path); + if (!rnode) + return -ENODEV; + + op->node = rnode; + + op->dev = of_find_device_by_node_path(rnode->full_name); + if (!op->dev) + return -ENODEV; + + i = 1; + + while (1) { + ret = of_property_read_string_index(node, propname, i++, &str); + if (ret) + break; + + ret = of_path_parse_one(op, str); + if (ret) + return ret; + } + + if (!op->devpath) + return -ENOENT; + + pr_debug("%s: devpath: %s ofs: 0x%08llx size: 0x%08lx\n", + __func__, op->devpath, op->offset, op->size); + + return 0; +} diff --git a/src/libdt.pc.in b/src/libdt.pc.in new file mode 100644 index 0000000..2fc7b76 --- /dev/null +++ b/src/libdt.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libabc +Description: Library for something with abc +Version: @VERSION@ +Libs: -L${libdir} -labc +Libs.private: +Cflags: -I${includedir} diff --git a/src/libdt.sym b/src/libdt.sym new file mode 100644 index 0000000..c034ea2 --- /dev/null +++ b/src/libdt.sym @@ -0,0 +1,74 @@ +LIBDT_1 { +global: + of_print_property; + of_n_addr_cells; + of_n_size_cells; + of_find_property; + of_alias_scan; + of_alias_get_id; + of_alias_get; + of_find_node_by_alias; + of_find_node_by_phandle; + of_get_tree_max_phandle; + of_node_create_phandle; + of_get_property; + of_device_is_compatible; + of_find_node_by_name; + of_find_node_by_type; + of_find_compatible_node; + of_find_node_with_property; + of_match_node; + of_find_matching_node_and_match; + of_property_read_u32_index; + of_property_read_u8_array; + of_property_read_u16_array; + of_property_read_u32_array; + of_property_read_u64; + of_property_read_string; + of_property_read_string_index; + of_property_match_string; + of_property_count_strings; + of_prop_next_u32; + of_prop_next_string; + of_property_write_bool; + of_property_write_u8_array; + of_property_write_u16_array; + of_property_write_u32_array; + of_property_write_u64_array; + of_parse_phandle; + of_parse_phandle_with_args; + of_count_phandle_with_args; + of_machine_is_compatible; + of_find_node_by_path_from; + of_find_node_by_path; + of_find_node_by_path_or_alias; + of_modalias_node; + of_get_root_node; + of_set_root_node; + of_device_is_available; + of_get_parent; + of_get_next_available_child; + of_get_child_count; + of_get_available_child_count; + of_get_child_by_name; + of_print_nodes; + of_new_node; + of_new_property; + of_delete_property; + of_set_property; + of_create_node; + of_delete_node; + of_device_enable; + of_device_enable_path; + of_device_disable; + of_device_disable_path; + of_read_proc_devicetree; + of_find_device_by_node_path; + device_find_partition; + of_find_path; + of_unflatten_dtb; + crc32; + crc32_no_comp; +local: + *; +}; diff --git a/src/state.c b/src/state.c new file mode 100644 index 0000000..97c6b4a --- /dev/null +++ b/src/state.c @@ -0,0 +1,1309 @@ +/* + * state.c - state handling tool + * + * Copyright (c) 2014 Sascha Hauer , Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int verbose; + +enum state_variable_type { + STATE_TYPE_INVALID = 0, + STATE_TYPE_ENUM, + STATE_TYPE_U32, + STATE_TYPE_MAC, +}; + +struct state_backend; + +struct state { + struct list_head variables; + const char *name; + struct list_head list; + struct state_backend *backend; + uint32_t magic; + int dirty; +}; + +struct state_backend { + int (*load)(struct state_backend *backend, struct state *state); + int (*save)(struct state_backend *backend, struct state *state); + const char *name; + char *path; +}; + +/* list of all registered state instances */ +static LIST_HEAD(state_list); + +/* instance of a single variable */ +struct state_variable { + enum state_variable_type type; + struct list_head list; + char *name; + void *raw; + int raw_size; + int index; +}; + +/* A variable type (uint32, enum32) */ +struct variable_type { + enum state_variable_type type; + const char *type_name; + struct list_head list; + int (*export)(struct state_variable *, struct device_node *); + int (*init)(struct state_variable *, struct device_node *); + struct state_variable *(*create)(struct state *state, + const char *name, struct device_node *); + char *(*get)(struct state_variable *); + int (*set)(struct state_variable *, const char *val); + void (*info)(struct state_variable *); +}; + +/* + * uint32 + */ +struct state_uint32 { + struct state_variable var; + struct param_d *param; + uint32_t value; + uint32_t value_default; +}; + +static int state_var_compare(struct list_head *a, struct list_head *b) +{ + struct state_variable *va = list_entry(a, struct state_variable, list); + struct state_variable *vb = list_entry(b, struct state_variable, list); + + if (va->index == vb->index) + return 0; + + return va->index < vb->index ? -1 : 1; +} + +static int state_add_variable(struct state *state, struct state_variable *var) +{ + list_add_sort(&var->list, &state->variables, state_var_compare); + + return 0; +} + +static inline struct state_uint32 *to_state_uint32(struct state_variable *s) +{ + return container_of(s, struct state_uint32, var); +} + +static int state_uint32_export(struct state_variable *var, + struct device_node *node) +{ + struct state_uint32 *su32 = to_state_uint32(var); + int ret; + + ret = of_property_write_u32(node, "default", su32->value_default); + if (ret) + return ret; + + return of_property_write_u32(node, "value", su32->value); +} + +static int state_uint32_init(struct state_variable *sv, + struct device_node *node) +{ + int len; + const __be32 *value, *value_default; + struct state_uint32 *su32 = to_state_uint32(sv); + + value_default = of_get_property(node, "default", &len); + if (value_default && len != sizeof(uint32_t)) + return -EINVAL; + + value = of_get_property(node, "value", &len); + if (value && len != sizeof(uint32_t)) + return -EINVAL; + + if (value_default) + su32->value_default = be32_to_cpu(*value_default); + if (value) + su32->value = be32_to_cpu(*value); + else + su32->value = su32->value_default; + + return 0; +} + +static struct state_variable *state_uint32_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_uint32 *su32; + + su32 = xzalloc(sizeof(*su32)); + + pr_debug("%s: %s\n", __func__, name); + + su32->var.raw_size = sizeof(uint32_t); + su32->var.raw = &su32->value; + + return &su32->var; +} + +static int state_uint32_set(struct state_variable *var, const char *val) +{ + struct state_uint32 *su32 = to_state_uint32(var); + + su32->value = strtoul(val, NULL, 0); + + return 0; +} + +static char *state_uint32_get(struct state_variable *var) +{ + struct state_uint32 *su32 = to_state_uint32(var); + char *str; + int ret; + + ret = asprintf(&str, "%d", su32->value); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + return str; +} + +/* + * enum32 + */ +struct state_enum32 { + struct state_variable var; + struct param_d *param; + uint32_t value; + uint32_t value_default; + const char **names; + int num_names; +}; + +static inline struct state_enum32 *to_state_enum32(struct state_variable *s) +{ + return container_of(s, struct state_enum32, var); +} + +static int state_enum32_export(struct state_variable *var, + struct device_node *node) +{ + struct state_enum32 *enum32 = to_state_enum32(var); + int ret, i, len; + char *prop, *str; + + ret = of_property_write_u32(node, "default", enum32->value_default); + if (ret) + return ret; + + ret = of_property_write_u32(node, "value", enum32->value); + if (ret) + return ret; + + len = 0; + + for (i = 0; i < enum32->num_names; i++) + len += strlen(enum32->names[i]) + 1; + + prop = xzalloc(len); + str = prop; + + for (i = 0; i < enum32->num_names; i++) + str += sprintf(str, "%s", enum32->names[i]) + 1; + + ret = of_set_property(node, "names", prop, len, 1); + + free(prop); + + return ret; +} + +static int state_enum32_init(struct state_variable *sv, struct device_node *node) +{ + struct state_enum32 *enum32 = to_state_enum32(sv); + int len; + const __be32 *value, *value_default; + + value = of_get_property(node, "value", &len); + if (value && len != sizeof(uint32_t)) + return -EINVAL; + + value_default = of_get_property(node, "default", &len); + if (value_default && len != sizeof(uint32_t)) + return -EINVAL; + + if (value_default) + enum32->value_default = be32_to_cpu(*value_default); + if (value) + enum32->value = be32_to_cpu(*value); + else + enum32->value = enum32->value_default; + + return 0; +} + +static struct state_variable *state_enum32_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_enum32 *enum32; + int ret, i, num_names; + + enum32 = xzalloc(sizeof(*enum32)); + + num_names = of_property_count_strings(node, "names"); + + enum32->names = xzalloc(sizeof(char *) * num_names); + enum32->num_names = num_names; + enum32->var.raw_size = sizeof(uint32_t); + enum32->var.raw = &enum32->value; + + for (i = 0; i < num_names; i++) { + const char *name; + + ret = of_property_read_string_index(node, "names", i, &name); + if (ret) + goto out; + enum32->names[i] = strdup(name); + } + + pr_debug("%s: %s\n", __func__, name); + + return &enum32->var; +out: + free(enum32->names); + free(enum32); + return ERR_PTR(ret); +} + +static int state_enum32_set(struct state_variable *sv, const char *val) +{ + struct state_enum32 *enum32 = to_state_enum32(sv); + int i; + + for (i = 0; i < enum32->num_names; i++) { + if (!strcmp(enum32->names[i], val)) { + enum32->value = i; + return 0; + } + } + + return -EINVAL; +} + +static char *state_enum32_get(struct state_variable *var) +{ + struct state_enum32 *enum32 = to_state_enum32(var); + char *str; + int ret; + + ret = asprintf(&str, "%s", enum32->names[enum32->value]); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + return str; +} + +static void state_enum32_info(struct state_variable *var) +{ + struct state_enum32 *enum32 = to_state_enum32(var); + int i; + + printf(", values=["); + + for (i = 0; i < enum32->num_names; i++) + printf("%s%s", enum32->names[i], + i == enum32->num_names - 1 ? "" : ","); + printf("]"); +} + +/* + * MAC address + */ +struct state_mac { + struct state_variable var; + struct param_d *param; + uint8_t value[6]; + uint8_t value_default[6]; +}; + +static inline struct state_mac *to_state_mac(struct state_variable *s) +{ + return container_of(s, struct state_mac, var); +} + +static int state_mac_export(struct state_variable *var, + struct device_node *node) +{ + struct state_mac *mac = to_state_mac(var); + int ret; + + ret = of_property_write_u8_array(node, "default", mac->value_default, 6); + if (ret) + return ret; + + return of_property_write_u8_array(node, "value", mac->value, 6); +} + +static int state_mac_init(struct state_variable *sv, struct device_node *node) +{ + struct state_mac *mac = to_state_mac(sv); + uint8_t value[6] = {}; + uint8_t value_default[6] = {}; + + of_property_read_u8_array(node, "default", value_default, 6); + memcpy(mac->value_default, value_default, 6); + + if (!of_property_read_u8_array(node, "value", value, 6)) + memcpy(mac->value, value, 6); + else + memcpy(mac->value, value_default, 6); + + return 0; +} + +static struct state_variable *state_mac_create(struct state *state, + const char *name, struct device_node *node) +{ + struct state_mac *mac; + int ret; + + mac = xzalloc(sizeof(*mac)); + + mac->var.raw_size = 6; + mac->var.raw = mac->value; + + pr_debug("%s: %s\n", __func__, name); + + return &mac->var; +out: + free(mac); + return ERR_PTR(ret); +} + +int string_to_ethaddr(const char *str, uint8_t enetaddr[6]) +{ + int reg; + char *e; + + if (!str || strlen(str) != 17) { + memset(enetaddr, 0, 6); + return -EINVAL; + } + + if (str[2] != ':' || str[5] != ':' || str[8] != ':' || + str[11] != ':' || str[14] != ':') + return -EINVAL; + + for (reg = 0; reg < 6; ++reg) { + enetaddr[reg] = strtoul(str, &e, 16); + str = e + 1; + } + + return 0; +} + +static int state_mac_set(struct state_variable *var, const char *val) +{ + struct state_mac *mac = to_state_mac(var); + char mac_save[6]; + int ret; + + ret = string_to_ethaddr(val, mac_save); + if (ret) + return ret; + + memcpy(mac->value, mac_save, 6); + + return 0; +} + +static char *state_mac_get(struct state_variable *var) +{ + struct state_mac *mac = to_state_mac(var); + char *str; + int ret; + + ret = asprintf(&str, "%02x:%02x:%02x:%02x:%02x:%02x", + mac->value[0], mac->value[1], mac->value[2], + mac->value[3], mac->value[4], mac->value[5]); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + return str; +} + +static struct variable_type types[] = { + { + .type = STATE_TYPE_U32, + .type_name = "uint32", + .export = state_uint32_export, + .init = state_uint32_init, + .create = state_uint32_create, + .set = state_uint32_set, + .get = state_uint32_get, + }, { + .type = STATE_TYPE_ENUM, + .type_name = "enum32", + .export = state_enum32_export, + .init = state_enum32_init, + .create = state_enum32_create, + .set = state_enum32_set, + .get = state_enum32_get, + .info = state_enum32_info, + }, { + .type = STATE_TYPE_MAC, + .type_name = "mac", + .export = state_mac_export, + .init = state_mac_init, + .create = state_mac_create, + .set = state_mac_set, + .get = state_mac_get, + }, +}; + +static struct variable_type *state_find_type(enum state_variable_type type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(types); i++) { + if (type == types[i].type) { + return &types[i]; + } + } + + return NULL; +} + +static struct variable_type *state_find_type_by_name(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(types); i++) { + if (!strcmp(name, types[i].type_name)) { + return &types[i]; + } + } + + return NULL; +} + +/* + * Generic state functions + */ + +static struct state *state_new(const char *name) +{ + struct state *state; + int ret; + + state = xzalloc(sizeof(*state)); + state->name = name; + INIT_LIST_HEAD(&state->variables); + + list_add_tail(&state->list, &state_list); + + return state; +} + +static void state_release(struct state *state) +{ + free(state); +} + +static struct device_node *state_to_node(struct state *state) +{ + struct device_node *root, *node; + struct state_variable *sv; + int ret; + + root = of_new_node(NULL, NULL); + + list_for_each_entry(sv, &state->variables, list) { + struct variable_type *vtype; + char *name; + + asprintf(&name, "%s@%d", sv->name, sv->index); + node = of_new_node(root, name); + free(name); + + vtype = state_find_type(sv->type); + if (!vtype) { + ret = -ENOENT; + goto out; + } + + of_set_property(node, "type", vtype->type_name, + strlen(vtype->type_name) + 1, 1); + + ret = vtype->export(sv, node); + if (ret) + goto out; + } + + of_property_write_u32(root, "magic", state->magic); + + return root; +out: + of_delete_node(root); + return ERR_PTR(ret); +} + +static struct state_variable *state_find_var(struct state *state, const char *name) +{ + struct state_variable *sv; + + list_for_each_entry(sv, &state->variables, list) { + if (!strcmp(sv->name, name)) + return sv; + } + + return NULL; +} + +static char *state_get_var(struct state *state, const char *var) +{ + struct state_variable *sv; + struct variable_type *vtype; + + sv = state_find_var(state, var); + if (!sv) + return NULL; + + vtype = state_find_type(sv->type); + + return vtype->get(sv); +} + +static int state_set_var(struct state *state, const char *var, const char *val) +{ + struct state_variable *sv; + struct variable_type *vtype; + int ret; + + sv = state_find_var(state, var); + if (!sv) + return -ENOENT; + + vtype = state_find_type(sv->type); + + if (!vtype->set) + return -EPERM; + + ret = vtype->set(sv, val); + if (ret) + return ret; + + state->dirty = 1; + + return 0; +} + +static int state_variable_from_node(struct state *state, struct device_node *node, + bool create) +{ + struct variable_type *vtype; + struct state_variable *sv; + char *name, *indexs; + int index = 0; + const char *type_name = NULL; + + of_property_read_string(node, "type", &type_name); + if (!type_name) + return -EINVAL; + + vtype = state_find_type_by_name(type_name); + if (!vtype) + return -ENOENT; + + name = strdup(node->name); + indexs = strchr(name, '@'); + if (indexs) { + *indexs++ = 0; + index = strtoul(indexs, NULL, 10); + } + + if (create) { + sv = vtype->create(state, name, node); + if (IS_ERR(sv)) { + int ret = PTR_ERR(sv); + pr_err("failed to create %s: %s\n", name, strerror(-ret)); + return ret; + } + sv->name = name; + sv->type = vtype->type; + sv->index = index; + state_add_variable(state, sv); + } else { + sv = state_find_var(state, name); + if (IS_ERR(sv)) { + int ret = PTR_ERR(sv); + pr_err("no such variable: %s: %s\n", name, strerror(-ret)); + return ret; + } + } + + vtype->init(sv, node); + + return 0; +} + +int state_from_node(struct state *state, struct device_node *node, bool create) +{ + struct device_node *child; + int ret; + uint32_t magic; + + of_property_read_u32(node, "magic", &magic); + + if (create) { + state->magic = magic; + } else { + if (state->magic && state->magic != magic) { + pr_err("invalid magic 0x%08x, should be 0x%08x\n", + magic, state->magic); + return -EINVAL; + } + } + + for_each_child_of_node(node, child) { + ret = state_variable_from_node(state, child, create); + if (ret) + return ret; + } + + return 0; +} + +/* + * state_new_from_node - create a new state instance from a device_node + * + * @name The name of the new state instance + * @node The device_node describing the new state instance + */ +struct state *state_new_from_node(const char *name, struct device_node *node) +{ + struct state *state; + int ret; + + state = state_new(name); + if (!state) + return ERR_PTR(-EINVAL); + + ret = state_from_node(state, node, 1); + if (ret) { + state_release(state); + return ERR_PTR(ret); + } + + return state; +} + +/* + * state_by_name - find a state instance by name + * + * @name The name of the state instance + */ +struct state *state_by_name(const char *name) +{ + struct state *s; + + list_for_each_entry(s, &state_list, list) { + if (!strcmp(name, s->name)) + return s; + } + + return NULL; +} + +/* + * state_load - load a state from the backing store + * + * @state The state instance to load + */ +int state_load(struct state *state) +{ + int ret; + + if (!state->backend) + return -ENOSYS; + + ret = state->backend->load(state->backend, state); + if (ret) + return ret; + + state->dirty = 0; + + return 0; +} + +/* + * state_save - save a state to the backing store + * + * @state The state instance to save + */ +int state_save(struct state *state) +{ + int ret; + + if (!state->backend) + return -ENOSYS; + + ret = state->backend->save(state->backend, state); + if (ret) + return ret; + + state->dirty = 0; + + return 0; +} + +void state_info(void) +{ + struct state *s; + + printf("registered state instances:\n"); + + list_for_each_entry(s, &state_list, list) { + printf("%-20s ", s->name); + if (s->backend) + printf("(backend: %s, path: %s)\n", s->backend->name, s->backend->path); + else + printf("(no backend)\n"); + } +} + +static int get_meminfo(const char *path, struct mtd_info_user *meminfo) +{ + int fd, ret; + + fd = open(path, O_RDWR); + if (fd < 0) + return -errno; + + ret = ioctl(fd, MEMGETINFO, meminfo); + + close(fd); + + if (ret) + return -errno; + + return 0; +} + +/* + * Raw backend implementation + */ +struct state_backend_raw { + struct state_backend backend; + struct state *state; + unsigned long size_data; /* The raw data size (without magic and crc) */ + unsigned long size_full; + unsigned long step; /* The step in bytes between two copies */ + off_t offset; /* offset in the storage file */ + size_t size; /* size of the storage area */ + int need_erase; + int num_copy_read; /* The first successfully read copy */ +}; + +struct backend_raw_header { + uint32_t magic; + uint16_t reserved; + uint16_t data_len; + uint32_t data_crc; + uint32_t header_crc; +}; + +static int backend_raw_load_one(struct state_backend_raw *backend_raw, + int fd, off_t offset) +{ + struct state *state = backend_raw->state; + uint32_t crc; + void *off; + struct state_variable *sv; + struct backend_raw_header header = {}; + int ret, len; + void *buf; + + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) + return ret; + + ret = read(fd, &header, sizeof(header)); + if (ret < 0) + return ret; + if (ret < sizeof(header)) + return -EINVAL; + + crc = crc32(0, &header, sizeof(header) - sizeof(uint32_t)); + if (crc != header.header_crc) { + pr_err("invalid header crc, calculated 0x%08x, found 0x%08x\n", + crc, header.header_crc); + return -EINVAL; + } + + if (state->magic && state->magic != header.magic) { + pr_err("invalid magic 0x%08x, should be 0x%08x\n", + header.magic, state->magic); + return -EINVAL; + } + + buf = xzalloc(header.data_len); + + ret = read(fd, buf, header.data_len); + if (ret < 0) + return ret; + if (ret < header.data_len) + return -EINVAL; + + crc = crc32(0, buf, header.data_len); + if (crc != header.data_crc) { + pr_err("invalid crc, calculated 0x%08x, found 0x%08x\n", + crc, header.data_crc); + return -EINVAL; + } + + off = buf; + len = header.data_len; + + list_for_each_entry(sv, &state->variables, list) { + if (len < sv->raw_size) { + break; + } + memcpy(sv->raw, off, sv->raw_size); + off += sv->raw_size; + len -= sv->raw_size; + } + + free(buf); + + return 0; +} + +static int state_backend_raw_load(struct state_backend *backend, struct state *state) +{ + struct state_backend_raw *backend_raw = container_of(backend, + struct state_backend_raw, backend); + int ret = 0, fd, i; + + fd = open(backend->path, O_RDONLY); + if (fd < 0) + return fd; + + for (i = 0; i < 2; i++) { + off_t offset = backend_raw->offset + i * backend_raw->step; + + ret = backend_raw_load_one(backend_raw, fd, offset); + if (!ret) { + backend_raw->num_copy_read = i; + pr_debug("copy %d successfully loaded\n", i); + break; + } + } + + close(fd); + + return ret; +} + +static int backend_raw_write_one(struct state_backend_raw *backend_raw, + int fd, int num, void *buf, size_t size) +{ + int ret; + off_t offset = backend_raw->offset + num * backend_raw->step; + + pr_debug(&backend_raw->state->dev, "%s: 0x%08lx 0x%08x\n", + __func__, offset, size); + + if (backend_raw->need_erase) { + struct erase_info_user erase = { + .start = offset, + .length = backend_raw->step, + }; + + ret = ioctl(fd, MEMERASE, &erase); + if (ret < 0) + return -errno; + } + + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) + return -errno; + + ret = write(fd, buf, size); + if (ret < 0) + return -errno; + + return 0; +} + +static int state_backend_raw_save(struct state_backend *backend, struct state *state) +{ + struct state_backend_raw *backend_raw = container_of(backend, + struct state_backend_raw, backend); + int ret = 0, size, fd; + void *buf, *freep, *off, *data, *tmp; + struct backend_raw_header *header; + struct state_variable *sv; + + size = backend_raw->size_data + sizeof(struct backend_raw_header); + + freep = off = buf = xzalloc(size); + + header = buf; + data = buf + sizeof(*header); + + tmp = data; + list_for_each_entry(sv, &state->variables, list) { + memcpy(tmp, sv->raw, sv->raw_size); + tmp += sv->raw_size; + } + + header->magic = state->magic; + header->data_len = backend_raw->size_data; + header->data_crc = crc32(0, data, backend_raw->size_data); + header->header_crc = crc32(0, header, sizeof(*header) - sizeof(uint32_t)); + + fd = open(backend->path, O_WRONLY); + if (fd < 0) + return fd; + + ret = backend_raw_write_one(backend_raw, fd, !backend_raw->num_copy_read, buf, size); + if (ret) + goto out; + + ret = backend_raw_write_one(backend_raw, fd, backend_raw->num_copy_read, buf, size); + if (ret) + goto out; + + pr_debug("wrote state to %s\n", backend->path); +out: + close(fd); + free(buf); + + return ret; +} + +/* + * state_backend_raw_file - create a raw file backend store for a state instance + * + * @state The state instance to work on + * @path The path where the state will be stored to + * @offset The offset in the storage file + * @size The maximum size to use in the storage file + * + * This backend stores raw binary data from a state instance. The binary data is + * protected with a magic value which has to match and a crc32 that must be valid. + * Up to four copies are stored if there is sufficient space available. + * @path can be a path to a device or a regular file. When it's a device @size may + * be 0. The four copies a spread to different eraseblocks if approriate for this + * device. + */ +int state_backend_raw_file(struct state *state, const char *path, off_t offset, + size_t size) +{ + struct state_backend_raw *backend_raw; + struct state_backend *backend; + struct state_variable *sv; + int ret; + struct stat s; + struct mtd_info_user meminfo; + + if (state->backend) + return -EBUSY; + + ret = stat(path, &s); + if (!ret && !S_ISCHR(s.st_mode)) { + if (size == 0) + size = s.st_size; + else if (offset + size > s.st_size) + return -EINVAL; + } + + backend_raw = xzalloc(sizeof(*backend_raw)); + backend = &backend_raw->backend; + + backend->load = state_backend_raw_load; + backend->save = state_backend_raw_save; + backend->path = strdup(path); + backend->name = "raw"; + + list_for_each_entry(sv, &state->variables, list) + backend_raw->size_data += sv->raw_size; + + backend_raw->state = state; + backend_raw->offset = offset; + backend_raw->size_full = backend_raw->size_data + sizeof(struct backend_raw_header); + + state->backend = backend; + + ret = get_meminfo(backend->path, &meminfo); + if (!ret) { + if (!size) + size = meminfo.size; + backend_raw->need_erase = 1; + backend_raw->step = ALIGN(backend_raw->size_full, meminfo.erasesize); + if (verbose) + fprintf(stderr, "%s is a mtd of size %d, adjust stepsize to %ld\n", + path, meminfo.size, backend_raw->step); + } else { + backend_raw->step = backend_raw->size_full; + } + + backend_raw->size = size; + + if (backend_raw->size / backend_raw->step < 2) { + pr_err("not enough space for two copies, have %d, need %d\n", + backend_raw->size, backend_raw->step * 2); + ret = -ENOSPC; + goto err; + } + + return 0; +err: + free(backend_raw); + return ret; +} + +static struct state *state_get(const char *name) +{ + struct device_node *root, *node; + char *path; + struct state *state; + int ret; + const char *backend_type = NULL; + struct of_path op; + struct state_variable *v; + + root = of_read_proc_devicetree(); + if (IS_ERR(root)) { + fprintf(stderr, "Unable to read devicetree from /proc/device-tree: %s\n", + strerror(-PTR_ERR(root))); + return ERR_CAST(root); + } + + of_set_root_node(root); + + node = of_find_node_by_path_or_alias(root, name); + if (!node) { + fprintf(stderr, "no such node: %s\n", name); + return ERR_PTR(-ENOENT); + } + + if (verbose > 1) { + printf("found state node %s:\n", node->full_name); + of_print_nodes(node, 0); + } + + state = state_new_from_node("state", node); + if (IS_ERR(state)) { + fprintf(stderr, "unable to initlialize state: %s\n", + strerror(PTR_ERR(state))); + return ERR_CAST(state); + } + + ret = of_find_path(node, "backend", &op); + if (ret) { + fprintf(stderr, "Cannot find backend path in %s\n", node->full_name); + return ERR_PTR(ret); + } + + of_property_read_string(node, "backend-type", &backend_type); + if (!strcmp(backend_type, "raw")) + ret = state_backend_raw_file(state, op.devpath, op.offset, op.size); + else + fprintf(stderr, "invalid backend type: %s\n", backend_type); + + if (ret) { + fprintf(stderr, "Cannot initialize backend: %s\n", strerror(-ret)); + return ERR_PTR(ret); + } + + return state; +} + +enum opt { + OPT_DUMP_SHELL = 1, +}; + +static struct option long_options[] = { + {"get", required_argument, 0, 'g' }, + {"set", required_argument, 0, 's' }, + {"name", required_argument, 0, 'n' }, + {"dump", no_argument, 0, 'd' }, + {"dump-shell", no_argument, 0, OPT_DUMP_SHELL }, + {"init", no_argument, 0, 'i' }, + {"verbose", no_argument, 0, 'v' }, + {"help", no_argument, 0, 'h' }, +}; + +static void usage(char *name) +{ + printf( +"Usage: %s [OPTIONS]\n" +"\n" +"-g, --get get the value of a variable\n" +"-s, --set = set the value of a variable\n" +"-n, --name specify the state to use (default=\"state\")\n" +"-d, --dump dump the state\n" +"--dump-shell dump the state suitable for shell sourcing\n" +"--init initialize the state (do not load from storage)\n" +"-v, --verbose increase verbosity\n" +"--help this help\n", + name); +} + +#define state_for_each_var(state, var) \ + list_for_each_entry(var, &(state)->variables, list) + +struct state_set_get { + char *arg; + int get; + struct list_head list; +}; + +int main(int argc, char *argv[]) +{ + struct state *state; + struct state_variable *v; + int ret, c, option_index; + int do_dump = 0, do_dump_shell = 0, do_initialize = 0; + struct state_set_get *sg; + struct list_head sg_list; + char *statename = "state"; + + INIT_LIST_HEAD(&sg_list); + + while (1) { + c = getopt_long(argc, argv, "hg:s:divn:", long_options, &option_index); + if (c < 0) + break; + switch (c) { + case 'h': + usage(argv[0]); + exit(0); + case 'g': + sg = xzalloc(sizeof(*sg)); + sg->get = 1; + sg->arg = optarg; + list_add_tail(&sg->list, &sg_list); + break; + case 's': + sg = xzalloc(sizeof(*sg)); + sg->get = 0; + sg->arg = optarg; + list_add_tail(&sg->list, &sg_list); + break; + case 'd': + do_dump = 1; + break; + case 'i': + do_initialize = 1; + break; + case OPT_DUMP_SHELL: + do_dump_shell = 1; + break; + case 'v': + verbose++; + break; + case 'n': + statename = optarg; + } + } + + state = state_get(statename); + if (IS_ERR(state)) + exit(1); + + ret = state_load(state); + if (!do_initialize && ret) { + fprintf(stderr, "Cannot load state: %s\n", strerror(-ret)); + exit(1); + } + + if (do_dump) { + state_for_each_var(state, v) { + struct variable_type *vtype; + vtype = state_find_type(v->type); + printf("%s=%s", v->name, vtype->get(v)); + if (verbose) { + printf(", type=%s", vtype->type_name); + if (vtype->info) + vtype->info(v); + } + printf("\n"); + } + } + + if (do_dump_shell) { + state_for_each_var(state, v) { + struct variable_type *vtype; + vtype = state_find_type(v->type); + printf("STATE_%s=\"%s\"\n", v->name, vtype->get(v)); + } + } + + list_for_each_entry(sg, &sg_list, list) { + if (sg->get) { + char *val = state_get_var(state, sg->arg); + if (!val) { + fprintf(stderr, "no such variable: %s\n", sg->arg); + exit (1); + } + + printf("%s\n", val); + } else { + char *var, *val; + + var = sg->arg; + val = index(sg->arg, '='); + if (!val) { + fprintf(stderr, "usage: -s var=val\n"); + exit (1); + } + *val++ = '\0'; + ret = state_set_var(state, var, val); + if (ret) { + fprintf(stderr, "Failed to set variable %s to %s: %s\n", + var, val, strerror(-ret)); + exit(1); + } + } + } + + if (state->dirty) { + ret = state_save(state); + if (ret) { + fprintf(stderr, "Failed to save state: %s\n", strerror(-ret)); + exit(1); + } + } + + return 0; +}