Date: | 2011-12-26 03:49:02 (12 years 3 months ago) |
---|---|
Author: | Xiangfu Liu |
Commit: | 1a1cdcb76de416b4a29b9e221f8d58d600fa6c13 |
Message: | Merge jzboot as xburst-tools subdirectory diff --cc jzboot/.gitignore index 0000000,0000000..53c644c new file mode 100644 --- /dev/null +++ b/jzboot/.gitignore @@@ -1,0 -1,0 +1,6 @@@ ++.deps ++Makefile ++Makefile.in ++jzboot ++*.o ++*.d diff --cc jzboot/COPYING index 0000000,0000000..e4cc176 new file mode 100644 --- /dev/null +++ b/jzboot/COPYING @@@ -1,0 -1,0 +1,4 @@@ ++firmware/spl_stage1.bin, firmware/spl_stage2_usb.bin are (c) Ingenic Semiconductor Co.,Ltd. ++ingenic.h is based on code by Ingenic Semiconductor Co.,Ltd. ++ ++All other files have their authors and licenses described at their beginning. diff --cc jzboot/COPYING.GPL3 index 0000000,0000000..94a9ed0 new file mode 100644 --- /dev/null +++ b/jzboot/COPYING.GPL3 @@@ -1,0 -1,0 +1,674 @@@ ++ GNU GENERAL PUBLIC LICENSE ++ Version 3, 29 June 2007 ++ ++ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The GNU General Public License is a free, copyleft license for ++software and other kinds of works. ++ ++ The licenses for most software and other practical works are designed ++to take away your freedom to share and change the works. By contrast, ++the GNU General Public License is intended to guarantee your freedom to ++share and change all versions of a program--to make sure it remains free ++software for all its users. We, the Free Software Foundation, use the ++GNU General Public License for most of our software; it applies also to ++any other work released this way by its authors. You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++them if you wish), that you receive source code or can get it if you ++want it, that you can change the software or use pieces of it in new ++free programs, and that you know you can do these things. ++ ++ To protect your rights, we need to prevent others from denying you ++these rights or asking you to surrender the rights. Therefore, you have ++certain responsibilities if you distribute copies of the software, or if ++you modify it: responsibilities to respect the freedom of others. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must pass on to the recipients the same ++freedoms that you received. You must make sure that they, too, receive ++or can get the source code. And you must show them these terms so they ++know their rights. ++ ++ Developers that use the GNU GPL protect your rights with two steps: ++(1) assert copyright on the software, and (2) offer you this License ++giving you legal permission to copy, distribute and/or modify it. ++ ++ For the developers' and authors' protection, the GPL clearly explains ++that there is no warranty for this free software. For both users' and ++authors' sake, the GPL requires that modified versions be marked as ++changed, so that their problems will not be attributed erroneously to ++authors of previous versions. ++ ++ Some devices are designed to deny users access to install or run ++modified versions of the software inside them, although the manufacturer ++can do so. This is fundamentally incompatible with the aim of ++protecting users' freedom to change the software. The systematic ++pattern of such abuse occurs in the area of products for individuals to ++use, which is precisely where it is most unacceptable. Therefore, we ++have designed this version of the GPL to prohibit the practice for those ++products. If such problems arise substantially in other domains, we ++stand ready to extend this provision to those domains in future versions ++of the GPL, as needed to protect the freedom of users. ++ ++ Finally, every program is threatened constantly by software patents. ++States should not allow patents to restrict development and use of ++software on general-purpose computers, but in those that do, we wish to ++avoid the special danger that patents applied to a free program could ++make it effectively proprietary. To prevent this, the GPL assures that ++patents cannot be used to render the program non-free. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ TERMS AND CONDITIONS ++ ++ 0. Definitions. ++ ++ "This License" refers to version 3 of the GNU General Public License. ++ ++ "Copyright" also means copyright-like laws that apply to other kinds of ++works, such as semiconductor masks. ++ ++ "The Program" refers to any copyrightable work licensed under this ++License. Each licensee is addressed as "you". "Licensees" and ++"recipients" may be individuals or organizations. ++ ++ To "modify" a work means to copy from or adapt all or part of the work ++in a fashion requiring copyright permission, other than the making of an ++exact copy. The resulting work is called a "modified version" of the ++earlier work or a work "based on" the earlier work. ++ ++ A "covered work" means either the unmodified Program or a work based ++on the Program. ++ ++ To "propagate" a work means to do anything with it that, without ++permission, would make you directly or secondarily liable for ++infringement under applicable copyright law, except executing it on a ++computer or modifying a private copy. Propagation includes copying, ++distribution (with or without modification), making available to the ++public, and in some countries other activities as well. ++ ++ To "convey" a work means any kind of propagation that enables other ++parties to make or receive copies. Mere interaction with a user through ++a computer network, with no transfer of a copy, is not conveying. ++ ++ An interactive user interface displays "Appropriate Legal Notices" ++to the extent that it includes a convenient and prominently visible ++feature that (1) displays an appropriate copyright notice, and (2) ++tells the user that there is no warranty for the work (except to the ++extent that warranties are provided), that licensees may convey the ++work under this License, and how to view a copy of this License. If ++the interface presents a list of user commands or options, such as a ++menu, a prominent item in the list meets this criterion. ++ ++ 1. Source Code. ++ ++ The "source code" for a work means the preferred form of the work ++for making modifications to it. "Object code" means any non-source ++form of a work. ++ ++ A "Standard Interface" means an interface that either is an official ++standard defined by a recognized standards body, or, in the case of ++interfaces specified for a particular programming language, one that ++is widely used among developers working in that language. ++ ++ The "System Libraries" of an executable work include anything, other ++than the work as a whole, that (a) is included in the normal form of ++packaging a Major Component, but which is not part of that Major ++Component, and (b) serves only to enable use of the work with that ++Major Component, or to implement a Standard Interface for which an ++implementation is available to the public in source code form. A ++"Major Component", in this context, means a major essential component ++(kernel, window system, and so on) of the specific operating system ++(if any) on which the executable work runs, or a compiler used to ++produce the work, or an object code interpreter used to run it. ++ ++ The "Corresponding Source" for a work in object code form means all ++the source code needed to generate, install, and (for an executable ++work) run the object code and to modify the work, including scripts to ++control those activities. However, it does not include the work's ++System Libraries, or general-purpose tools or generally available free ++programs which are used unmodified in performing those activities but ++which are not part of the work. For example, Corresponding Source ++includes interface definition files associated with source files for ++the work, and the source code for shared libraries and dynamically ++linked subprograms that the work is specifically designed to require, ++such as by intimate data communication or control flow between those ++subprograms and other parts of the work. ++ ++ The Corresponding Source need not include anything that users ++can regenerate automatically from other parts of the Corresponding ++Source. ++ ++ The Corresponding Source for a work in source code form is that ++same work. ++ ++ 2. Basic Permissions. ++ ++ All rights granted under this License are granted for the term of ++copyright on the Program, and are irrevocable provided the stated ++conditions are met. This License explicitly affirms your unlimited ++permission to run the unmodified Program. The output from running a ++covered work is covered by this License only if the output, given its ++content, constitutes a covered work. This License acknowledges your ++rights of fair use or other equivalent, as provided by copyright law. ++ ++ You may make, run and propagate covered works that you do not ++convey, without conditions so long as your license otherwise remains ++in force. You may convey covered works to others for the sole purpose ++of having them make modifications exclusively for you, or provide you ++with facilities for running those works, provided that you comply with ++the terms of this License in conveying all material for which you do ++not control copyright. Those thus making or running the covered works ++for you must do so exclusively on your behalf, under your direction ++and control, on terms that prohibit them from making any copies of ++your copyrighted material outside their relationship with you. ++ ++ Conveying under any other circumstances is permitted solely under ++the conditions stated below. Sublicensing is not allowed; section 10 ++makes it unnecessary. ++ ++ 3. Protecting Users' Legal Rights From Anti-Circumvention Law. ++ ++ No covered work shall be deemed part of an effective technological ++measure under any applicable law fulfilling obligations under article ++11 of the WIPO copyright treaty adopted on 20 December 1996, or ++similar laws prohibiting or restricting circumvention of such ++measures. ++ ++ When you convey a covered work, you waive any legal power to forbid ++circumvention of technological measures to the extent such circumvention ++is effected by exercising rights under this License with respect to ++the covered work, and you disclaim any intention to limit operation or ++modification of the work as a means of enforcing, against the work's ++users, your or third parties' legal rights to forbid circumvention of ++technological measures. ++ ++ 4. Conveying Verbatim Copies. ++ ++ You may convey verbatim copies of the Program's source code as you ++receive it, in any medium, provided that you conspicuously and ++appropriately publish on each copy an appropriate copyright notice; ++keep intact all notices stating that this License and any ++non-permissive terms added in accord with section 7 apply to the code; ++keep intact all notices of the absence of any warranty; and give all ++recipients a copy of this License along with the Program. ++ ++ You may charge any price or no price for each copy that you convey, ++and you may offer support or warranty protection for a fee. ++ ++ 5. Conveying Modified Source Versions. ++ ++ You may convey a work based on the Program, or the modifications to ++produce it from the Program, in the form of source code under the ++terms of section 4, provided that you also meet all of these conditions: ++ ++ a) The work must carry prominent notices stating that you modified ++ it, and giving a relevant date. ++ ++ b) The work must carry prominent notices stating that it is ++ released under this License and any conditions added under section ++ 7. This requirement modifies the requirement in section 4 to ++ "keep intact all notices". ++ ++ c) You must license the entire work, as a whole, under this ++ License to anyone who comes into possession of a copy. This ++ License will therefore apply, along with any applicable section 7 ++ additional terms, to the whole of the work, and all its parts, ++ regardless of how they are packaged. This License gives no ++ permission to license the work in any other way, but it does not ++ invalidate such permission if you have separately received it. ++ ++ d) If the work has interactive user interfaces, each must display ++ Appropriate Legal Notices; however, if the Program has interactive ++ interfaces that do not display Appropriate Legal Notices, your ++ work need not make them do so. ++ ++ A compilation of a covered work with other separate and independent ++works, which are not by their nature extensions of the covered work, ++and which are not combined with it such as to form a larger program, ++in or on a volume of a storage or distribution medium, is called an ++"aggregate" if the compilation and its resulting copyright are not ++used to limit the access or legal rights of the compilation's users ++beyond what the individual works permit. Inclusion of a covered work ++in an aggregate does not cause this License to apply to the other ++parts of the aggregate. ++ ++ 6. Conveying Non-Source Forms. ++ ++ You may convey a covered work in object code form under the terms ++of sections 4 and 5, provided that you also convey the ++machine-readable Corresponding Source under the terms of this License, ++in one of these ways: ++ ++ a) Convey the object code in, or embodied in, a physical product ++ (including a physical distribution medium), accompanied by the ++ Corresponding Source fixed on a durable physical medium ++ customarily used for software interchange. ++ ++ b) Convey the object code in, or embodied in, a physical product ++ (including a physical distribution medium), accompanied by a ++ written offer, valid for at least three years and valid for as ++ long as you offer spare parts or customer support for that product ++ model, to give anyone who possesses the object code either (1) a ++ copy of the Corresponding Source for all the software in the ++ product that is covered by this License, on a durable physical ++ medium customarily used for software interchange, for a price no ++ more than your reasonable cost of physically performing this ++ conveying of source, or (2) access to copy the ++ Corresponding Source from a network server at no charge. ++ ++ c) Convey individual copies of the object code with a copy of the ++ written offer to provide the Corresponding Source. This ++ alternative is allowed only occasionally and noncommercially, and ++ only if you received the object code with such an offer, in accord ++ with subsection 6b. ++ ++ d) Convey the object code by offering access from a designated ++ place (gratis or for a charge), and offer equivalent access to the ++ Corresponding Source in the same way through the same place at no ++ further charge. You need not require recipients to copy the ++ Corresponding Source along with the object code. If the place to ++ copy the object code is a network server, the Corresponding Source ++ may be on a different server (operated by you or a third party) ++ that supports equivalent copying facilities, provided you maintain ++ clear directions next to the object code saying where to find the ++ Corresponding Source. Regardless of what server hosts the ++ Corresponding Source, you remain obligated to ensure that it is ++ available for as long as needed to satisfy these requirements. ++ ++ e) Convey the object code using peer-to-peer transmission, provided ++ you inform other peers where the object code and Corresponding ++ Source of the work are being offered to the general public at no ++ charge under subsection 6d. ++ ++ A separable portion of the object code, whose source code is excluded ++from the Corresponding Source as a System Library, need not be ++included in conveying the object code work. ++ ++ A "User Product" is either (1) a "consumer product", which means any ++tangible personal property which is normally used for personal, family, ++or household purposes, or (2) anything designed or sold for incorporation ++into a dwelling. In determining whether a product is a consumer product, ++doubtful cases shall be resolved in favor of coverage. For a particular ++product received by a particular user, "normally used" refers to a ++typical or common use of that class of product, regardless of the status ++of the particular user or of the way in which the particular user ++actually uses, or expects or is expected to use, the product. A product ++is a consumer product regardless of whether the product has substantial ++commercial, industrial or non-consumer uses, unless such uses represent ++the only significant mode of use of the product. ++ ++ "Installation Information" for a User Product means any methods, ++procedures, authorization keys, or other information required to install ++and execute modified versions of a covered work in that User Product from ++a modified version of its Corresponding Source. The information must ++suffice to ensure that the continued functioning of the modified object ++code is in no case prevented or interfered with solely because ++modification has been made. ++ ++ If you convey an object code work under this section in, or with, or ++specifically for use in, a User Product, and the conveying occurs as ++part of a transaction in which the right of possession and use of the ++User Product is transferred to the recipient in perpetuity or for a ++fixed term (regardless of how the transaction is characterized), the ++Corresponding Source conveyed under this section must be accompanied ++by the Installation Information. But this requirement does not apply ++if neither you nor any third party retains the ability to install ++modified object code on the User Product (for example, the work has ++been installed in ROM). ++ ++ The requirement to provide Installation Information does not include a ++requirement to continue to provide support service, warranty, or updates ++for a work that has been modified or installed by the recipient, or for ++the User Product in which it has been modified or installed. Access to a ++network may be denied when the modification itself materially and ++adversely affects the operation of the network or violates the rules and ++protocols for communication across the network. ++ ++ Corresponding Source conveyed, and Installation Information provided, ++in accord with this section must be in a format that is publicly ++documented (and with an implementation available to the public in ++source code form), and must require no special password or key for ++unpacking, reading or copying. ++ ++ 7. Additional Terms. ++ ++ "Additional permissions" are terms that supplement the terms of this ++License by making exceptions from one or more of its conditions. ++Additional permissions that are applicable to the entire Program shall ++be treated as though they were included in this License, to the extent ++that they are valid under applicable law. If additional permissions ++apply only to part of the Program, that part may be used separately ++under those permissions, but the entire Program remains governed by ++this License without regard to the additional permissions. ++ ++ When you convey a copy of a covered work, you may at your option ++remove any additional permissions from that copy, or from any part of ++it. (Additional permissions may be written to require their own ++removal in certain cases when you modify the work.) You may place ++additional permissions on material, added by you to a covered work, ++for which you have or can give appropriate copyright permission. ++ ++ Notwithstanding any other provision of this License, for material you ++add to a covered work, you may (if authorized by the copyright holders of ++that material) supplement the terms of this License with terms: ++ ++ a) Disclaiming warranty or limiting liability differently from the ++ terms of sections 15 and 16 of this License; or ++ ++ b) Requiring preservation of specified reasonable legal notices or ++ author attributions in that material or in the Appropriate Legal ++ Notices displayed by works containing it; or ++ ++ c) Prohibiting misrepresentation of the origin of that material, or ++ requiring that modified versions of such material be marked in ++ reasonable ways as different from the original version; or ++ ++ d) Limiting the use for publicity purposes of names of licensors or ++ authors of the material; or ++ ++ e) Declining to grant rights under trademark law for use of some ++ trade names, trademarks, or service marks; or ++ ++ f) Requiring indemnification of licensors and authors of that ++ material by anyone who conveys the material (or modified versions of ++ it) with contractual assumptions of liability to the recipient, for ++ any liability that these contractual assumptions directly impose on ++ those licensors and authors. ++ ++ All other non-permissive additional terms are considered "further ++restrictions" within the meaning of section 10. If the Program as you ++received it, or any part of it, contains a notice stating that it is ++governed by this License along with a term that is a further ++restriction, you may remove that term. If a license document contains ++a further restriction but permits relicensing or conveying under this ++License, you may add to a covered work material governed by the terms ++of that license document, provided that the further restriction does ++not survive such relicensing or conveying. ++ ++ If you add terms to a covered work in accord with this section, you ++must place, in the relevant source files, a statement of the ++additional terms that apply to those files, or a notice indicating ++where to find the applicable terms. ++ ++ Additional terms, permissive or non-permissive, may be stated in the ++form of a separately written license, or stated as exceptions; ++the above requirements apply either way. ++ ++ 8. Termination. ++ ++ You may not propagate or modify a covered work except as expressly ++provided under this License. Any attempt otherwise to propagate or ++modify it is void, and will automatically terminate your rights under ++this License (including any patent licenses granted under the third ++paragraph of section 11). ++ ++ However, if you cease all violation of this License, then your ++license from a particular copyright holder is reinstated (a) ++provisionally, unless and until the copyright holder explicitly and ++finally terminates your license, and (b) permanently, if the copyright ++holder fails to notify you of the violation by some reasonable means ++prior to 60 days after the cessation. ++ ++ Moreover, your license from a particular copyright holder is ++reinstated permanently if the copyright holder notifies you of the ++violation by some reasonable means, this is the first time you have ++received notice of violation of this License (for any work) from that ++copyright holder, and you cure the violation prior to 30 days after ++your receipt of the notice. ++ ++ Termination of your rights under this section does not terminate the ++licenses of parties who have received copies or rights from you under ++this License. If your rights have been terminated and not permanently ++reinstated, you do not qualify to receive new licenses for the same ++material under section 10. ++ ++ 9. Acceptance Not Required for Having Copies. ++ ++ You are not required to accept this License in order to receive or ++run a copy of the Program. Ancillary propagation of a covered work ++occurring solely as a consequence of using peer-to-peer transmission ++to receive a copy likewise does not require acceptance. However, ++nothing other than this License grants you permission to propagate or ++modify any covered work. These actions infringe copyright if you do ++not accept this License. Therefore, by modifying or propagating a ++covered work, you indicate your acceptance of this License to do so. ++ ++ 10. Automatic Licensing of Downstream Recipients. ++ ++ Each time you convey a covered work, the recipient automatically ++receives a license from the original licensors, to run, modify and ++propagate that work, subject to this License. You are not responsible ++for enforcing compliance by third parties with this License. ++ ++ An "entity transaction" is a transaction transferring control of an ++organization, or substantially all assets of one, or subdividing an ++organization, or merging organizations. If propagation of a covered ++work results from an entity transaction, each party to that ++transaction who receives a copy of the work also receives whatever ++licenses to the work the party's predecessor in interest had or could ++give under the previous paragraph, plus a right to possession of the ++Corresponding Source of the work from the predecessor in interest, if ++the predecessor has it or can get it with reasonable efforts. ++ ++ You may not impose any further restrictions on the exercise of the ++rights granted or affirmed under this License. For example, you may ++not impose a license fee, royalty, or other charge for exercise of ++rights granted under this License, and you may not initiate litigation ++(including a cross-claim or counterclaim in a lawsuit) alleging that ++any patent claim is infringed by making, using, selling, offering for ++sale, or importing the Program or any portion of it. ++ ++ 11. Patents. ++ ++ A "contributor" is a copyright holder who authorizes use under this ++License of the Program or a work on which the Program is based. The ++work thus licensed is called the contributor's "contributor version". ++ ++ A contributor's "essential patent claims" are all patent claims ++owned or controlled by the contributor, whether already acquired or ++hereafter acquired, that would be infringed by some manner, permitted ++by this License, of making, using, or selling its contributor version, ++but do not include claims that would be infringed only as a ++consequence of further modification of the contributor version. For ++purposes of this definition, "control" includes the right to grant ++patent sublicenses in a manner consistent with the requirements of ++this License. ++ ++ Each contributor grants you a non-exclusive, worldwide, royalty-free ++patent license under the contributor's essential patent claims, to ++make, use, sell, offer for sale, import and otherwise run, modify and ++propagate the contents of its contributor version. ++ ++ In the following three paragraphs, a "patent license" is any express ++agreement or commitment, however denominated, not to enforce a patent ++(such as an express permission to practice a patent or covenant not to ++sue for patent infringement). To "grant" such a patent license to a ++party means to make such an agreement or commitment not to enforce a ++patent against the party. ++ ++ If you convey a covered work, knowingly relying on a patent license, ++and the Corresponding Source of the work is not available for anyone ++to copy, free of charge and under the terms of this License, through a ++publicly available network server or other readily accessible means, ++then you must either (1) cause the Corresponding Source to be so ++available, or (2) arrange to deprive yourself of the benefit of the ++patent license for this particular work, or (3) arrange, in a manner ++consistent with the requirements of this License, to extend the patent ++license to downstream recipients. "Knowingly relying" means you have ++actual knowledge that, but for the patent license, your conveying the ++covered work in a country, or your recipient's use of the covered work ++in a country, would infringe one or more identifiable patents in that ++country that you have reason to believe are valid. ++ ++ If, pursuant to or in connection with a single transaction or ++arrangement, you convey, or propagate by procuring conveyance of, a ++covered work, and grant a patent license to some of the parties ++receiving the covered work authorizing them to use, propagate, modify ++or convey a specific copy of the covered work, then the patent license ++you grant is automatically extended to all recipients of the covered ++work and works based on it. ++ ++ A patent license is "discriminatory" if it does not include within ++the scope of its coverage, prohibits the exercise of, or is ++conditioned on the non-exercise of one or more of the rights that are ++specifically granted under this License. You may not convey a covered ++work if you are a party to an arrangement with a third party that is ++in the business of distributing software, under which you make payment ++to the third party based on the extent of your activity of conveying ++the work, and under which the third party grants, to any of the ++parties who would receive the covered work from you, a discriminatory ++patent license (a) in connection with copies of the covered work ++conveyed by you (or copies made from those copies), or (b) primarily ++for and in connection with specific products or compilations that ++contain the covered work, unless you entered into that arrangement, ++or that patent license was granted, prior to 28 March 2007. ++ ++ Nothing in this License shall be construed as excluding or limiting ++any implied license or other defenses to infringement that may ++otherwise be available to you under applicable patent law. ++ ++ 12. No Surrender of Others' Freedom. ++ ++ If 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 convey a ++covered work so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you may ++not convey it at all. For example, if you agree to terms that obligate you ++to collect a royalty for further conveying from those to whom you convey ++the Program, the only way you could satisfy both those terms and this ++License would be to refrain entirely from conveying the Program. ++ ++ 13. Use with the GNU Affero General Public License. ++ ++ Notwithstanding any other provision of this License, you have ++permission to link or combine any covered work with a work licensed ++under version 3 of the GNU Affero General Public License into a single ++combined work, and to convey the resulting work. The terms of this ++License will continue to apply to the part which is the covered work, ++but the special requirements of the GNU Affero General Public License, ++section 13, concerning interaction through a network will apply to the ++combination as such. ++ ++ 14. Revised Versions of this License. ++ ++ The Free Software Foundation may publish revised and/or new versions of ++the GNU General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++ Each version is given a distinguishing version number. If the ++Program specifies that a certain numbered version of the GNU General ++Public License "or any later version" applies to it, you have the ++option of following the terms and conditions either of that numbered ++version or of any later version published by the Free Software ++Foundation. If the Program does not specify a version number of the ++GNU General Public License, you may choose any version ever published ++by the Free Software Foundation. ++ ++ If the Program specifies that a proxy can decide which future ++versions of the GNU General Public License can be used, that proxy's ++public statement of acceptance of a version permanently authorizes you ++to choose that version for the Program. ++ ++ Later license versions may give you additional or different ++permissions. However, no additional obligations are imposed on any ++author or copyright holder as a result of your choosing to follow a ++later version. ++ ++ 15. Disclaimer of Warranty. ++ ++ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY ++APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT ++HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY ++OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ++THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM ++IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ++ALL NECESSARY SERVICING, REPAIR OR CORRECTION. ++ ++ 16. Limitation of Liability. ++ ++ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS ++THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY ++GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE ++USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF ++DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD ++PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), ++EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF ++SUCH DAMAGES. ++ ++ 17. Interpretation of Sections 15 and 16. ++ ++ If the disclaimer of warranty and limitation of liability provided ++above cannot be given local legal effect according to their terms, ++reviewing courts shall apply local law that most closely approximates ++an absolute waiver of all civil liability in connection with the ++Program, unless a warranty or assumption of liability accompanies a ++copy of the Program in return for a fee. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++state the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ <one line to give the program's name and a brief idea of what it does.> ++ Copyright (C) <year> <name of author> ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see <http://www.gnu.org/licenses/>. ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++ If the program does terminal interaction, make it output a short ++notice like this when it starts in an interactive mode: ++ ++ <program> Copyright (C) <year> <name of author> ++ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, your program's commands ++might be different; for a GUI interface, you would use an "about box". ++ ++ You should also get your employer (if you work as a programmer) or school, ++if any, to sign a "copyright disclaimer" for the program, if necessary. ++For more information on this, and how to apply and follow the GNU GPL, see ++<http://www.gnu.org/licenses/>. ++ ++ The GNU General Public License does not permit incorporating your program ++into proprietary programs. If your program is a subroutine library, you ++may consider it more useful to permit linking proprietary applications with ++the library. If this is what you want to do, use the GNU Lesser General ++Public License instead of this License. But first, please read ++<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --cc jzboot/Makefile.am index 0000000,0000000..f963eff new file mode 100644 --- /dev/null +++ b/jzboot/Makefile.am @@@ -1,0 -1,0 +1,1 @@@ ++SUBDIRS = src diff --cc jzboot/README index 0000000,0000000..e16acdd new file mode 100644 --- /dev/null +++ b/jzboot/README @@@ -1,0 -1,0 +1,5 @@@ ++Needs libusb-1.0 (not 0.1!) to work. Readline is optional. ++To build: ++ make -C src ++If you have readline (recommended): ++ make -C src READLINE=1 diff --cc jzboot/config/boot.cfg index 0000000,0000000..15993e7 new file mode 100644 --- /dev/null +++ b/jzboot/config/boot.cfg @@@ -1,0 -1,0 +1,4 @@@ ++source config/initial.cfg ++ ++boot ++ diff --cc jzboot/config/initial.cfg index 0000000,0000000..a2c9370 new file mode 100644 --- /dev/null +++ b/jzboot/config/initial.cfg @@@ -1,0 -1,0 +1,34 @@@ ++# Configuration variables: ++# STAGE1_FILE, STAGE2_FILE ++ ++set STAGE1_FILE firmware/spl_stage1.bin ++set STAGE2_FILE firmware/spl_stage2_usb.bin ++ ++set EXTCLK 12 # Define the external crystal in MHz ++set CPUSPEED 252 # Define the PLL output frequency ++set PHMDIV 3 # Define the frequency divider ratio of PLL=CCLK:PCLK=HCLK=MCLK ++set BAUDRATE 57600 # Define the uart baudrate ++set USEUART 0 # UART number ++ ++set SDRAM_BUSWIDTH 16 # The bus width of the SDRAM in bits (16|32) ++set SDRAM_BANKS 4 # The bank number (2|4) ++set SDRAM_ROWADDR 13 # Row address width in bits (11-13) ++set SDRAM_COLADDR 9 # Column address width in bits (8-12) ++set SDRAM_ISMOBILE 0 # Define whether SDRAM is mobile SDRAM (only or Jz4750), 1: yes 0: no ++set SDRAM_ISBUSSHARE 1 # Define whether SDRAM bus share with NAND 1:shared 0:unshared ++ ++set NAND_BUSWIDTH 8 # The width of the NAND flash chip in bits (8|16|32) ++set NAND_ROWCYCLES 3 # The row address cycles (2|3) ++set NAND_PAGESIZE 2048 # The page size of the NAND chip in bytes(512|2048|4096) ++set NAND_PAGEPERBLOCK 128 # The page number per block ++set NAND_FORCEERASE 1 # The force to erase flag (0|1) ++set NAND_OOBSIZE 64 # OOB size in byte ++set NAND_ECCPOS 3 # Specify the ECC offset inside the oob data (0-[oobsize-1]) ++set NAND_BADBLOCKPOS 0 # Specify the badblock flag offset inside the oob (0-[oobsize-1]) ++set NAND_BADBLOCKPAGE 0 # Specify the page number of badblock flag inside a block(0-[PAGEPERBLOCK-1]) ++set NAND_PLANENUM 1 # The planes number of target nand flash ++set NAND_BCHBIT 8 # Specify the hardware BCH algorithm for 4750 (4|8) ++set NAND_WPPIN 0 # Specify the write protect pin number ++set NAND_BLOCKPERCHIP 4096 # Specify the block number per chip,0 means ignore ++ ++rebuildcfg diff --cc jzboot/firmware/spl_stage1.bin index 0000000,0000000..cfdcd02 new file mode 100644 Binary files differ diff --cc jzboot/firmware/spl_stage2_usb.bin index 0000000,0000000..8f11c6f new file mode 100644 Binary files differ diff --cc jzboot/include/app_config.h index 0000000,0000000..dd4307b new file mode 100644 --- /dev/null +++ b/jzboot/include/app_config.h @@@ -1,0 -1,0 +1,28 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __CONFIG__H__ ++#define __CONFIG__H__ ++ ++char *cfg_getenv(const char *variable); ++void cfg_setenv(const char *variable, const char *newval); ++void cfg_unsetenv(const char *variable); ++ ++extern char **cfg_environ; ++ ++#endif diff --cc jzboot/include/debug.h index 0000000,0000000..c5eabbd new file mode 100644 --- /dev/null +++ b/jzboot/include/debug.h @@@ -1,0 -1,0 +1,34 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __DEBUG__H__ ++#define __DEBUG__H__ ++ ++void set_debug_level(int level); ++int get_debug_level(); ++void hexdump(const void *data, size_t size); ++ ++void debug(int level, const char *fmt, ...); ++ ++#define LEVEL_SILENT 0 ++#define LEVEL_ERROR 1 ++#define LEVEL_WARNING 2 ++#define LEVEL_INFO 3 ++#define LEVEL_DEBUG 4 ++ ++#endif diff --cc jzboot/include/devmgr.h index 0000000,0000000..49a92c4 new file mode 100644 --- /dev/null +++ b/jzboot/include/devmgr.h @@@ -1,0 -1,0 +1,34 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __DEVMGR__H__ ++#define __DEVMGR__H__ ++ ++#include <stdint.h> ++ ++#define INTERFACE_BOOT 0 ++#define ENDPOINT_OUT 0x01 ++#define ENDPOINT_IN 0x81 ++ ++int is_ingenic(uint16_t vid, uint16_t pid); ++ ++void add_device(uint16_t vid, uint16_t pid, void *data); ++void enum_devices(void (*handler)(int idx, uint16_t vid, uint16_t pid, void *data)); ++void *get_device(int idx); ++ ++#endif diff --cc jzboot/include/elf.h index 0000000,0000000..591047c new file mode 100644 --- /dev/null +++ b/jzboot/include/elf.h @@@ -1,0 -1,0 +1,78 @@@ ++#ifndef __ELF__H__ ++#define __ELF__H__ ++ ++#include <stdint.h> ++ ++typedef uint16_t Elf32_Half; ++typedef uint32_t Elf32_Word; ++typedef uint32_t Elf32_Addr; ++typedef uint32_t Elf32_Off; ++typedef int32_t Elf32_Sword; ++ ++#define EI_NIDENT 16 ++#define EI_MAG0 0 ++#define EI_MAG1 1 ++#define EI_MAG2 2 ++#define EI_MAG3 3 ++#define EI_CLASS 4 ++#define EI_DATA 5 ++#define EI_VERSION 6 ++#define EI_PAD 7 ++ ++#define ELFMAG0 0x7F ++#define ELFMAG1 'E' ++#define ELFMAG2 'L' ++#define ELFMAG3 'F' ++ ++#define ELFCLASSNONE 0 ++#define ELFCLASS32 1 ++#define ELFCLASS64 2 ++ ++#define ELFDATANONE 0 ++#define ELFDATA2LSB 1 ++#define ELFDATA2MSB 2 ++ ++#define ET_NONE 0 ++#define ET_REL 1 ++#define ET_EXEC 2 ++#define ET_DYN 3 ++#define ET_CORE 4 ++ ++#define EM_MIPS 8 ++ ++#define EV_NONE 0 ++#define EV_CURRENT 1 ++ ++#define PT_NULL 0 ++#define PT_LOAD 1 ++ ++typedef struct { ++ unsigned char e_ident[EI_NIDENT]; ++ Elf32_Half e_type; ++ Elf32_Half e_machine; ++ Elf32_Word e_version; ++ Elf32_Addr e_entry; ++ Elf32_Off e_phoff; ++ Elf32_Off e_shoff; ++ Elf32_Word e_flags; ++ Elf32_Half e_ehsize; ++ Elf32_Half e_phentsize; ++ Elf32_Half e_phnum; ++ Elf32_Half e_shentsize; ++ Elf32_Half e_shnum; ++ Elf32_Half e_shstrndx; ++} Elf32_Ehdr; ++ ++typedef struct { ++ Elf32_Word p_type; ++ Elf32_Off p_offset; ++ Elf32_Addr p_vaddr; ++ Elf32_Addr p_paddr; ++ Elf32_Word p_filesz; ++ Elf32_Word p_memsz; ++ Elf32_Word p_flags; ++ Elf32_Word p_align; ++} Elf32_Phdr; ++ ++#endif ++ diff --cc jzboot/include/elfldr.h index 0000000,0000000..b4a0b9a new file mode 100644 --- /dev/null +++ b/jzboot/include/elfldr.h @@@ -1,0 -1,0 +1,10 @@@ ++#ifndef __ELFLDR__H__ ++#define __ELFLDR__H__ ++ ++int load_elf(void *ingenic, ++ const char *filename, ++ const char *args, ++ const char *initrd); ++ ++#endif ++ diff --cc jzboot/include/ingenic.h index 0000000,0000000..8c09d5f new file mode 100644 --- /dev/null +++ b/jzboot/include/ingenic.h @@@ -1,0 -1,0 +1,149 @@@ ++/* This file is based on code by Ingenic Semiconductor Co., Ltd. */ ++ ++#ifndef __INGENIC__H__ ++#define __INGENIC__H__ ++ ++#include <stdint.h> ++ ++#define VR_GET_CPU_INFO 0x00 ++#define VR_SET_DATA_ADDRESS 0x01 ++#define VR_SET_DATA_LENGTH 0x02 ++#define VR_FLUSH_CACHES 0x03 ++#define VR_PROGRAM_START1 0x04 ++#define VR_PROGRAM_START2 0x05 ++#define VR_NOR_OPS 0x06 ++#define VR_NAND_OPS 0x07 ++#define VR_SDRAM_OPS 0x08 ++#define VR_CONFIGRATION 0x09 ++#define VR_GET_NUM 0x0a ++ ++#define CMDSET_SPL 1 ++#define CMDSET_USBBOOT 2 ++ ++#define INGENIC_STAGE1 1 ++#define INGENIC_STAGE2 2 ++ ++#define STAGE1_DEBUG_BOOT 0 ++#define STAGE1_DEBUG_MEMTEST 1 ++#define STAGE1_DEBUG_GPIO_SET 2 ++#define STAGE1_DEBUG_GPIO_CLEAR 3 ++ ++#define STAGE1_BASE 0x2000 ++#define STAGE2_CODESIZE 0x400000 ++#define SDRAM_BASE 0x80000000 ++ ++#define STAGE2_IOBUF (2048 * 128) ++ ++#define DS_flash_info 0 ++#define DS_hand 1 ++ ++#define SDRAM_LOAD 0 ++ ++#define NAND_QUERY 0 ++#define NAND_INIT 1 ++#define NAND_MARK_BAD 2 ++#define NAND_READ_OOB 3 ++#define NAND_READ_RAW 4 ++#define NAND_ERASE 5 ++#define NAND_READ 6 ++#define NAND_PROGRAM 7 ++#define NAND_READ_TO_RAM 8 ++ ++#define OOB_ECC 0 ++#define OOB_NO_ECC 1 ++#define NO_OOB 2 ++#define NAND_RAW (1 << 7) ++ ++#define PROGRESS_INIT 0 ++#define PROGRESS_UPDATE 1 ++#define PROGRESS_FINI 2 ++ ++typedef struct { ++ /* debug args */ ++ uint8_t debug_ops; ++ uint8_t pin_num; ++ uint32_t start; ++ uint32_t size; ++} __attribute__((packed)) ingenic_stage1_debug_t; ++ ++typedef struct { ++ /* CPU ID */ ++ uint32_t cpu_id; ++ ++ /* PLL args */ ++ uint8_t ext_clk; ++ uint8_t cpu_speed; ++ uint8_t phm_div; ++ uint8_t use_uart; ++ uint32_t baudrate; ++ ++ /* SDRAM args */ ++ uint8_t bus_width; ++ uint8_t bank_num; ++ uint8_t row_addr; ++ uint8_t col_addr; ++ uint8_t is_mobile; ++ uint8_t is_busshare; ++ ++ ingenic_stage1_debug_t debug; ++} __attribute__((packed)) firmware_config_t; ++ ++typedef struct { ++ /* nand flash info */ ++ uint32_t cpuid; /* cpu type */ ++ uint32_t nand_bw; /* bus width */ ++ uint32_t nand_rc; /* row cycle */ ++ uint32_t nand_ps; /* page size */ ++ uint32_t nand_ppb; /* page number per block */ ++ uint32_t nand_force_erase; ++ uint32_t nand_pn; /* page number in total */ ++ uint32_t nand_os; /* oob size */ ++ uint32_t nand_eccpos; ++ uint32_t nand_bbpage; ++ uint32_t nand_bbpos; ++ uint32_t nand_plane; ++ uint32_t nand_bchbit; ++ uint32_t nand_wppin; ++ uint32_t nand_bpc; /* block number per chip */ ++} nand_config_t; ++ ++typedef struct { ++ uint8_t vid; ++ uint8_t pid; ++ uint8_t chip; ++ uint8_t page; ++ uint8_t plane; ++} nand_info_t; ++ ++ ++typedef struct { ++ void (*cmdset_change)(uint32_t cmdset, void *arg); ++ void (*progress)(int action, int value, int max, void *arg); ++} ingenic_callbacks_t; ++ ++void *ingenic_open(void *usb_hndl); ++void ingenic_close(void *hndl); ++void ingenic_set_callbacks(void *hndl, const ingenic_callbacks_t *callbacks, void *arg); ++ ++int ingenic_redetect(void *hndl); ++int ingenic_cmdset(void *hndl); ++int ingenic_type(void *hndl); ++uint32_t ingenic_sdram_size(void *hndl); ++ ++int ingenic_rebuild(void *hndl); ++int ingenic_loadstage(void *hndl, int id, const char *filename); ++int ingenic_stage1_debugop(void *device, const char *filename, uint32_t op, uint32_t pin, uint32_t base, uint32_t size); ++int ingenic_memtest(void *hndl, const char *filename, uint32_t base, uint32_t size, uint32_t *fail); ++ ++int ingenic_configure_stage2(void *hndl); ++int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size); ++int ingenic_load_sdram_file(void *hndl, uint32_t base, const char *filename); ++int ingenic_go(void *hndl, uint32_t address); ++ ++int ingenic_query_nand(void *hndl, int cs, nand_info_t *info); ++int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const char *filename); ++int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *filename); ++int ingenic_erase_nand(void *hndl, int cs, int start, int blocks); ++int ingenic_load_nand(void *hndl, int cs, int start, int pages, uint32_t base); ++ ++#endif diff --cc jzboot/include/shell.h index 0000000,0000000..f9255a4 new file mode 100644 --- /dev/null +++ b/jzboot/include/shell.h @@@ -1,0 -1,0 +1,49 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __SHELL__H__ ++#define __SHELL__H__ ++ ++#ifndef SHELL_INTERNALS ++typedef void shell_context_t; ++#endif ++ ++typedef struct shell_command { ++ const char *cmd; ++ const char *description; ++ int (*handler)(shell_context_t *ctx, int argc, char *argv[]); ++ const char *args; ++} shell_command_t; ++ ++shell_context_t *shell_init(void *ingenic); ++void shell_fini(shell_context_t *context); ++ ++void shell_interactive(shell_context_t *ctx); ++int shell_source(shell_context_t *ctx, const char *filename); ++int shell_execute(shell_context_t *ctx, const char *input); ++void *shell_device(shell_context_t *ctx); ++int shell_run(shell_context_t *ctx, int argc, char *argv[]); ++ ++void shell_exit(shell_context_t *ctx, int val); ++int shell_enumerate_commands(shell_context_t *ctx, int (*callback)(shell_context_t *ctx, const shell_command_t *cmd, void *arg), void *arg); ++ ++extern const shell_command_t spl_cmdset[]; ++extern const shell_command_t usbboot_cmdset[]; ++extern const shell_command_t builtin_cmdset[]; ++ ++#endif diff --cc jzboot/include/shell_internal.h index 0000000,0000000..0378e26 new file mode 100644 --- /dev/null +++ b/jzboot/include/shell_internal.h @@@ -1,0 -1,0 +1,63 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __SHELL_INTERNAL__H__ ++#define __SHELL_INTERNAL__H__ ++ ++#define SHELL_INTERNALS ++#define STATE_WANTSTR 0 ++#define STATE_WANTSPACE 1 ++ ++#define TOK_SEPARATOR 1 ++#define TOK_STRING 2 ++#define TOK_SPACE 3 ++#define TOK_COMMENT 4 ++ ++typedef struct { ++ void *device; ++ char linebuf[512]; ++ char *strval; ++ char *line; ++ const struct shell_command *set_cmds; ++ int shell_exit; ++ int prev_progress; ++} shell_context_t; ++ ++ ++typedef struct { ++ int argc; ++ char **argv; ++} shell_run_data_t; ++ ++int shell_pull(shell_context_t *ctx, char *buf, int maxlen); ++ ++#ifndef FLEX_SCANNER ++typedef void *yyscan_t; ++int yylex_init(yyscan_t *ptr_yy_globals); ++int yylex_init_extra(shell_context_t *user_defined, yyscan_t *ptr_yy_globals); ++int yylex(yyscan_t yyscanner) ; ++int yylex_destroy (yyscan_t yyscanner) ; ++#else ++#define YY_EXTRA_TYPE shell_context_t * ++#define YY_INPUT(buf, result, max_size) result = shell_pull(yyextra, buf, max_size); ++#endif ++ ++#include "shell.h" ++ ++#endif ++ diff --cc jzboot/include/usbdev.h index 0000000,0000000..6bc24d1 new file mode 100644 --- /dev/null +++ b/jzboot/include/usbdev.h @@@ -1,0 -1,0 +1,38 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com>, ++ * Peter Zotov <whitequark@whitequark.org> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __USBDEV__H__ ++#define __USBDEV__H__ ++ ++#include <stdint.h> ++ ++int usbdev_init(); ++void usbdev_fini(); ++ ++#define USBDEV_FROMDEV 0 ++#define USBDEV_TODEV 1 ++ ++int usbdev_enumerate(); ++void *usbdev_open(void *dev); ++void usbdev_close(void *hndl); ++int usbdev_vendor(void *hndl, int direction, uint8_t req, uint16_t value, uint16_t index, void *data, uint16_t size); ++int usbdev_sendbulk(void *hndl, void *data, int size); ++int usbdev_recvbulk(void *hndl, void *data, int size); ++ ++#endif diff --cc jzboot/script/dump_minios.scr index 0000000,0000000..d5a027a new file mode 100644 --- /dev/null +++ b/jzboot/script/dump_minios.scr @@@ -1,0 -1,0 +1,25 @@@ ++echo "Dumping script" ++nquery 0 ++ ++#set NAND_RAW 1 ++set NAND_ECCPOS 3 ++rebuildcfg ++boot ++ ++echo "Configured for bootloader IO!" ++ ++ndump_oob 0 0 128 "dump/nand.bin" ++ ++set NAND_RAW ++set NAND_ECCPOS 8 ++rebuildcfg ++boot ++ ++echo "Configuration restored" ++ ++ndump 0 128 66 "dump/loader.bin" ++ndump 0 256 1 "dump/def_boot.bin" ++ndump 0 512 3061 "dump/img_boot.bin" ++ndump 0 8192 8192 "dump/minios.bin" ++ndump 0 32768 32768 "dump/res.bin" ++ diff --cc jzboot/script/ecc_boot.scr index 0000000,0000000..a895357 new file mode 100644 --- /dev/null +++ b/jzboot/script/ecc_boot.scr @@@ -1,0 -1,0 +1,3 @@@ ++set NAND_ECCPOS 3 ++rebuildcfg ++boot diff --cc jzboot/script/ecc_normal.scr index 0000000,0000000..7f54054 new file mode 100644 --- /dev/null +++ b/jzboot/script/ecc_normal.scr @@@ -1,0 -1,0 +1,3 @@@ ++set NAND_ECCPOS 8 ++rebuildcfg ++boot diff --cc jzboot/script/flash_xz0032_linux.scr index 0000000,0000000..0c55582 new file mode 100644 --- /dev/null +++ b/jzboot/script/flash_xz0032_linux.scr @@@ -1,0 -1,0 +1,27 @@@ ++#11.12.2010 --rzk ++# orig from http://pastie.org/1368585 ++# fixes by whitequark ++ ++echo "---- Linux kernel+loader+rootfs flashing script ----" ++ ++echo "Including initial config for 4750 XZ0032 board" ++source config/boot.cfg ++echo "jzboot successfully configured for XZ0032" ++ ++echo "Erasing all flash" ++nerase 0 0 4096 ++echo "Erased all flash" ++ ++echo "Flashing loader" ++nprogram 0 0 u-boot-nand.bin ++echo "Flashed loader" ++ ++echo "Flashing kernel" ++nprogram 0 512 uImage ++echo "Flashed kernel" ++ ++echo "Flashing rootfs" ++nprogram_oob 0 8192 rootfs.ubifs ++echo "Flashed rootfs" ++ ++echo "---- All done ----" diff --cc jzboot/script/restore_minios.scr index 0000000,0000000..cb8f369 new file mode 100644 --- /dev/null +++ b/jzboot/script/restore_minios.scr @@@ -1,0 -1,0 +1,42 @@@ ++#11.12.2010 --rzk ++# orig from http://pastie.org/1368586 ++# fixes by whitequark ++ ++echo "---- Restore MINIOS script ----" ++echo "Including initial config for 4750 XZ0032 board" ++source config/boot.cfg ++echo "jzboot successfully configured for XZ0032" ++ ++echo "Erasing all flash" ++nerase 0 0 4096 ++echo "Erased all flash" ++ ++echo "Configuring for bootloader IO" ++source script/ecc_boot.scr ++echo "Configured for bootloader IO" ++ ++echo "Flashing SPL (nand.bin)" ++nprogram 0 0 nand.bin ++echo "Flashed SPL (nand.bin)" ++ ++echo "Configuring for standard IO" ++source script/ecc_normal.scr ++echo "Configured for standard IO" ++ ++echo "Flashing loader.bin" ++nprogram 0 128 dump/loader.bin ++echo "Flashed loader.bin" ++echo "Flashing def_boot.bin" ++nprogram 0 256 dump/def_boot.bin ++echo "Flashed def_boot.bin" ++echo "Flashing img_boot.bin" ++nprogram 0 512 dump/img_boot.bin ++echo "Flashed img_boot.bin" ++echo "Flashing minios.bin" ++nprogram 0 8192 dump/minios.bin ++echo "Flashed minios.bin" ++echo "Flashing res.bin" ++nprogram 0 32768 dump/res.bin ++echo "Flashed res.bin" ++ ++echo "---- All done ----" diff --cc jzboot/src/Makefile.am index 0000000,0000000..cee8e39 new file mode 100644 --- /dev/null +++ b/jzboot/src/Makefile.am @@@ -1,0 -1,0 +1,6 @@@ ++AM_CFLAGS = --std=gnu99 -Wall -I../include ++ ++bin_PROGRAMS = jzboot ++jzboot_SOURCES = debug.c devmgr.c ingenic.c main.c shell_lex.c \ ++ usbdev.c shell.c shell_builtins.c config.c spl_cmdset.c \ ++ usbboot_cmdset.c elfldr.c diff --cc jzboot/src/config.c index 0000000,0000000..d58294c new file mode 100644 --- /dev/null +++ b/jzboot/src/config.c @@@ -1,0 -1,0 +1,110 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <string.h> ++#include <stdlib.h> ++#include <string.h> ++#include <stdio.h> ++ ++#include "app_config.h" ++#include "debug.h" ++ ++char **cfg_environ = NULL; ++ ++static int env_size() { ++ int size = 0; ++ ++ if(cfg_environ == NULL) ++ return 0; ++ ++ for(int i = 0; cfg_environ[i] != NULL; i++) ++ size++; ++ ++ return size; ++} ++ ++char *cfg_getenv(const char *variable) { ++ if(cfg_environ == NULL) ++ return NULL; ++ ++ size_t len = strlen(variable); ++ ++ for(int i = 0; cfg_environ[i] != NULL; i++) { ++ char *str = cfg_environ[i], *sep = strchr(str, '='); ++ ++ if(sep - str == len && memcmp(str, variable, len) == 0) { ++ return sep + 1; ++ } ++ } ++ ++ return NULL; ++} ++ ++void cfg_unsetenv(const char *variable) { ++ int size = env_size(); ++ ++ if(size == 0) ++ return; ++ ++ size_t len = strlen(variable); ++ ++ for(int i = 0; cfg_environ[i] != NULL; i++) { ++ char *str = cfg_environ[i], *sep = strchr(str, '='); ++ ++ if(sep - str == len && memcmp(str, variable, len) == 0) { ++ free(str); ++ ++ memcpy(cfg_environ + i, cfg_environ + i + 1, sizeof(char *) * (size - i)); ++ ++ cfg_environ = realloc(cfg_environ, sizeof(char *) * size); ++ ++ return; ++ } ++ } ++} ++ ++void cfg_setenv(const char *variable, const char *newval) { ++ int size = env_size(); ++ ++ size_t len = strlen(variable); ++ ++ char *newstr = malloc(len + 1 + strlen(newval) + 1); ++ ++ strcpy(newstr, variable); ++ strcat(newstr, "="); ++ strcat(newstr, newval); ++ ++ if(size > 0) { ++ for(int i = 0; cfg_environ[i] != NULL; i++) { ++ char *str = cfg_environ[i], *sep = strchr(str, '='); ++ ++ if(sep - str == len && memcmp(str, variable, len) == 0) { ++ free(str); ++ ++ cfg_environ[i] = newstr; ++ ++ return; ++ } ++ } ++ } ++ ++ cfg_environ = realloc(cfg_environ, sizeof(char *) * (size + 2)); ++ ++ cfg_environ[size] = newstr; ++ cfg_environ[size + 1] = NULL; ++} diff --cc jzboot/src/debug.c index 0000000,0000000..d9fa13b new file mode 100644 --- /dev/null +++ b/jzboot/src/debug.c @@@ -1,0 -1,0 +1,82 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdarg.h> ++#include <stdio.h> ++ ++#include "debug.h" ++ ++static int debug_level = LEVEL_ERROR; ++ ++void set_debug_level(int level) { ++ debug_level = level; ++} ++ ++int get_debug_level() { ++ return debug_level; ++} ++ ++void debug(int level, const char *fmt, ...) { ++ va_list list; ++ ++ va_start(list, fmt); ++ ++ if(level <= debug_level) { ++ if(level <= LEVEL_ERROR) ++ vfprintf(stderr, fmt, list); ++ else ++ vprintf(fmt, list); ++ } ++ ++ va_end(list); ++} ++ ++void hexdump(const void *data, size_t size) { ++ const unsigned char *bytes = data; ++ ++ for(int i = 0; i < size; i+= 16) { ++ debug(LEVEL_DEBUG, "%04X ", i); ++ ++ int chunk_size = size - i; ++ if(chunk_size > 16) ++ chunk_size = 16; ++ ++ for(int j = 0; j < chunk_size; j++) { ++ debug(LEVEL_DEBUG, "%02X ", bytes[i + j]); ++ ++ if(j == 7) ++ debug(LEVEL_DEBUG, " "); ++ } ++ ++ for(int j = 0; j < 16 - chunk_size; j++) { ++ debug(LEVEL_DEBUG, " "); ++ ++ if(j == 8) ++ debug(LEVEL_DEBUG, " "); ++ } ++ ++ debug(LEVEL_DEBUG, "|"); ++ ++ for(int j = 0; j < chunk_size; j++) { ++ debug(LEVEL_DEBUG, "%c", isprint(bytes[i + j]) ? bytes[i + j] : '.'); ++ } ++ ++ debug(LEVEL_DEBUG, "|\n"); ++ } ++} ++ diff --cc jzboot/src/devmgr.c index 0000000,0000000..6e83ac4 new file mode 100644 --- /dev/null +++ b/jzboot/src/devmgr.c @@@ -1,0 -1,0 +1,77 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++ ++#include "devmgr.h" ++#include "debug.h" ++ ++typedef struct device { ++ struct device *next; ++ uint16_t vid; ++ uint16_t pid; ++ void *data; ++} usb_device_t; ++ ++static const struct { ++ uint16_t vid; ++ uint16_t pid; ++} devices[] = { ++ { 0x601a, 0x4740 }, ++ { 0x601a, 0x4750 }, ++ { 0x601a, 0x4760 }, ++ { 0, 0 } ++}; ++ ++static usb_device_t *list = NULL; ++ ++int is_ingenic(uint16_t vid, uint16_t pid) { ++ for(int i = 0; devices[i].vid != 0; i++) ++ if(devices[i].vid == vid && devices[i].pid == pid) ++ return 1; ++ ++ return 0; ++} ++ ++void add_device(uint16_t vid, uint16_t pid, void *data) { ++ usb_device_t *newdev = malloc(sizeof(usb_device_t)); ++ ++ newdev->next = list; ++ newdev->vid = vid; ++ newdev->pid = pid; ++ newdev->data = data; ++ ++ list = newdev; ++ ++ debug(LEVEL_DEBUG, "Device manager: registered %04hX:%04hX with data %p\n", vid, pid, data); ++} ++ ++void enum_devices(void (*handler)(int idx, uint16_t vid, uint16_t pid, void *data)) { ++ int idx = 0; ++ ++ for(usb_device_t *dev = list; dev; dev = dev->next) ++ handler(idx++, dev->vid, dev->pid, dev->data); ++} ++ ++void *get_device(int idx) { ++ for(usb_device_t *dev = list; dev; dev = dev->next) ++ if(idx-- == 0) ++ return dev->data; ++ ++ return NULL; ++} diff --cc jzboot/src/elfldr.c index 0000000,0000000..fc72573 new file mode 100644 --- /dev/null +++ b/jzboot/src/elfldr.c @@@ -1,0 -1,0 +1,318 @@@ ++#include <sys/stat.h> ++#include <stdio.h> ++#include <errno.h> ++#include <string.h> ++#include <stdlib.h> ++#include "debug.h" ++#include "elfldr.h" ++#include "elf.h" ++#include "ingenic.h" ++ ++#define max(a, b) ((a) > (b) ? (a) : (b)) ++#define ALIGN(a) ((a + 4095) & ~4095) ++ ++#define TRAMP_ARGC 0 // command line argument count ++#define TRAMP_ARGV 1 // command line argument array ++#define TRAMP_ARG2 2 ++#define TRAMP_ARG3 3 ++#define TRAMP_ENTRY 4 // Kernel entry point ++ ++static const uint32_t trampoline_template[] = { ++ 0x3c04ffff, // lui a0, 0xffff ++ 0x3484ffff, // ori a0,a0,0xffff ++ ++ 0x3c05ffff, // lui a1, 0xffff ++ 0x34a5ffff, // ori a1,a1,0xffff ++ ++ 0x3c06ffff, // lui a2, 0xffff ++ 0x34c6ffff, // ori a2,a2,0xffff ++ ++ 0x3c07ffff, // lui a3, 0xffff ++ 0x34e7ffff, // ori a3,a3,0xffff ++ ++ 0x3c08ffff, // lui t0, 0xffff ++ 0x3508ffff, // ori t0,t0,0xffff ++ 0x01000008, // jr t0 ++ 0x00000000, // nop ++}; ++ ++static const unsigned char valid_ident[EI_PAD] = { ++ [EI_MAG0] = ELFMAG0, ++ [EI_MAG1] = ELFMAG1, ++ [EI_MAG2] = ELFMAG2, ++ [EI_MAG3] = ELFMAG3, ++ [EI_CLASS] = ELFCLASS32, ++ [EI_DATA] = ELFDATA2LSB, ++ [EI_VERSION] = EV_CURRENT ++}; ++ ++static int load_segment(void *ingenic, void *data, uint32_t base, uint32_t filesz, uint32_t memsz) { ++ uint32_t end = base + memsz, tail = memsz - filesz; ++ int ret = 0; ++ ++ printf("Loading segment: base 0x%08X, file 0x%08X, mem 0x%08X\n", base, filesz, memsz); ++ ++ if(end > ingenic_sdram_size(ingenic) + SDRAM_BASE - STAGE2_CODESIZE) { ++ fputs(" Segment doesn't fit into SDRAM\n", stderr); ++ ++ return -1; ++ } ++ ++ if(filesz && ingenic_load_sdram(ingenic, data, base, filesz) == -1) ++ return -1; ++ ++ if(tail) { ++ char *dummy_data = malloc(tail); ++ ++ if(dummy_data == NULL) ++ return -1; ++ ++ memset(dummy_data, 0, tail); ++ ++ ret = ingenic_load_sdram(ingenic, dummy_data, base + filesz, tail); ++ ++ free(dummy_data); ++ } ++ ++ return ret; ++} ++ ++static int load_elf_image(FILE *elf, void *ingenic, uint32_t *entry, uint32_t *end) { ++ Elf32_Ehdr ehdr; ++ Elf32_Phdr phdr; ++ int i, ret; ++ char *data; ++ ++ if(fread(&ehdr, 1, sizeof(Elf32_Ehdr), elf) != sizeof(Elf32_Ehdr)) { ++ if(feof(elf)) ++ errno = EINVAL; ++ ++ return -1; ++ } ++ ++ *entry = ehdr.e_entry; ++ ++ if(memcmp(ehdr.e_ident, valid_ident, EI_PAD) != 0 || ehdr.e_type != ET_EXEC || ehdr.e_machine != EM_MIPS || ehdr.e_version != EV_CURRENT ++ || ehdr.e_phoff == 0 || ehdr.e_phentsize != sizeof(Elf32_Phdr)) { ++ ++ fputs("Bad ELF identification\n", stderr); ++ ++ errno = EINVAL; ++ ++ return -1; ++ } ++ ++ fseek(elf, ehdr.e_phoff, SEEK_SET); ++ ++ *end = 0; ++ ++ for(i = 0; i < ehdr.e_phnum; i++) { ++ if(fread(&phdr, 1, sizeof(Elf32_Phdr), elf) != sizeof(Elf32_Phdr)) { ++ if(feof(elf)) ++ errno = EINVAL; ++ ++ return -1; ++ } ++ ++ if(phdr.p_type == PT_LOAD) { ++ data = malloc(phdr.p_filesz); ++ ++ if(data == NULL) ++ return -1; ++ ++ long save = ftell(elf); ++ fseek(elf, phdr.p_offset, SEEK_SET); ++ ret = fread(data, 1, phdr.p_filesz, elf); ++ fseek(elf, save, SEEK_SET); ++ ++ if(ret != phdr.p_filesz) { ++ free(data); ++ ++ if(feof(elf)) ++ errno = EINVAL; ++ ++ return -1; ++ } ++ ++ ret = load_segment(ingenic, data, phdr.p_paddr, phdr.p_filesz, phdr.p_memsz); ++ ++ free(data); ++ ++ if(ret == -1) ++ return -1; ++ ++ *end = max(phdr.p_paddr + phdr.p_memsz, *end); ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static void trampoline_set(uint32_t *trampoline, int index, ++ uint32_t value) { ++ index *= 2; ++ ++ trampoline[index] = (trampoline[index] & 0xFFFF0000) | ((value & 0xFFFF0000) >> 16); ++ trampoline[index + 1] = (trampoline[index + 1] & 0xFFFF0000) | (value & 0x0000FFFF); ++} ++ ++static int load_args(void *ingenic, uint32_t base, const char *filename, ++ const char *const *args, int *pargc, uint32_t *end) { ++ ++ size_t total_len = 0; ++ int argc = 0; ++ ++ for(int i = 0; args[i]; i++) { ++ size_t len = strlen(args[i]); ++ total_len += len + 1; ++ ++ for(int j = 0; j < len; j++) ++ if(args[i][j] == ' ') ++ argc++; ++ ++ argc++; ++ } ++ ++ *pargc = argc; ++ *end = base + total_len + sizeof(uint32_t) * argc; ++ ++ uint32_t *buf = malloc(sizeof(uint32_t) * argc + total_len); ++ if(buf == NULL) ++ return -1; ++ ++ char *cmdline = (char *)(buf + argc); ++ size_t off = 0; ++ ++ for(int i = 0; args[i]; i++) { ++ size_t len = strlen(args[i]); ++ memcpy(cmdline + off, args[i], len + 1); ++ ++ if(args[i + 1]) ++ cmdline[off + len] = ' '; ++ ++ off += len + 1; ++ } ++ ++ printf("Compiled cmdline: '%s'\n", cmdline); ++ ++ uint32_t offset = 0; ++ char *ptr = cmdline; ++ ++ for(int i = 0; i < argc; i++) { ++ buf[i] = base + argc * sizeof(uint32_t) + offset; ++ ++ ptr = strchr(ptr, ' '); ++ ++ if(ptr == NULL) ++ break; ++ ++ *ptr++ = 0; ++ offset = ptr - cmdline; ++ } ++ ++ int ret = load_segment(ingenic, ++ buf, ++ base, ++ sizeof(uint32_t) * argc + total_len, ++ sizeof(uint32_t) * argc + total_len); ++ free(buf); ++ ++ return ret; ++} ++ ++int load_elf(void *ingenic, ++ const char *filename, ++ const char *args, ++ const char *initrd) { ++ ++ uint32_t entry, end, trampoline_base, args_base; ++ uint32_t initrd_base, initrd_size; ++ ++ int argc; ++ const char *all_args[4] = { filename, args, NULL, NULL }; ++ char initrd_args[64]; ++ ++ printf( ++ "Loading kernel %s:\n" ++ " Command line: '%s'\n", ++ filename, ++ args ++ ); ++ ++ FILE *elf = fopen(filename, "rb"); ++ ++ if(elf == NULL) ++ return -1; ++ ++ int ret = load_elf_image(elf, ingenic, &entry, &end); ++ ++ fclose(elf); ++ ++ if(ret == -1) ++ return -1; ++ ++ if(initrd) { ++ struct stat statbuf; ++ ++ initrd_base = ALIGN(end); ++ ++ if(stat(initrd, &statbuf) == -1) ++ return -1; ++ ++ initrd_size = statbuf.st_size; ++ ++ printf("Loading initrd to 0x%08X, size 0x%08X\n", ++ initrd_base, initrd_size); ++ ++ ++ end = initrd_base + initrd_size; ++ ++ if(end > ingenic_sdram_size(ingenic) + SDRAM_BASE - STAGE2_CODESIZE) { ++ fputs(" Initrd doesn't fit into SDRAM\n", stderr); ++ ++ return -1; ++ } ++ ++ if(ingenic_load_sdram_file(ingenic, initrd_base, initrd) == -1) ++ return -1; ++ ++ snprintf(initrd_args, sizeof(initrd_args), ++ "rd_start=0x%08X rd_size=0x%08X", ++ initrd_base, initrd_size); ++ ++ all_args[2] = initrd_args; ++ } ++ ++ args_base = ALIGN(end); ++ ++ if(load_args(ingenic, args_base, filename, all_args, &argc, &end) == -1) ++ return -1; ++ ++ trampoline_base = ALIGN(end); ++ end = trampoline_base + sizeof(trampoline_template); ++ ++ uint32_t *trampoline = malloc(sizeof(trampoline_template)); ++ if(trampoline == NULL) ++ return -1; ++ ++ memcpy(trampoline, trampoline_template, sizeof(trampoline_template)); ++ trampoline_set(trampoline, TRAMP_ARGC, argc); ++ trampoline_set(trampoline, TRAMP_ARGV, args_base); ++ trampoline_set(trampoline, TRAMP_ARG2, 0); ++ trampoline_set(trampoline, TRAMP_ARG3, 0); ++ trampoline_set(trampoline, TRAMP_ENTRY, entry); ++ ++ ret = load_segment(ingenic, trampoline, trampoline_base, sizeof(trampoline_template), sizeof(trampoline_template)); ++ ++ free(trampoline); ++ ++ if(ret == -1) ++ return -1; ++ ++ printf("Image end: 0x%08X, entry: 0x%08X\n", end, entry); ++ ++ //return 0; ++ return ingenic_go(ingenic, trampoline_base); ++} ++ diff --cc jzboot/src/ingenic.c index 0000000,0000000..2be21ed new file mode 100644 --- /dev/null +++ b/jzboot/src/ingenic.c @@@ -1,0 -1,0 +1,733 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com>, ++ * Peter Zotov <whitequark@whitequark.org> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdlib.h> ++#include <errno.h> ++#include <string.h> ++#include <stdio.h> ++#include <unistd.h> ++#include <ctype.h> ++ ++#include "ingenic.h" ++#include "usbdev.h" ++#include "debug.h" ++#include "app_config.h" ++ ++#define HANDLE ingenic_handle_t *handle = hndl ++#define BUILDTYPE(cmdset, id) (((cmdset) << 16) | (0x##id & 0xFFFF)) ++#define CPUID(id) ((id) & 0xFFFF) ++#define CMDSET(id) (((id) & 0xFFFF0000) >> 16) ++ ++#define CFGOPT(name, var, exp) { \ ++ char *str = cfg_getenv(name); \ ++ if(str == NULL) { \ ++ debug(LEVEL_ERROR, "%s is not set\n", name); errno = EINVAL; return -1; }; \ ++ int v = atoi(str); \ ++ if(!(exp)) { debug(LEVEL_ERROR, "%s must be in %s\n", name, #exp); return -1; }; \ ++ var = v; \ ++ } ++ ++#define NOPT(name, var, exp) { \ ++ char *str = cfg_getenv("NAND_" name); \ ++ if(str == NULL) { debug(LEVEL_ERROR, "%s is not set\n", "NAND_" name); errno = EINVAL; return -1; }; \ ++ int v = atoi(str); \ ++ if(!(exp)) { debug(LEVEL_ERROR, "%s must be in %s\n", "NAND_" name, #exp); return -1; }; \ ++ var = v; \ ++} ++ ++#define CALLBACK(function, ...) if(handle->callbacks && handle->callbacks->function) handle->callbacks->function(__VA_ARGS__, handle->callbacks_data) ++ ++typedef struct { ++ void *usb; ++ uint32_t type; ++ uint32_t total_sdram_size; ++ ++ const ingenic_callbacks_t *callbacks; ++ void *callbacks_data; ++ ++ firmware_config_t cfg; ++ nand_config_t nand; ++} ingenic_handle_t; ++ ++static const struct { ++ const char * const magic; ++ uint32_t id; ++} magic_list[] = { ++ { "JZ4740V1", BUILDTYPE(CMDSET_SPL, 4740) }, ++ { "JZ4750V1", BUILDTYPE(CMDSET_SPL, 4750) }, ++ { "JZ4760V1", BUILDTYPE(CMDSET_SPL, 4760) }, ++ ++ { "Boot4740", BUILDTYPE(CMDSET_USBBOOT, 4740) }, ++ { "Boot4750", BUILDTYPE(CMDSET_USBBOOT, 4750) }, ++ { "Boot4760", BUILDTYPE(CMDSET_USBBOOT, 4760) }, ++ ++ { NULL, 0 } ++}; ++ ++static uint32_t ingenic_probe(void *usb_hndl) { ++ char magic[9]; ++ ++ if(usbdev_vendor(usb_hndl, USBDEV_FROMDEV, VR_GET_CPU_INFO, 0, 0, magic, 8) == -1) ++ return 0; ++ ++ magic[8] = 0; ++ ++ for(int i = 0; magic_list[i].magic != NULL; i++) ++ if(strcmp(magic_list[i].magic, magic) == 0) ++ return magic_list[i].id; ++ ++ debug(LEVEL_ERROR, "Unknown CPU: '%s'\n", magic); ++ errno = EINVAL; ++ return 0; ++} ++ ++void *ingenic_open(void *usb_hndl) { ++ uint32_t type = ingenic_probe(usb_hndl); ++ ++ if(type == 0) ++ return NULL; ++ ++ ingenic_handle_t *ret = malloc(sizeof(ingenic_handle_t)); ++ ret->usb = usb_hndl; ++ ret->type = type; ++ ret->callbacks = NULL; ++ ++ return ret; ++} ++ ++int ingenic_redetect(void *hndl) { ++ HANDLE; ++ ++ uint32_t type = ingenic_probe(handle->usb); ++ ++ if(type == 0) ++ return -1; ++ ++ uint32_t prev = handle->type; ++ ++ handle->type = type; ++ ++ if(CMDSET(prev) != CMDSET(type)) { ++ CALLBACK(cmdset_change, CMDSET(type)); ++ } ++ ++ return 0; ++} ++ ++void ingenic_set_callbacks(void *hndl, const ingenic_callbacks_t *callbacks, void *arg) { ++ HANDLE; ++ ++ handle->callbacks = callbacks; ++ handle->callbacks_data = arg; ++} ++ ++int ingenic_cmdset(void *hndl) { ++ HANDLE; ++ ++ return CMDSET(handle->type); ++} ++ ++int ingenic_type(void *hndl) { ++ HANDLE; ++ ++ return CPUID(handle->type); ++} ++ ++void ingenic_close(void *hndl) { ++ HANDLE; ++ ++ free(handle); ++} ++ ++int ingenic_rebuild(void *hndl) { ++ HANDLE; ++ unsigned int cpu_speed; /* the uint8_t in handle structure won't do for values > 255 */ ++ ++ handle->cfg.cpu_id = CPUID(handle->type); ++ ++ CFGOPT("EXTCLK", handle->cfg.ext_clk, v <= 27 && v >= 12); ++ CFGOPT("CPUSPEED", cpu_speed, (v % 12) == 0); ++ handle->cfg.cpu_speed = cpu_speed / handle->cfg.ext_clk; ++ CFGOPT("PHMDIV", handle->cfg.phm_div, v <= 32 && v >= 2); ++ CFGOPT("USEUART", handle->cfg.use_uart, 1); ++ CFGOPT("BAUDRATE", handle->cfg.baudrate, 1); ++ ++ CFGOPT("SDRAM_BUSWIDTH", handle->cfg.bus_width, (v == 16) || (v == 32)); ++ handle->cfg.bus_width = handle->cfg.bus_width == 16 ? 1 : 0; ++ CFGOPT("SDRAM_BANKS", handle->cfg.bank_num, (v >= 4) && ((v % 4) == 0)); ++ handle->cfg.bank_num /= 4; ++ CFGOPT("SDRAM_ROWADDR", handle->cfg.row_addr, 1); ++ CFGOPT("SDRAM_COLADDR", handle->cfg.col_addr, 1); ++ CFGOPT("SDRAM_ISMOBILE", handle->cfg.is_mobile, v == 0 || v == 1); ++ CFGOPT("SDRAM_ISBUSSHARE", handle->cfg.is_busshare, v == 0 || v == 1); ++ ++ memset(&handle->cfg.debug, 0, sizeof(ingenic_stage1_debug_t)); ++ ++ handle->total_sdram_size = (uint32_t) ++ (2 << (handle->cfg.row_addr + handle->cfg.col_addr - 1)) * 2 ++ * (handle->cfg.bank_num + 1) * 2 ++ * (2 - handle->cfg.bus_width); ++ ++ handle->nand.cpuid = CPUID(handle->type); ++ ++ NOPT("BUSWIDTH", handle->nand.nand_bw, 1); ++ NOPT("ROWCYCLES", handle->nand.nand_rc, 1); ++ NOPT("PAGESIZE", handle->nand.nand_ps, 1); ++ NOPT("PAGEPERBLOCK", handle->nand.nand_ppb, 1); ++ NOPT("FORCEERASE", handle->nand.nand_force_erase, 1); ++// FIXME: pn is not set by xburst-tools usbboot. Is this intended? ++ NOPT("OOBSIZE", handle->nand.nand_os, 1); ++ NOPT("ECCPOS", handle->nand.nand_eccpos, 1); ++ NOPT("BADBLOCKPOS", handle->nand.nand_bbpos, 1); ++ NOPT("BADBLOCKPAGE", handle->nand.nand_bbpage, 1); ++ NOPT("PLANENUM", handle->nand.nand_plane, 1); ++ NOPT("BCHBIT", handle->nand.nand_bchbit, 1); ++ NOPT("WPPIN", handle->nand.nand_wppin, 1); ++ NOPT("BLOCKPERCHIP", handle->nand.nand_bpc, 1); ++ ++ return 0; ++} ++ ++uint32_t ingenic_sdram_size(void *hndl) { ++ HANDLE; ++ ++ return handle->total_sdram_size; ++} ++ ++static int ingenic_wordop(void *usb, int op, uint32_t base) { ++ return usbdev_vendor(usb, USBDEV_TODEV, op, (base >> 16), base & 0xFFFF, 0, 0); ++} ++ ++int ingenic_stage1_debugop(void *hndl, const char *filename, uint32_t op, uint32_t pin, uint32_t base, uint32_t size) { ++ HANDLE; ++ ++ handle->cfg.debug.debug_ops = op; ++ handle->cfg.debug.pin_num = pin; ++ handle->cfg.debug.start = base; ++ handle->cfg.debug.size = size; ++ ++ int ret = ingenic_loadstage(handle, INGENIC_STAGE1, filename); ++ ++ memset(&handle->cfg.debug, 0, sizeof(ingenic_stage1_debug_t)); ++ ++ return ret; ++} ++ ++int ingenic_loadstage(void *hndl, int id, const char *file) { ++ HANDLE; ++ ++ if(file == NULL) { ++ errno = EINVAL; ++ ++ return -1; ++ } ++ ++ uint32_t base; ++ int cmd; ++ ++ switch(id) { ++ case INGENIC_STAGE1: ++ base = SDRAM_BASE + STAGE1_BASE; ++ cmd = VR_PROGRAM_START1; ++ ++ break; ++ ++ case INGENIC_STAGE2: ++ base = SDRAM_BASE + handle->total_sdram_size - STAGE2_CODESIZE; ++ cmd = VR_PROGRAM_START2; ++ ++ break; ++ ++ default: ++ errno = EINVAL; ++ ++ return -1; ++ } ++ ++ FILE *fd = fopen(file, "rb"); ++ ++ if(fd == NULL) ++ return -1; ++ ++ fseek(fd, 0, SEEK_END); ++ int size = ftell(fd); ++ fseek(fd, 0, SEEK_SET); ++ ++ void *data = malloc(size); ++ size_t read_bytes = fread(data, 1, size, fd); ++ ++ fclose(fd); ++ ++ if(read_bytes != size) { ++ free(data); ++ ++ errno = EIO; ++ ++ return -1; ++ } ++ ++ memcpy(data + 8, &handle->cfg, sizeof(firmware_config_t)); ++ ++ if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, base) == -1) { ++ free(data); ++ ++ return -1; ++ } ++ ++ int ret = usbdev_sendbulk(handle->usb, data, size); ++ ++ free(data); ++ ++ if(ret == -1) ++ return -1; ++ ++ if(id == INGENIC_STAGE2) { ++ ret = usbdev_vendor(handle->usb, USBDEV_TODEV, VR_FLUSH_CACHES, 0, 0, 0, 0); ++ ++ if(ret == -1) ++ return -1; ++ } ++ ++ ret = usbdev_vendor(handle->usb, USBDEV_TODEV, cmd, (base >> 16), base & 0xFFFF, 0, 0); ++ ++ if(ret == -1) ++ return -1; ++ ++ usleep(250); ++ ++ if(id == INGENIC_STAGE2) ++ return ingenic_redetect(hndl); ++ else ++ return 0; ++} ++ ++int ingenic_memtest(void *hndl, const char *filename, uint32_t base, uint32_t size, uint32_t *fail) { ++ HANDLE; ++ ++ int ret = ingenic_stage1_debugop(handle, filename, STAGE1_DEBUG_MEMTEST, 0, base, size); ++ ++ if(ret == -1) ++ return -1; ++ ++ uint32_t data[2]; ++ ++ ret = usbdev_recvbulk(handle->usb, &data, sizeof(data)); ++ ++ if(ret == -1) ++ return -1; ++ ++ hexdump(data, ret); ++ ++ if(ret < 4) { ++ errno = EIO; ++ ++ return -1; ++ } ++ ++ if(data[0] != 0) { ++ errno = EFAULT; ++ ++ *fail = data[0]; ++ ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int ingenic_configure_stage2(void *hndl) { ++ HANDLE; ++ ++// DS_flash_info (nand_config_t only) is not implemented in stage2, so using DS_hand (nand_config_t + firmware_config_t) ++ uint8_t *hand = malloc(sizeof(nand_config_t) + sizeof(firmware_config_t)); ++ ++ memcpy(hand, &handle->nand, sizeof(nand_config_t)); ++ memcpy(hand + sizeof(nand_config_t), &handle->cfg, sizeof(firmware_config_t)); ++ ++ int ret = usbdev_sendbulk(handle->usb, hand, sizeof(nand_config_t) + sizeof(firmware_config_t)); ++ ++ free(hand); ++ ++ if(ret == -1) ++ return -1; ++ ++ if(usbdev_vendor(handle->usb, USBDEV_TODEV, VR_CONFIGRATION, DS_hand, 0, 0, 0) == -1) ++ return -1; ++ ++ uint32_t result[8]; ++ ++ ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); ++ ++ if(ret == -1) ++ return -1; ++ ++ return 0; ++} ++ ++int ingenic_load_sdram(void *hndl, void *data, uint32_t base, uint32_t size) { ++ HANDLE; ++ ++ int max = size, value = 0; ++ ++ CALLBACK(progress, PROGRESS_INIT, 0, max); ++ ++ while(size) { ++ int block = size > STAGE2_IOBUF ? STAGE2_IOBUF : size; ++ ++ debug(LEVEL_DEBUG, "Loading %d bytes from %p to 0x%08X\n", block, data, base); ++ ++ if(usbdev_sendbulk(handle->usb, data, block) == -1) ++ return -1; ++ ++ if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, base) == -1) ++ return -1; ++ ++ if(ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, block) == -1) ++ return -1; ++ ++ ++ if(usbdev_vendor(handle->usb, USBDEV_TODEV, VR_SDRAM_OPS, SDRAM_LOAD, 0, 0, 0) == -1) ++ return -1; ++ ++ uint32_t result[8]; ++ ++ int ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); ++ if(ret == -1) ++ return -1; ++ ++ hexdump(result, ret); ++ ++ data += block; ++ base += block; ++ size -= block; ++ value += block; ++ ++ CALLBACK(progress, PROGRESS_UPDATE, value, max); ++ ++ } ++ ++ CALLBACK(progress, PROGRESS_FINI, 0, 0); ++ ++ debug(LEVEL_DEBUG, "Load done\n"); ++ ++ return 0; ++} ++ ++int ingenic_load_sdram_file(void *hndl, uint32_t base, const char *file) { ++ HANDLE; ++ ++ FILE *fd = fopen(file, "rb"); ++ ++ if(fd == NULL) ++ return -1; ++ ++ fseek(fd, 0, SEEK_END); ++ int size = ftell(fd); ++ fseek(fd, 0, SEEK_SET); ++ ++ void *data = malloc(size); ++ size_t bytes = fread(data, 1, size, fd); ++ ++ fclose(fd); ++ ++ if(bytes != size) { ++ free(data); ++ ++ errno = EIO; ++ ++ return -1; ++ } ++ ++ int ret = ingenic_load_sdram(handle, data, base, size); ++ ++ free(data); ++ ++ return ret; ++} ++ ++int ingenic_go(void *hndl, uint32_t address) { ++ HANDLE; ++ ++ debug(LEVEL_DEBUG, "Go to 0x%08X\n", address); ++ ++ return ingenic_wordop(handle->usb, VR_PROGRAM_START2, address); ++} ++ ++static inline int ingenic_nandop(void *usb, uint8_t cs, uint8_t request, uint8_t param) { ++ return usbdev_vendor(usb, USBDEV_TODEV, VR_NAND_OPS, (param << 12) | (cs << 4) | (request & 0x0F), 0, 0, 0); ++} ++ ++int ingenic_query_nand(void *hndl, int cs, nand_info_t *info) { ++ HANDLE; ++ ++ if(ingenic_nandop(handle->usb, cs, NAND_QUERY, 0) == -1) ++ return -1; ++ ++ uint32_t dummy[8]; ++ ++ int ret = usbdev_recvbulk(handle->usb, dummy, sizeof(dummy)); ++ ++ if(ret == -1) ++ return -1; ++ ++ if(ret < sizeof(nand_info_t)) { ++ errno = EIO; ++ ++ return -1; ++ } ++ ++ memcpy(info, dummy, sizeof(nand_info_t)); ++ ++ if(usbdev_recvbulk(handle->usb, dummy, sizeof(dummy)) == -1) ++ return -1; ++ ++ return 0; ++} ++ ++int ingenic_dump_nand(void *hndl, int cs, int start, int pages, int type, const char *filename) { ++ HANDLE; ++ ++ int raw = type & NAND_RAW; ++ type &= ~NAND_RAW; ++ ++ int page_size = (handle->nand.nand_ps + (type == NO_OOB ? 0 : handle->nand.nand_os)); ++ int chunk_pages = STAGE2_IOBUF / page_size; ++ ++ FILE *dest = fopen(filename, "wb"); ++ ++ if(dest == NULL) ++ return -1; ++ ++ void *iobuf = malloc(chunk_pages * page_size); ++ ++ int ret = 0; ++ int value = 0, max = pages; ++ ++ CALLBACK(progress, PROGRESS_INIT, 0, max); ++ ++ while(pages > 0) { ++ int chunk = pages < chunk_pages ? pages : chunk_pages; ++ int bytes = chunk * page_size; ++ ++ ret = ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start); ++ ++ if(ret == -1) ++ break; ++ ++ ret = ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, chunk); ++ ++ if(ret == -1) ++ break; ++ ++ ret = ingenic_nandop(handle->usb, cs, raw ? NAND_READ_RAW : NAND_READ, type); ++ ++ if(ret == -1) ++ break; ++ ++ int ret = usbdev_recvbulk(handle->usb, iobuf, bytes); ++ ++ if(ret == -1) ++ return -1; ++ ++ if(ret != bytes) { ++ debug(LEVEL_ERROR, "Ingenic: NAND dump truncated: expected %d bytes, received %d\n", bytes, ret); ++ ++ errno = EIO; ++ ++ break; ++ } ++ ++ uint16_t result[4]; ++ ++ ++ ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); ++ ++ if(ret == -1) ++ return -1; ++ ++ if(result[3] != 0 && !raw) { ++ debug(LEVEL_ERROR, "Ingenic: ECC failure while reading NAND. See UART output for details\n"); ++ ++ errno = EIO; ++ ++ break; ++ } ++ ++ fwrite(iobuf, bytes, 1, dest); ++ ++ start += chunk; ++ pages -= chunk; ++ ++ value += chunk; ++ ++ CALLBACK(progress, PROGRESS_UPDATE, value, max); ++ } ++ ++ free(iobuf); ++ fclose(dest); ++ ++ CALLBACK(progress, PROGRESS_FINI, 0, 0); ++ ++ return ret; ++} ++ ++int ingenic_erase_nand(void *hndl, int cs, int start, int blocks) { ++ HANDLE; ++ ++ if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start) == -1) ++ return -1; ++ ++ if(ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, blocks) == -1) ++ return -1; ++ ++ if(ingenic_nandop(handle->usb, cs, NAND_ERASE, 0) == -1) ++ return -1; ++ ++ uint16_t result[4]; ++ ++ int ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); ++ ++ if(ret == -1) ++ return -1; ++ ++ hexdump(result, ret); ++ ++ return 0; ++} ++ ++int ingenic_program_nand(void *hndl, int cs, int start, int type, const char *filename) { ++ HANDLE; ++ ++ int page_size = (handle->nand.nand_ps + (type == NO_OOB ? 0 : handle->nand.nand_os)); ++ int chunk_pages = STAGE2_IOBUF / page_size; ++ ++ FILE *in = fopen(filename, "rb"); ++ ++ if(in == NULL) ++ return -1; ++ ++ fseek(in, 0, SEEK_END); ++ int file_size = ftell(in); ++ fseek(in, 0, SEEK_SET); ++ ++ int tail = file_size % page_size; ++ ++ if(tail) { ++ tail = page_size - tail; ++ ++ file_size += tail; ++ } ++ ++ int pages = file_size / page_size; ++ int ret = 0; ++ ++ void *iobuf = malloc(chunk_pages * page_size); ++ ++ debug(LEVEL_INFO, "Programming %d pages from %d (%d bytes, %d bytes/page)\n", pages, start, file_size, page_size); ++ ++ int value = 0, max = pages; ++ ++ CALLBACK(progress, PROGRESS_INIT, 0, max); ++ ++ while(pages > 0) { ++ int chunk = pages < chunk_pages ? pages : chunk_pages; ++ int bytes = chunk * page_size; ++ ++ ret = fread(iobuf, 1, bytes, in); ++ ++ if(pages < chunk_pages && tail) { ++ memset(iobuf + ret, 0xFF, tail); ++ ++ ret += tail; ++ } ++ ++ if(ret != bytes) { ++ debug(LEVEL_ERROR, "fread: %d\n", ret); ++ ++ ret = -1; ++ errno = EIO; ++ ++ break; ++ } ++ ++ if(usbdev_sendbulk(handle->usb, iobuf, bytes) == -1) ++ return -1; ++ ++ ret = ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start); ++ ++ if(ret == -1) ++ break; ++ ++ ret = ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, chunk); ++ ++ if(ret == -1) ++ break; ++ ++ ret = ingenic_nandop(handle->usb, cs, NAND_PROGRAM, type); ++ ++ if(ret == -1) ++ break; ++ ++ uint16_t result[4]; ++ ++ ret = usbdev_recvbulk(handle->usb, result, sizeof(result)); ++ ++ if(ret == -1) ++ return -1; ++ ++ hexdump(result, ret); ++ ++ start += chunk; ++ pages -= chunk; ++ value += chunk; ++ ++ CALLBACK(progress, PROGRESS_UPDATE, value, max); ++ } ++ ++ free(iobuf); ++ fclose(in); ++ ++ CALLBACK(progress, PROGRESS_FINI, 0, 0); ++ ++ return ret; ++} ++ ++int ingenic_load_nand(void *hndl, int cs, int start, int pages, uint32_t base) { ++ HANDLE; ++ ++ if(ingenic_wordop(handle->usb, VR_PROGRAM_START1, base) == -1) ++ return -1; ++ ++ if(ingenic_wordop(handle->usb, VR_SET_DATA_ADDRESS, start) == -1) ++ return -1; ++ ++ if(ingenic_wordop(handle->usb, VR_SET_DATA_LENGTH, pages) == -1) ++ return -1; ++ ++ if(ingenic_nandop(handle->usb, cs, NAND_READ_TO_RAM, 0) == -1) ++ return -1; ++ ++ uint16_t result[4]; ++ ++ if(usbdev_recvbulk(handle->usb, result, sizeof(result)) == -1) ++ return -1; ++ ++ return 0; ++} ++ diff --cc jzboot/src/main.c index 0000000,0000000..0d9c151 new file mode 100644 --- /dev/null +++ b/jzboot/src/main.c @@@ -1,0 -1,0 +1,202 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <unistd.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include "usbdev.h" ++#include "debug.h" ++#include "devmgr.h" ++#include "ingenic.h" ++#include "shell.h" ++#include "xburst-tools-config.h" ++ ++static void usage(const char *app) { ++ printf( ++ "Usage: \n" ++ " Enumeration: %1$s -e\n" ++ " Interactive mode: %1$s -i <INDEX>\n" ++ " Batch mode (with script): %1$s -i <INDEX> -b <FILE>\n" ++ " Batch mode (command list): %1$s -i <INDEX> -c <COMMAND>\n\n" ++ ++ "USB loader tool for Ingenic Semiconductor XBurst-based SoC\n\n" ++ " -e Enumerate devices only\n" ++ " -i <INDEX> Open device with index INDEX in interactive or batch mode\n" ++ " -c <CMD> Run semicolon-separated commands and exit\n" ++ " -d <DEBUG> Set output level (0 - no reporting, 4 - max reporting), default = 1 (errors only)\n" ++ " -C <FILE> Execute configuration script FILE before anything else\n" ++ " -b <FILE> Execute script in FILE\n" ++ " -v Print program version\n\n", app); ++} ++ ++static void dev_handler(int idx, uint16_t vid, uint16_t pid, void *data) { ++ printf(" Device %d: %04hX:%04hX\n", idx, vid, pid); ++} ++ ++int main(int argc, char *argv[]) { ++ int ch; ++ int idx = -1, enumerate = 0; ++ char *cmd = NULL, *script = NULL, *config = NULL; ++ ++ while((ch = getopt(argc, argv, "b:i:ec:d:C:v")) != -1) { ++ switch(ch) { ++ case 'e': ++ enumerate = 1; ++ ++ break; ++ ++ case 'i': ++ idx = atoi(optarg); ++ ++ break; ++ ++ case 'c': ++ cmd = optarg; ++ ++ break; ++ ++ case 'b': ++ script = optarg; ++ ++ break; ++ ++ case 'C': ++ config = optarg; ++ ++ break; ++ ++ case 'd': ++ set_debug_level(atoi(optarg)); ++ ++ break; ++ ++ case 'v': ++ printf("JZboot version %s\n", PACKAGE_VERSION); ++ ++ return 0; ++ ++ default: ++ usage(argv[0]); ++ ++ return 1; ++ } ++ } ++ ++ if(!enumerate && idx < 0) { ++ usage(argv[0]); ++ ++ return 1; ++ } ++ ++ if(usbdev_init() == -1) { ++ perror("usbdev_init"); ++ ++ return 1; ++ } ++ ++ atexit(usbdev_fini); ++ ++ if(usbdev_enumerate() == -1) { ++ perror("usbdev_enumerate"); ++ ++ return 1; ++ } ++ ++ if(enumerate) { ++ printf("Ingenic devices list:\n"); ++ ++ enum_devices(dev_handler); ++ ++ return 0; ++ } ++ ++ void *data = get_device(idx); ++ ++ if(data == NULL) { ++ fprintf(stderr, "Device with index %d not found\n", idx); ++ ++ return 1; ++ } ++ ++ void *hndl = usbdev_open(data); ++ ++ if(hndl == NULL) { ++ perror("usbdev_open"); ++ ++ return 1; ++ } ++ ++ int ret = 0; ++ ++ void *ingenic = ingenic_open(hndl); ++ ++ if(ingenic == NULL) { ++ perror("ingenic_open"); ++ ++ ret = 1; ++ ++ goto exit_usb; ++ } ++ ++ shell_context_t *shell = shell_init(ingenic); ++ ++ if(shell == NULL) { ++ perror("shell_init"); ++ ++ ret = 1; ++ ++ goto exit_ingenic; ++ } ++ ++ if(config) { ++ if(shell_source(shell, config) == -1) { ++ perror("shell_source"); ++ ++ ret = 1; ++ ++ goto exit_shell; ++ } ++ } ++ ++ if(cmd != NULL) { ++ if(shell_execute(shell, cmd) == -1) { ++ perror("shell_execute"); ++ ++ ret = 1; ++ } ++ ++ } else if(script != NULL) { ++ if(shell_source(shell, script) == -1) { ++ perror("shell_source"); ++ ++ ret = 1; ++ } ++ } else ++ shell_interactive(shell); ++ ++exit_shell: ++ shell_fini(shell); ++ ++exit_ingenic: ++ ingenic_close(ingenic); ++ ++exit_usb: ++ usbdev_close(hndl); ++ ++ return ret; ++} diff --cc jzboot/src/shell.c index 0000000,0000000..37434b6 new file mode 100644 --- /dev/null +++ b/jzboot/src/shell.c @@@ -1,0 -1,0 +1,514 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com>, ++ * Peter Zotov <whitequark@whitequark.org> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <string.h> ++#include <stdio.h> ++#ifdef HAVE_LIBREADLINE ++#include <readline/readline.h> ++#include <readline/history.h> ++#endif ++#include <stdlib.h> ++#include <unistd.h> ++#include <errno.h> ++#include <sys/ioctl.h> ++ ++#include "shell_internal.h" ++#include "debug.h" ++#include "ingenic.h" ++ ++static void shell_update_cmdset(uint32_t cmdset, void *arg); ++static void shell_progress(int action, int value, int max, void *arg); ++ ++static const ingenic_callbacks_t shell_callbacks = { ++ shell_update_cmdset, ++ shell_progress ++}; ++ ++static const struct { ++ int set; ++ const char *name; ++ const shell_command_t *commands; ++} cmdsets[] = { ++ { CMDSET_SPL, "SPL", spl_cmdset }, ++ { CMDSET_USBBOOT, "USBBoot", usbboot_cmdset }, ++ { 0, NULL, NULL } ++}; ++ ++shell_context_t *shell_init(void *ingenic) { ++#ifdef HAVE_LIBREADLINE ++ rl_initialize(); ++#endif ++ ++ debug(LEVEL_DEBUG, "Initializing shell\n"); ++ ++ shell_context_t *ctx = malloc(sizeof(shell_context_t)); ++ memset(ctx, 0, sizeof(shell_context_t)); ++ ctx->device = ingenic; ++ ++ ingenic_set_callbacks(ingenic, &shell_callbacks, ctx); ++ ++ shell_update_cmdset(ingenic_cmdset(ingenic), ctx); ++ ++ return ctx; ++} ++ ++int shell_enumerate_commands(shell_context_t *ctx, int (*callback)(shell_context_t *ctx, const shell_command_t *cmd, void *arg), void *arg) { ++ for(int i = 0; builtin_cmdset[i].cmd != NULL; i++) { ++ int ret = callback(ctx, builtin_cmdset + i, arg); ++ ++ if(ret != 0) ++ return ret; ++ } ++ ++ if(ctx->set_cmds) ++ for(int i = 0; ctx->set_cmds[i].cmd != NULL; i++) { ++ int ret = callback(ctx, ctx->set_cmds + i, arg); ++ ++ if(ret != 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int shell_run_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { ++ shell_run_data_t *data = arg; ++ ++ if(strcmp(cmd->cmd, data->argv[0]) == 0) { ++ int invalid = 0; ++ ++ if(cmd->args == NULL && data->argc != 1) ++ invalid = 1; ++ else if(cmd->args) { ++ char *dup = strdup(cmd->args), *save = dup, *ptrptr = NULL; ++ ++ int pos = 1; ++ int max_tokens = 1; ++ ++ for(char *token = strtok_r(dup, " ", &ptrptr); token; token = strtok_r(NULL, " ", &ptrptr)) { ++ if(strcmp(token, "...") == 0) { ++ max_tokens = -1; ++ ++ break; ++ } ++ ++ max_tokens++; ++ ++ if(data->argc - 1 < pos) { ++ if(*token == '[') { ++ break; ++ } else if(*token == '<') { ++ invalid = 1; ++ ++ break; ++ } ++ } ++ ++ pos++; ++ } ++ ++ if(max_tokens != -1 && data->argc > max_tokens) ++ invalid = 1; ++ ++ ++ free(save); ++ } ++ ++ if(invalid) { ++ if(cmd->args) ++ fprintf(stderr, "Usage: %s %s\n", cmd->cmd, cmd->args); ++ else ++ fprintf(stderr, "Usage: %s\n", cmd->cmd); ++ ++ errno = EINVAL; ++ ++ return -1; ++ ++ } else { ++ int ret = cmd->handler(ctx, data->argc, data->argv); ++ ++ if(ret == 0) ++ return 1; ++ else ++ return ret; ++ } ++ } else ++ return 0; ++} ++ ++int shell_run(shell_context_t *ctx, int argc, char *argv[]) { ++ shell_run_data_t data = { argc, argv }; ++ ++ int ret = shell_enumerate_commands(ctx, shell_run_function, &data); ++ ++ if(ret == 0) { ++ debug(LEVEL_ERROR, "Bad command '%s'\n", argv[0]); ++ ++ errno = EINVAL; ++ return -1; ++ ++ } else if(ret == 1) { ++ return 0; ++ } else ++ return ret; ++} ++ ++int shell_execute(shell_context_t *ctx, const char *cmd) { ++ yyscan_t scanner; ++ if(yylex_init_extra(ctx, &scanner) == -1) ++ return -1; ++ ++ ctx->line = strdup(cmd); ++ char *ptr = ctx->line; ++ ++ int token; ++ int state = STATE_WANTSTR; ++ int argc = 0; ++ char **argv = NULL; ++ int fret = 0; ++ ++ do { ++ int noway = 0; ++ ++ token = yylex(scanner); ++ ++ if((token == TOK_SEPARATOR || token == TOK_COMMENT || token == 0)) { ++ if(argc > 0) { ++ int ret = shell_run(ctx, argc, argv); ++ ++ for(int i = 0; i < argc; i++) { ++ free(argv[i]); ++ } ++ ++ free(argv); ++ ++ argv = NULL; ++ argc = 0; ++ ++ if(ret == -1) { ++ fret = -1; ++ ++ break; ++ } ++ } ++ ++ state = STATE_WANTSTR; ++ } else { ++ switch(state) { ++ case STATE_WANTSTR: ++ if(token == TOK_SPACE) { ++ state = STATE_WANTSTR; ++ } else if(token == TOK_STRING) { ++ int oargc = argc++; ++ ++ argv = realloc(argv, sizeof(char *) * argc); ++ ++ argv[oargc] = ctx->strval; ++ ++ state = STATE_WANTSPACE; ++ } else { ++ noway = 1; ++ } ++ ++ break; ++ ++ case STATE_WANTSPACE: ++ if(token == TOK_STRING) { ++ free(ctx->strval); ++ ++ noway = 1; ++ } else if(token == TOK_SPACE) { ++ state = STATE_WANTSTR; ++ } else ++ noway = 1; ++ } ++ ++ if(noway) { ++ debug(LEVEL_ERROR, "No way from state %d by token %d\n", state, token); ++ ++ for(int i = 0; i < argc; i++) ++ free(argv[i]); ++ ++ free(argv); ++ ++ fret = -1; ++ ++ break; ++ } ++ } ++ ++ } while(token && token != TOK_COMMENT); ++ ++ free(ptr); ++ ++ yylex_destroy(scanner); ++ ++ return fret; ++} ++ ++int shell_pull(shell_context_t *ctx, char *buf, int maxlen) { ++ size_t len = strlen(ctx->line); ++ ++ if(len < maxlen) ++ maxlen = len; ++ ++ memcpy(buf, ctx->line, maxlen); ++ ++ ctx->line += maxlen; ++ ++ return maxlen; ++} ++ ++void shell_fini(shell_context_t *ctx) { ++ free(ctx); ++} ++ ++int shell_source(shell_context_t *ctx, const char *filename) { ++ ctx->shell_exit = 0; ++ ++ FILE *file = fopen(filename, "r"); ++ ++ if(file == NULL) { ++ return -1; ++ } ++ ++ char *line; ++ ++ while((line = fgets(ctx->linebuf, sizeof(ctx->linebuf), file)) && !ctx->shell_exit) { ++ if(shell_execute(ctx, line) == -1) { ++ fclose(file); ++ ++ return -1; ++ } ++ } ++ ++ fclose(file); ++ ++ return 0; ++} ++ ++#ifdef HAVE_LIBREADLINE ++static shell_context_t *completion_context; ++static char **completion_matches; ++static int completion_matches_count = 0; ++ ++static int shell_completion_filler(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { ++ const char *part = arg; ++ ++ size_t len = strlen(part), cmdlen = strlen(cmd->cmd); ++ ++ if(cmdlen >= len && memcmp(part, cmd->cmd, len) == 0) { ++ int idx = completion_matches_count++; ++ ++ completion_matches = realloc(completion_matches, sizeof(char **) * completion_matches_count); ++ completion_matches[idx] = strdup(cmd->cmd); ++ } ++ ++ return 0; ++} ++ ++static char *shell_completion(const char *partial, int state) { ++ static int completion_pass = 0, completion_matches_offset = 0; ++ ++ if(state == 0) { ++ if(completion_matches) { ++ for(int i = 0; i < completion_matches_count; i++) ++ if(completion_matches[i]) ++ free(completion_matches[i]); ++ ++ free(completion_matches); ++ ++ completion_matches = NULL; ++ completion_matches_count = 0; ++ } ++ ++ completion_pass = 0; ++ ++ char *tmp = rl_line_buffer; ++ ++ while(isspace(*tmp)) tmp++; ++ ++ int not_first = 0; ++ ++ for(; *tmp; tmp++) { ++ for(const char *sep = rl_basic_word_break_characters; *sep; sep++) { ++ if(*tmp == *sep) { ++ not_first = 1; ++ ++ break; ++ } ++ } ++ ++ if(not_first) ++ break; ++ } ++ ++ if(not_first) { ++ completion_pass = 1; ++ ++ return rl_filename_completion_function(partial, state); ++ } else { ++ shell_enumerate_commands(completion_context, shell_completion_filler, (void *) partial); ++ ++ completion_matches_offset = 0; ++ } ++ } ++ ++ if(completion_pass) { ++ return rl_filename_completion_function(partial, state); ++ ++ } else if(completion_matches_offset == completion_matches_count) { ++ return NULL; ++ } else { ++ char *val = completion_matches[completion_matches_offset]; ++ ++ completion_matches[completion_matches_offset++] = NULL; ++ ++ return val; ++ } ++} ++#endif ++ ++void shell_interactive(shell_context_t *ctx) { ++ ctx->shell_exit = 0; ++ ++#ifndef WITH_READLINE ++ char *line; ++ ++ while(!ctx->shell_exit) { ++ fputs("jzboot> ", stdout); ++ fflush(stdout); ++ ++ line = fgets(ctx->linebuf, sizeof(ctx->linebuf), stdin); ++ ++ if(line == NULL) ++ break; ++ ++ shell_execute(ctx, line); ++ } ++#else ++ rl_completion_entry_function = shell_completion; ++ completion_context = ctx; ++ ++ rl_set_signals(); ++ ++ rl_filename_quote_characters = "\" "; ++ while(!ctx->shell_exit) { ++ char *line = readline("jzboot> "); ++ ++ if(line == NULL) { ++ break; ++ } ++ ++ add_history(line); ++ ++ shell_execute(ctx, line); ++ ++ free(line); ++ } ++ ++ rl_clear_signals(); ++#endif ++} ++ ++static void shell_update_cmdset(uint32_t cmdset, void *arg) { ++ shell_context_t *ctx = arg; ++ ++ ctx->set_cmds = NULL; ++ ++ for(int i = 0; cmdsets[i].name != NULL; i++) { ++ if(cmdsets[i].set == cmdset) { ++ printf("Shell: using command set '%s', run 'help' for command list. CPU: %04X\n", cmdsets[i].name, ingenic_type(ctx->device)); ++ ++ ctx->set_cmds = cmdsets[i].commands; ++ ++ return; ++ } ++ } ++ ++ debug(LEVEL_ERROR, "Shell: unknown cmdset %u\n", cmdset); ++} ++ ++void *shell_device(shell_context_t *ctx) { ++ return ctx->device; ++} ++ ++void shell_exit(shell_context_t *ctx, int val) { ++ ctx->shell_exit = val; ++} ++ ++static void shell_progress(int action, int value, int max, void *arg) { ++ shell_context_t *ctx = arg; ++ ++ if(isatty(STDOUT_FILENO)) { ++ struct winsize size; ++ ++ int progress, percent; ++ ++ if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &size) == -1) ++ return; ++ ++ int bar_size = size.ws_col - 6; ++ ++ switch(action) { ++ case PROGRESS_INIT: ++ ctx->prev_progress = -1; ++ ++ ++ case PROGRESS_FINI: ++ putchar('\r'); ++ ++ for(int i = 0; i < size.ws_col; i++) ++ putchar(' '); ++ ++ putchar('\r'); ++ ++ fflush(stdout); ++ ++ break; ++ ++ case PROGRESS_UPDATE: ++ progress = value * bar_size / max; ++ percent = value * 100 / max; ++ ++ if(progress != ctx->prev_progress) { ++ fputs("\r|", stdout); ++ ++ for(int i = 0; i < progress; i++) { ++ putchar('='); ++ } ++ ++ for(int i = progress; i < bar_size; i++) ++ putchar(' '); ++ ++ printf("|%3d%%", percent); ++ ++ fflush(stdout); ++ ++ ctx->prev_progress = progress; ++ ++ } ++ ++ ++ break; ++ ++ } ++ } ++} ++ diff --cc jzboot/src/shell_builtins.c index 0000000,0000000..e85fb40 new file mode 100644 --- /dev/null +++ b/jzboot/src/shell_builtins.c @@@ -1,0 -1,0 +1,171 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com>, ++ * Peter Zotov <whitequark@whitequark.org> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <stdio.h> ++#include <string.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <errno.h> ++ ++#include "shell.h" ++#include "app_config.h" ++#include "ingenic.h" ++ ++static int builtin_help(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_exit(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_source(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_echo(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_sleep(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_redetect(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_rebuildcfg(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_set(shell_context_t *ctx, int argc, char *argv[]); ++static int builtin_safe(shell_context_t *ctx, int argc, char *argv[]); ++ ++const shell_command_t builtin_cmdset[] = { ++ { "help", "Display this message", builtin_help, NULL }, ++ { "exit", "Batch: stop current script, interactive: end session", builtin_exit, NULL }, ++ { "source", "Run specified script", builtin_source, "<FILENAME>" }, ++ { "echo", "Output specified string", builtin_echo, "<STRING> ..." }, ++ { "sleep", "Sleep a specified amount of time", builtin_sleep, "<MILLISECONDS>" }, ++ { "set", "Print or set configuraton variables", builtin_set, "[VARIABLE] [VALUE]" }, ++ { "safe", "Run command ignoring errors", builtin_safe, "<COMMAND> [ARG] ..." }, ++ ++ { "redetect", "Redetect CPU", builtin_redetect, NULL }, ++ { "rebuildcfg", "Rebuild firmware configuration data", builtin_rebuildcfg, NULL }, ++ ++ { NULL, NULL, NULL } ++}; ++ ++static int help_maxwidth_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { ++ int len = strlen(cmd->cmd), *maxlen = arg; ++ ++ if(cmd->args) ++ len += strlen(cmd->args) + 1; ++ ++ if(len > *maxlen) ++ *maxlen = len; ++ ++ return 0; ++} ++ ++static int help_print_function(shell_context_t *ctx, const shell_command_t *cmd, void *arg) { ++ int len = strlen(cmd->cmd), *maxlen = arg; ++ ++ fputs(cmd->cmd, stdout); ++ ++ if(cmd->args) { ++ len += strlen(cmd->args) + 1; ++ ++ putchar(' '); ++ fputs(cmd->args, stdout); ++ } ++ ++ for(int i = 0; i < *maxlen - len; i++) ++ putchar(' '); ++ ++ puts(cmd->description); ++ ++ return 0; ++} ++ ++static int builtin_help(shell_context_t *ctx, int argc, char *argv[]) { ++ int maxwidth = 0; ++ ++ shell_enumerate_commands(ctx, help_maxwidth_function, &maxwidth); ++ ++ maxwidth += 2; ++ ++ return shell_enumerate_commands(ctx, help_print_function, &maxwidth); ++} ++ ++static int builtin_exit(shell_context_t *ctx, int argc, char *argv[]) { ++ shell_exit(ctx, 1); ++ ++ return 0; ++} ++ ++static int builtin_source(shell_context_t *ctx, int argc, char *argv[]) { ++ int ret = shell_source(ctx, argv[1]); ++ ++ if(ret == -1) { ++ fprintf(stderr, "Error while sourcing file %s: %s\n", argv[1], strerror(errno)); ++ } ++ ++ shell_exit(ctx, 0); ++ ++ return ret; ++} ++ ++static int builtin_echo(shell_context_t *ctx, int argc, char *argv[]) { ++ for(int i = 1; i < argc; i++) { ++ fputs(argv[i], stdout); ++ ++ putchar((i < argc - 1) ? ' ' : '\n'); ++ } ++ ++ return 0; ++} ++ ++static int builtin_sleep(shell_context_t *ctx, int argc, char *argv[]) { ++ uint32_t ms = atoi(argv[1]); ++ ++ usleep(ms * 1000); ++ ++ return 0; ++} ++ ++static int builtin_redetect(shell_context_t *ctx, int argc, char *argv[]) { ++ if(ingenic_redetect(shell_device(ctx)) == -1) { ++ perror("ingenic_redetect"); ++ ++ return -1; ++ } else ++ return 0; ++} ++ ++ ++static int builtin_set(shell_context_t *ctx, int argc, char *argv[]) { ++ if(argc == 1) { ++ if(cfg_environ) { ++ for(int i = 0; cfg_environ[i] != NULL; i++) ++ printf("%s\n", cfg_environ[i]); ++ } ++ ++ } else if(argc == 2) { ++ cfg_unsetenv(argv[1]); ++ ++ } else if(argc == 3) { ++ cfg_setenv(argv[1], argv[2]); ++ } ++ ++ return 0; ++} ++ ++ ++static int builtin_rebuildcfg(shell_context_t *ctx, int argc, char *argv[]) { ++ return ingenic_rebuild(shell_device(ctx)); ++} ++ ++static int builtin_safe(shell_context_t *ctx, int argc, char *argv[]) { ++ if(shell_run(ctx, argc - 1, argv + 1) == -1) ++ perror("shell_run"); ++ ++ return 0; ++} ++ diff --cc jzboot/src/shell_lex.c index 0000000,0000000..c32427d new file mode 100644 --- /dev/null +++ b/jzboot/src/shell_lex.c @@@ -1,0 -1,0 +1,1965 @@@ ++#line 2 "shell_lex.c" ++ ++#line 4 "shell_lex.c" ++ ++#define YY_INT_ALIGNED short int ++ ++/* A lexical scanner generated by flex */ ++ ++#define FLEX_SCANNER ++#define YY_FLEX_MAJOR_VERSION 2 ++#define YY_FLEX_MINOR_VERSION 5 ++#define YY_FLEX_SUBMINOR_VERSION 35 ++#if YY_FLEX_SUBMINOR_VERSION > 0 ++#define FLEX_BETA ++#endif ++ ++/* First, we deal with platform-specific or compiler-specific issues. */ ++ ++/* begin standard C headers. */ ++#include <stdio.h> ++#include <string.h> ++#include <errno.h> ++#include <stdlib.h> ++ ++/* end standard C headers. */ ++ ++/* flex integer type definitions */ ++ ++#ifndef FLEXINT_H ++#define FLEXINT_H ++ ++/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ ++ ++#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L ++ ++/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, ++ * if you want the limit (max/min) macros for int types. ++ */ ++#ifndef __STDC_LIMIT_MACROS ++#define __STDC_LIMIT_MACROS 1 ++#endif ++ ++#include <inttypes.h> ++typedef int8_t flex_int8_t; ++typedef uint8_t flex_uint8_t; ++typedef int16_t flex_int16_t; ++typedef uint16_t flex_uint16_t; ++typedef int32_t flex_int32_t; ++typedef uint32_t flex_uint32_t; ++#else ++typedef signed char flex_int8_t; ++typedef short int flex_int16_t; ++typedef int flex_int32_t; ++typedef unsigned char flex_uint8_t; ++typedef unsigned short int flex_uint16_t; ++typedef unsigned int flex_uint32_t; ++ ++/* Limits of integral types. */ ++#ifndef INT8_MIN ++#define INT8_MIN (-128) ++#endif ++#ifndef INT16_MIN ++#define INT16_MIN (-32767-1) ++#endif ++#ifndef INT32_MIN ++#define INT32_MIN (-2147483647-1) ++#endif ++#ifndef INT8_MAX ++#define INT8_MAX (127) ++#endif ++#ifndef INT16_MAX ++#define INT16_MAX (32767) ++#endif ++#ifndef INT32_MAX ++#define INT32_MAX (2147483647) ++#endif ++#ifndef UINT8_MAX ++#define UINT8_MAX (255U) ++#endif ++#ifndef UINT16_MAX ++#define UINT16_MAX (65535U) ++#endif ++#ifndef UINT32_MAX ++#define UINT32_MAX (4294967295U) ++#endif ++ ++#endif /* ! C99 */ ++ ++#endif /* ! FLEXINT_H */ ++ ++#ifdef __cplusplus ++ ++/* The "const" storage-class-modifier is valid. */ ++#define YY_USE_CONST ++ ++#else /* ! __cplusplus */ ++ ++/* C99 requires __STDC__ to be defined as 1. */ ++#if defined (__STDC__) ++ ++#define YY_USE_CONST ++ ++#endif /* defined (__STDC__) */ ++#endif /* ! __cplusplus */ ++ ++#ifdef YY_USE_CONST ++#define yyconst const ++#else ++#define yyconst ++#endif ++ ++/* Returned upon end-of-file. */ ++#define YY_NULL 0 ++ ++/* Promotes a possibly negative, possibly signed char to an unsigned ++ * integer for use as an array index. If the signed char is negative, ++ * we want to instead treat it as an 8-bit unsigned char, hence the ++ * double cast. ++ */ ++#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) ++ ++/* An opaque pointer. */ ++#ifndef YY_TYPEDEF_YY_SCANNER_T ++#define YY_TYPEDEF_YY_SCANNER_T ++typedef void* yyscan_t; ++#endif ++ ++/* For convenience, these vars (plus the bison vars far below) ++ are macros in the reentrant scanner. */ ++#define yyin yyg->yyin_r ++#define yyout yyg->yyout_r ++#define yyextra yyg->yyextra_r ++#define yyleng yyg->yyleng_r ++#define yytext yyg->yytext_r ++#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) ++#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) ++#define yy_flex_debug yyg->yy_flex_debug_r ++ ++/* Enter a start condition. This macro really ought to take a parameter, ++ * but we do it the disgusting crufty way forced on us by the ()-less ++ * definition of BEGIN. ++ */ ++#define BEGIN yyg->yy_start = 1 + 2 * ++ ++/* Translate the current start state into a value that can be later handed ++ * to BEGIN to return to the state. The YYSTATE alias is for lex ++ * compatibility. ++ */ ++#define YY_START ((yyg->yy_start - 1) / 2) ++#define YYSTATE YY_START ++ ++/* Action number for EOF rule of a given start state. */ ++#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) ++ ++/* Special action meaning "start processing a new file". */ ++#define YY_NEW_FILE yyrestart(yyin ,yyscanner ) ++ ++#define YY_END_OF_BUFFER_CHAR 0 ++ ++/* Size of default input buffer. */ ++#ifndef YY_BUF_SIZE ++#ifdef __ia64__ ++/* On IA-64, the buffer size is 16k, not 8k. ++ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. ++ * Ditto for the __ia64__ case accordingly. ++ */ ++#define YY_BUF_SIZE 32768 ++#else ++#define YY_BUF_SIZE 16384 ++#endif /* __ia64__ */ ++#endif ++ ++/* The state buf must be large enough to hold one state per character in the main buffer. ++ */ ++#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) ++ ++#ifndef YY_TYPEDEF_YY_BUFFER_STATE ++#define YY_TYPEDEF_YY_BUFFER_STATE ++typedef struct yy_buffer_state *YY_BUFFER_STATE; ++#endif ++ ++#define EOB_ACT_CONTINUE_SCAN 0 ++#define EOB_ACT_END_OF_FILE 1 ++#define EOB_ACT_LAST_MATCH 2 ++ ++ #define YY_LESS_LINENO(n) ++ ++/* Return all but the first "n" matched characters back to the input stream. */ ++#define yyless(n) \ ++ do \ ++ { \ ++ /* Undo effects of setting up yytext. */ \ ++ int yyless_macro_arg = (n); \ ++ YY_LESS_LINENO(yyless_macro_arg);\ ++ *yy_cp = yyg->yy_hold_char; \ ++ YY_RESTORE_YY_MORE_OFFSET \ ++ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ ++ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ ++ } \ ++ while ( 0 ) ++ ++#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) ++ ++#ifndef YY_TYPEDEF_YY_SIZE_T ++#define YY_TYPEDEF_YY_SIZE_T ++typedef size_t yy_size_t; ++#endif ++ ++#ifndef YY_STRUCT_YY_BUFFER_STATE ++#define YY_STRUCT_YY_BUFFER_STATE ++struct yy_buffer_state ++ { ++ FILE *yy_input_file; ++ ++ char *yy_ch_buf; /* input buffer */ ++ char *yy_buf_pos; /* current position in input buffer */ ++ ++ /* Size of input buffer in bytes, not including room for EOB ++ * characters. ++ */ ++ yy_size_t yy_buf_size; ++ ++ /* Number of characters read into yy_ch_buf, not including EOB ++ * characters. ++ */ ++ int yy_n_chars; ++ ++ /* Whether we "own" the buffer - i.e., we know we created it, ++ * and can realloc() it to grow it, and should free() it to ++ * delete it. ++ */ ++ int yy_is_our_buffer; ++ ++ /* Whether this is an "interactive" input source; if so, and ++ * if we're using stdio for input, then we want to use getc() ++ * instead of fread(), to make sure we stop fetching input after ++ * each newline. ++ */ ++ int yy_is_interactive; ++ ++ /* Whether we're considered to be at the beginning of a line. ++ * If so, '^' rules will be active on the next match, otherwise ++ * not. ++ */ ++ int yy_at_bol; ++ ++ int yy_bs_lineno; /**< The line count. */ ++ int yy_bs_column; /**< The column count. */ ++ ++ /* Whether to try to fill the input buffer when we reach the ++ * end of it. ++ */ ++ int yy_fill_buffer; ++ ++ int yy_buffer_status; ++ ++#define YY_BUFFER_NEW 0 ++#define YY_BUFFER_NORMAL 1 ++ /* When an EOF's been seen but there's still some text to process ++ * then we mark the buffer as YY_EOF_PENDING, to indicate that we ++ * shouldn't try reading from the input source any more. We might ++ * still have a bunch of tokens to match, though, because of ++ * possible backing-up. ++ * ++ * When we actually see the EOF, we change the status to "new" ++ * (via yyrestart()), so that the user can continue scanning by ++ * just pointing yyin at a new input file. ++ */ ++#define YY_BUFFER_EOF_PENDING 2 ++ ++ }; ++#endif /* !YY_STRUCT_YY_BUFFER_STATE */ ++ ++/* We provide macros for accessing buffer states in case in the ++ * future we want to put the buffer states in a more general ++ * "scanner state". ++ * ++ * Returns the top of the stack, or NULL. ++ */ ++#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ++ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ ++ : NULL) ++ ++/* Same as previous macro, but useful when we know that the buffer stack is not ++ * NULL or when we need an lvalue. For internal use only. ++ */ ++#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] ++ ++void yyrestart (FILE *input_file ,yyscan_t yyscanner ); ++void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); ++YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); ++void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); ++void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); ++void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); ++void yypop_buffer_state (yyscan_t yyscanner ); ++ ++static void yyensure_buffer_stack (yyscan_t yyscanner ); ++static void yy_load_buffer_state (yyscan_t yyscanner ); ++static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); ++ ++#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) ++ ++YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); ++YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); ++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); ++ ++void *yyalloc (yy_size_t ,yyscan_t yyscanner ); ++void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); ++void yyfree (void * ,yyscan_t yyscanner ); ++ ++#define yy_new_buffer yy_create_buffer ++ ++#define yy_set_interactive(is_interactive) \ ++ { \ ++ if ( ! YY_CURRENT_BUFFER ){ \ ++ yyensure_buffer_stack (yyscanner); \ ++ YY_CURRENT_BUFFER_LVALUE = \ ++ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ ++ } \ ++ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ ++ } ++ ++#define yy_set_bol(at_bol) \ ++ { \ ++ if ( ! YY_CURRENT_BUFFER ){\ ++ yyensure_buffer_stack (yyscanner); \ ++ YY_CURRENT_BUFFER_LVALUE = \ ++ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ ++ } \ ++ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ ++ } ++ ++#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) ++ ++#define yywrap(n) 1 ++#define YY_SKIP_YYWRAP ++ ++typedef unsigned char YY_CHAR; ++ ++typedef int yy_state_type; ++ ++#define yytext_ptr yytext_r ++ ++static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); ++static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); ++static int yy_get_next_buffer (yyscan_t yyscanner ); ++static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); ++ ++/* Done after the current pattern has been matched and before the ++ * corresponding action - sets up yytext. ++ */ ++#define YY_DO_BEFORE_ACTION \ ++ yyg->yytext_ptr = yy_bp; \ ++ yyleng = (size_t) (yy_cp - yy_bp); \ ++ yyg->yy_hold_char = *yy_cp; \ ++ *yy_cp = '\0'; \ ++ yyg->yy_c_buf_p = yy_cp; ++ ++#define YY_NUM_RULES 10 ++#define YY_END_OF_BUFFER 11 ++/* This struct is not used in this scanner, ++ but its presence is necessary. */ ++struct yy_trans_info ++ { ++ flex_int32_t yy_verify; ++ flex_int32_t yy_nxt; ++ }; ++static yyconst flex_int16_t yy_accept[19] = ++ { 0, ++ 0, 0, 0, 0, 11, 5, 3, 1, 4, 2, ++ 6, 9, 8, 5, 3, 6, 7, 0 ++ } ; ++ ++static yyconst flex_int32_t yy_ec[256] = ++ { 0, ++ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, ++ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 2, 1, 3, 4, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, ++ ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1 ++ } ; ++ ++static yyconst flex_int32_t yy_meta[7] = ++ { 0, ++ 1, 2, 3, 4, 4, 5 ++ } ; ++ ++static yyconst flex_int16_t yy_base[24] = ++ { 0, ++ 0, 0, 4, 8, 12, 0, 0, 29, 29, 29, ++ 0, 29, 0, 0, 0, 0, 29, 29, 14, 19, ++ 7, 24, 5 ++ } ; ++ ++static yyconst flex_int16_t yy_def[24] = ++ { 0, ++ 18, 1, 19, 19, 18, 20, 21, 18, 18, 18, ++ 22, 18, 23, 20, 21, 22, 18, 0, 18, 18, ++ 18, 18, 18 ++ } ; ++ ++static yyconst flex_int16_t yy_nxt[36] = ++ { 0, ++ 6, 7, 8, 9, 10, 6, 12, 17, 15, 13, ++ 12, 18, 18, 13, 11, 11, 11, 11, 11, 14, ++ 18, 18, 18, 14, 16, 16, 18, 16, 5, 18, ++ 18, 18, 18, 18, 18 ++ } ; ++ ++static yyconst flex_int16_t yy_chk[36] = ++ { 0, ++ 1, 1, 1, 1, 1, 1, 3, 23, 21, 3, ++ 4, 5, 0, 4, 19, 19, 19, 19, 19, 20, ++ 0, 0, 0, 20, 22, 22, 0, 22, 18, 18, ++ 18, 18, 18, 18, 18 ++ } ; ++ ++/* The intent behind this definition is that it'll catch ++ * any uses of REJECT which flex missed. ++ */ ++#define REJECT reject_used_but_not_detected ++#define yymore() yymore_used_but_not_detected ++#define YY_MORE_ADJ 0 ++#define YY_RESTORE_YY_MORE_OFFSET ++#line 1 "shell_lex.l" ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++#line 20 "shell_lex.l" ++#include "shell_internal.h" ++#include <string.h> ++#include <stdlib.h> ++ ++static char *str_append(char *str, const char *src) { ++ if(str) { ++ size_t newlen = strlen(str) + strlen(src) + 1; ++ ++ char *newstr = malloc(newlen); ++ ++ strcpy(newstr, str); ++ strcat(newstr, src); ++ ++ free(str); ++ ++ return newstr; ++ } else ++ return strdup(src); ++} ++#define YY_NO_INPUT 1 ++ ++#line 489 "shell_lex.c" ++ ++#define INITIAL 0 ++#define STR 1 ++ ++#ifndef YY_NO_UNISTD_H ++/* Special case for "unistd.h", since it is non-ANSI. We include it way ++ * down here because we want the user's section 1 to have been scanned first. ++ * The user has a chance to override it with an option. ++ */ ++#include <unistd.h> ++#endif ++ ++#ifndef YY_EXTRA_TYPE ++#define YY_EXTRA_TYPE void * ++#endif ++ ++/* Holds the entire state of the reentrant scanner. */ ++struct yyguts_t ++ { ++ ++ /* User-defined. Not touched by flex. */ ++ YY_EXTRA_TYPE yyextra_r; ++ ++ /* The rest are the same as the globals declared in the non-reentrant scanner. */ ++ FILE *yyin_r, *yyout_r; ++ size_t yy_buffer_stack_top; /**< index of top of stack. */ ++ size_t yy_buffer_stack_max; /**< capacity of stack. */ ++ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ ++ char yy_hold_char; ++ int yy_n_chars; ++ int yyleng_r; ++ char *yy_c_buf_p; ++ int yy_init; ++ int yy_start; ++ int yy_did_buffer_switch_on_eof; ++ int yy_start_stack_ptr; ++ int yy_start_stack_depth; ++ int *yy_start_stack; ++ yy_state_type yy_last_accepting_state; ++ char* yy_last_accepting_cpos; ++ ++ int yylineno_r; ++ int yy_flex_debug_r; ++ ++ char *yytext_r; ++ int yy_more_flag; ++ int yy_more_len; ++ ++ }; /* end struct yyguts_t */ ++ ++static int yy_init_globals (yyscan_t yyscanner ); ++ ++int yylex_init (yyscan_t* scanner); ++ ++int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); ++ ++/* Accessor methods to globals. ++ These are made visible to non-reentrant scanners for convenience. */ ++ ++int yylex_destroy (yyscan_t yyscanner ); ++ ++int yyget_debug (yyscan_t yyscanner ); ++ ++void yyset_debug (int debug_flag ,yyscan_t yyscanner ); ++ ++YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); ++ ++void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); ++ ++FILE *yyget_in (yyscan_t yyscanner ); ++ ++void yyset_in (FILE * in_str ,yyscan_t yyscanner ); ++ ++FILE *yyget_out (yyscan_t yyscanner ); ++ ++void yyset_out (FILE * out_str ,yyscan_t yyscanner ); ++ ++int yyget_leng (yyscan_t yyscanner ); ++ ++char *yyget_text (yyscan_t yyscanner ); ++ ++int yyget_lineno (yyscan_t yyscanner ); ++ ++void yyset_lineno (int line_number ,yyscan_t yyscanner ); ++ ++/* Macros after this point can all be overridden by user definitions in ++ * section 1. ++ */ ++ ++#ifndef YY_SKIP_YYWRAP ++#ifdef __cplusplus ++extern "C" int yywrap (yyscan_t yyscanner ); ++#else ++extern int yywrap (yyscan_t yyscanner ); ++#endif ++#endif ++ ++#ifndef yytext_ptr ++static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); ++#endif ++ ++#ifdef YY_NEED_STRLEN ++static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); ++#endif ++ ++#ifndef YY_NO_INPUT ++ ++#ifdef __cplusplus ++static int yyinput (yyscan_t yyscanner ); ++#else ++static int input (yyscan_t yyscanner ); ++#endif ++ ++#endif ++ ++/* Amount of stuff to slurp up with each read. */ ++#ifndef YY_READ_BUF_SIZE ++#ifdef __ia64__ ++/* On IA-64, the buffer size is 16k, not 8k */ ++#define YY_READ_BUF_SIZE 16384 ++#else ++#define YY_READ_BUF_SIZE 8192 ++#endif /* __ia64__ */ ++#endif ++ ++/* Copy whatever the last rule matched to the standard output. */ ++#ifndef ECHO ++/* This used to be an fputs(), but since the string might contain NUL's, ++ * we now use fwrite(). ++ */ ++#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) ++#endif ++ ++/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, ++ * is returned in "result". ++ */ ++#ifndef YY_INPUT ++#define YY_INPUT(buf,result,max_size) \ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ ++ { \ ++ int c = '*'; \ ++ size_t n; \ ++ for ( n = 0; n < max_size && \ ++ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ ++ buf[n] = (char) c; \ ++ if ( c == '\n' ) \ ++ buf[n++] = (char) c; \ ++ if ( c == EOF && ferror( yyin ) ) \ ++ YY_FATAL_ERROR( "input in flex scanner failed" ); \ ++ result = n; \ ++ } \ ++ else \ ++ { \ ++ errno=0; \ ++ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ ++ { \ ++ if( errno != EINTR) \ ++ { \ ++ YY_FATAL_ERROR( "input in flex scanner failed" ); \ ++ break; \ ++ } \ ++ errno=0; \ ++ clearerr(yyin); \ ++ } \ ++ }\ ++\ ++ ++#endif ++ ++/* No semi-colon after return; correct usage is to write "yyterminate();" - ++ * we don't want an extra ';' after the "return" because that will cause ++ * some compilers to complain about unreachable statements. ++ */ ++#ifndef yyterminate ++#define yyterminate() return YY_NULL ++#endif ++ ++/* Number of entries by which start-condition stack grows. */ ++#ifndef YY_START_STACK_INCR ++#define YY_START_STACK_INCR 25 ++#endif ++ ++/* Report a fatal error. */ ++#ifndef YY_FATAL_ERROR ++#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) ++#endif ++ ++/* end tables serialization structures and prototypes */ ++ ++/* Default declaration of generated scanner - a define so the user can ++ * easily add parameters. ++ */ ++#ifndef YY_DECL ++#define YY_DECL_IS_OURS 1 ++ ++extern int yylex (yyscan_t yyscanner); ++ ++#define YY_DECL int yylex (yyscan_t yyscanner) ++#endif /* !YY_DECL */ ++ ++/* Code executed at the beginning of each rule, after yytext and yyleng ++ * have been set up. ++ */ ++#ifndef YY_USER_ACTION ++#define YY_USER_ACTION ++#endif ++ ++/* Code executed at the end of each rule. */ ++#ifndef YY_BREAK ++#define YY_BREAK break; ++#endif ++ ++#define YY_RULE_SETUP \ ++ YY_USER_ACTION ++ ++/** The main scanner function which does all the work. ++ */ ++YY_DECL ++{ ++ register yy_state_type yy_current_state; ++ register char *yy_cp, *yy_bp; ++ register int yy_act; ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++#line 43 "shell_lex.l" ++ ++#line 716 "shell_lex.c" ++ ++ if ( !yyg->yy_init ) ++ { ++ yyg->yy_init = 1; ++ ++#ifdef YY_USER_INIT ++ YY_USER_INIT; ++#endif ++ ++ if ( ! yyg->yy_start ) ++ yyg->yy_start = 1; /* first start state */ ++ ++ if ( ! yyin ) ++ yyin = stdin; ++ ++ if ( ! yyout ) ++ yyout = stdout; ++ ++ if ( ! YY_CURRENT_BUFFER ) { ++ yyensure_buffer_stack (yyscanner); ++ YY_CURRENT_BUFFER_LVALUE = ++ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); ++ } ++ ++ yy_load_buffer_state(yyscanner ); ++ } ++ ++ while ( 1 ) /* loops until end-of-file is reached */ ++ { ++ yy_cp = yyg->yy_c_buf_p; ++ ++ /* Support of yytext. */ ++ *yy_cp = yyg->yy_hold_char; ++ ++ /* yy_bp points to the position in yy_ch_buf of the start of ++ * the current run. ++ */ ++ yy_bp = yy_cp; ++ ++ yy_current_state = yyg->yy_start; ++yy_match: ++ do ++ { ++ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; ++ if ( yy_accept[yy_current_state] ) ++ { ++ yyg->yy_last_accepting_state = yy_current_state; ++ yyg->yy_last_accepting_cpos = yy_cp; ++ } ++ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) ++ { ++ yy_current_state = (int) yy_def[yy_current_state]; ++ if ( yy_current_state >= 19 ) ++ yy_c = yy_meta[(unsigned int) yy_c]; ++ } ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ ++yy_cp; ++ } ++ while ( yy_current_state != 18 ); ++ yy_cp = yyg->yy_last_accepting_cpos; ++ yy_current_state = yyg->yy_last_accepting_state; ++ ++yy_find_action: ++ yy_act = yy_accept[yy_current_state]; ++ ++ YY_DO_BEFORE_ACTION; ++ ++do_action: /* This label is used only to access EOF actions. */ ++ ++ switch ( yy_act ) ++ { /* beginning of action switch */ ++ case 0: /* must back up */ ++ /* undo the effects of YY_DO_BEFORE_ACTION */ ++ *yy_cp = yyg->yy_hold_char; ++ yy_cp = yyg->yy_last_accepting_cpos; ++ yy_current_state = yyg->yy_last_accepting_state; ++ goto yy_find_action; ++ ++case 1: ++YY_RULE_SETUP ++#line 44 "shell_lex.l" ++{ yyextra->strval = NULL; BEGIN(STR); } ++ YY_BREAK ++case 2: ++YY_RULE_SETUP ++#line 45 "shell_lex.l" ++return TOK_SEPARATOR; ++ YY_BREAK ++case 3: ++/* rule 3 can match eol */ ++YY_RULE_SETUP ++#line 46 "shell_lex.l" ++return TOK_SPACE; ++ YY_BREAK ++case 4: ++YY_RULE_SETUP ++#line 47 "shell_lex.l" ++return TOK_COMMENT; ++ YY_BREAK ++case 5: ++YY_RULE_SETUP ++#line 48 "shell_lex.l" ++{ yyextra->strval = strdup(yytext); return TOK_STRING; } ++ YY_BREAK ++case 6: ++/* rule 6 can match eol */ ++YY_RULE_SETUP ++#line 49 "shell_lex.l" ++yyextra->strval = str_append(yyextra->strval, yytext); ++ YY_BREAK ++case 7: ++YY_RULE_SETUP ++#line 50 "shell_lex.l" ++yyextra->strval = str_append(yyextra->strval, "\""); ++ YY_BREAK ++case 8: ++YY_RULE_SETUP ++#line 51 "shell_lex.l" ++yyextra->strval = str_append(yyextra->strval, "\\"); ++ YY_BREAK ++case 9: ++YY_RULE_SETUP ++#line 52 "shell_lex.l" ++{ BEGIN(INITIAL); return TOK_STRING; } ++ YY_BREAK ++case 10: ++YY_RULE_SETUP ++#line 53 "shell_lex.l" ++ECHO; ++ YY_BREAK ++#line 847 "shell_lex.c" ++case YY_STATE_EOF(INITIAL): ++case YY_STATE_EOF(STR): ++ yyterminate(); ++ ++ case YY_END_OF_BUFFER: ++ { ++ /* Amount of text matched not including the EOB char. */ ++ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; ++ ++ /* Undo the effects of YY_DO_BEFORE_ACTION. */ ++ *yy_cp = yyg->yy_hold_char; ++ YY_RESTORE_YY_MORE_OFFSET ++ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) ++ { ++ /* We're scanning a new file or input source. It's ++ * possible that this happened because the user ++ * just pointed yyin at a new source and called ++ * yylex(). If so, then we have to assure ++ * consistency between YY_CURRENT_BUFFER and our ++ * globals. Here is the right place to do so, because ++ * this is the first action (other than possibly a ++ * back-up) that will match for the new input source. ++ */ ++ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; ++ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; ++ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; ++ } ++ ++ /* Note that here we test for yy_c_buf_p "<=" to the position ++ * of the first EOB in the buffer, since yy_c_buf_p will ++ * already have been incremented past the NUL character ++ * (since all states make transitions on EOB to the ++ * end-of-buffer state). Contrast this with the test ++ * in input(). ++ */ ++ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) ++ { /* This was really a NUL. */ ++ yy_state_type yy_next_state; ++ ++ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; ++ ++ yy_current_state = yy_get_previous_state( yyscanner ); ++ ++ /* Okay, we're now positioned to make the NUL ++ * transition. We couldn't have ++ * yy_get_previous_state() go ahead and do it ++ * for us because it doesn't know how to deal ++ * with the possibility of jamming (and we don't ++ * want to build jamming into it because then it ++ * will run more slowly). ++ */ ++ ++ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); ++ ++ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; ++ ++ if ( yy_next_state ) ++ { ++ /* Consume the NUL. */ ++ yy_cp = ++yyg->yy_c_buf_p; ++ yy_current_state = yy_next_state; ++ goto yy_match; ++ } ++ ++ else ++ { ++ yy_cp = yyg->yy_last_accepting_cpos; ++ yy_current_state = yyg->yy_last_accepting_state; ++ goto yy_find_action; ++ } ++ } ++ ++ else switch ( yy_get_next_buffer( yyscanner ) ) ++ { ++ case EOB_ACT_END_OF_FILE: ++ { ++ yyg->yy_did_buffer_switch_on_eof = 0; ++ ++ if ( yywrap(yyscanner ) ) ++ { ++ /* Note: because we've taken care in ++ * yy_get_next_buffer() to have set up ++ * yytext, we can now set up ++ * yy_c_buf_p so that if some total ++ * hoser (like flex itself) wants to ++ * call the scanner after we return the ++ * YY_NULL, it'll still work - another ++ * YY_NULL will get returned. ++ */ ++ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; ++ ++ yy_act = YY_STATE_EOF(YY_START); ++ goto do_action; ++ } ++ ++ else ++ { ++ if ( ! yyg->yy_did_buffer_switch_on_eof ) ++ YY_NEW_FILE; ++ } ++ break; ++ } ++ ++ case EOB_ACT_CONTINUE_SCAN: ++ yyg->yy_c_buf_p = ++ yyg->yytext_ptr + yy_amount_of_matched_text; ++ ++ yy_current_state = yy_get_previous_state( yyscanner ); ++ ++ yy_cp = yyg->yy_c_buf_p; ++ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; ++ goto yy_match; ++ ++ case EOB_ACT_LAST_MATCH: ++ yyg->yy_c_buf_p = ++ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; ++ ++ yy_current_state = yy_get_previous_state( yyscanner ); ++ ++ yy_cp = yyg->yy_c_buf_p; ++ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; ++ goto yy_find_action; ++ } ++ break; ++ } ++ ++ default: ++ YY_FATAL_ERROR( ++ "fatal flex scanner internal error--no action found" ); ++ } /* end of action switch */ ++ } /* end of scanning one token */ ++} /* end of yylex */ ++ ++/* yy_get_next_buffer - try to read in a new buffer ++ * ++ * Returns a code representing an action: ++ * EOB_ACT_LAST_MATCH - ++ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position ++ * EOB_ACT_END_OF_FILE - end of file ++ */ ++static int yy_get_next_buffer (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; ++ register char *source = yyg->yytext_ptr; ++ register int number_to_move, i; ++ int ret_val; ++ ++ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) ++ YY_FATAL_ERROR( ++ "fatal flex scanner internal error--end of buffer missed" ); ++ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) ++ { /* Don't try to fill the buffer, so this is an EOF. */ ++ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) ++ { ++ /* We matched a single character, the EOB, so ++ * treat this as a final EOF. ++ */ ++ return EOB_ACT_END_OF_FILE; ++ } ++ ++ else ++ { ++ /* We matched some text prior to the EOB, first ++ * process it. ++ */ ++ return EOB_ACT_LAST_MATCH; ++ } ++ } ++ ++ /* Try to read more data. */ ++ ++ /* First move last chars to start of buffer. */ ++ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; ++ ++ for ( i = 0; i < number_to_move; ++i ) ++ *(dest++) = *(source++); ++ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) ++ /* don't do the read, it's not guaranteed to return an EOF, ++ * just force an EOF ++ */ ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; ++ ++ else ++ { ++ int num_to_read = ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; ++ ++ while ( num_to_read <= 0 ) ++ { /* Not enough room in the buffer - grow it. */ ++ ++ /* just a shorter name for the current buffer */ ++ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; ++ ++ int yy_c_buf_p_offset = ++ (int) (yyg->yy_c_buf_p - b->yy_ch_buf); ++ ++ if ( b->yy_is_our_buffer ) ++ { ++ int new_size = b->yy_buf_size * 2; ++ ++ if ( new_size <= 0 ) ++ b->yy_buf_size += b->yy_buf_size / 8; ++ else ++ b->yy_buf_size *= 2; ++ ++ b->yy_ch_buf = (char *) ++ /* Include room in for 2 EOB chars. */ ++ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); ++ } ++ else ++ /* Can't grow it, we don't own it. */ ++ b->yy_ch_buf = 0; ++ ++ if ( ! b->yy_ch_buf ) ++ YY_FATAL_ERROR( ++ "fatal error - scanner input buffer overflow" ); ++ ++ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; ++ ++ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - ++ number_to_move - 1; ++ ++ } ++ ++ if ( num_to_read > YY_READ_BUF_SIZE ) ++ num_to_read = YY_READ_BUF_SIZE; ++ ++ /* Read in more data. */ ++ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), ++ yyg->yy_n_chars, (size_t) num_to_read ); ++ ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; ++ } ++ ++ if ( yyg->yy_n_chars == 0 ) ++ { ++ if ( number_to_move == YY_MORE_ADJ ) ++ { ++ ret_val = EOB_ACT_END_OF_FILE; ++ yyrestart(yyin ,yyscanner); ++ } ++ ++ else ++ { ++ ret_val = EOB_ACT_LAST_MATCH; ++ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = ++ YY_BUFFER_EOF_PENDING; ++ } ++ } ++ ++ else ++ ret_val = EOB_ACT_CONTINUE_SCAN; ++ ++ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { ++ /* Extend the array by 50%, plus the number we really need. */ ++ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); ++ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); ++ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); ++ } ++ ++ yyg->yy_n_chars += number_to_move; ++ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; ++ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; ++ ++ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; ++ ++ return ret_val; ++} ++ ++/* yy_get_previous_state - get the state just before the EOB char was reached */ ++ ++ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) ++{ ++ register yy_state_type yy_current_state; ++ register char *yy_cp; ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ yy_current_state = yyg->yy_start; ++ ++ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) ++ { ++ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); ++ if ( yy_accept[yy_current_state] ) ++ { ++ yyg->yy_last_accepting_state = yy_current_state; ++ yyg->yy_last_accepting_cpos = yy_cp; ++ } ++ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) ++ { ++ yy_current_state = (int) yy_def[yy_current_state]; ++ if ( yy_current_state >= 19 ) ++ yy_c = yy_meta[(unsigned int) yy_c]; ++ } ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ } ++ ++ return yy_current_state; ++} ++ ++/* yy_try_NUL_trans - try to make a transition on the NUL character ++ * ++ * synopsis ++ * next_state = yy_try_NUL_trans( current_state ); ++ */ ++ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) ++{ ++ register int yy_is_jam; ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ ++ register char *yy_cp = yyg->yy_c_buf_p; ++ ++ register YY_CHAR yy_c = 1; ++ if ( yy_accept[yy_current_state] ) ++ { ++ yyg->yy_last_accepting_state = yy_current_state; ++ yyg->yy_last_accepting_cpos = yy_cp; ++ } ++ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) ++ { ++ yy_current_state = (int) yy_def[yy_current_state]; ++ if ( yy_current_state >= 19 ) ++ yy_c = yy_meta[(unsigned int) yy_c]; ++ } ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ yy_is_jam = (yy_current_state == 18); ++ ++ return yy_is_jam ? 0 : yy_current_state; ++} ++ ++#ifndef YY_NO_INPUT ++#ifdef __cplusplus ++ static int yyinput (yyscan_t yyscanner) ++#else ++ static int input (yyscan_t yyscanner) ++#endif ++ ++{ ++ int c; ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ *yyg->yy_c_buf_p = yyg->yy_hold_char; ++ ++ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) ++ { ++ /* yy_c_buf_p now points to the character we want to return. ++ * If this occurs *before* the EOB characters, then it's a ++ * valid NUL; if not, then we've hit the end of the buffer. ++ */ ++ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) ++ /* This was really a NUL. */ ++ *yyg->yy_c_buf_p = '\0'; ++ ++ else ++ { /* need more input */ ++ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; ++ ++yyg->yy_c_buf_p; ++ ++ switch ( yy_get_next_buffer( yyscanner ) ) ++ { ++ case EOB_ACT_LAST_MATCH: ++ /* This happens because yy_g_n_b() ++ * sees that we've accumulated a ++ * token and flags that we need to ++ * try matching the token before ++ * proceeding. But for input(), ++ * there's no matching to consider. ++ * So convert the EOB_ACT_LAST_MATCH ++ * to EOB_ACT_END_OF_FILE. ++ */ ++ ++ /* Reset buffer status. */ ++ yyrestart(yyin ,yyscanner); ++ ++ /*FALLTHROUGH*/ ++ ++ case EOB_ACT_END_OF_FILE: ++ { ++ if ( yywrap(yyscanner ) ) ++ return EOF; ++ ++ if ( ! yyg->yy_did_buffer_switch_on_eof ) ++ YY_NEW_FILE; ++#ifdef __cplusplus ++ return yyinput(yyscanner); ++#else ++ return input(yyscanner); ++#endif ++ } ++ ++ case EOB_ACT_CONTINUE_SCAN: ++ yyg->yy_c_buf_p = yyg->yytext_ptr + offset; ++ break; ++ } ++ } ++ } ++ ++ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ ++ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ ++ yyg->yy_hold_char = *++yyg->yy_c_buf_p; ++ ++ return c; ++} ++#endif /* ifndef YY_NO_INPUT */ ++ ++/** Immediately switch to a different input stream. ++ * @param input_file A readable stream. ++ * @param yyscanner The scanner object. ++ * @note This function does not reset the start condition to @c INITIAL . ++ */ ++ void yyrestart (FILE * input_file , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ if ( ! YY_CURRENT_BUFFER ){ ++ yyensure_buffer_stack (yyscanner); ++ YY_CURRENT_BUFFER_LVALUE = ++ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); ++ } ++ ++ yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); ++ yy_load_buffer_state(yyscanner ); ++} ++ ++/** Switch to a different input buffer. ++ * @param new_buffer The new input buffer. ++ * @param yyscanner The scanner object. ++ */ ++ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ /* TODO. We should be able to replace this entire function body ++ * with ++ * yypop_buffer_state(); ++ * yypush_buffer_state(new_buffer); ++ */ ++ yyensure_buffer_stack (yyscanner); ++ if ( YY_CURRENT_BUFFER == new_buffer ) ++ return; ++ ++ if ( YY_CURRENT_BUFFER ) ++ { ++ /* Flush out information for old buffer. */ ++ *yyg->yy_c_buf_p = yyg->yy_hold_char; ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; ++ } ++ ++ YY_CURRENT_BUFFER_LVALUE = new_buffer; ++ yy_load_buffer_state(yyscanner ); ++ ++ /* We don't actually know whether we did this switch during ++ * EOF (yywrap()) processing, but the only time this flag ++ * is looked at is after yywrap() is called, so it's safe ++ * to go ahead and always set it. ++ */ ++ yyg->yy_did_buffer_switch_on_eof = 1; ++} ++ ++static void yy_load_buffer_state (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; ++ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; ++ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; ++ yyg->yy_hold_char = *yyg->yy_c_buf_p; ++} ++ ++/** Allocate and initialize an input buffer state. ++ * @param file A readable stream. ++ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. ++ * @param yyscanner The scanner object. ++ * @return the allocated buffer state. ++ */ ++ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) ++{ ++ YY_BUFFER_STATE b; ++ ++ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); ++ if ( ! b ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); ++ ++ b->yy_buf_size = size; ++ ++ /* yy_ch_buf has to be 2 characters longer than the size given because ++ * we need to put in 2 end-of-buffer characters. ++ */ ++ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); ++ if ( ! b->yy_ch_buf ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); ++ ++ b->yy_is_our_buffer = 1; ++ ++ yy_init_buffer(b,file ,yyscanner); ++ ++ return b; ++} ++ ++/** Destroy the buffer. ++ * @param b a buffer created with yy_create_buffer() ++ * @param yyscanner The scanner object. ++ */ ++ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ if ( ! b ) ++ return; ++ ++ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ ++ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; ++ ++ if ( b->yy_is_our_buffer ) ++ yyfree((void *) b->yy_ch_buf ,yyscanner ); ++ ++ yyfree((void *) b ,yyscanner ); ++} ++ ++#ifndef __cplusplus ++extern int isatty (int ); ++#endif /* __cplusplus */ ++ ++/* Initializes or reinitializes a buffer. ++ * This function is sometimes called more than once on the same buffer, ++ * such as during a yyrestart() or at EOF. ++ */ ++ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) ++ ++{ ++ int oerrno = errno; ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ yy_flush_buffer(b ,yyscanner); ++ ++ b->yy_input_file = file; ++ b->yy_fill_buffer = 1; ++ ++ /* If b is the current buffer, then yy_init_buffer was _probably_ ++ * called from yyrestart() or through yy_get_next_buffer. ++ * In that case, we don't want to reset the lineno or column. ++ */ ++ if (b != YY_CURRENT_BUFFER){ ++ b->yy_bs_lineno = 1; ++ b->yy_bs_column = 0; ++ } ++ ++ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; ++ ++ errno = oerrno; ++} ++ ++/** Discard all buffered characters. On the next scan, YY_INPUT will be called. ++ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. ++ * @param yyscanner The scanner object. ++ */ ++ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ if ( ! b ) ++ return; ++ ++ b->yy_n_chars = 0; ++ ++ /* We always need two end-of-buffer characters. The first causes ++ * a transition to the end-of-buffer state. The second causes ++ * a jam in that state. ++ */ ++ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; ++ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; ++ ++ b->yy_buf_pos = &b->yy_ch_buf[0]; ++ ++ b->yy_at_bol = 1; ++ b->yy_buffer_status = YY_BUFFER_NEW; ++ ++ if ( b == YY_CURRENT_BUFFER ) ++ yy_load_buffer_state(yyscanner ); ++} ++ ++/** Pushes the new state onto the stack. The new state becomes ++ * the current state. This function will allocate the stack ++ * if necessary. ++ * @param new_buffer The new state. ++ * @param yyscanner The scanner object. ++ */ ++void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ if (new_buffer == NULL) ++ return; ++ ++ yyensure_buffer_stack(yyscanner); ++ ++ /* This block is copied from yy_switch_to_buffer. */ ++ if ( YY_CURRENT_BUFFER ) ++ { ++ /* Flush out information for old buffer. */ ++ *yyg->yy_c_buf_p = yyg->yy_hold_char; ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; ++ } ++ ++ /* Only push if top exists. Otherwise, replace top. */ ++ if (YY_CURRENT_BUFFER) ++ yyg->yy_buffer_stack_top++; ++ YY_CURRENT_BUFFER_LVALUE = new_buffer; ++ ++ /* copied from yy_switch_to_buffer. */ ++ yy_load_buffer_state(yyscanner ); ++ yyg->yy_did_buffer_switch_on_eof = 1; ++} ++ ++/** Removes and deletes the top of the stack, if present. ++ * The next element becomes the new top. ++ * @param yyscanner The scanner object. ++ */ ++void yypop_buffer_state (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ if (!YY_CURRENT_BUFFER) ++ return; ++ ++ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); ++ YY_CURRENT_BUFFER_LVALUE = NULL; ++ if (yyg->yy_buffer_stack_top > 0) ++ --yyg->yy_buffer_stack_top; ++ ++ if (YY_CURRENT_BUFFER) { ++ yy_load_buffer_state(yyscanner ); ++ yyg->yy_did_buffer_switch_on_eof = 1; ++ } ++} ++ ++/* Allocates the stack if it does not exist. ++ * Guarantees space for at least one push. ++ */ ++static void yyensure_buffer_stack (yyscan_t yyscanner) ++{ ++ int num_to_alloc; ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ if (!yyg->yy_buffer_stack) { ++ ++ /* First allocation is just for 2 elements, since we don't know if this ++ * scanner will even need a stack. We use 2 instead of 1 to avoid an ++ * immediate realloc on the next call. ++ */ ++ num_to_alloc = 1; ++ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc ++ (num_to_alloc * sizeof(struct yy_buffer_state*) ++ , yyscanner); ++ if ( ! yyg->yy_buffer_stack ) ++ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); ++ ++ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); ++ ++ yyg->yy_buffer_stack_max = num_to_alloc; ++ yyg->yy_buffer_stack_top = 0; ++ return; ++ } ++ ++ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ ++ ++ /* Increase the buffer to prepare for a possible push. */ ++ int grow_size = 8 /* arbitrary grow size */; ++ ++ num_to_alloc = yyg->yy_buffer_stack_max + grow_size; ++ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc ++ (yyg->yy_buffer_stack, ++ num_to_alloc * sizeof(struct yy_buffer_state*) ++ , yyscanner); ++ if ( ! yyg->yy_buffer_stack ) ++ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); ++ ++ /* zero only the new slots.*/ ++ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); ++ yyg->yy_buffer_stack_max = num_to_alloc; ++ } ++} ++ ++/** Setup the input buffer state to scan directly from a user-specified character buffer. ++ * @param base the character buffer ++ * @param size the size in bytes of the character buffer ++ * @param yyscanner The scanner object. ++ * @return the newly allocated buffer state object. ++ */ ++YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) ++{ ++ YY_BUFFER_STATE b; ++ ++ if ( size < 2 || ++ base[size-2] != YY_END_OF_BUFFER_CHAR || ++ base[size-1] != YY_END_OF_BUFFER_CHAR ) ++ /* They forgot to leave room for the EOB's. */ ++ return 0; ++ ++ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); ++ if ( ! b ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); ++ ++ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ ++ b->yy_buf_pos = b->yy_ch_buf = base; ++ b->yy_is_our_buffer = 0; ++ b->yy_input_file = 0; ++ b->yy_n_chars = b->yy_buf_size; ++ b->yy_is_interactive = 0; ++ b->yy_at_bol = 1; ++ b->yy_fill_buffer = 0; ++ b->yy_buffer_status = YY_BUFFER_NEW; ++ ++ yy_switch_to_buffer(b ,yyscanner ); ++ ++ return b; ++} ++ ++/** Setup the input buffer state to scan a string. The next call to yylex() will ++ * scan from a @e copy of @a str. ++ * @param yystr a NUL-terminated string to scan ++ * @param yyscanner The scanner object. ++ * @return the newly allocated buffer state object. ++ * @note If you want to scan bytes that may contain NUL values, then use ++ * yy_scan_bytes() instead. ++ */ ++YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) ++{ ++ ++ return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); ++} ++ ++/** Setup the input buffer state to scan the given bytes. The next call to yylex() will ++ * scan from a @e copy of @a bytes. ++ * @param yybytes the byte buffer to scan ++ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. ++ * @param yyscanner The scanner object. ++ * @return the newly allocated buffer state object. ++ */ ++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) ++{ ++ YY_BUFFER_STATE b; ++ char *buf; ++ yy_size_t n; ++ int i; ++ ++ /* Get memory for full buffer, including space for trailing EOB's. */ ++ n = _yybytes_len + 2; ++ buf = (char *) yyalloc(n ,yyscanner ); ++ if ( ! buf ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); ++ ++ for ( i = 0; i < _yybytes_len; ++i ) ++ buf[i] = yybytes[i]; ++ ++ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; ++ ++ b = yy_scan_buffer(buf,n ,yyscanner); ++ if ( ! b ) ++ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); ++ ++ /* It's okay to grow etc. this buffer, and we should throw it ++ * away when we're done. ++ */ ++ b->yy_is_our_buffer = 1; ++ ++ return b; ++} ++ ++#ifndef YY_EXIT_FAILURE ++#define YY_EXIT_FAILURE 2 ++#endif ++ ++static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) ++{ ++ (void) fprintf( stderr, "%s\n", msg ); ++ exit( YY_EXIT_FAILURE ); ++} ++ ++/* Redefine yyless() so it works in section 3 code. */ ++ ++#undef yyless ++#define yyless(n) \ ++ do \ ++ { \ ++ /* Undo effects of setting up yytext. */ \ ++ int yyless_macro_arg = (n); \ ++ YY_LESS_LINENO(yyless_macro_arg);\ ++ yytext[yyleng] = yyg->yy_hold_char; \ ++ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ ++ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ ++ *yyg->yy_c_buf_p = '\0'; \ ++ yyleng = yyless_macro_arg; \ ++ } \ ++ while ( 0 ) ++ ++/* Accessor methods (get/set functions) to struct members. */ ++ ++/** Get the user-defined data for this scanner. ++ * @param yyscanner The scanner object. ++ */ ++YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ return yyextra; ++} ++ ++/** Get the current line number. ++ * @param yyscanner The scanner object. ++ */ ++int yyget_lineno (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ if (! YY_CURRENT_BUFFER) ++ return 0; ++ ++ return yylineno; ++} ++ ++/** Get the current column number. ++ * @param yyscanner The scanner object. ++ */ ++int yyget_column (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ if (! YY_CURRENT_BUFFER) ++ return 0; ++ ++ return yycolumn; ++} ++ ++/** Get the input stream. ++ * @param yyscanner The scanner object. ++ */ ++FILE *yyget_in (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ return yyin; ++} ++ ++/** Get the output stream. ++ * @param yyscanner The scanner object. ++ */ ++FILE *yyget_out (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ return yyout; ++} ++ ++/** Get the length of the current token. ++ * @param yyscanner The scanner object. ++ */ ++int yyget_leng (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ return yyleng; ++} ++ ++/** Get the current token. ++ * @param yyscanner The scanner object. ++ */ ++ ++char *yyget_text (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ return yytext; ++} ++ ++/** Set the user-defined data. This data is never touched by the scanner. ++ * @param user_defined The data to be associated with this scanner. ++ * @param yyscanner The scanner object. ++ */ ++void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ yyextra = user_defined ; ++} ++ ++/** Set the current line number. ++ * @param line_number ++ * @param yyscanner The scanner object. ++ */ ++void yyset_lineno (int line_number , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ /* lineno is only valid if an input buffer exists. */ ++ if (! YY_CURRENT_BUFFER ) ++ yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); ++ ++ yylineno = line_number; ++} ++ ++/** Set the current column. ++ * @param line_number ++ * @param yyscanner The scanner object. ++ */ ++void yyset_column (int column_no , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ /* column is only valid if an input buffer exists. */ ++ if (! YY_CURRENT_BUFFER ) ++ yy_fatal_error( "yyset_column called with no buffer" , yyscanner); ++ ++ yycolumn = column_no; ++} ++ ++/** Set the input stream. This does not discard the current ++ * input buffer. ++ * @param in_str A readable stream. ++ * @param yyscanner The scanner object. ++ * @see yy_switch_to_buffer ++ */ ++void yyset_in (FILE * in_str , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ yyin = in_str ; ++} ++ ++void yyset_out (FILE * out_str , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ yyout = out_str ; ++} ++ ++int yyget_debug (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ return yy_flex_debug; ++} ++ ++void yyset_debug (int bdebug , yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ yy_flex_debug = bdebug ; ++} ++ ++/* Accessor methods for yylval and yylloc */ ++ ++/* User-visible API */ ++ ++/* yylex_init is special because it creates the scanner itself, so it is ++ * the ONLY reentrant function that doesn't take the scanner as the last argument. ++ * That's why we explicitly handle the declaration, instead of using our macros. ++ */ ++ ++int yylex_init(yyscan_t* ptr_yy_globals) ++ ++{ ++ if (ptr_yy_globals == NULL){ ++ errno = EINVAL; ++ return 1; ++ } ++ ++ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); ++ ++ if (*ptr_yy_globals == NULL){ ++ errno = ENOMEM; ++ return 1; ++ } ++ ++ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ ++ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); ++ ++ return yy_init_globals ( *ptr_yy_globals ); ++} ++ ++/* yylex_init_extra has the same functionality as yylex_init, but follows the ++ * convention of taking the scanner as the last argument. Note however, that ++ * this is a *pointer* to a scanner, as it will be allocated by this call (and ++ * is the reason, too, why this function also must handle its own declaration). ++ * The user defined value in the first argument will be available to yyalloc in ++ * the yyextra field. ++ */ ++ ++int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) ++ ++{ ++ struct yyguts_t dummy_yyguts; ++ ++ yyset_extra (yy_user_defined, &dummy_yyguts); ++ ++ if (ptr_yy_globals == NULL){ ++ errno = EINVAL; ++ return 1; ++ } ++ ++ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); ++ ++ if (*ptr_yy_globals == NULL){ ++ errno = ENOMEM; ++ return 1; ++ } ++ ++ /* By setting to 0xAA, we expose bugs in ++ yy_init_globals. Leave at 0x00 for releases. */ ++ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); ++ ++ yyset_extra (yy_user_defined, *ptr_yy_globals); ++ ++ return yy_init_globals ( *ptr_yy_globals ); ++} ++ ++static int yy_init_globals (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ /* Initialization is the same as for the non-reentrant scanner. ++ * This function is called from yylex_destroy(), so don't allocate here. ++ */ ++ ++ yyg->yy_buffer_stack = 0; ++ yyg->yy_buffer_stack_top = 0; ++ yyg->yy_buffer_stack_max = 0; ++ yyg->yy_c_buf_p = (char *) 0; ++ yyg->yy_init = 0; ++ yyg->yy_start = 0; ++ ++ yyg->yy_start_stack_ptr = 0; ++ yyg->yy_start_stack_depth = 0; ++ yyg->yy_start_stack = NULL; ++ ++/* Defined in main.c */ ++#ifdef YY_STDINIT ++ yyin = stdin; ++ yyout = stdout; ++#else ++ yyin = (FILE *) 0; ++ yyout = (FILE *) 0; ++#endif ++ ++ /* For future reference: Set errno on error, since we are called by ++ * yylex_init() ++ */ ++ return 0; ++} ++ ++/* yylex_destroy is for both reentrant and non-reentrant scanners. */ ++int yylex_destroy (yyscan_t yyscanner) ++{ ++ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; ++ ++ /* Pop the buffer stack, destroying each element. */ ++ while(YY_CURRENT_BUFFER){ ++ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); ++ YY_CURRENT_BUFFER_LVALUE = NULL; ++ yypop_buffer_state(yyscanner); ++ } ++ ++ /* Destroy the stack itself. */ ++ yyfree(yyg->yy_buffer_stack ,yyscanner); ++ yyg->yy_buffer_stack = NULL; ++ ++ /* Destroy the start condition stack. */ ++ yyfree(yyg->yy_start_stack ,yyscanner ); ++ yyg->yy_start_stack = NULL; ++ ++ /* Reset the globals. This is important in a non-reentrant scanner so the next time ++ * yylex() is called, initialization will occur. */ ++ yy_init_globals( yyscanner); ++ ++ /* Destroy the main struct (reentrant only). */ ++ yyfree ( yyscanner , yyscanner ); ++ yyscanner = NULL; ++ return 0; ++} ++ ++/* ++ * Internal utility routines. ++ */ ++ ++#ifndef yytext_ptr ++static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) ++{ ++ register int i; ++ for ( i = 0; i < n; ++i ) ++ s1[i] = s2[i]; ++} ++#endif ++ ++#ifdef YY_NEED_STRLEN ++static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) ++{ ++ register int n; ++ for ( n = 0; s[n]; ++n ) ++ ; ++ ++ return n; ++} ++#endif ++ ++void *yyalloc (yy_size_t size , yyscan_t yyscanner) ++{ ++ return (void *) malloc( size ); ++} ++ ++void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) ++{ ++ /* The cast to (char *) in the following accommodates both ++ * implementations that use char* generic pointers, and those ++ * that use void* generic pointers. It works with the latter ++ * because both ANSI C and C++ allow castless assignment from ++ * any pointer type to void*, and deal with argument conversions ++ * as though doing an assignment. ++ */ ++ return (void *) realloc( (char *) ptr, size ); ++} ++ ++void yyfree (void * ptr , yyscan_t yyscanner) ++{ ++ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ ++} ++ ++#define YYTABLES_NAME "yytables" ++ ++#line 53 "shell_lex.l" diff --cc jzboot/src/shell_lex.l index 0000000,0000000..65f8987 new file mode 100644 --- /dev/null +++ b/jzboot/src/shell_lex.l @@@ -1,0 -1,0 +1,52 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++%{ ++#include "shell_internal.h" ++#include <string.h> ++#include <stdlib.h> ++ ++static char *str_append(char *str, const char *src) { ++ if(str) { ++ size_t newlen = strlen(str) + strlen(src) + 1; ++ ++ char *newstr = malloc(newlen); ++ ++ strcpy(newstr, str); ++ strcat(newstr, src); ++ ++ free(str); ++ ++ return newstr; ++ } else ++ return strdup(src); ++} ++%} ++%option noyywrap nounput noinput batch reentrant ++ ++%x STR ++%% ++["] { yyextra->strval = NULL; BEGIN(STR); } ++; return TOK_SEPARATOR; ++[[:space:]]+ return TOK_SPACE; ++[#] return TOK_COMMENT; ++[^[:space:];"#]+ { yyextra->strval = strdup(yytext); return TOK_STRING; } ++<STR>[^\\"]+ yyextra->strval = str_append(yyextra->strval, yytext); ++<STR>\\["] yyextra->strval = str_append(yyextra->strval, "\""); ++<STR>\\ yyextra->strval = str_append(yyextra->strval, "\\"); ++<STR>["] { BEGIN(INITIAL); return TOK_STRING; } diff --cc jzboot/src/spl_cmdset.c index 0000000,0000000..76a3c77 new file mode 100644 --- /dev/null +++ b/jzboot/src/spl_cmdset.c @@@ -1,0 -1,0 +1,128 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com>, ++ * Peter Zotov <whitequark@whitequark.org> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <string.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <errno.h> ++ ++#include "shell.h" ++#include "app_config.h" ++#include "ingenic.h" ++ ++static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]); ++static int spl_gpio(shell_context_t *ctx, int argc, char *argv[]); ++static int spl_boot(shell_context_t *ctx, int argc, char *argv[]); ++ ++const shell_command_t spl_cmdset[] = { ++ { "memtest", "SDRAM test", spl_memtest, "[BASE] <SIZE>" }, ++ { "gpio", "Set GPIO #PIN to STATE 0 or 1", spl_gpio, "<PIN> <STATE>" }, ++ { "boot", "Load stage2 USB bootloader", spl_boot, NULL }, ++ { NULL, NULL, NULL, NULL } ++}; ++ ++static int spl_stage1_op(shell_context_t *ctx, uint32_t op, uint32_t pin, uint32_t base, uint32_t size) { ++ if(cfg_getenv("STAGE1_FILE") == NULL) { ++ printf("Variable STAGE1_FILE is not set\n"); ++ ++ return -1; ++ } ++ ++ int ret = ingenic_stage1_debugop(shell_device(ctx), cfg_getenv("STAGE1_FILE"), op, pin, base, size); ++ ++ if(ret == -1) ++ perror("ingenic_stage1_debugop"); ++ ++ return ret; ++} ++ ++static int spl_memtest(shell_context_t *ctx, int argc, char *argv[]) { ++ uint32_t start, size; ++ ++ if(argc == 3) { ++ start = strtoul(argv[1], NULL, 0); ++ size = strtoul(argv[2], NULL, 0); ++ } else { ++ start = SDRAM_BASE; ++ size = ingenic_sdram_size(shell_device(ctx)); ++ } ++ ++ if(cfg_getenv("STAGE1_FILE") == NULL) { ++ printf("Variable STAGE1_FILE is not set\n"); ++ ++ return -1; ++ } ++ ++ uint32_t fail; ++ ++ int ret = ingenic_memtest(shell_device(ctx), cfg_getenv("STAGE1_FILE"), start, size, &fail); ++ ++ if(ret == -1) { ++ if(errno == EFAULT) { ++ printf("Memory test failed at address 0x%08X\n", fail); ++ } else { ++ perror("ingenic_memtest"); ++ } ++ ++ } else { ++ printf("Memory test passed\n"); ++ } ++ ++ return ret; ++} ++ ++static int spl_gpio(shell_context_t *ctx, int argc, char *argv[]) { ++ if(strcmp(argv[2], "0") && strcmp(argv[2], "1")) { ++ printf("Usage: %s <PIN> <STATE>\n", argv[0]); ++ printf(" STATE := 0 | 1\n"); ++ ++ return -1; ++ } ++ ++ return spl_stage1_op(ctx, !strcmp(argv[2], "1") ? STAGE1_DEBUG_GPIO_SET : STAGE1_DEBUG_GPIO_CLEAR, atoi(argv[1]), 0, 0); ++} ++ ++static int spl_boot(shell_context_t *ctx, int argc, char *argv[]) { ++ int ret = spl_stage1_op(ctx, STAGE1_DEBUG_BOOT, 0, 0, 0); ++ ++ if(ret == -1) ++ return -1; ++ ++ if(cfg_getenv("STAGE2_FILE") == NULL) { ++ printf("Variable STAGE2_FILE is not set\n"); ++ ++ return -1; ++ } ++ ++ ret = ingenic_loadstage(shell_device(ctx), INGENIC_STAGE2, cfg_getenv("STAGE2_FILE")); ++ ++ if(ret == -1) { ++ perror("ingenic_loadstage"); ++ ++ return -1; ++ } ++ ++ ret = ingenic_configure_stage2(shell_device(ctx)); ++ ++ if(ret == -1) ++ perror("ingenic_configure_stage2"); ++ ++ return ret; ++} ++ diff --cc jzboot/src/usbboot_cmdset.c index 0000000,0000000..6d9ec2c new file mode 100644 --- /dev/null +++ b/jzboot/src/usbboot_cmdset.c @@@ -1,0 -1,0 +1,162 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Peter Zotov <whitequark@whitequark.org> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <string.h> ++#include <stdio.h> ++#include <stdlib.h> ++ ++#include "shell.h" ++#include "app_config.h" ++#include "ingenic.h" ++#include "elfldr.h" ++ ++static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_go(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_load_kernel(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_nquery(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_ndump(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_nerase(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_nprogram(shell_context_t *ctx, int argc, char *argv[]); ++static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]); ++ ++const shell_command_t usbboot_cmdset[] = { ++ ++ { "boot", "Reconfigure stage2", usbboot_boot, NULL }, ++ { "load", "Load file to SDRAM", usbboot_load, "<FILE> <BASE>" }, ++ { "go", "Jump to <ADDRESS>", usbboot_go, "<ADDRESS>" }, ++ { "load_kernel", "Load ELF kernel and initrd to memory", usbboot_load_kernel, "<KERNEL> <CMDLINE> [INITRAMFS]" }, ++ ++ { "nquery", "Query NAND information", usbboot_nquery, "<DEVICE>" }, ++ { "ndump", "Dump NAND to file", usbboot_ndump, "<DEVICE> <STARTPAGE> <PAGES> <FILE>" }, ++ { "ndump_oob", "Dump NAND with OOB to file", usbboot_ndump, "<DEVICE> <STARTPAGE> <PAGES> <FILE>" }, ++ { "nerase", "Erase NAND blocks", usbboot_nerase, "<DEVICE> <STARTBLOCK> <BLOCKS>" }, ++ { "nprogram", "Program NAND from file", usbboot_nprogram, "<DEVICE> <STARTPAGE> <FILE>" }, ++ { "nprogram_oob", "Program NAND with OOB from file", usbboot_nprogram, "<DEVICE> <STARTPAGE> <FILE>" }, ++ { "nload", "Load NAND data to SDRAM", usbboot_nload, "<DEVICE> <STARTPAGE> <PAGES> <BASE>" }, ++ ++ { NULL, NULL, NULL, NULL } ++}; ++ ++static int usbboot_boot(shell_context_t *ctx, int argc, char *argv[]) { ++ int ret = ingenic_configure_stage2(shell_device(ctx)); ++ ++ if(ret == -1) ++ perror("ingenic_configure_stage2"); ++ ++ return ret; ++} ++ ++static int usbboot_load(shell_context_t *ctx, int argc, char *argv[]) { ++ int ret = ingenic_load_sdram_file(shell_device(ctx), strtoul(argv[2], NULL, 0), argv[1]); ++ ++ if(ret == -1) ++ perror("ingenic_load_sdram_file"); ++ ++ return ret; ++} ++ ++static int usbboot_go(shell_context_t *ctx, int argc, char *argv[]) { ++ int ret = ingenic_go(shell_device(ctx), strtoul(argv[1], NULL, 0)); ++ ++ if(ret == -1) ++ perror("ingenic_go"); ++ ++ return ret; ++} ++ ++static int usbboot_nquery(shell_context_t *ctx, int argc, char *argv[]) { ++ nand_info_t info; ++ ++ int ret = ingenic_query_nand(shell_device(ctx), atoi(argv[1]), &info); ++ ++ if(ret == -1) { ++ perror("ingenic_query_nand"); ++ ++ return -1; ++ } ++ ++ printf( ++ "VID: %02hhX\n" ++ "PID: %02hhX\n" ++ "Chip: %02hhX\n" ++ "Page: %02hhX\n" ++ "Plane: %02hhX\n", ++ info.vid, info.pid, info.chip, info.page, info.plane); ++ ++ ++ return 0; ++} ++ ++static int usbboot_ndump(shell_context_t *ctx, int argc, char *argv[]) { ++ int type = strcmp(argv[0], "ndump_oob") ? NO_OOB : OOB_ECC; ++ ++ if(cfg_getenv("NAND_RAW")) ++ type |= NAND_RAW; ++ ++ int ret = ingenic_dump_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), type, argv[4]); ++ ++ if(ret == -1) ++ perror("ingenic_dump_nand"); ++ ++ return ret; ++} ++ ++static int usbboot_nerase(shell_context_t *ctx, int argc, char *argv[]) { ++ int ret = ingenic_erase_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3])); ++ ++ if(ret == -1) ++ perror("ingenic_erase_nand"); ++ ++ return ret; ++ ++} ++ ++static int usbboot_nprogram(shell_context_t *ctx, int argc, char *argv[]) { ++ int type = strcmp(argv[0], "nprogram_oob") ? NO_OOB : OOB_ECC; ++ ++ if(strcmp(argv[0], "nprogram_oob") == 0) { ++ if(cfg_getenv("NAND_RAW")) ++ type = OOB_ECC; ++ else ++ type = OOB_NO_ECC; ++ } else ++ type = NO_OOB; ++ ++ int ret = ingenic_program_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), type, argv[3]); ++ ++ if(ret == -1) ++ perror("ingenic_program_nand"); ++ ++ return ret; ++} ++ ++static int usbboot_nload(shell_context_t *ctx, int argc, char *argv[]) { ++ int ret = ingenic_load_nand(shell_device(ctx), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), strtoul(argv[4], NULL, 0)); ++ ++ if(ret == -1) ++ perror("ingenic_load_nand"); ++ ++ return ret; ++} ++ ++static int usbboot_load_kernel(shell_context_t *ctx, int argc, char *argv[]) { ++ return load_elf(shell_device(ctx), argv[1], argv[2], ++ argc == 4 ? argv[3] : NULL); ++} ++ diff --cc jzboot/src/usbdev.c index 0000000,0000000..d202e5c new file mode 100644 --- /dev/null +++ b/jzboot/src/usbdev.c @@@ -1,0 -1,0 +1,239 @@@ ++/* ++ * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors. ++ * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com>, ++ * Peter Zotov <whitequark@whitequark.org> ++ * ++ * 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 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <errno.h> ++#include <libusb.h> ++ ++#include "usbdev.h" ++#include "debug.h" ++#include "devmgr.h" ++ ++#define CONTROL_TIMEOUT 5000 ++ ++static libusb_context *ctx = NULL; ++ ++static int translate_libusb(int code); ++ ++int usbdev_enumerate() { ++ libusb_device **list; ++ ssize_t devices_count = libusb_get_device_list(ctx, &list); ++ ++ if(devices_count < 0) ++ return translate_libusb(devices_count); ++ ++ for(int i = 0; i < devices_count; i++) { ++ struct libusb_device_descriptor descr; ++ ++ int ret = libusb_get_device_descriptor(list[i], &descr); ++ ++ if(ret != LIBUSB_SUCCESS) { ++ libusb_free_device_list(list, 1); ++ ++ return translate_libusb(ret); ++ } ++ ++ if(is_ingenic(descr.idVendor, descr.idProduct)) { ++ add_device(descr.idVendor, descr.idProduct, libusb_ref_device(list[i])); ++ } ++ } ++ ++ libusb_free_device_list(list, 1); ++ ++ return 0; ++} ++ ++int usbdev_init() { ++ if(translate_libusb(libusb_init(&ctx)) == -1) ++ return -1; ++ ++ libusb_set_debug(ctx, get_debug_level()); ++ ++ return 0; ++} ++ ++void usbdev_fini() { ++ libusb_exit(ctx); ++ ctx = NULL; ++} ++ ++void *usbdev_open(void *dev) { ++ libusb_device_handle *hndl; ++ ++ if(translate_libusb(libusb_open(dev, &hndl)) == -1) ++ return NULL; ++ ++ int ret = libusb_kernel_driver_active(hndl, INTERFACE_BOOT); ++ ++ if(ret < 0) { ++ libusb_close(hndl); ++ ++ translate_libusb(ret); ++ ++ return NULL; ++ ++ } else if(ret == 1) { ++ debug(LEVEL_INFO, "Deactivating kernel driver\n"); ++ ++ if(translate_libusb(libusb_detach_kernel_driver(hndl, INTERFACE_BOOT)) == -1) { ++ libusb_close(hndl); ++ ++ return NULL; ++ } ++ } ++ ++ if(translate_libusb(libusb_claim_interface(hndl, INTERFACE_BOOT)) == -1) { ++ libusb_close(hndl); ++ ++ return NULL; ++ } ++ ++ debug(LEVEL_DEBUG, "Device open\n"); ++ ++ return hndl; ++} ++ ++void usbdev_close(void *_hndl) { ++ libusb_device_handle *hndl = _hndl; ++ ++ libusb_release_interface(hndl, INTERFACE_BOOT); ++ ++ libusb_close(hndl); ++ ++ debug(LEVEL_DEBUG, "Device closed\n"); ++} ++ ++int usbdev_vendor(void *_hndl, int direction, uint8_t req, uint16_t value, uint16_t index, void *data, uint16_t size) { ++ libusb_device_handle *hndl = _hndl; ++ ++ uint8_t type = LIBUSB_REQUEST_TYPE_VENDOR; ++ ++ if(direction == USBDEV_FROMDEV) ++ type |= LIBUSB_ENDPOINT_IN; ++ ++ debug(LEVEL_DEBUG, "Control: type %02hhX, request %hhu, value %hu, index %hu, data %p, size %hu\n", type, req, value, index, data, size); ++ ++ int ret = libusb_control_transfer(hndl, type, req, value, index, data, size, CONTROL_TIMEOUT); ++ ++ if(ret >= 0) ++ return ret; ++ else ++ return translate_libusb(ret); ++} ++ ++int usbdev_sendbulk(void *hndl, void *data, int size) { ++ int trans; ++ ++ debug(LEVEL_DEBUG, "Bulk: writing data %p, size %d\n", data, size); ++ ++ if(translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_OUT, data, size, &trans, CONTROL_TIMEOUT)) == -1) { ++ return -1; ++ } ++ ++ if(trans != size) { ++ debug(LEVEL_WARNING, "Bulk data truncated: requested %d, sent %d\n", size, trans); ++ ++ errno = EIO; ++ ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int usbdev_recvbulk(void *hndl, void *data, int size) { ++ int trans; ++ ++ debug(LEVEL_DEBUG, "Bulk: reading data %p, size %d\n", data, size); ++ ++ int ret = translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_IN, data, size, &trans, CONTROL_TIMEOUT)); ++ ++ return ret == -1 ? -1 : trans; ++} ++ ++static int translate_libusb(int code) { ++ switch(code) { ++ case LIBUSB_SUCCESS: ++ return 0; ++ ++ case LIBUSB_ERROR_IO: ++ errno = EIO; ++ ++ break; ++ ++ case LIBUSB_ERROR_INVALID_PARAM: ++ errno = EINVAL; ++ ++ break; ++ ++ case LIBUSB_ERROR_ACCESS: ++ errno = EACCES; ++ ++ break; ++ ++ case LIBUSB_ERROR_NO_DEVICE: ++ case LIBUSB_ERROR_NOT_FOUND: ++ errno = ENOENT; ++ ++ break; ++ ++ case LIBUSB_ERROR_BUSY: ++ errno = EBUSY; ++ ++ break; ++ ++ case LIBUSB_ERROR_TIMEOUT: ++ errno = ETIMEDOUT; ++ ++ break; ++ ++ case LIBUSB_ERROR_OVERFLOW: ++ errno = EOVERFLOW; ++ ++ break; ++ ++ case LIBUSB_ERROR_PIPE: ++ errno = EPIPE; ++ ++ break; ++ ++ case LIBUSB_ERROR_INTERRUPTED: ++ errno = EINTR; ++ ++ break; ++ ++ case LIBUSB_ERROR_NO_MEM: ++ errno = ENOMEM; ++ ++ break; ++ ++ case LIBUSB_ERROR_NOT_SUPPORTED: ++ errno = ENOTSUP; ++ ++ break; ++ ++ ++ case LIBUSB_ERROR_OTHER: ++ default: ++ errno = EFAULT; ++ } ++ ++ debug(LEVEL_DEBUG, "Translated libusb return %d to %d\n", code, errno); ++ ++ return -1; ++} |