--- /dev/null
+#
+# Automatically generated make config: don't edit
+# SeaBIOS Configuration
+# Wed Mar 14 18:51:09 2012
+#
+
+#
+# General Features
+#
+# CONFIG_COREBOOT is not set
+# CONFIG_XEN is not set
+# CONFIG_THREADS is not set
+CONFIG_RELOCATE_INIT=y
+CONFIG_BOOTMENU=y
+CONFIG_BOOTSPLASH=y
+CONFIG_BOOTORDER=y
+
+#
+# Hardware support
+#
+CONFIG_ATA=y
+CONFIG_ATA_DMA=y
+CONFIG_ATA_PIO32=y
+# CONFIG_AHCI is not set
+CONFIG_VIRTIO_BLK=y
+CONFIG_FLOPPY=y
+CONFIG_PS2PORT=y
+CONFIG_USB=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_MSC=y
+CONFIG_USB_HUB=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_USB_MOUSE=y
+CONFIG_SERIAL=y
+CONFIG_LPT=y
+CONFIG_USE_SMM=y
+# CONFIG_MTRR_INIT is not set
+
+#
+# BIOS interfaces
+#
+CONFIG_DRIVES=y
+CONFIG_CDROM_BOOT=y
+CONFIG_CDROM_EMU=y
+CONFIG_PCIBIOS=y
+CONFIG_APMBIOS=y
+CONFIG_PNPBIOS=y
+CONFIG_OPTIONROMS=y
+CONFIG_OPTIONROMS_DEPLOYED=y
+CONFIG_PMM=y
+CONFIG_BOOT=y
+CONFIG_KEYBOARD=y
+CONFIG_KBD_CALL_INT15_4F=y
+CONFIG_MOUSE=y
+CONFIG_S3_RESUME=y
+# CONFIG_DISABLE_A20 is not set
+
+#
+# BIOS Tables
+#
+CONFIG_PIRTABLE=y
+CONFIG_MPTABLE=y
+CONFIG_SMBIOS=y
+CONFIG_ACPI=y
+
+#
+# Debugging
+#
+CONFIG_DEBUG_LEVEL=1
+# CONFIG_DEBUG_SERIAL is not set
--- /dev/null
+ 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>.
--- /dev/null
+ GNU LESSER 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.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
--- /dev/null
+# SeaBIOS build system
+#
+# Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU LGPLv3 license.
+
+# Program version
+VERSION=1.6.3-$(shell date +"%Y%m%d_%H%M%S")-$(shell hostname)
+
+# Output directory
+OUT=out/
+
+# Source files
+SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \
+ kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.c \
+ pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \
+ usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \
+ virtio-ring.c virtio-pci.c virtio-blk.c apm.c ahci.c
+SRC16=$(SRCBOTH) system.c disk.c font.c
+SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
+ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
+ lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c \
+ biostables.c xen.c bmp.c
+SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
+
+cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
+ /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;)
+
+# Default compiler flags
+COMMONCFLAGS = -I$(OUT) -Os -MD \
+ -Wall -Wno-strict-aliasing -Wold-style-definition \
+ $(call cc-option,$(CC),-Wtype-limits,) \
+ -m32 -march=i386 -mregparm=3 -mpreferred-stack-boundary=2 \
+ -mrtd -minline-all-stringops \
+ -freg-struct-return -ffreestanding -fomit-frame-pointer \
+ -fno-delete-null-pointer-checks \
+ -ffunction-sections -fdata-sections -fno-common
+COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+
+CFLAGS32FLAT = $(COMMONCFLAGS) -g -DMODE16=0 -DMODESEGMENT=0
+CFLAGSSEG = $(COMMONCFLAGS) -DMODESEGMENT=1 -fno-defer-pop \
+ $(call cc-option,$(CC),-fno-jump-tables,-DMANUAL_NO_JUMP_TABLE) \
+ $(call cc-option,$(CC),-fno-tree-switch-conversion,)
+CFLAGS32SEG = $(CFLAGSSEG) -DMODE16=0 -g
+CFLAGS16INC = $(CFLAGSSEG) -DMODE16=1 \
+ $(call cc-option,$(CC),--param large-stack-frame=4,-fno-inline)
+CFLAGS16 = $(CFLAGS16INC) -g
+
+all: $(OUT) $(OUT)bios.bin
+
+# Run with "make V=1" to see the actual compile commands
+ifdef V
+Q=
+else
+Q=@
+MAKEFLAGS += --no-print-directory
+endif
+
+OBJCOPY=objcopy
+OBJDUMP=objdump
+STRIP=strip
+
+.PHONY : all clean distclean FORCE
+
+vpath %.c src vgasrc
+vpath %.S src vgasrc
+
+################ Build rules
+
+# Verify the gcc configuration and test if -fwhole-program works.
+TESTGCC:=$(shell CC="$(CC)" LD="$(LD)" tools/test-gcc.sh)
+ifeq "$(TESTGCC)" "-1"
+$(error "Please upgrade GCC and/or binutils")
+endif
+
+ifndef COMPSTRAT
+COMPSTRAT=$(TESTGCC)
+endif
+
+# Do a whole file compile - three methods are supported.
+ifeq "$(COMPSTRAT)" "1"
+# First method - use -fwhole-program without -combine.
+define whole-compile
+@echo " Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -c $3.tmp.c -o $3
+endef
+else
+ifeq "$(COMPSTRAT)" "2"
+# Second menthod - don't use -fwhole-program at all.
+define whole-compile
+@echo " Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "../$i"\n)' > $3.tmp.c
+$(Q)$(CC) $1 -c $3.tmp.c -o $3
+endef
+else
+# Third (and preferred) method - use -fwhole-program with -combine
+define whole-compile
+@echo " Compiling whole program $3"
+$(Q)$(CC) $1 -fwhole-program -DWHOLE_PROGRAM -combine -c $2 -o $3
+endef
+endif
+endif
+
+%.strip.o: %.o
+ @echo " Stripping $@"
+ $(Q)$(STRIP) $< -o $@
+
+$(OUT)%.s: %.c
+ @echo " Compiling to assembler $@"
+ $(Q)$(CC) $(CFLAGS16INC) -S -c $< -o $@
+
+$(OUT)%.lds: %.lds.S
+ @echo " Precompiling $@"
+ $(Q)$(CPP) -P -D__ASSEMBLY__ $< -o $@
+
+$(OUT)asm-offsets.s: $(OUT)autoconf.h
+
+$(OUT)asm-offsets.h: $(OUT)asm-offsets.s
+ @echo " Generating offset file $@"
+ $(Q)./tools/gen-offsets.sh $< $@
+
+
+$(OUT)ccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S, $(addprefix src/, $(SRC16)),$@)
+
+$(OUT)code32seg.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32SEG), $(addprefix src/, $(SRC32SEG)),$@)
+
+$(OUT)ccode32flat.o: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS32FLAT), $(addprefix src/, $(SRC32FLAT)),$@)
+
+$(OUT)code16.o: romlayout.S $(OUT)ccode.16.s $(OUT)asm-offsets.h
+ @echo " Compiling (16bit) $@"
+ $(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ $< -o $@
+
+$(OUT)romlayout16.lds: $(OUT)ccode32flat.o $(OUT)code32seg.o $(OUT)code16.o tools/layoutrom.py
+ @echo " Building ld scripts (version \"$(VERSION)\")"
+ $(Q)echo 'const char VERSION[] = "$(VERSION)";' > $(OUT)version.c
+ $(Q)$(CC) $(CFLAGS32FLAT) -c $(OUT)version.c -o $(OUT)version.o
+ $(Q)$(LD) -melf_i386 -r $(OUT)ccode32flat.o $(OUT)version.o -o $(OUT)code32flat.o
+ $(Q)$(OBJDUMP) -thr $(OUT)code32flat.o > $(OUT)code32flat.o.objdump
+ $(Q)$(OBJDUMP) -thr $(OUT)code32seg.o > $(OUT)code32seg.o.objdump
+ $(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump
+ $(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds
+
+# These are actually built by tools/layoutrom.py above, but by pulling them
+# into an extra rule we prevent make -j from spawning layoutrom.py 4 times.
+$(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds $(OUT)code32flat.o: $(OUT)romlayout16.lds
+
+$(OUT)rom16.o: $(OUT)code16.o $(OUT)romlayout16.lds
+ @echo " Linking $@"
+ $(Q)$(LD) -T $(OUT)romlayout16.lds $< -o $@
+
+$(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds
+ @echo " Linking $@"
+ $(Q)$(LD) -T $(OUT)romlayout32seg.lds $< -o $@
+
+$(OUT)rom.o: $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o $(OUT)romlayout32flat.lds
+ @echo " Linking $@"
+ $(Q)$(LD) -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@
+
+$(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
+ @echo " Prepping $@"
+ $(Q)$(OBJDUMP) -thr $< > $<.objdump
+ $(Q)$(OBJCOPY) -O binary $< $(OUT)bios.bin.raw
+ $(Q)./tools/checkrom.py $<.objdump $(OUT)bios.bin.raw $(OUT)bios.bin
+ $(Q)$(STRIP) -R .comment $< -o $(OUT)bios.bin.elf
+
+
+################ VGA build rules
+
+# VGA src files
+SRCVGA=src/output.c src/util.c vgasrc/vga.c vgasrc/vgafb.c vgasrc/vgaio.c \
+ vgasrc/vgatables.c vgasrc/vgafonts.c vgasrc/clext.c
+
+$(OUT)vgaccode.16.s: $(OUT)autoconf.h ; $(call whole-compile, $(CFLAGS16) -S -Isrc, $(SRCVGA),$@)
+
+$(OUT)vgalayout16.o: vgaentry.S $(OUT)vgaccode.16.s $(OUT)asm-offsets.h
+ @echo " Compiling (16bit) $@"
+ $(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ -Isrc $< -o $@
+
+$(OUT)vgarom.o: $(OUT)vgalayout16.o $(OUT)vgalayout.lds
+ @echo " Linking $@"
+ $(Q)$(LD) --gc-sections -T $(OUT)vgalayout.lds $(OUT)vgalayout16.o -o $@
+
+$(OUT)vgabios.bin.raw: $(OUT)vgarom.o
+ @echo " Extracting binary $@"
+ $(Q)$(OBJCOPY) -O binary $< $@
+
+$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw tools/buildrom.py
+ @echo " Finalizing rom $@"
+ $(Q)./tools/buildrom.py $< $@
+
+####### dsdt build rules
+src/%.hex: src/%.dsl
+ @echo "Compiling DSDT"
+ $(Q)cpp -P $< > $(OUT)$*.dsl.i
+ $(Q)iasl -tc -p $(OUT)$* $(OUT)$*.dsl.i
+ $(Q)cp $(OUT)$*.hex $@
+
+$(OUT)ccode32flat.o: src/acpi-dsdt.hex
+
+####### Kconfig rules
+export HOSTCC := $(CC)
+export CONFIG_SHELL := sh
+export KCONFIG_AUTOHEADER := autoconf.h
+export KCONFIG_CONFIG := $(CURDIR)/.config
+
+$(OUT)autoconf.h : $(KCONFIG_CONFIG)
+ $(Q)$(MAKE) silentoldconfig
+
+$(KCONFIG_CONFIG):
+ $(Q)$(MAKE) defconfig
+
+%onfig:
+ $(Q)mkdir -p $(OUT)/tools/kconfig/lxdialog
+ $(Q)mkdir -p $(OUT)/include/config
+ $(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/tools/kconfig/Makefile srctree=$(CURDIR) src=tools/kconfig obj=tools/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $@
+
+####### Generic rules
+clean:
+ $(Q)rm -rf $(OUT)
+
+distclean: clean
+ $(Q)rm -f .config .config.old
+
+$(OUT):
+ $(Q)mkdir $@
+
+-include $(OUT)*.d
--- /dev/null
+This code implements an X86 legacy bios. It is intended to be
+compiled using standard gnu tools (eg, gas and gcc).
+
+To build, one should be able to run "make" in the main directory. The
+resulting file "out/bios.bin" contains the processed bios image.
+
+
+Testing of images:
+
+To test the bios under bochs, one will need to instruct bochs to use
+the new bios image. Use the 'romimage' option - for example:
+
+bochs -q 'floppya: 1_44=myfdimage.img' 'romimage: file=out/bios.bin'
+
+To test under qemu, one will need to create a directory with all the
+bios images and then overwrite the main bios image. For example:
+
+cp /usr/share/qemu/*.bin mybiosdir/
+cp out/bios.bin mybiosdir/
+
+Once this is setup, one can instruct qemu to use the newly created
+directory for rom images. For example:
+
+qemu -L mybiosdir/ -fda myfdimage.img
+
+
+Overview of files:
+
+The src/ directory contains the bios source code. Several of the
+files are compiled twice - once for 16bit mode and once for 32bit
+mode. (The build system will remove code that is not needed for a
+particular mode.)
+
+The tools/ directory contains helper utilities for manipulating and
+building the final rom.
+
+The out/ directory is created by the build process - it contains all
+temporary and final files.
+
+
+Build overview:
+
+The 16bit code is compiled via gcc to assembler (file out/ccode.16.s).
+The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections"
+options are used to optimize the process so that gcc can efficiently
+compile and discard unneeded code. (In the code, one can use the
+macros 'VISIBLE16' and 'VISIBLE32FLAT' to instruct a symbol to be
+outputted in 16bit and 32bit mode respectively.)
+
+This resulting assembler code is pulled into romlayout.S. The gas
+option ".code16gcc" is used prior to including the gcc generated
+assembler - this option enables gcc to generate valid 16 bit code.
+
+The post code (post.c) is entered, via the function handle_post(), in
+32bit mode. The 16bit post vector (in romlayout.S) transitions the
+cpu into 32 bit mode before calling the post.c code.
+
+In the last step of compilation, the 32 bit code is merged into the 16
+bit code so that one binary file contains both. Currently, both 16bit
+and 32bit code will be located in the memory at 0xe0000-0xfffff.
+
+
+GCC 16 bit limitations:
+
+Although the 16bit code is compiled with gcc, developers need to be
+aware of the environment. In particular, global variables _must_ be
+treated specially.
+
+The code has full access to stack variables and general purpose
+registers. The entry code in romlayout.S will push the original
+registers on the stack before calling the C code and then pop them off
+(including any required changes) before returning from the interrupt.
+Changes to CS, DS, and ES segment registers in C code is also safe.
+Changes to other segment registers (SS, FS, GS) need to be restored
+manually.
+
+Stack variables (and pointers to stack variables) work as they
+normally do in standard C code.
+
+However, variables stored outside the stack need to be accessed via
+the GET_VAR and SET_VAR macros (or one of the helper macros described
+below). This is due to the 16bit segment nature of the X86 cpu when
+it is in "real mode". The C entry code will set DS and SS to point to
+the stack segment. Variables not on the stack need to be accessed via
+an explicit segment register. Any other access requires altering one
+of the other segment registers (usually ES) and then accessing the
+variable via that segment register.
+
+There are three low-level ways to access a remote variable:
+GET/SET_VAR, GET/SET_FARVAR, and GET/SET_FLATPTR. The first set takes
+an explicit segment descriptor (eg, "CS") and offset. The second set
+will take a segment id and offset, set ES to the segment id, and then
+make the access via the ES segment. The last method is similar to the
+second, except it takes a pointer that would be valid in 32-bit flat
+mode instead of a segment/offset pair.
+
+Most BIOS variables are stored in global variables, the "BDA", or
+"EBDA" memory areas. Because this is common, three sets of helper
+macros (GET/SET_GLOBAL, GET/SET_BDA, and GET/SET_EBDA) are available
+to simplify these accesses.
+
+Global variables defined in the C code can be read in 16bit mode if
+the variable declaration is marked with VAR16, VAR16VISIBLE,
+VAR16EXPORT, or VAR16FIXED. The GET_GLOBAL macro will then allow read
+access to the variable. Global variables are stored in the 0xf000
+segment, and their values are persistent across soft resets. Because
+the f-segment is marked read-only during run-time, the 16bit code is
+not permitted to change the value of 16bit variables (use of the
+SET_GLOBAL macro from 16bit mode will cause a link error). Code
+running in 32bit mode can not access variables with VAR16, but can
+access variables marked with VAR16VISIBLE, VAR16EXPORT, VAR16FIXED, or
+with no marking at all. The 32bit code can use the GET/SET_GLOBAL
+macros, but they are not required.
+
+
+GCC 16 bit stack limitations:
+
+Another limitation of gcc is its use of 32-bit temporaries. Gcc will
+allocate 32-bits of space for every variable - even if that variable
+is only defined as a 'u8' or 'u16'. If one is not careful, using too
+much stack space can break old DOS applications.
+
+There does not appear to be explicit documentation on the minimum
+stack space available for bios calls. However, Freedos has been
+observed to call into the bios with less than 150 bytes available.
+
+Note that the post code and boot code (irq 18/19) do not have a stack
+limitation because the entry points for these functions transition the
+cpu to 32bit mode and reset the stack to a known state. Only the
+general purpose 16-bit service entry points are affected.
+
+There are some ways to reduce stack usage: making sure functions are
+tail-recursive often helps, reducing the number of parameters passed
+to functions often helps, sometimes reordering variable declarations
+helps, inlining of functions can sometimes help, and passing of packed
+structures can also help. It is also possible to transition to/from
+an extra stack stored in the EBDA using the stack_hop helper function.
+
+Some useful stats: the overhead for the entry to a bios handler that
+takes a 'struct bregs' is 42 bytes of stack space (6 bytes from
+interrupt insn, 32 bytes to store registers, and 4 bytes for call
+insn). An entry to an ISR handler without args takes 30 bytes (6 + 20
++ 4).
+
+
+Debugging the bios:
+
+The bios will output information messages to a special debug port.
+Under qemu, one can view these messages by adding '-chardev
+stdio,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios' to
+the qemu command line. Once this is done, one should see status
+messages on the console.
+
+The gdb-server mechanism of qemu is also useful. One can use gdb with
+qemu to debug system images. To use this, add '-s -S' to the qemu
+command line. For example:
+
+qemu -L mybiosdir/ -fda myfdimage.img -s -S
+
+Then, in another session, run gdb with either out/rom16.o (to debug
+bios 16bit code) or out/rom32.o (to debug bios 32bit code). For
+example:
+
+gdb out/rom16.o
+
+Once in gdb, use the command "target remote localhost:1234" to have
+gdb connect to qemu. See the qemu documentation for more information
+on using gdb and qemu in this mode. Note that gdb seems to get
+breakpoints confused when the cpu is in 16-bit real mode. This makes
+stepping through the program difficult (though 'step instruction'
+still works). Also, one may need to set 16bit break points at both
+the cpu address and memory address (eg, break *0x1234 ; break
+*0xf1234).
--- /dev/null
+cp palacios_config .config and then make
--- /dev/null
+Review changes committed to coreboot, virtualbox, qemu, kvm, and bochs
+cvs tip.
+ * bochs cvs (20100104):
+ -- changes synched
+ * coreboot (r3348): (bochs 20060708)
+ -- no noteworthy enhancements
+ * qemu - now uses SeaBIOS
+ * kvm - now uses SeaBIOS
+ * virtualbox (r13560): (bochs 20061231)
+ -- lots of mouse changes, logo, scsi/etherboot hooks,
+ floppy data rate?, int19 calls post
+
+The __call16 code does a long jump to the interrupt trampolines - this
+is unnecessary.
+
+Support PCIv3 roms? Add support for PCI "configuration code"
+extensions?
+
+Possibly add option to eliminate tsc based delays on emulators.
+
+Possibly support sending debug information over EHCI debug port.
--- /dev/null
+#
+# Automatically generated make config: don't edit
+# SeaBIOS Configuration
+# Wed Mar 14 18:51:09 2012
+#
+
+#
+# General Features
+#
+# CONFIG_COREBOOT is not set
+# CONFIG_XEN is not set
+# CONFIG_THREADS is not set
+CONFIG_RELOCATE_INIT=y
+CONFIG_BOOTMENU=y
+CONFIG_BOOTSPLASH=y
+CONFIG_BOOTORDER=y
+
+#
+# Hardware support
+#
+CONFIG_ATA=y
+CONFIG_ATA_DMA=y
+CONFIG_ATA_PIO32=y
+# CONFIG_AHCI is not set
+CONFIG_VIRTIO_BLK=y
+CONFIG_FLOPPY=y
+CONFIG_PS2PORT=y
+CONFIG_USB=y
+CONFIG_USB_UHCI=y
+CONFIG_USB_OHCI=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_MSC=y
+CONFIG_USB_HUB=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_USB_MOUSE=y
+CONFIG_SERIAL=y
+CONFIG_LPT=y
+CONFIG_USE_SMM=y
+# CONFIG_MTRR_INIT is not set
+
+#
+# BIOS interfaces
+#
+CONFIG_DRIVES=y
+CONFIG_CDROM_BOOT=y
+CONFIG_CDROM_EMU=y
+CONFIG_PCIBIOS=y
+CONFIG_APMBIOS=y
+CONFIG_PNPBIOS=y
+CONFIG_OPTIONROMS=y
+CONFIG_OPTIONROMS_DEPLOYED=y
+CONFIG_PMM=y
+CONFIG_BOOT=y
+CONFIG_KEYBOARD=y
+CONFIG_KBD_CALL_INT15_4F=y
+CONFIG_MOUSE=y
+CONFIG_S3_RESUME=y
+# CONFIG_DISABLE_A20 is not set
+
+#
+# BIOS Tables
+#
+CONFIG_PIRTABLE=y
+CONFIG_MPTABLE=y
+CONFIG_SMBIOS=y
+CONFIG_ACPI=y
+
+#
+# Debugging
+#
+CONFIG_DEBUG_LEVEL=1
+# CONFIG_DEBUG_SERIAL is not set
--- /dev/null
+From 83f115d2f7f26dddcbbffe89aa8a7a97b28a6228 Mon Sep 17 00:00:00 2001
+From: Alexander Kudryavtsev <alexk@ispras.ru>
+Date: Mon, 12 Mar 2012 13:07:07 +0400
+Subject: [PATCH] Fixes needed to launch SEABIOS inside Palacios's VM: 1.
+ Allow to build ACPI tables without PIIX4 PM device 2.
+ Disable HPET table generation 3. Do not perform PCI setup
+ since it breaks Palacios 4. Do not initialize AP cores
+ since it breaks Palacios 5. Fix SRAT generation - do not
+ cut PCI hole since it is already cut off by Palacios
+
+---
+ src/acpi.c | 44 +++++++++++++++++++++++++++++---------------
+ src/pciinit.c | 2 +-
+ src/smp.c | 5 ++++-
+ 3 files changed, 34 insertions(+), 17 deletions(-)
+
+diff --git a/src/acpi.c b/src/acpi.c
+index 3d8b7c8..7d50990 100644
+--- a/src/acpi.c
++++ b/src/acpi.c
+@@ -262,18 +262,32 @@ build_fadt(struct pci_device *pci)
+ fadt->dsdt = cpu_to_le32((u32)dsdt);
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+- int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
++ int pm_sci_int;
++ if (pci)
++ pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
++ else
++ pm_sci_int = 0;
+ fadt->sci_int = cpu_to_le16(pm_sci_int);
+- fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+- fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
+- fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
+- fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
+- fadt->pm1_evt_len = 4;
+- fadt->pm1_cnt_len = 2;
+- fadt->pm_tmr_len = 4;
++ if (pci) {
++ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
++ fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
++ fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
++ fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
++ fadt->pm1_evt_len = 4;
++ fadt->pm1_cnt_len = 2;
++ fadt->pm_tmr_len = 4;
++ pci_init_device(fadt_init_tbl, pci, fadt);
++ } else {
++ fadt->smi_cmd = 0;
++ fadt->pm1a_evt_blk = 0;
++ fadt->pm1a_cnt_blk = 0;
++ fadt->pm_tmr_blk = 0;
++ fadt->pm1_evt_len = 0;
++ fadt->pm1_cnt_len = 0;
++ fadt->pm_tmr_len = 0;
++ }
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+- pci_init_device(fadt_init_tbl, pci, fadt);
+ /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */
+ fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7));
+
+@@ -516,6 +530,7 @@ build_srat(void)
+ if (nb_numa_nodes == 0)
+ return NULL;
+
++
+ u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes));
+ if (!numadata) {
+ warn_noalloc();
+@@ -577,7 +592,7 @@ build_srat(void)
+ next_base = mem_base + mem_len;
+
+ /* Cut out the PCI hole */
+- if (mem_base <= RamSize && next_base > RamSize) {
++ /*if (mem_base <= RamSize && next_base > RamSize) {
+ mem_len -= next_base - RamSize;
+ if (mem_len > 0) {
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+@@ -587,7 +602,7 @@ build_srat(void)
+ mem_base = 1ULL << 32;
+ mem_len = next_base - RamSize;
+ next_base += (1ULL << 32) - RamSize;
+- }
++ }*/
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ numamem++;
+ slots++;
+@@ -623,9 +638,7 @@ acpi_bios_init(void)
+
+ // This code is hardcoded for PIIX4 Power Management device.
+ struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL);
+- if (!pci)
+- // Device not found
+- return;
++ // If no PIIX4 is found we will not build certain structures and init it.
+
+ // Build ACPI tables
+ u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
+@@ -640,7 +653,8 @@ acpi_bios_init(void)
+ ACPI_INIT_TABLE(build_fadt(pci));
+ ACPI_INIT_TABLE(build_ssdt());
+ ACPI_INIT_TABLE(build_madt());
+- ACPI_INIT_TABLE(build_hpet());
++ if(pci)
++ ACPI_INIT_TABLE(build_hpet());
+ ACPI_INIT_TABLE(build_srat());
+
+ u16 i, external_tables = qemu_cfg_acpi_additional_tables();
+diff --git a/src/pciinit.c b/src/pciinit.c
+index 0d8758e..ef8ccda 100644
+--- a/src/pciinit.c
++++ b/src/pciinit.c
+@@ -575,7 +575,7 @@ static int pci_bios_init_root_regions(u32 start, u32 end)
+ void
+ pci_setup(void)
+ {
+- if (CONFIG_COREBOOT || usingXen()) {
++ if (1 || CONFIG_COREBOOT || usingXen()) {
+ // PCI setup already done by coreboot or Xen - just do probe.
+ pci_probe_devices();
+ return;
+diff --git a/src/smp.c b/src/smp.c
+index 8c077a1..21e7437 100644
+--- a/src/smp.c
++++ b/src/smp.c
+@@ -81,7 +81,7 @@ smp_probe(void)
+ MaxCountCPUs = 1;
+ return;
+ }
+-
++#if 0
+ // Init the counter.
+ writel(&CountCPUs, 1);
+
+@@ -121,6 +121,9 @@ smp_probe(void)
+
+ // Restore memory.
+ *(u64*)BUILD_AP_BOOT_ADDR = old;
++#endif
+
++ CountCPUs = inb_cmos(CMOS_BIOS_SMP_COUNT) + 1; // Fix for Palacios
+
+ MaxCountCPUs = qemu_cfg_get_max_cpus();
+ if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
+--
+1.7.5.4
--- /dev/null
+# Kconfig SeaBIOS configuration
+
+mainmenu "SeaBIOS Configuration"
+
+menu "General Features"
+
+ config COREBOOT
+ bool "Build for coreboot"
+ default n
+ help
+ Configure as a coreboot payload.
+
+ config XEN
+ depends on !COREBOOT
+ bool "Build for Xen HVM"
+ default n
+ help
+ Configure to be used by xen hvmloader, for a HVM guest.
+
+ config THREADS
+ bool "Parallelize hardware init"
+ default y
+ help
+ Support running hardware initialization in parallel.
+ config THREAD_OPTIONROMS
+ depends on THREADS
+ bool "Hardware init during option ROM execution"
+ default n
+ help
+ Allow hardware init to run in parallel with optionrom execution.
+
+ This can reduce boot time, but can cause some timing
+ variations during option ROM code execution. It is not
+ known if all option ROMs will behave properly with this
+ option.
+
+ config RELOCATE_INIT
+ bool "Copy init code to high memory"
+ default y
+ help
+ Support relocating the one time initialization code to high memory.
+
+ config BOOTMENU
+ depends on BOOT
+ bool "Bootmenu"
+ default y
+ help
+ Support an interactive boot menu at end of post.
+ config BOOTSPLASH
+ depends on BOOTMENU
+ bool "Graphical boot splash screen"
+ default y
+ help
+ Support showing a graphical boot splash screen.
+ config BOOTORDER
+ depends on BOOT
+ bool "Boot ordering"
+ default y
+ help
+ Support controlling of the boot order via the fw_cfg/CBFS
+ "bootorder" file.
+
+ config COREBOOT_FLASH
+ depends on COREBOOT
+ bool "coreboot CBFS support"
+ default y
+ help
+ Support searching coreboot flash format.
+ config LZMA
+ depends on COREBOOT_FLASH
+ bool "CBFS lzma support"
+ default y
+ help
+ Support CBFS files compressed using the lzma decompression
+ algorighm.
+ config FLASH_FLOPPY
+ depends on COREBOOT_FLASH
+ bool "Floppy images in CBFS"
+ default y
+ help
+ Support floppy images in coreboot flash.
+
+endmenu
+
+menu "Hardware support"
+ config ATA
+ depends on DRIVES
+ bool "ATA controllers"
+ default y
+ help
+ Support for IDE disk code.
+ config ATA_DMA
+ depends on ATA
+ bool "ATA DMA"
+ default n
+ help
+ Detect and try to use ATA bus mastering DMA controllers.
+ config ATA_PIO32
+ depends on ATA
+ bool "ATA 32bit PIO"
+ default n
+ help
+ Use 32bit PIO accesses on ATA (minor optimization on PCI transfers).
+ config AHCI
+ depends on DRIVES
+ bool "AHCI controllers"
+ default y
+ help
+ Support for AHCI disk code.
+ config VIRTIO_BLK
+ depends on DRIVES && !COREBOOT
+ bool "VirtIO controllers"
+ default y
+ help
+ Support boot from virtio storage.
+ config FLOPPY
+ depends on DRIVES
+ bool "Floppy controller"
+ default y
+ help
+ Support floppy drive access.
+
+ config PS2PORT
+ depends on KEYBOARD || MOUSE
+ bool "PS/2 port"
+ default y
+ help
+ Support PS2 ports (keyboard and mouse).
+
+ config USB
+ bool "USB"
+ default y
+ help
+ Support USB devices.
+ config USB_UHCI
+ depends on USB
+ bool "USB UHCI controllers"
+ default y
+ help
+ Support USB UHCI controllers.
+ config USB_OHCI
+ depends on USB
+ bool "USB OHCI controllers"
+ default y
+ help
+ Support USB OHCI controllers.
+ config USB_EHCI
+ depends on USB
+ bool "USB EHCI controllers"
+ default y
+ help
+ Support USB EHCI controllers.
+ config USB_MSC
+ depends on USB && DRIVES
+ bool "USB drives"
+ default y
+ help
+ Support USB disks.
+ config USB_HUB
+ depends on USB
+ bool "USB hubs"
+ default y
+ help
+ Support USB hubs.
+ config USB_KEYBOARD
+ depends on USB && KEYBOARD
+ bool "USB keyboards"
+ default y
+ help
+ Support USB keyboards.
+ config USB_MOUSE
+ depends on USB && MOUSE
+ bool "USB mice"
+ default y
+ help
+ Support USB mice.
+
+ config SERIAL
+ bool "Serial port"
+ default y
+ help
+ Support serial ports. This also enables int 14 serial port calls.
+ config LPT
+ bool "Parallel port"
+ default y
+ help
+ Support parallel ports. This also enables int 17 parallel port calls.
+
+ config USE_SMM
+ depends on !COREBOOT
+ bool "System Management Mode (SMM)"
+ default y
+ help
+ Support System Management Mode (on emulators).
+ config MTRR_INIT
+ depends on !COREBOOT
+ bool "Initialize MTRRs"
+ default y
+ help
+ Initialize the Memory Type Range Registers (on emulators).
+endmenu
+
+menu "BIOS interfaces"
+ config DRIVES
+ bool "Drive interface"
+ default y
+ help
+ Support int13 disk/floppy drive functions.
+
+ config CDROM_BOOT
+ depends on DRIVES
+ bool "DVD/CDROM booting"
+ default y
+ help
+ Support for booting from a CD. (El Torito spec support.)
+ config CDROM_EMU
+ depends on CDROM_BOOT
+ bool "DVD/CDROM boot drive emulation"
+ default y
+ help
+ Support bootable CDROMs that emulate a floppy/harddrive.
+
+ config PCIBIOS
+ bool "PCIBIOS interface"
+ default y
+ help
+ Support int 1a/b1 PCI BIOS calls.
+ config APMBIOS
+ bool "APM interface"
+ default y
+ help
+ Support int 15/53 APM BIOS calls.
+ config PNPBIOS
+ bool "PnP BIOS interface"
+ default y
+ help
+ Support PnP BIOS entry point.
+ config OPTIONROMS
+ bool "Option ROMS"
+ default y
+ help
+ Support finding and running option roms during POST.
+ config OPTIONROMS_DEPLOYED
+ depends on OPTIONROMS
+ bool "Option roms are already at 0xc0000-0xf0000"
+ default n
+ help
+ Select this if option ROMs are already copied to
+ 0xc0000-0xf0000. This must only be selected when using
+ Bochs or QEMU versions older than 0.12.
+ config PMM
+ depends on OPTIONROMS
+ bool "PMM interface"
+ default y
+ help
+ Support Post Memory Manager (PMM) entry point.
+ config BOOT
+ bool "Boot interface"
+ default y
+ help
+ Support int 19/18 system bootup support.
+ config KEYBOARD
+ bool "Keyboard interface"
+ default y
+ help
+ Support int 16 keyboard calls.
+ config KBD_CALL_INT15_4F
+ depends on KEYBOARD
+ bool "Keyboard hook interface"
+ default y
+ help
+ Support calling int155f on each keyboard event.
+ config MOUSE
+ bool "Mouse interface"
+ default y
+ help
+ Support for int15c2 mouse calls.
+
+ config S3_RESUME
+ bool "S3 resume"
+ default y
+ help
+ Support S3 resume handler.
+
+ config VGAHOOKS
+ depends on COREBOOT
+ bool "Hardware specific VGA helpers"
+ default y
+ help
+ Support int 155f BIOS callbacks specific to some Intel and
+ VIA on-board vga devices.
+
+ config DISABLE_A20
+ bool "Disable A20"
+ default n
+ help
+ Disable A20 on 16bit boot.
+endmenu
+
+menu "BIOS Tables"
+ config PIRTABLE
+ depends on !COREBOOT
+ bool "PIR table"
+ default y
+ help
+ Support generation of a PIR table in 0xf000 segment.
+ config MPTABLE
+ depends on !COREBOOT
+ bool "MPTable"
+ default y
+ help
+ Support generation of MPTable.
+ config SMBIOS
+ bool "SMBIOS"
+ default y
+ help
+ Support generation of SM BIOS tables. This is also
+ sometimes called DMI.
+ config ACPI
+ depends on !COREBOOT
+ bool "ACPI"
+ default y
+ help
+ Support generation of ACPI tables.
+endmenu
+
+menu "Debugging"
+ config DEBUG_LEVEL
+ int "Debug level"
+ default 1
+ help
+ Control how verbose debug output is. The higher the
+ number, the more verbose SeaBIOS will be.
+
+ Set to zero to disable debugging.
+
+ config DEBUG_SERIAL
+ depends on DEBUG_LEVEL != 0
+ bool "Serial port debugging"
+ default n
+ help
+ Send debugging information to serial port.
+ config DEBUG_SERIAL_PORT
+ depends on DEBUG_SERIAL
+ hex "Serial port base address"
+ default 0x3f8
+ help
+ Base port for serial - generally 0x3f8, 0x2f8, 0x3e8, or 0x2e8.
+endmenu
--- /dev/null
+/*
+ * Bochs/QEMU ACPI DSDT ASL definition
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+DefinitionBlock (
+ "acpi-dsdt.aml", // Output Filename
+ "DSDT", // Signature
+ 0x01, // DSDT Compliance Revision
+ "BXPC", // OEMID
+ "BXDSDT", // TABLE ID
+ 0x1 // OEM Revision
+ )
+{
+ Scope (\)
+ {
+ /* Debug Output */
+ OperationRegion (DBG, SystemIO, 0x0402, 0x01)
+ Field (DBG, ByteAcc, NoLock, Preserve)
+ {
+ DBGB, 8,
+ }
+
+ /* Debug method - use this method to send output to the QEMU
+ * BIOS debug port. This method handles strings, integers,
+ * and buffers. For example: DBUG("abc") DBUG(0x123) */
+ Method(DBUG, 1) {
+ ToHexString(Arg0, Local0)
+ ToBuffer(Local0, Local0)
+ Subtract(SizeOf(Local0), 1, Local1)
+ Store(Zero, Local2)
+ While (LLess(Local2, Local1)) {
+ Store(DerefOf(Index(Local0, Local2)), DBGB)
+ Increment(Local2)
+ }
+ Store(0x0A, DBGB)
+ }
+ }
+
+ /* PCI Bus definition */
+ Scope(\_SB) {
+ Device(PCI0) {
+ Name (_HID, EisaId ("PNP0A03"))
+ Name (_ADR, 0x00)
+ Name (_UID, 1)
+ Name(_PRT, Package() {
+ /* PCI IRQ routing table, example from ACPI 2.0a specification,
+ section 6.2.8.1 */
+ /* Note: we provide the same info as the PCI routing
+ table of the Bochs BIOS */
+#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \
+ Package() { nr##ffff, 0, lnk0, 0 }, \
+ Package() { nr##ffff, 1, lnk1, 0 }, \
+ Package() { nr##ffff, 2, lnk2, 0 }, \
+ Package() { nr##ffff, 3, lnk3, 0 }
+
+#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC)
+#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD)
+#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA)
+#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB)
+ prt_slot0(0x0000),
+ /* Device 1 is power mgmt device, and can only use irq 9 */
+ Package() { 0x0001ffff, 0, LNKS, 0 },
+ Package() { 0x0001ffff, 1, LNKB, 0 },
+ Package() { 0x0001ffff, 2, LNKC, 0 },
+ Package() { 0x0001ffff, 3, LNKD, 0 },
+ prt_slot2(0x0002),
+ prt_slot3(0x0003),
+ prt_slot0(0x0004),
+ prt_slot1(0x0005),
+ prt_slot2(0x0006),
+ prt_slot3(0x0007),
+ prt_slot0(0x0008),
+ prt_slot1(0x0009),
+ prt_slot2(0x000a),
+ prt_slot3(0x000b),
+ prt_slot0(0x000c),
+ prt_slot1(0x000d),
+ prt_slot2(0x000e),
+ prt_slot3(0x000f),
+ prt_slot0(0x0010),
+ prt_slot1(0x0011),
+ prt_slot2(0x0012),
+ prt_slot3(0x0013),
+ prt_slot0(0x0014),
+ prt_slot1(0x0015),
+ prt_slot2(0x0016),
+ prt_slot3(0x0017),
+ prt_slot0(0x0018),
+ prt_slot1(0x0019),
+ prt_slot2(0x001a),
+ prt_slot3(0x001b),
+ prt_slot0(0x001c),
+ prt_slot1(0x001d),
+ prt_slot2(0x001e),
+ prt_slot3(0x001f),
+ })
+
+ OperationRegion(PCST, SystemIO, 0xae00, 0x08)
+ Field (PCST, DWordAcc, NoLock, WriteAsZeros)
+ {
+ PCIU, 32,
+ PCID, 32,
+ }
+
+ OperationRegion(SEJ, SystemIO, 0xae08, 0x04)
+ Field (SEJ, DWordAcc, NoLock, WriteAsZeros)
+ {
+ B0EJ, 32,
+ }
+
+ OperationRegion(RMVC, SystemIO, 0xae0c, 0x04)
+ Field(RMVC, DWordAcc, NoLock, WriteAsZeros)
+ {
+ PCRM, 32,
+ }
+
+#define hotplug_slot(name, nr) \
+ Device (S##name) { \
+ Name (_ADR, nr##0000) \
+ Method (_EJ0,1) { \
+ Store(ShiftLeft(1, nr), B0EJ) \
+ Return (0x0) \
+ } \
+ Name (_SUN, name) \
+ }
+
+ hotplug_slot(1, 0x0001)
+ hotplug_slot(2, 0x0002)
+ hotplug_slot(3, 0x0003)
+ hotplug_slot(4, 0x0004)
+ hotplug_slot(5, 0x0005)
+ hotplug_slot(6, 0x0006)
+ hotplug_slot(7, 0x0007)
+ hotplug_slot(8, 0x0008)
+ hotplug_slot(9, 0x0009)
+ hotplug_slot(10, 0x000a)
+ hotplug_slot(11, 0x000b)
+ hotplug_slot(12, 0x000c)
+ hotplug_slot(13, 0x000d)
+ hotplug_slot(14, 0x000e)
+ hotplug_slot(15, 0x000f)
+ hotplug_slot(16, 0x0010)
+ hotplug_slot(17, 0x0011)
+ hotplug_slot(18, 0x0012)
+ hotplug_slot(19, 0x0013)
+ hotplug_slot(20, 0x0014)
+ hotplug_slot(21, 0x0015)
+ hotplug_slot(22, 0x0016)
+ hotplug_slot(23, 0x0017)
+ hotplug_slot(24, 0x0018)
+ hotplug_slot(25, 0x0019)
+ hotplug_slot(26, 0x001a)
+ hotplug_slot(27, 0x001b)
+ hotplug_slot(28, 0x001c)
+ hotplug_slot(29, 0x001d)
+ hotplug_slot(30, 0x001e)
+ hotplug_slot(31, 0x001f)
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x00FF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0100, // Address Length
+ ,, )
+ IO (Decode16,
+ 0x0CF8, // Address Range Minimum
+ 0x0CF8, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x08, // Address Length
+ )
+ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0000, // Address Range Minimum
+ 0x0CF7, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0x0CF8, // Address Length
+ ,, , TypeStatic)
+ WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, // Address Space Granularity
+ 0x0D00, // Address Range Minimum
+ 0xFFFF, // Address Range Maximum
+ 0x0000, // Address Translation Offset
+ 0xF300, // Address Length
+ ,, , TypeStatic)
+ DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0x000A0000, // Address Range Minimum
+ 0x000BFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x00020000, // Address Length
+ ,, , AddressRangeMemory, TypeStatic)
+ DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
+ 0x00000000, // Address Space Granularity
+ 0xE0000000, // Address Range Minimum
+ 0xFEBFFFFF, // Address Range Maximum
+ 0x00000000, // Address Translation Offset
+ 0x1EC00000, // Address Length
+ ,, , AddressRangeMemory, TypeStatic)
+ })
+ }
+
+ Device(HPET) {
+ Name(_HID, EISAID("PNP0103"))
+ Name(_UID, 0)
+ Method (_STA, 0, NotSerialized) {
+ Return(0x0F)
+ }
+ Name(_CRS, ResourceTemplate() {
+ DWordMemory(
+ ResourceConsumer, PosDecode, MinFixed, MaxFixed,
+ NonCacheable, ReadWrite,
+ 0x00000000,
+ 0xFED00000,
+ 0xFED003FF,
+ 0x00000000,
+ 0x00000400 /* 1K memory: FED00000 - FED003FF */
+ )
+ })
+ }
+ }
+
+ Scope(\_SB.PCI0) {
+ Device (VGA) {
+ Name (_ADR, 0x00020000)
+ OperationRegion(PCIC, PCI_Config, Zero, 0x4)
+ Field(PCIC, DWordAcc, NoLock, Preserve) {
+ VEND, 32
+ }
+ Method (_S1D, 0, NotSerialized)
+ {
+ Return (0x00)
+ }
+ Method (_S2D, 0, NotSerialized)
+ {
+ Return (0x00)
+ }
+ Method (_S3D, 0, NotSerialized)
+ {
+ If (LEqual(VEND, 0x1001b36)) {
+ Return (0x03) // QXL
+ } Else {
+ Return (0x00)
+ }
+ }
+ Method(_RMV) { Return (0x00) }
+ }
+
+ /* PIIX3 ISA bridge */
+ Device (ISA) {
+ Name (_ADR, 0x00010000)
+ Method(_RMV) { Return (0x00) }
+
+
+ /* PIIX PCI to ISA irq remapping */
+ OperationRegion (P40C, PCI_Config, 0x60, 0x04)
+
+ /* Real-time clock */
+ Device (RTC)
+ {
+ Name (_HID, EisaId ("PNP0B00"))
+ Name (_CRS, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0070, 0x0070, 0x10, 0x02)
+ IRQNoFlags () {8}
+ IO (Decode16, 0x0072, 0x0072, 0x02, 0x06)
+ })
+ }
+
+ /* Keyboard seems to be important for WinXP install */
+ Device (KBD)
+ {
+ Name (_HID, EisaId ("PNP0303"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0f)
+ }
+
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (TMP, ResourceTemplate ()
+ {
+ IO (Decode16,
+ 0x0060, // Address Range Minimum
+ 0x0060, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x01, // Address Length
+ )
+ IO (Decode16,
+ 0x0064, // Address Range Minimum
+ 0x0064, // Address Range Maximum
+ 0x01, // Address Alignment
+ 0x01, // Address Length
+ )
+ IRQNoFlags ()
+ {1}
+ })
+ Return (TMP)
+ }
+ }
+
+ /* PS/2 mouse */
+ Device (MOU)
+ {
+ Name (_HID, EisaId ("PNP0F13"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0f)
+ }
+
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (TMP, ResourceTemplate ()
+ {
+ IRQNoFlags () {12}
+ })
+ Return (TMP)
+ }
+ }
+
+ /* PS/2 floppy controller */
+ Device (FDC0)
+ {
+ Name (_HID, EisaId ("PNP0700"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
+ IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
+ IRQNoFlags () {6}
+ DMA (Compatibility, NotBusMaster, Transfer8) {2}
+ })
+ Return (BUF0)
+ }
+ }
+
+ /* Parallel port */
+ Device (LPT)
+ {
+ Name (_HID, EisaId ("PNP0400"))
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (\_SB.PCI0.PX13.DRSA, Local0)
+ And (Local0, 0x80000000, Local0)
+ If (LEqual (Local0, 0))
+ {
+ Return (0x00)
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
+ IRQNoFlags () {7}
+ })
+ Return (BUF0)
+ }
+ }
+
+ /* Serial Ports */
+ Device (COM1)
+ {
+ Name (_HID, EisaId ("PNP0501"))
+ Name (_UID, 0x01)
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (\_SB.PCI0.PX13.DRSC, Local0)
+ And (Local0, 0x08000000, Local0)
+ If (LEqual (Local0, 0))
+ {
+ Return (0x00)
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
+ IRQNoFlags () {4}
+ })
+ Return (BUF0)
+ }
+ }
+
+ Device (COM2)
+ {
+ Name (_HID, EisaId ("PNP0501"))
+ Name (_UID, 0x02)
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (\_SB.PCI0.PX13.DRSC, Local0)
+ And (Local0, 0x80000000, Local0)
+ If (LEqual (Local0, 0))
+ {
+ Return (0x00)
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (BUF0, ResourceTemplate ()
+ {
+ IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
+ IRQNoFlags () {3}
+ })
+ Return (BUF0)
+ }
+ }
+ }
+
+ /* PIIX4 PM */
+ Device (PX13) {
+ Name (_ADR, 0x00010003)
+
+ OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
+ Field (P13C, DWordAcc, NoLock, Preserve)
+ {
+ DRSA, 32,
+ DRSB, 32,
+ DRSC, 32,
+ DRSE, 32,
+ DRSF, 32,
+ DRSG, 32,
+ DRSH, 32,
+ DRSI, 32,
+ DRSJ, 32
+ }
+ }
+
+#define gen_pci_device(name, nr) \
+ Device(SL##name) { \
+ Name (_ADR, nr##0000) \
+ Method (_RMV) { \
+ If (And(\_SB.PCI0.PCRM, ShiftLeft(1, nr))) { \
+ Return (0x1) \
+ } \
+ Return (0x0) \
+ } \
+ Name (_SUN, name) \
+ }
+
+ /* VGA (slot 1) and ISA bus (slot 2) defined above */
+ gen_pci_device(3, 0x0003)
+ gen_pci_device(4, 0x0004)
+ gen_pci_device(5, 0x0005)
+ gen_pci_device(6, 0x0006)
+ gen_pci_device(7, 0x0007)
+ gen_pci_device(8, 0x0008)
+ gen_pci_device(9, 0x0009)
+ gen_pci_device(10, 0x000a)
+ gen_pci_device(11, 0x000b)
+ gen_pci_device(12, 0x000c)
+ gen_pci_device(13, 0x000d)
+ gen_pci_device(14, 0x000e)
+ gen_pci_device(15, 0x000f)
+ gen_pci_device(16, 0x0010)
+ gen_pci_device(17, 0x0011)
+ gen_pci_device(18, 0x0012)
+ gen_pci_device(19, 0x0013)
+ gen_pci_device(20, 0x0014)
+ gen_pci_device(21, 0x0015)
+ gen_pci_device(22, 0x0016)
+ gen_pci_device(23, 0x0017)
+ gen_pci_device(24, 0x0018)
+ gen_pci_device(25, 0x0019)
+ gen_pci_device(26, 0x001a)
+ gen_pci_device(27, 0x001b)
+ gen_pci_device(28, 0x001c)
+ gen_pci_device(29, 0x001d)
+ gen_pci_device(30, 0x001e)
+ gen_pci_device(31, 0x001f)
+ }
+
+ /* PCI IRQs */
+ Scope(\_SB) {
+ Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
+ {
+ PRQ0, 8,
+ PRQ1, 8,
+ PRQ2, 8,
+ PRQ3, 8
+ }
+
+ Device(LNKA){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 1)
+ Name(_PRS, ResourceTemplate(){
+ Interrupt (, Level, ActiveHigh, Shared)
+ { 5, 10, 11 }
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ0, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ0, 0x80, PRQ0)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ Interrupt (, Level, ActiveHigh, Shared)
+ {1}
+ })
+ CreateDWordField (PRR0, 0x05, TMP)
+ Store (PRQ0, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ Store (Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateDWordField (Arg0, 0x05, TMP)
+ Store (TMP, PRQ0)
+ }
+ }
+ Device(LNKB){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 2)
+ Name(_PRS, ResourceTemplate(){
+ Interrupt (, Level, ActiveHigh, Shared)
+ { 5, 10, 11 }
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ1, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ1, 0x80, PRQ1)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ Interrupt (, Level, ActiveHigh, Shared)
+ {1}
+ })
+ CreateDWordField (PRR0, 0x05, TMP)
+ Store (PRQ1, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ Store (Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateDWordField (Arg0, 0x05, TMP)
+ Store (TMP, PRQ1)
+ }
+ }
+ Device(LNKC){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 3)
+ Name(_PRS, ResourceTemplate(){
+ Interrupt (, Level, ActiveHigh, Shared)
+ { 5, 10, 11 }
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ2, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ2, 0x80, PRQ2)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ Interrupt (, Level, ActiveHigh, Shared)
+ {1}
+ })
+ CreateDWordField (PRR0, 0x05, TMP)
+ Store (PRQ2, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ Store (Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateDWordField (Arg0, 0x05, TMP)
+ Store (TMP, PRQ2)
+ }
+ }
+ Device(LNKD){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 4)
+ Name(_PRS, ResourceTemplate(){
+ Interrupt (, Level, ActiveHigh, Shared)
+ { 5, 10, 11 }
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ3, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ3, 0x80, PRQ3)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ Interrupt (, Level, ActiveHigh, Shared)
+ {1}
+ })
+ CreateDWordField (PRR0, 0x05, TMP)
+ Store (PRQ3, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ Store (Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ Method (_SRS, 1, NotSerialized)
+ {
+ CreateDWordField (Arg0, 0x05, TMP)
+ Store (TMP, PRQ3)
+ }
+ }
+ Device(LNKS){
+ Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
+ Name(_UID, 5)
+ Name(_PRS, ResourceTemplate(){
+ Interrupt (, Level, ActiveHigh, Shared)
+ { 9 }
+ })
+ Method (_STA, 0, NotSerialized)
+ {
+ Store (0x0B, Local0)
+ If (And (0x80, PRQ0, Local1))
+ {
+ Store (0x09, Local0)
+ }
+ Return (Local0)
+ }
+ Method (_DIS, 0, NotSerialized)
+ {
+ Or (PRQ0, 0x80, PRQ0)
+ }
+ Method (_CRS, 0, NotSerialized)
+ {
+ Name (PRR0, ResourceTemplate ()
+ {
+ Interrupt (, Level, ActiveHigh, Shared)
+ {9}
+ })
+ CreateDWordField (PRR0, 0x05, TMP)
+ Store (PRQ0, Local0)
+ If (LLess (Local0, 0x80))
+ {
+ Store (Local0, TMP)
+ }
+ Else
+ {
+ Store (Zero, TMP)
+ }
+ Return (PRR0)
+ }
+ }
+ }
+
+ /*
+ * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes:
+ * must match piix4 emulation.
+ */
+ Name (\_S3, Package (0x04)
+ {
+ 0x01, /* PM1a_CNT.SLP_TYP */
+ 0x01, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ Name (\_S4, Package (0x04)
+ {
+ Zero, /* PM1a_CNT.SLP_TYP */
+ Zero, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+ Name (\_S5, Package (0x04)
+ {
+ Zero, /* PM1a_CNT.SLP_TYP */
+ Zero, /* PM1b_CNT.SLP_TYP */
+ Zero, /* reserved */
+ Zero /* reserved */
+ })
+
+ /* CPU hotplug */
+ Scope(\_SB) {
+ /* Objects filled in by run-time generated SSDT */
+ External(NTFY, MethodObj)
+ External(CPON, PkgObj)
+
+ /* Methods called by run-time generated SSDT Processor objects */
+ Method (CPMA, 1, NotSerialized) {
+ // _MAT method - create an madt apic buffer
+ // Local0 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Arg0)), Local0)
+ // Local1 = Buffer (in madt apic form) to return
+ Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1)
+ // Update the processor id, lapic id, and enable/disable status
+ Store(Arg0, Index(Local1, 2))
+ Store(Arg0, Index(Local1, 3))
+ Store(Local0, Index(Local1, 4))
+ Return (Local1)
+ }
+ Method (CPST, 1, NotSerialized) {
+ // _STA method - return ON status of cpu
+ // Local0 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Arg0)), Local0)
+ If (Local0) { Return(0xF) } Else { Return(0x0) }
+ }
+ Method (CPEJ, 2, NotSerialized) {
+ // _EJ0 method - eject callback
+ Sleep(200)
+ }
+
+ /* CPU hotplug notify method */
+ OperationRegion(PRST, SystemIO, 0xaf00, 32)
+ Field (PRST, ByteAcc, NoLock, Preserve)
+ {
+ PRS, 256
+ }
+ Method(PRSC, 0) {
+ // Local5 = active cpu bitmap
+ Store (PRS, Local5)
+ // Local2 = last read byte from bitmap
+ Store (Zero, Local2)
+ // Local0 = cpuid iterator
+ Store (Zero, Local0)
+ While (LLess(Local0, SizeOf(CPON))) {
+ // Local1 = CPON flag for this cpu
+ Store(DerefOf(Index(CPON, Local0)), Local1)
+ If (And(Local0, 0x07)) {
+ // Shift down previously read bitmap byte
+ ShiftRight(Local2, 1, Local2)
+ } Else {
+ // Read next byte from cpu bitmap
+ Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2)
+ }
+ // Local3 = active state for this cpu
+ Store(And(Local2, 1), Local3)
+
+ If (LNotEqual(Local1, Local3)) {
+ // State change - update CPON with new state
+ Store(Local3, Index(CPON, Local0))
+ // Do CPU notify
+ If (LEqual(Local3, 1)) {
+ NTFY(Local0, 1)
+ } Else {
+ NTFY(Local0, 3)
+ }
+ }
+ Increment(Local0)
+ }
+ Return(One)
+ }
+ }
+
+ Scope (\_GPE)
+ {
+ Name(_HID, "ACPI0006")
+
+ Method(_L00) {
+ Return(0x01)
+ }
+
+#define gen_pci_hotplug(nr) \
+ If (And(\_SB.PCI0.PCIU, ShiftLeft(1, nr))) { \
+ Notify(\_SB.PCI0.S##nr, 1) \
+ } \
+ If (And(\_SB.PCI0.PCID, ShiftLeft(1, nr))) { \
+ Notify(\_SB.PCI0.S##nr, 3) \
+ }
+
+ Method(_L01) {
+ gen_pci_hotplug(1)
+ gen_pci_hotplug(2)
+ gen_pci_hotplug(3)
+ gen_pci_hotplug(4)
+ gen_pci_hotplug(5)
+ gen_pci_hotplug(6)
+ gen_pci_hotplug(7)
+ gen_pci_hotplug(8)
+ gen_pci_hotplug(9)
+ gen_pci_hotplug(10)
+ gen_pci_hotplug(11)
+ gen_pci_hotplug(12)
+ gen_pci_hotplug(13)
+ gen_pci_hotplug(14)
+ gen_pci_hotplug(15)
+ gen_pci_hotplug(16)
+ gen_pci_hotplug(17)
+ gen_pci_hotplug(18)
+ gen_pci_hotplug(19)
+ gen_pci_hotplug(20)
+ gen_pci_hotplug(21)
+ gen_pci_hotplug(22)
+ gen_pci_hotplug(23)
+ gen_pci_hotplug(24)
+ gen_pci_hotplug(25)
+ gen_pci_hotplug(26)
+ gen_pci_hotplug(27)
+ gen_pci_hotplug(28)
+ gen_pci_hotplug(29)
+ gen_pci_hotplug(30)
+ gen_pci_hotplug(31)
+
+ Return (0x01)
+
+ }
+ Method(_L02) {
+ // CPU hotplug event
+ Return(\_SB.PRSC())
+ }
+ Method(_L03) {
+ Return(0x01)
+ }
+ Method(_L04) {
+ Return(0x01)
+ }
+ Method(_L05) {
+ Return(0x01)
+ }
+ Method(_L06) {
+ Return(0x01)
+ }
+ Method(_L07) {
+ Return(0x01)
+ }
+ Method(_L08) {
+ Return(0x01)
+ }
+ Method(_L09) {
+ Return(0x01)
+ }
+ Method(_L0A) {
+ Return(0x01)
+ }
+ Method(_L0B) {
+ Return(0x01)
+ }
+ Method(_L0C) {
+ Return(0x01)
+ }
+ Method(_L0D) {
+ Return(0x01)
+ }
+ Method(_L0E) {
+ Return(0x01)
+ }
+ Method(_L0F) {
+ Return(0x01)
+ }
+ }
+
+}
--- /dev/null
+/*
+ *
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler version 20100528 [Feb 9 2011]
+ * Copyright (c) 2000 - 2010 Intel Corporation
+ * Supports ACPI Specification Revision 4.0a
+ *
+ * Compilation of "out/acpi-dsdt.dsl.i" - Tue Jan 22 14:33:33 2013
+ *
+ * C source code output
+ * AML code block contains 0x2589 bytes
+ *
+ */
+unsigned char AmlCode[] =
+{
+ 0x44,0x53,0x44,0x54,0x89,0x25,0x00,0x00, /* 00000000 "DSDT.%.." */
+ 0x01,0x13,0x42,0x58,0x50,0x43,0x00,0x00, /* 00000008 "..BXPC.." */
+ 0x42,0x58,0x44,0x53,0x44,0x54,0x00,0x00, /* 00000010 "BXDSDT.." */
+ 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
+ 0x28,0x05,0x10,0x20,0x10,0x49,0x04,0x5C, /* 00000020 "(.. .I.\" */
+ 0x00,0x5B,0x80,0x44,0x42,0x47,0x5F,0x01, /* 00000028 ".[.DBG_." */
+ 0x0B,0x02,0x04,0x01,0x5B,0x81,0x0B,0x44, /* 00000030 "....[..D" */
+ 0x42,0x47,0x5F,0x01,0x44,0x42,0x47,0x42, /* 00000038 "BG_.DBGB" */
+ 0x08,0x14,0x2C,0x44,0x42,0x55,0x47,0x01, /* 00000040 "..,DBUG." */
+ 0x98,0x68,0x60,0x96,0x60,0x60,0x74,0x87, /* 00000048 ".h`.``t." */
+ 0x60,0x01,0x61,0x70,0x00,0x62,0xA2,0x10, /* 00000050 "`.ap.b.." */
+ 0x95,0x62,0x61,0x70,0x83,0x88,0x60,0x62, /* 00000058 ".bap..`b" */
+ 0x00,0x44,0x42,0x47,0x42,0x75,0x62,0x70, /* 00000060 ".DBGBubp" */
+ 0x0A,0x0A,0x44,0x42,0x47,0x42,0x10,0x43, /* 00000068 "..DBGB.C" */
+ 0xD8,0x5F,0x53,0x42,0x5F,0x5B,0x82,0x44, /* 00000070 "._SB_[.D" */
+ 0xD3,0x50,0x43,0x49,0x30,0x08,0x5F,0x48, /* 00000078 ".PCI0._H" */
+ 0x49,0x44,0x0C,0x41,0xD0,0x0A,0x03,0x08, /* 00000080 "ID.A...." */
+ 0x5F,0x41,0x44,0x52,0x00,0x08,0x5F,0x55, /* 00000088 "_ADR.._U" */
+ 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x54, /* 00000090 "ID.._PRT" */
+ 0x12,0x4B,0x73,0x80,0x12,0x0B,0x04,0x0B, /* 00000098 ".Ks....." */
+ 0xFF,0xFF,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 000000A0 "...LNKD." */
+ 0x12,0x0B,0x04,0x0B,0xFF,0xFF,0x01,0x4C, /* 000000A8 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0C,0x04,0x0B, /* 000000B0 "NKA....." */
+ 0xFF,0xFF,0x0A,0x02,0x4C,0x4E,0x4B,0x42, /* 000000B8 "....LNKB" */
+ 0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF,0x0A, /* 000000C0 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 000000C8 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x01,0x00,0x00,0x4C, /* 000000D0 ".......L" */
+ 0x4E,0x4B,0x53,0x00,0x12,0x0D,0x04,0x0C, /* 000000D8 "NKS....." */
+ 0xFF,0xFF,0x01,0x00,0x01,0x4C,0x4E,0x4B, /* 000000E0 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000000E8 "B......." */
+ 0x01,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000000F0 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01, /* 000000F8 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000100 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x02,0x00, /* 00000108 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000110 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x01,0x4C, /* 00000118 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000120 "NKC....." */
+ 0xFF,0xFF,0x02,0x00,0x0A,0x02,0x4C,0x4E, /* 00000128 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000130 "KD......" */
+ 0xFF,0x02,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000138 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000140 "A......." */
+ 0x03,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000148 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000150 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000158 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x02, /* 00000160 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000168 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x03,0x00,0x0A,0x03,0x4C, /* 00000170 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000178 "NKB....." */
+ 0xFF,0xFF,0x04,0x00,0x00,0x4C,0x4E,0x4B, /* 00000180 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000188 "D......." */
+ 0x04,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000190 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000198 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000001A0 "..LNKB.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A, /* 000001A8 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 000001B0 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x05,0x00,0x00,0x4C, /* 000001B8 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000001C0 "NKA....." */
+ 0xFF,0xFF,0x05,0x00,0x01,0x4C,0x4E,0x4B, /* 000001C8 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000001D0 "B......." */
+ 0x05,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000001D8 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05, /* 000001E0 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000001E8 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x06,0x00, /* 000001F0 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000001F8 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x06,0x00,0x01,0x4C, /* 00000200 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000208 "NKC....." */
+ 0xFF,0xFF,0x06,0x00,0x0A,0x02,0x4C,0x4E, /* 00000210 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000218 "KD......" */
+ 0xFF,0x06,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000220 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000228 "A......." */
+ 0x07,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000230 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x07,0x00, /* 00000238 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000240 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x02, /* 00000248 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000250 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x07,0x00,0x0A,0x03,0x4C, /* 00000258 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000260 "NKB....." */
+ 0xFF,0xFF,0x08,0x00,0x00,0x4C,0x4E,0x4B, /* 00000268 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000270 "D......." */
+ 0x08,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000278 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00, /* 00000280 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000288 "..LNKB.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x08,0x00,0x0A, /* 00000290 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000298 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x09,0x00,0x00,0x4C, /* 000002A0 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 000002A8 "NKA....." */
+ 0xFF,0xFF,0x09,0x00,0x01,0x4C,0x4E,0x4B, /* 000002B0 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000002B8 "B......." */
+ 0x09,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000002C0 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x09, /* 000002C8 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000002D0 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0A,0x00, /* 000002D8 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000002E0 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x0A,0x00,0x01,0x4C, /* 000002E8 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000002F0 "NKC....." */
+ 0xFF,0xFF,0x0A,0x00,0x0A,0x02,0x4C,0x4E, /* 000002F8 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000300 "KD......" */
+ 0xFF,0x0A,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000308 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000310 "A......." */
+ 0x0B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000318 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0B,0x00, /* 00000320 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000328 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x02, /* 00000330 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000338 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x0B,0x00,0x0A,0x03,0x4C, /* 00000340 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000348 "NKB....." */
+ 0xFF,0xFF,0x0C,0x00,0x00,0x4C,0x4E,0x4B, /* 00000350 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000358 "D......." */
+ 0x0C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000360 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00, /* 00000368 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000370 "..LNKB.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x0C,0x00,0x0A, /* 00000378 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000380 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x0D,0x00,0x00,0x4C, /* 00000388 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000390 "NKA....." */
+ 0xFF,0xFF,0x0D,0x00,0x01,0x4C,0x4E,0x4B, /* 00000398 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 000003A0 "B......." */
+ 0x0D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 000003A8 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x0D, /* 000003B0 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000003B8 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0E,0x00, /* 000003C0 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000003C8 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x0E,0x00,0x01,0x4C, /* 000003D0 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000003D8 "NKC....." */
+ 0xFF,0xFF,0x0E,0x00,0x0A,0x02,0x4C,0x4E, /* 000003E0 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000003E8 "KD......" */
+ 0xFF,0x0E,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000003F0 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000003F8 "A......." */
+ 0x0F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 00000400 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x0F,0x00, /* 00000408 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 00000410 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x02, /* 00000418 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000420 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x0F,0x00,0x0A,0x03,0x4C, /* 00000428 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000430 "NKB....." */
+ 0xFF,0xFF,0x10,0x00,0x00,0x4C,0x4E,0x4B, /* 00000438 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000440 "D......." */
+ 0x10,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000448 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00, /* 00000450 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000458 "..LNKB.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x10,0x00,0x0A, /* 00000460 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000468 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x11,0x00,0x00,0x4C, /* 00000470 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000478 "NKA....." */
+ 0xFF,0xFF,0x11,0x00,0x01,0x4C,0x4E,0x4B, /* 00000480 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000488 "B......." */
+ 0x11,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000490 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x11, /* 00000498 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 000004A0 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x12,0x00, /* 000004A8 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 000004B0 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x12,0x00,0x01,0x4C, /* 000004B8 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000004C0 "NKC....." */
+ 0xFF,0xFF,0x12,0x00,0x0A,0x02,0x4C,0x4E, /* 000004C8 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000004D0 "KD......" */
+ 0xFF,0x12,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000004D8 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000004E0 "A......." */
+ 0x13,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000004E8 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x13,0x00, /* 000004F0 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000004F8 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x02, /* 00000500 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 00000508 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x13,0x00,0x0A,0x03,0x4C, /* 00000510 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000518 "NKB....." */
+ 0xFF,0xFF,0x14,0x00,0x00,0x4C,0x4E,0x4B, /* 00000520 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000528 "D......." */
+ 0x14,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000530 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00, /* 00000538 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000540 "..LNKB.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x14,0x00,0x0A, /* 00000548 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000550 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x15,0x00,0x00,0x4C, /* 00000558 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000560 "NKA....." */
+ 0xFF,0xFF,0x15,0x00,0x01,0x4C,0x4E,0x4B, /* 00000568 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000570 "B......." */
+ 0x15,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000578 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x15, /* 00000580 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000588 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x16,0x00, /* 00000590 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000598 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x16,0x00,0x01,0x4C, /* 000005A0 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 000005A8 "NKC....." */
+ 0xFF,0xFF,0x16,0x00,0x0A,0x02,0x4C,0x4E, /* 000005B0 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000005B8 "KD......" */
+ 0xFF,0x16,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000005C0 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000005C8 "A......." */
+ 0x17,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000005D0 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x17,0x00, /* 000005D8 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000005E0 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x02, /* 000005E8 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 000005F0 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x17,0x00,0x0A,0x03,0x4C, /* 000005F8 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000600 "NKB....." */
+ 0xFF,0xFF,0x18,0x00,0x00,0x4C,0x4E,0x4B, /* 00000608 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000610 "D......." */
+ 0x18,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000618 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00, /* 00000620 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000628 "..LNKB.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x18,0x00,0x0A, /* 00000630 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000638 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x19,0x00,0x00,0x4C, /* 00000640 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000648 "NKA....." */
+ 0xFF,0xFF,0x19,0x00,0x01,0x4C,0x4E,0x4B, /* 00000650 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000658 "B......." */
+ 0x19,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000660 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x19, /* 00000668 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000670 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1A,0x00, /* 00000678 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000680 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x1A,0x00,0x01,0x4C, /* 00000688 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000690 "NKC....." */
+ 0xFF,0xFF,0x1A,0x00,0x0A,0x02,0x4C,0x4E, /* 00000698 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 000006A0 "KD......" */
+ 0xFF,0x1A,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 000006A8 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000006B0 "A......." */
+ 0x1B,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000006B8 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1B,0x00, /* 000006C0 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000006C8 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x02, /* 000006D0 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 000006D8 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x1B,0x00,0x0A,0x03,0x4C, /* 000006E0 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 000006E8 "NKB....." */
+ 0xFF,0xFF,0x1C,0x00,0x00,0x4C,0x4E,0x4B, /* 000006F0 ".....LNK" */
+ 0x44,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000006F8 "D......." */
+ 0x1C,0x00,0x01,0x4C,0x4E,0x4B,0x41,0x00, /* 00000700 "...LNKA." */
+ 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00, /* 00000708 "........" */
+ 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 00000710 "..LNKB.." */
+ 0x0E,0x04,0x0C,0xFF,0xFF,0x1C,0x00,0x0A, /* 00000718 "........" */
+ 0x03,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000720 ".LNKC..." */
+ 0x04,0x0C,0xFF,0xFF,0x1D,0x00,0x00,0x4C, /* 00000728 ".......L" */
+ 0x4E,0x4B,0x41,0x00,0x12,0x0D,0x04,0x0C, /* 00000730 "NKA....." */
+ 0xFF,0xFF,0x1D,0x00,0x01,0x4C,0x4E,0x4B, /* 00000738 ".....LNK" */
+ 0x42,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000740 "B......." */
+ 0x1D,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x43, /* 00000748 "....LNKC" */
+ 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x1D, /* 00000750 "........" */
+ 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x44,0x00, /* 00000758 "...LNKD." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1E,0x00, /* 00000760 "........" */
+ 0x00,0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0D, /* 00000768 ".LNKB..." */
+ 0x04,0x0C,0xFF,0xFF,0x1E,0x00,0x01,0x4C, /* 00000770 ".......L" */
+ 0x4E,0x4B,0x43,0x00,0x12,0x0E,0x04,0x0C, /* 00000778 "NKC....." */
+ 0xFF,0xFF,0x1E,0x00,0x0A,0x02,0x4C,0x4E, /* 00000780 "......LN" */
+ 0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000788 "KD......" */
+ 0xFF,0x1E,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000790 ".....LNK" */
+ 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000798 "A......." */
+ 0x1F,0x00,0x00,0x4C,0x4E,0x4B,0x43,0x00, /* 000007A0 "...LNKC." */
+ 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x1F,0x00, /* 000007A8 "........" */
+ 0x01,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0E, /* 000007B0 ".LNKD..." */
+ 0x04,0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x02, /* 000007B8 "........" */
+ 0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E,0x04, /* 000007C0 "LNKA...." */
+ 0x0C,0xFF,0xFF,0x1F,0x00,0x0A,0x03,0x4C, /* 000007C8 ".......L" */
+ 0x4E,0x4B,0x42,0x00,0x5B,0x80,0x50,0x43, /* 000007D0 "NKB.[.PC" */
+ 0x53,0x54,0x01,0x0B,0x00,0xAE,0x0A,0x08, /* 000007D8 "ST......" */
+ 0x5B,0x81,0x10,0x50,0x43,0x53,0x54,0x43, /* 000007E0 "[..PCSTC" */
+ 0x50,0x43,0x49,0x55,0x20,0x50,0x43,0x49, /* 000007E8 "PCIU PCI" */
+ 0x44,0x20,0x5B,0x80,0x53,0x45,0x4A,0x5F, /* 000007F0 "D [.SEJ_" */
+ 0x01,0x0B,0x08,0xAE,0x0A,0x04,0x5B,0x81, /* 000007F8 "......[." */
+ 0x0B,0x53,0x45,0x4A,0x5F,0x43,0x42,0x30, /* 00000800 ".SEJ_CB0" */
+ 0x45,0x4A,0x20,0x5B,0x80,0x52,0x4D,0x56, /* 00000808 "EJ [.RMV" */
+ 0x43,0x01,0x0B,0x0C,0xAE,0x0A,0x04,0x5B, /* 00000810 "C......[" */
+ 0x81,0x0B,0x52,0x4D,0x56,0x43,0x43,0x50, /* 00000818 "..RMVCCP" */
+ 0x43,0x52,0x4D,0x20,0x5B,0x82,0x25,0x53, /* 00000820 "CRM [.%S" */
+ 0x31,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000828 "1__._ADR" */
+ 0x0C,0x00,0x00,0x01,0x00,0x14,0x0F,0x5F, /* 00000830 "......._" */
+ 0x45,0x4A,0x30,0x01,0x70,0x0A,0x02,0x42, /* 00000838 "EJ0.p..B" */
+ 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000840 "0EJ..._S" */
+ 0x55,0x4E,0x01,0x5B,0x82,0x26,0x53,0x32, /* 00000848 "UN.[.&S2" */
+ 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000850 "__._ADR." */
+ 0x00,0x00,0x02,0x00,0x14,0x0F,0x5F,0x45, /* 00000858 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0A,0x04,0x42,0x30, /* 00000860 "J0.p..B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000868 "EJ..._SU" */
+ 0x4E,0x0A,0x02,0x5B,0x82,0x26,0x53,0x33, /* 00000870 "N..[.&S3" */
+ 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000878 "__._ADR." */
+ 0x00,0x00,0x03,0x00,0x14,0x0F,0x5F,0x45, /* 00000880 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0A,0x08,0x42,0x30, /* 00000888 "J0.p..B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000890 "EJ..._SU" */
+ 0x4E,0x0A,0x03,0x5B,0x82,0x26,0x53,0x34, /* 00000898 "N..[.&S4" */
+ 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000008A0 "__._ADR." */
+ 0x00,0x00,0x04,0x00,0x14,0x0F,0x5F,0x45, /* 000008A8 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0A,0x10,0x42,0x30, /* 000008B0 "J0.p..B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 000008B8 "EJ..._SU" */
+ 0x4E,0x0A,0x04,0x5B,0x82,0x26,0x53,0x35, /* 000008C0 "N..[.&S5" */
+ 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000008C8 "__._ADR." */
+ 0x00,0x00,0x05,0x00,0x14,0x0F,0x5F,0x45, /* 000008D0 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0A,0x20,0x42,0x30, /* 000008D8 "J0.p. B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 000008E0 "EJ..._SU" */
+ 0x4E,0x0A,0x05,0x5B,0x82,0x26,0x53,0x36, /* 000008E8 "N..[.&S6" */
+ 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000008F0 "__._ADR." */
+ 0x00,0x00,0x06,0x00,0x14,0x0F,0x5F,0x45, /* 000008F8 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0A,0x40,0x42,0x30, /* 00000900 "J0.p.@B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000908 "EJ..._SU" */
+ 0x4E,0x0A,0x06,0x5B,0x82,0x26,0x53,0x37, /* 00000910 "N..[.&S7" */
+ 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000918 "__._ADR." */
+ 0x00,0x00,0x07,0x00,0x14,0x0F,0x5F,0x45, /* 00000920 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0A,0x80,0x42,0x30, /* 00000928 "J0.p..B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000930 "EJ..._SU" */
+ 0x4E,0x0A,0x07,0x5B,0x82,0x27,0x53,0x38, /* 00000938 "N..[.'S8" */
+ 0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000940 "__._ADR." */
+ 0x00,0x00,0x08,0x00,0x14,0x10,0x5F,0x45, /* 00000948 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0B,0x00,0x01,0x42, /* 00000950 "J0.p...B" */
+ 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000958 "0EJ..._S" */
+ 0x55,0x4E,0x0A,0x08,0x5B,0x82,0x27,0x53, /* 00000960 "UN..[.'S" */
+ 0x39,0x5F,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000968 "9__._ADR" */
+ 0x0C,0x00,0x00,0x09,0x00,0x14,0x10,0x5F, /* 00000970 "......._" */
+ 0x45,0x4A,0x30,0x01,0x70,0x0B,0x00,0x02, /* 00000978 "EJ0.p..." */
+ 0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F, /* 00000980 "B0EJ..._" */
+ 0x53,0x55,0x4E,0x0A,0x09,0x5B,0x82,0x27, /* 00000988 "SUN..[.'" */
+ 0x53,0x31,0x30,0x5F,0x08,0x5F,0x41,0x44, /* 00000990 "S10_._AD" */
+ 0x52,0x0C,0x00,0x00,0x0A,0x00,0x14,0x10, /* 00000998 "R......." */
+ 0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B,0x00, /* 000009A0 "_EJ0.p.." */
+ 0x04,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08, /* 000009A8 ".B0EJ..." */
+ 0x5F,0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82, /* 000009B0 "_SUN..[." */
+ 0x27,0x53,0x31,0x31,0x5F,0x08,0x5F,0x41, /* 000009B8 "'S11_._A" */
+ 0x44,0x52,0x0C,0x00,0x00,0x0B,0x00,0x14, /* 000009C0 "DR......" */
+ 0x10,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0B, /* 000009C8 "._EJ0.p." */
+ 0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00, /* 000009D0 "..B0EJ.." */
+ 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0B,0x5B, /* 000009D8 "._SUN..[" */
+ 0x82,0x27,0x53,0x31,0x32,0x5F,0x08,0x5F, /* 000009E0 ".'S12_._" */
+ 0x41,0x44,0x52,0x0C,0x00,0x00,0x0C,0x00, /* 000009E8 "ADR....." */
+ 0x14,0x10,0x5F,0x45,0x4A,0x30,0x01,0x70, /* 000009F0 ".._EJ0.p" */
+ 0x0B,0x00,0x10,0x42,0x30,0x45,0x4A,0xA4, /* 000009F8 "...B0EJ." */
+ 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0C, /* 00000A00 ".._SUN.." */
+ 0x5B,0x82,0x27,0x53,0x31,0x33,0x5F,0x08, /* 00000A08 "[.'S13_." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0D, /* 00000A10 "_ADR...." */
+ 0x00,0x14,0x10,0x5F,0x45,0x4A,0x30,0x01, /* 00000A18 "..._EJ0." */
+ 0x70,0x0B,0x00,0x20,0x42,0x30,0x45,0x4A, /* 00000A20 "p.. B0EJ" */
+ 0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A, /* 00000A28 "..._SUN." */
+ 0x0D,0x5B,0x82,0x27,0x53,0x31,0x34,0x5F, /* 00000A30 ".[.'S14_" */
+ 0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00, /* 00000A38 "._ADR..." */
+ 0x0E,0x00,0x14,0x10,0x5F,0x45,0x4A,0x30, /* 00000A40 "...._EJ0" */
+ 0x01,0x70,0x0B,0x00,0x40,0x42,0x30,0x45, /* 00000A48 ".p..@B0E" */
+ 0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00000A50 "J..._SUN" */
+ 0x0A,0x0E,0x5B,0x82,0x27,0x53,0x31,0x35, /* 00000A58 "..[.'S15" */
+ 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00000A60 "_._ADR.." */
+ 0x00,0x0F,0x00,0x14,0x10,0x5F,0x45,0x4A, /* 00000A68 "....._EJ" */
+ 0x30,0x01,0x70,0x0B,0x00,0x80,0x42,0x30, /* 00000A70 "0.p...B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000A78 "EJ..._SU" */
+ 0x4E,0x0A,0x0F,0x5B,0x82,0x29,0x53,0x31, /* 00000A80 "N..[.)S1" */
+ 0x36,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000A88 "6_._ADR." */
+ 0x00,0x00,0x10,0x00,0x14,0x12,0x5F,0x45, /* 00000A90 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x01, /* 00000A98 "J0.p...." */
+ 0x00,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08, /* 00000AA0 ".B0EJ..." */
+ 0x5F,0x53,0x55,0x4E,0x0A,0x10,0x5B,0x82, /* 00000AA8 "_SUN..[." */
+ 0x29,0x53,0x31,0x37,0x5F,0x08,0x5F,0x41, /* 00000AB0 ")S17_._A" */
+ 0x44,0x52,0x0C,0x00,0x00,0x11,0x00,0x14, /* 00000AB8 "DR......" */
+ 0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C, /* 00000AC0 "._EJ0.p." */
+ 0x00,0x00,0x02,0x00,0x42,0x30,0x45,0x4A, /* 00000AC8 "....B0EJ" */
+ 0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A, /* 00000AD0 "..._SUN." */
+ 0x11,0x5B,0x82,0x29,0x53,0x31,0x38,0x5F, /* 00000AD8 ".[.)S18_" */
+ 0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00, /* 00000AE0 "._ADR..." */
+ 0x12,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30, /* 00000AE8 "...._EJ0" */
+ 0x01,0x70,0x0C,0x00,0x00,0x04,0x00,0x42, /* 00000AF0 ".p.....B" */
+ 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000AF8 "0EJ..._S" */
+ 0x55,0x4E,0x0A,0x12,0x5B,0x82,0x29,0x53, /* 00000B00 "UN..[.)S" */
+ 0x31,0x39,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000B08 "19_._ADR" */
+ 0x0C,0x00,0x00,0x13,0x00,0x14,0x12,0x5F, /* 00000B10 "......._" */
+ 0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00, /* 00000B18 "EJ0.p..." */
+ 0x08,0x00,0x42,0x30,0x45,0x4A,0xA4,0x00, /* 00000B20 "..B0EJ.." */
+ 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x13,0x5B, /* 00000B28 "._SUN..[" */
+ 0x82,0x29,0x53,0x32,0x30,0x5F,0x08,0x5F, /* 00000B30 ".)S20_._" */
+ 0x41,0x44,0x52,0x0C,0x00,0x00,0x14,0x00, /* 00000B38 "ADR....." */
+ 0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70, /* 00000B40 ".._EJ0.p" */
+ 0x0C,0x00,0x00,0x10,0x00,0x42,0x30,0x45, /* 00000B48 ".....B0E" */
+ 0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00000B50 "J..._SUN" */
+ 0x0A,0x14,0x5B,0x82,0x29,0x53,0x32,0x31, /* 00000B58 "..[.)S21" */
+ 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00000B60 "_._ADR.." */
+ 0x00,0x15,0x00,0x14,0x12,0x5F,0x45,0x4A, /* 00000B68 "....._EJ" */
+ 0x30,0x01,0x70,0x0C,0x00,0x00,0x20,0x00, /* 00000B70 "0.p... ." */
+ 0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F, /* 00000B78 "B0EJ..._" */
+ 0x53,0x55,0x4E,0x0A,0x15,0x5B,0x82,0x29, /* 00000B80 "SUN..[.)" */
+ 0x53,0x32,0x32,0x5F,0x08,0x5F,0x41,0x44, /* 00000B88 "S22_._AD" */
+ 0x52,0x0C,0x00,0x00,0x16,0x00,0x14,0x12, /* 00000B90 "R......." */
+ 0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00, /* 00000B98 "_EJ0.p.." */
+ 0x00,0x40,0x00,0x42,0x30,0x45,0x4A,0xA4, /* 00000BA0 ".@.B0EJ." */
+ 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x16, /* 00000BA8 ".._SUN.." */
+ 0x5B,0x82,0x29,0x53,0x32,0x33,0x5F,0x08, /* 00000BB0 "[.)S23_." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x17, /* 00000BB8 "_ADR...." */
+ 0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01, /* 00000BC0 "..._EJ0." */
+ 0x70,0x0C,0x00,0x00,0x80,0x00,0x42,0x30, /* 00000BC8 "p.....B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000BD0 "EJ..._SU" */
+ 0x4E,0x0A,0x17,0x5B,0x82,0x29,0x53,0x32, /* 00000BD8 "N..[.)S2" */
+ 0x34,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 00000BE0 "4_._ADR." */
+ 0x00,0x00,0x18,0x00,0x14,0x12,0x5F,0x45, /* 00000BE8 "......_E" */
+ 0x4A,0x30,0x01,0x70,0x0C,0x00,0x00,0x00, /* 00000BF0 "J0.p...." */
+ 0x01,0x42,0x30,0x45,0x4A,0xA4,0x00,0x08, /* 00000BF8 ".B0EJ..." */
+ 0x5F,0x53,0x55,0x4E,0x0A,0x18,0x5B,0x82, /* 00000C00 "_SUN..[." */
+ 0x29,0x53,0x32,0x35,0x5F,0x08,0x5F,0x41, /* 00000C08 ")S25_._A" */
+ 0x44,0x52,0x0C,0x00,0x00,0x19,0x00,0x14, /* 00000C10 "DR......" */
+ 0x12,0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C, /* 00000C18 "._EJ0.p." */
+ 0x00,0x00,0x00,0x02,0x42,0x30,0x45,0x4A, /* 00000C20 "....B0EJ" */
+ 0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A, /* 00000C28 "..._SUN." */
+ 0x19,0x5B,0x82,0x29,0x53,0x32,0x36,0x5F, /* 00000C30 ".[.)S26_" */
+ 0x08,0x5F,0x41,0x44,0x52,0x0C,0x00,0x00, /* 00000C38 "._ADR..." */
+ 0x1A,0x00,0x14,0x12,0x5F,0x45,0x4A,0x30, /* 00000C40 "...._EJ0" */
+ 0x01,0x70,0x0C,0x00,0x00,0x00,0x04,0x42, /* 00000C48 ".p.....B" */
+ 0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53, /* 00000C50 "0EJ..._S" */
+ 0x55,0x4E,0x0A,0x1A,0x5B,0x82,0x29,0x53, /* 00000C58 "UN..[.)S" */
+ 0x32,0x37,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 00000C60 "27_._ADR" */
+ 0x0C,0x00,0x00,0x1B,0x00,0x14,0x12,0x5F, /* 00000C68 "......._" */
+ 0x45,0x4A,0x30,0x01,0x70,0x0C,0x00,0x00, /* 00000C70 "EJ0.p..." */
+ 0x00,0x08,0x42,0x30,0x45,0x4A,0xA4,0x00, /* 00000C78 "..B0EJ.." */
+ 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1B,0x5B, /* 00000C80 "._SUN..[" */
+ 0x82,0x29,0x53,0x32,0x38,0x5F,0x08,0x5F, /* 00000C88 ".)S28_._" */
+ 0x41,0x44,0x52,0x0C,0x00,0x00,0x1C,0x00, /* 00000C90 "ADR....." */
+ 0x14,0x12,0x5F,0x45,0x4A,0x30,0x01,0x70, /* 00000C98 ".._EJ0.p" */
+ 0x0C,0x00,0x00,0x00,0x10,0x42,0x30,0x45, /* 00000CA0 ".....B0E" */
+ 0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00000CA8 "J..._SUN" */
+ 0x0A,0x1C,0x5B,0x82,0x29,0x53,0x32,0x39, /* 00000CB0 "..[.)S29" */
+ 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00000CB8 "_._ADR.." */
+ 0x00,0x1D,0x00,0x14,0x12,0x5F,0x45,0x4A, /* 00000CC0 "....._EJ" */
+ 0x30,0x01,0x70,0x0C,0x00,0x00,0x00,0x20, /* 00000CC8 "0.p.... " */
+ 0x42,0x30,0x45,0x4A,0xA4,0x00,0x08,0x5F, /* 00000CD0 "B0EJ..._" */
+ 0x53,0x55,0x4E,0x0A,0x1D,0x5B,0x82,0x29, /* 00000CD8 "SUN..[.)" */
+ 0x53,0x33,0x30,0x5F,0x08,0x5F,0x41,0x44, /* 00000CE0 "S30_._AD" */
+ 0x52,0x0C,0x00,0x00,0x1E,0x00,0x14,0x12, /* 00000CE8 "R......." */
+ 0x5F,0x45,0x4A,0x30,0x01,0x70,0x0C,0x00, /* 00000CF0 "_EJ0.p.." */
+ 0x00,0x00,0x40,0x42,0x30,0x45,0x4A,0xA4, /* 00000CF8 "..@B0EJ." */
+ 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x1E, /* 00000D00 ".._SUN.." */
+ 0x5B,0x82,0x29,0x53,0x33,0x31,0x5F,0x08, /* 00000D08 "[.)S31_." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x1F, /* 00000D10 "_ADR...." */
+ 0x00,0x14,0x12,0x5F,0x45,0x4A,0x30,0x01, /* 00000D18 "..._EJ0." */
+ 0x70,0x0C,0x00,0x00,0x00,0x80,0x42,0x30, /* 00000D20 "p.....B0" */
+ 0x45,0x4A,0xA4,0x00,0x08,0x5F,0x53,0x55, /* 00000D28 "EJ..._SU" */
+ 0x4E,0x0A,0x1F,0x08,0x5F,0x43,0x52,0x53, /* 00000D30 "N..._CRS" */
+ 0x11,0x42,0x07,0x0A,0x6E,0x88,0x0D,0x00, /* 00000D38 ".B..n..." */
+ 0x02,0x0C,0x00,0x00,0x00,0x00,0x00,0xFF, /* 00000D40 "........" */
+ 0x00,0x00,0x00,0x00,0x01,0x47,0x01,0xF8, /* 00000D48 ".....G.." */
+ 0x0C,0xF8,0x0C,0x01,0x08,0x88,0x0D,0x00, /* 00000D50 "........" */
+ 0x01,0x0C,0x03,0x00,0x00,0x00,0x00,0xF7, /* 00000D58 "........" */
+ 0x0C,0x00,0x00,0xF8,0x0C,0x88,0x0D,0x00, /* 00000D60 "........" */
+ 0x01,0x0C,0x03,0x00,0x00,0x00,0x0D,0xFF, /* 00000D68 "........" */
+ 0xFF,0x00,0x00,0x00,0xF3,0x87,0x17,0x00, /* 00000D70 "........" */
+ 0x00,0x0C,0x03,0x00,0x00,0x00,0x00,0x00, /* 00000D78 "........" */
+ 0x00,0x0A,0x00,0xFF,0xFF,0x0B,0x00,0x00, /* 00000D80 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x87, /* 00000D88 "........" */
+ 0x17,0x00,0x00,0x0C,0x01,0x00,0x00,0x00, /* 00000D90 "........" */
+ 0x00,0x00,0x00,0x00,0xE0,0xFF,0xFF,0xBF, /* 00000D98 "........" */
+ 0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0xC0, /* 00000DA0 "........" */
+ 0x1E,0x79,0x00,0x5B,0x82,0x45,0x04,0x48, /* 00000DA8 ".y.[.E.H" */
+ 0x50,0x45,0x54,0x08,0x5F,0x48,0x49,0x44, /* 00000DB0 "PET._HID" */
+ 0x0C,0x41,0xD0,0x01,0x03,0x08,0x5F,0x55, /* 00000DB8 ".A...._U" */
+ 0x49,0x44,0x00,0x14,0x09,0x5F,0x53,0x54, /* 00000DC0 "ID..._ST" */
+ 0x41,0x00,0xA4,0x0A,0x0F,0x08,0x5F,0x43, /* 00000DC8 "A....._C" */
+ 0x52,0x53,0x11,0x1F,0x0A,0x1C,0x87,0x17, /* 00000DD0 "RS......" */
+ 0x00,0x00,0x0D,0x01,0x00,0x00,0x00,0x00, /* 00000DD8 "........" */
+ 0x00,0x00,0xD0,0xFE,0xFF,0x03,0xD0,0xFE, /* 00000DE0 "........" */
+ 0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, /* 00000DE8 "........" */
+ 0x79,0x00,0x10,0x49,0x84,0x2E,0x5F,0x53, /* 00000DF0 "y..I.._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x5B,0x82, /* 00000DF8 "B_PCI0[." */
+ 0x4C,0x05,0x56,0x47,0x41,0x5F,0x08,0x5F, /* 00000E00 "L.VGA_._" */
+ 0x41,0x44,0x52,0x0C,0x00,0x00,0x02,0x00, /* 00000E08 "ADR....." */
+ 0x5B,0x80,0x50,0x43,0x49,0x43,0x02,0x00, /* 00000E10 "[.PCIC.." */
+ 0x0A,0x04,0x5B,0x81,0x0B,0x50,0x43,0x49, /* 00000E18 "..[..PCI" */
+ 0x43,0x03,0x56,0x45,0x4E,0x44,0x20,0x14, /* 00000E20 "C.VEND ." */
+ 0x08,0x5F,0x53,0x31,0x44,0x00,0xA4,0x00, /* 00000E28 "._S1D..." */
+ 0x14,0x08,0x5F,0x53,0x32,0x44,0x00,0xA4, /* 00000E30 ".._S2D.." */
+ 0x00,0x14,0x19,0x5F,0x53,0x33,0x44,0x00, /* 00000E38 "..._S3D." */
+ 0xA0,0x0E,0x93,0x56,0x45,0x4E,0x44,0x0C, /* 00000E40 "...VEND." */
+ 0x36,0x1B,0x00,0x01,0xA4,0x0A,0x03,0xA1, /* 00000E48 "6......." */
+ 0x03,0xA4,0x00,0x14,0x08,0x5F,0x52,0x4D, /* 00000E50 "....._RM" */
+ 0x56,0x00,0xA4,0x00,0x5B,0x82,0x4B,0x23, /* 00000E58 "V...[.K#" */
+ 0x49,0x53,0x41,0x5F,0x08,0x5F,0x41,0x44, /* 00000E60 "ISA_._AD" */
+ 0x52,0x0C,0x00,0x00,0x01,0x00,0x14,0x08, /* 00000E68 "R......." */
+ 0x5F,0x52,0x4D,0x56,0x00,0xA4,0x00,0x5B, /* 00000E70 "_RMV...[" */
+ 0x80,0x50,0x34,0x30,0x43,0x02,0x0A,0x60, /* 00000E78 ".P40C..`" */
+ 0x0A,0x04,0x5B,0x82,0x2D,0x52,0x54,0x43, /* 00000E80 "..[.-RTC" */
+ 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000E88 "_._HID.A" */
+ 0xD0,0x0B,0x00,0x08,0x5F,0x43,0x52,0x53, /* 00000E90 "...._CRS" */
+ 0x11,0x18,0x0A,0x15,0x47,0x01,0x70,0x00, /* 00000E98 "....G.p." */
+ 0x70,0x00,0x10,0x02,0x22,0x00,0x01,0x47, /* 00000EA0 "p..."..G" */
+ 0x01,0x72,0x00,0x72,0x00,0x02,0x06,0x79, /* 00000EA8 ".r.r...y" */
+ 0x00,0x5B,0x82,0x44,0x04,0x4B,0x42,0x44, /* 00000EB0 ".[.D.KBD" */
+ 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000EB8 "_._HID.A" */
+ 0xD0,0x03,0x03,0x14,0x09,0x5F,0x53,0x54, /* 00000EC0 "....._ST" */
+ 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x29,0x5F, /* 00000EC8 "A.....)_" */
+ 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000ED0 "CRS..TMP" */
+ 0x5F,0x11,0x18,0x0A,0x15,0x47,0x01,0x60, /* 00000ED8 "_....G.`" */
+ 0x00,0x60,0x00,0x01,0x01,0x47,0x01,0x64, /* 00000EE0 ".`...G.d" */
+ 0x00,0x64,0x00,0x01,0x01,0x22,0x02,0x00, /* 00000EE8 ".d...".." */
+ 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000EF0 "y..TMP_[" */
+ 0x82,0x33,0x4D,0x4F,0x55,0x5F,0x08,0x5F, /* 00000EF8 ".3MOU_._" */
+ 0x48,0x49,0x44,0x0C,0x41,0xD0,0x0F,0x13, /* 00000F00 "HID.A..." */
+ 0x14,0x09,0x5F,0x53,0x54,0x41,0x00,0xA4, /* 00000F08 ".._STA.." */
+ 0x0A,0x0F,0x14,0x19,0x5F,0x43,0x52,0x53, /* 00000F10 "...._CRS" */
+ 0x00,0x08,0x54,0x4D,0x50,0x5F,0x11,0x08, /* 00000F18 "..TMP_.." */
+ 0x0A,0x05,0x22,0x00,0x10,0x79,0x00,0xA4, /* 00000F20 ".."..y.." */
+ 0x54,0x4D,0x50,0x5F,0x5B,0x82,0x47,0x04, /* 00000F28 "TMP_[.G." */
+ 0x46,0x44,0x43,0x30,0x08,0x5F,0x48,0x49, /* 00000F30 "FDC0._HI" */
+ 0x44,0x0C,0x41,0xD0,0x07,0x00,0x14,0x09, /* 00000F38 "D.A....." */
+ 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000F40 "_STA...." */
+ 0x14,0x2C,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000F48 ".,_CRS.." */
+ 0x42,0x55,0x46,0x30,0x11,0x1B,0x0A,0x18, /* 00000F50 "BUF0...." */
+ 0x47,0x01,0xF2,0x03,0xF2,0x03,0x00,0x04, /* 00000F58 "G......." */
+ 0x47,0x01,0xF7,0x03,0xF7,0x03,0x00,0x01, /* 00000F60 "G......." */
+ 0x22,0x40,0x00,0x2A,0x04,0x00,0x79,0x00, /* 00000F68 ""@.*..y." */
+ 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x4B, /* 00000F70 ".BUF0[.K" */
+ 0x05,0x4C,0x50,0x54,0x5F,0x08,0x5F,0x48, /* 00000F78 ".LPT_._H" */
+ 0x49,0x44,0x0C,0x41,0xD0,0x04,0x00,0x14, /* 00000F80 "ID.A...." */
+ 0x28,0x5F,0x53,0x54,0x41,0x00,0x70,0x5E, /* 00000F88 "(_STA.p^" */
+ 0x5E,0x5E,0x2E,0x50,0x58,0x31,0x33,0x44, /* 00000F90 "^^.PX13D" */
+ 0x52,0x53,0x41,0x60,0x7B,0x60,0x0C,0x00, /* 00000F98 "RSA`{`.." */
+ 0x00,0x00,0x80,0x60,0xA0,0x06,0x93,0x60, /* 00000FA0 "...`...`" */
+ 0x00,0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F, /* 00000FA8 "........" */
+ 0x14,0x21,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000FB0 ".!_CRS.." */
+ 0x42,0x55,0x46,0x30,0x11,0x10,0x0A,0x0D, /* 00000FB8 "BUF0...." */
+ 0x47,0x01,0x78,0x03,0x78,0x03,0x08,0x08, /* 00000FC0 "G.x.x..." */
+ 0x22,0x80,0x00,0x79,0x00,0xA4,0x42,0x55, /* 00000FC8 ""..y..BU" */
+ 0x46,0x30,0x5B,0x82,0x41,0x06,0x43,0x4F, /* 00000FD0 "F0[.A.CO" */
+ 0x4D,0x31,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000FD8 "M1._HID." */
+ 0x41,0xD0,0x05,0x01,0x08,0x5F,0x55,0x49, /* 00000FE0 "A...._UI" */
+ 0x44,0x01,0x14,0x28,0x5F,0x53,0x54,0x41, /* 00000FE8 "D..(_STA" */
+ 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 00000FF0 ".p^^^.PX" */
+ 0x31,0x33,0x44,0x52,0x53,0x43,0x60,0x7B, /* 00000FF8 "13DRSC`{" */
+ 0x60,0x0C,0x00,0x00,0x00,0x08,0x60,0xA0, /* 00001000 "`.....`." */
+ 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 00001008 "..`....." */
+ 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 00001010 "....!_CR" */
+ 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00001018 "S..BUF0." */
+ 0x10,0x0A,0x0D,0x47,0x01,0xF8,0x03,0xF8, /* 00001020 "...G...." */
+ 0x03,0x00,0x08,0x22,0x10,0x00,0x79,0x00, /* 00001028 "..."..y." */
+ 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x42, /* 00001030 ".BUF0[.B" */
+ 0x06,0x43,0x4F,0x4D,0x32,0x08,0x5F,0x48, /* 00001038 ".COM2._H" */
+ 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00001040 "ID.A...." */
+ 0x5F,0x55,0x49,0x44,0x0A,0x02,0x14,0x28, /* 00001048 "_UID...(" */
+ 0x5F,0x53,0x54,0x41,0x00,0x70,0x5E,0x5E, /* 00001050 "_STA.p^^" */
+ 0x5E,0x2E,0x50,0x58,0x31,0x33,0x44,0x52, /* 00001058 "^.PX13DR" */
+ 0x53,0x43,0x60,0x7B,0x60,0x0C,0x00,0x00, /* 00001060 "SC`{`..." */
+ 0x00,0x80,0x60,0xA0,0x06,0x93,0x60,0x00, /* 00001068 "..`...`." */
+ 0xA4,0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14, /* 00001070 "........" */
+ 0x21,0x5F,0x43,0x52,0x53,0x00,0x08,0x42, /* 00001078 "!_CRS..B" */
+ 0x55,0x46,0x30,0x11,0x10,0x0A,0x0D,0x47, /* 00001080 "UF0....G" */
+ 0x01,0xF8,0x02,0xF8,0x02,0x00,0x08,0x22, /* 00001088 "......."" */
+ 0x08,0x00,0x79,0x00,0xA4,0x42,0x55,0x46, /* 00001090 "..y..BUF" */
+ 0x30,0x5B,0x82,0x40,0x05,0x50,0x58,0x31, /* 00001098 "0[.@.PX1" */
+ 0x33,0x08,0x5F,0x41,0x44,0x52,0x0C,0x03, /* 000010A0 "3._ADR.." */
+ 0x00,0x01,0x00,0x5B,0x80,0x50,0x31,0x33, /* 000010A8 "...[.P13" */
+ 0x43,0x02,0x0A,0x5C,0x0A,0x24,0x5B,0x81, /* 000010B0 "C..\.$[." */
+ 0x33,0x50,0x31,0x33,0x43,0x03,0x44,0x52, /* 000010B8 "3P13C.DR" */
+ 0x53,0x41,0x20,0x44,0x52,0x53,0x42,0x20, /* 000010C0 "SA DRSB " */
+ 0x44,0x52,0x53,0x43,0x20,0x44,0x52,0x53, /* 000010C8 "DRSC DRS" */
+ 0x45,0x20,0x44,0x52,0x53,0x46,0x20,0x44, /* 000010D0 "E DRSF D" */
+ 0x52,0x53,0x47,0x20,0x44,0x52,0x53,0x48, /* 000010D8 "RSG DRSH" */
+ 0x20,0x44,0x52,0x53,0x49,0x20,0x44,0x52, /* 000010E0 " DRSI DR" */
+ 0x53,0x4A,0x20,0x5B,0x82,0x2B,0x53,0x4C, /* 000010E8 "SJ [.+SL" */
+ 0x33,0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C, /* 000010F0 "3_._ADR." */
+ 0x00,0x00,0x03,0x00,0x14,0x14,0x5F,0x52, /* 000010F8 "......_R" */
+ 0x4D,0x56,0x00,0xA0,0x0B,0x7B,0x50,0x43, /* 00001100 "MV...{PC" */
+ 0x52,0x4D,0x0A,0x08,0x00,0xA4,0x01,0xA4, /* 00001108 "RM......" */
+ 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x03, /* 00001110 ".._SUN.." */
+ 0x5B,0x82,0x2B,0x53,0x4C,0x34,0x5F,0x08, /* 00001118 "[.+SL4_." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x04, /* 00001120 "_ADR...." */
+ 0x00,0x14,0x14,0x5F,0x52,0x4D,0x56,0x00, /* 00001128 "..._RMV." */
+ 0xA0,0x0B,0x7B,0x50,0x43,0x52,0x4D,0x0A, /* 00001130 "..{PCRM." */
+ 0x10,0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F, /* 00001138 "......._" */
+ 0x53,0x55,0x4E,0x0A,0x04,0x5B,0x82,0x2B, /* 00001140 "SUN..[.+" */
+ 0x53,0x4C,0x35,0x5F,0x08,0x5F,0x41,0x44, /* 00001148 "SL5_._AD" */
+ 0x52,0x0C,0x00,0x00,0x05,0x00,0x14,0x14, /* 00001150 "R......." */
+ 0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0B,0x7B, /* 00001158 "_RMV...{" */
+ 0x50,0x43,0x52,0x4D,0x0A,0x20,0x00,0xA4, /* 00001160 "PCRM. .." */
+ 0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 00001168 "...._SUN" */
+ 0x0A,0x05,0x5B,0x82,0x2B,0x53,0x4C,0x36, /* 00001170 "..[.+SL6" */
+ 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00001178 "_._ADR.." */
+ 0x00,0x06,0x00,0x14,0x14,0x5F,0x52,0x4D, /* 00001180 "....._RM" */
+ 0x56,0x00,0xA0,0x0B,0x7B,0x50,0x43,0x52, /* 00001188 "V...{PCR" */
+ 0x4D,0x0A,0x40,0x00,0xA4,0x01,0xA4,0x00, /* 00001190 "M.@....." */
+ 0x08,0x5F,0x53,0x55,0x4E,0x0A,0x06,0x5B, /* 00001198 "._SUN..[" */
+ 0x82,0x2B,0x53,0x4C,0x37,0x5F,0x08,0x5F, /* 000011A0 ".+SL7_._" */
+ 0x41,0x44,0x52,0x0C,0x00,0x00,0x07,0x00, /* 000011A8 "ADR....." */
+ 0x14,0x14,0x5F,0x52,0x4D,0x56,0x00,0xA0, /* 000011B0 ".._RMV.." */
+ 0x0B,0x7B,0x50,0x43,0x52,0x4D,0x0A,0x80, /* 000011B8 ".{PCRM.." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000011C0 "......_S" */
+ 0x55,0x4E,0x0A,0x07,0x5B,0x82,0x2C,0x53, /* 000011C8 "UN..[.,S" */
+ 0x4C,0x38,0x5F,0x08,0x5F,0x41,0x44,0x52, /* 000011D0 "L8_._ADR" */
+ 0x0C,0x00,0x00,0x08,0x00,0x14,0x15,0x5F, /* 000011D8 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50, /* 000011E0 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0B,0x00,0x01,0x00,0xA4, /* 000011E8 "CRM....." */
+ 0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 000011F0 "...._SUN" */
+ 0x0A,0x08,0x5B,0x82,0x2C,0x53,0x4C,0x39, /* 000011F8 "..[.,SL9" */
+ 0x5F,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 00001200 "_._ADR.." */
+ 0x00,0x09,0x00,0x14,0x15,0x5F,0x52,0x4D, /* 00001208 "....._RM" */
+ 0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52, /* 00001210 "V...{PCR" */
+ 0x4D,0x0B,0x00,0x02,0x00,0xA4,0x01,0xA4, /* 00001218 "M......." */
+ 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x09, /* 00001220 ".._SUN.." */
+ 0x5B,0x82,0x2C,0x53,0x4C,0x31,0x30,0x08, /* 00001228 "[.,SL10." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0A, /* 00001230 "_ADR...." */
+ 0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,0x00, /* 00001238 "..._RMV." */
+ 0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B, /* 00001240 "..{PCRM." */
+ 0x00,0x04,0x00,0xA4,0x01,0xA4,0x00,0x08, /* 00001248 "........" */
+ 0x5F,0x53,0x55,0x4E,0x0A,0x0A,0x5B,0x82, /* 00001250 "_SUN..[." */
+ 0x2C,0x53,0x4C,0x31,0x31,0x08,0x5F,0x41, /* 00001258 ",SL11._A" */
+ 0x44,0x52,0x0C,0x00,0x00,0x0B,0x00,0x14, /* 00001260 "DR......" */
+ 0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C, /* 00001268 "._RMV..." */
+ 0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,0x08, /* 00001270 "{PCRM..." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001278 "......_S" */
+ 0x55,0x4E,0x0A,0x0B,0x5B,0x82,0x2C,0x53, /* 00001280 "UN..[.,S" */
+ 0x4C,0x31,0x32,0x08,0x5F,0x41,0x44,0x52, /* 00001288 "L12._ADR" */
+ 0x0C,0x00,0x00,0x0C,0x00,0x14,0x15,0x5F, /* 00001290 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0C,0x7B,0x50, /* 00001298 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0B,0x00,0x10,0x00,0xA4, /* 000012A0 "CRM....." */
+ 0x01,0xA4,0x00,0x08,0x5F,0x53,0x55,0x4E, /* 000012A8 "...._SUN" */
+ 0x0A,0x0C,0x5B,0x82,0x2C,0x53,0x4C,0x31, /* 000012B0 "..[.,SL1" */
+ 0x33,0x08,0x5F,0x41,0x44,0x52,0x0C,0x00, /* 000012B8 "3._ADR.." */
+ 0x00,0x0D,0x00,0x14,0x15,0x5F,0x52,0x4D, /* 000012C0 "....._RM" */
+ 0x56,0x00,0xA0,0x0C,0x7B,0x50,0x43,0x52, /* 000012C8 "V...{PCR" */
+ 0x4D,0x0B,0x00,0x20,0x00,0xA4,0x01,0xA4, /* 000012D0 "M.. ...." */
+ 0x00,0x08,0x5F,0x53,0x55,0x4E,0x0A,0x0D, /* 000012D8 ".._SUN.." */
+ 0x5B,0x82,0x2C,0x53,0x4C,0x31,0x34,0x08, /* 000012E0 "[.,SL14." */
+ 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x0E, /* 000012E8 "_ADR...." */
+ 0x00,0x14,0x15,0x5F,0x52,0x4D,0x56,0x00, /* 000012F0 "..._RMV." */
+ 0xA0,0x0C,0x7B,0x50,0x43,0x52,0x4D,0x0B, /* 000012F8 "..{PCRM." */
+ 0x00,0x40,0x00,0xA4,0x01,0xA4,0x00,0x08, /* 00001300 ".@......" */
+ 0x5F,0x53,0x55,0x4E,0x0A,0x0E,0x5B,0x82, /* 00001308 "_SUN..[." */
+ 0x2C,0x53,0x4C,0x31,0x35,0x08,0x5F,0x41, /* 00001310 ",SL15._A" */
+ 0x44,0x52,0x0C,0x00,0x00,0x0F,0x00,0x14, /* 00001318 "DR......" */
+ 0x15,0x5F,0x52,0x4D,0x56,0x00,0xA0,0x0C, /* 00001320 "._RMV..." */
+ 0x7B,0x50,0x43,0x52,0x4D,0x0B,0x00,0x80, /* 00001328 "{PCRM..." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001330 "......_S" */
+ 0x55,0x4E,0x0A,0x0F,0x5B,0x82,0x2E,0x53, /* 00001338 "UN..[..S" */
+ 0x4C,0x31,0x36,0x08,0x5F,0x41,0x44,0x52, /* 00001340 "L16._ADR" */
+ 0x0C,0x00,0x00,0x10,0x00,0x14,0x17,0x5F, /* 00001348 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001350 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x01,0x00, /* 00001358 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001360 "......_S" */
+ 0x55,0x4E,0x0A,0x10,0x5B,0x82,0x2E,0x53, /* 00001368 "UN..[..S" */
+ 0x4C,0x31,0x37,0x08,0x5F,0x41,0x44,0x52, /* 00001370 "L17._ADR" */
+ 0x0C,0x00,0x00,0x11,0x00,0x14,0x17,0x5F, /* 00001378 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001380 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x02,0x00, /* 00001388 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001390 "......_S" */
+ 0x55,0x4E,0x0A,0x11,0x5B,0x82,0x2E,0x53, /* 00001398 "UN..[..S" */
+ 0x4C,0x31,0x38,0x08,0x5F,0x41,0x44,0x52, /* 000013A0 "L18._ADR" */
+ 0x0C,0x00,0x00,0x12,0x00,0x14,0x17,0x5F, /* 000013A8 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000013B0 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x04,0x00, /* 000013B8 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000013C0 "......_S" */
+ 0x55,0x4E,0x0A,0x12,0x5B,0x82,0x2E,0x53, /* 000013C8 "UN..[..S" */
+ 0x4C,0x31,0x39,0x08,0x5F,0x41,0x44,0x52, /* 000013D0 "L19._ADR" */
+ 0x0C,0x00,0x00,0x13,0x00,0x14,0x17,0x5F, /* 000013D8 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000013E0 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x08,0x00, /* 000013E8 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000013F0 "......_S" */
+ 0x55,0x4E,0x0A,0x13,0x5B,0x82,0x2E,0x53, /* 000013F8 "UN..[..S" */
+ 0x4C,0x32,0x30,0x08,0x5F,0x41,0x44,0x52, /* 00001400 "L20._ADR" */
+ 0x0C,0x00,0x00,0x14,0x00,0x14,0x17,0x5F, /* 00001408 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001410 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x10,0x00, /* 00001418 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001420 "......_S" */
+ 0x55,0x4E,0x0A,0x14,0x5B,0x82,0x2E,0x53, /* 00001428 "UN..[..S" */
+ 0x4C,0x32,0x31,0x08,0x5F,0x41,0x44,0x52, /* 00001430 "L21._ADR" */
+ 0x0C,0x00,0x00,0x15,0x00,0x14,0x17,0x5F, /* 00001438 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001440 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x20,0x00, /* 00001448 "CRM... ." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001450 "......_S" */
+ 0x55,0x4E,0x0A,0x15,0x5B,0x82,0x2E,0x53, /* 00001458 "UN..[..S" */
+ 0x4C,0x32,0x32,0x08,0x5F,0x41,0x44,0x52, /* 00001460 "L22._ADR" */
+ 0x0C,0x00,0x00,0x16,0x00,0x14,0x17,0x5F, /* 00001468 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001470 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x40,0x00, /* 00001478 "CRM...@." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001480 "......_S" */
+ 0x55,0x4E,0x0A,0x16,0x5B,0x82,0x2E,0x53, /* 00001488 "UN..[..S" */
+ 0x4C,0x32,0x33,0x08,0x5F,0x41,0x44,0x52, /* 00001490 "L23._ADR" */
+ 0x0C,0x00,0x00,0x17,0x00,0x14,0x17,0x5F, /* 00001498 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000014A0 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x80,0x00, /* 000014A8 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000014B0 "......_S" */
+ 0x55,0x4E,0x0A,0x17,0x5B,0x82,0x2E,0x53, /* 000014B8 "UN..[..S" */
+ 0x4C,0x32,0x34,0x08,0x5F,0x41,0x44,0x52, /* 000014C0 "L24._ADR" */
+ 0x0C,0x00,0x00,0x18,0x00,0x14,0x17,0x5F, /* 000014C8 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000014D0 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x01, /* 000014D8 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000014E0 "......_S" */
+ 0x55,0x4E,0x0A,0x18,0x5B,0x82,0x2E,0x53, /* 000014E8 "UN..[..S" */
+ 0x4C,0x32,0x35,0x08,0x5F,0x41,0x44,0x52, /* 000014F0 "L25._ADR" */
+ 0x0C,0x00,0x00,0x19,0x00,0x14,0x17,0x5F, /* 000014F8 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001500 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x02, /* 00001508 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001510 "......_S" */
+ 0x55,0x4E,0x0A,0x19,0x5B,0x82,0x2E,0x53, /* 00001518 "UN..[..S" */
+ 0x4C,0x32,0x36,0x08,0x5F,0x41,0x44,0x52, /* 00001520 "L26._ADR" */
+ 0x0C,0x00,0x00,0x1A,0x00,0x14,0x17,0x5F, /* 00001528 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001530 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x04, /* 00001538 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001540 "......_S" */
+ 0x55,0x4E,0x0A,0x1A,0x5B,0x82,0x2E,0x53, /* 00001548 "UN..[..S" */
+ 0x4C,0x32,0x37,0x08,0x5F,0x41,0x44,0x52, /* 00001550 "L27._ADR" */
+ 0x0C,0x00,0x00,0x1B,0x00,0x14,0x17,0x5F, /* 00001558 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001560 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x08, /* 00001568 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001570 "......_S" */
+ 0x55,0x4E,0x0A,0x1B,0x5B,0x82,0x2E,0x53, /* 00001578 "UN..[..S" */
+ 0x4C,0x32,0x38,0x08,0x5F,0x41,0x44,0x52, /* 00001580 "L28._ADR" */
+ 0x0C,0x00,0x00,0x1C,0x00,0x14,0x17,0x5F, /* 00001588 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001590 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x10, /* 00001598 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000015A0 "......_S" */
+ 0x55,0x4E,0x0A,0x1C,0x5B,0x82,0x2E,0x53, /* 000015A8 "UN..[..S" */
+ 0x4C,0x32,0x39,0x08,0x5F,0x41,0x44,0x52, /* 000015B0 "L29._ADR" */
+ 0x0C,0x00,0x00,0x1D,0x00,0x14,0x17,0x5F, /* 000015B8 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000015C0 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x20, /* 000015C8 "CRM.... " */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 000015D0 "......_S" */
+ 0x55,0x4E,0x0A,0x1D,0x5B,0x82,0x2E,0x53, /* 000015D8 "UN..[..S" */
+ 0x4C,0x33,0x30,0x08,0x5F,0x41,0x44,0x52, /* 000015E0 "L30._ADR" */
+ 0x0C,0x00,0x00,0x1E,0x00,0x14,0x17,0x5F, /* 000015E8 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 000015F0 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x40, /* 000015F8 "CRM....@" */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001600 "......_S" */
+ 0x55,0x4E,0x0A,0x1E,0x5B,0x82,0x2E,0x53, /* 00001608 "UN..[..S" */
+ 0x4C,0x33,0x31,0x08,0x5F,0x41,0x44,0x52, /* 00001610 "L31._ADR" */
+ 0x0C,0x00,0x00,0x1F,0x00,0x14,0x17,0x5F, /* 00001618 "......._" */
+ 0x52,0x4D,0x56,0x00,0xA0,0x0E,0x7B,0x50, /* 00001620 "RMV...{P" */
+ 0x43,0x52,0x4D,0x0C,0x00,0x00,0x00,0x80, /* 00001628 "CRM....." */
+ 0x00,0xA4,0x01,0xA4,0x00,0x08,0x5F,0x53, /* 00001630 "......_S" */
+ 0x55,0x4E,0x0A,0x1F,0x10,0x4B,0x3C,0x5F, /* 00001638 "UN...K<_" */
+ 0x53,0x42,0x5F,0x5B,0x81,0x24,0x2F,0x03, /* 00001640 "SB_[.$/." */
+ 0x50,0x43,0x49,0x30,0x49,0x53,0x41,0x5F, /* 00001648 "PCI0ISA_" */
+ 0x50,0x34,0x30,0x43,0x01,0x50,0x52,0x51, /* 00001650 "P40C.PRQ" */
+ 0x30,0x08,0x50,0x52,0x51,0x31,0x08,0x50, /* 00001658 "0.PRQ1.P" */
+ 0x52,0x51,0x32,0x08,0x50,0x52,0x51,0x33, /* 00001660 "RQ2.PRQ3" */
+ 0x08,0x5B,0x82,0x4D,0x0B,0x4C,0x4E,0x4B, /* 00001668 ".[.M.LNK" */
+ 0x41,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00001670 "A._HID.A" */
+ 0xD0,0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44, /* 00001678 "...._UID" */
+ 0x01,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 00001680 ".._PRS.." */
+ 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 00001688 "........" */
+ 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 00001690 "........" */
+ 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001698 "...y..._" */
+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000016A0 "STA.p..`" */
+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000016A8 "..{..PRQ" */
+ 0x30,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000016B0 "0ap..`.`" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000016B8 ".._DIS.}" */
+ 0x50,0x52,0x51,0x30,0x0A,0x80,0x50,0x52, /* 000016C0 "PRQ0..PR" */
+ 0x51,0x30,0x14,0x45,0x04,0x5F,0x43,0x52, /* 000016C8 "Q0.E._CR" */
+ 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 000016D0 "S..PRR0." */
+ 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 000016D8 "........" */
+ 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 000016E0 "....y..P" */
+ 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 000016E8 "RR0..TMP" */
+ 0x5F,0x70,0x50,0x52,0x51,0x30,0x60,0xA0, /* 000016F0 "_pPRQ0`." */
+ 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 000016F8 "..`..p`T" */
+ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00001700 "MP_..p.T" */
+ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001708 "MP_.PRR0" */
+ 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 00001710 ".._SRS.." */
+ 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 00001718 "h..TMP_p" */
+ 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x30, /* 00001720 "TMP_PRQ0" */
+ 0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x42, /* 00001728 "[.N.LNKB" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00001730 "._HID.A." */
+ 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00001738 "..._UID." */
+ 0x02,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 00001740 ".._PRS.." */
+ 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 00001748 "........" */
+ 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 00001750 "........" */
+ 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001758 "...y..._" */
+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00001760 "STA.p..`" */
+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 00001768 "..{..PRQ" */
+ 0x31,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 00001770 "1ap..`.`" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00001778 ".._DIS.}" */
+ 0x50,0x52,0x51,0x31,0x0A,0x80,0x50,0x52, /* 00001780 "PRQ1..PR" */
+ 0x51,0x31,0x14,0x45,0x04,0x5F,0x43,0x52, /* 00001788 "Q1.E._CR" */
+ 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00001790 "S..PRR0." */
+ 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 00001798 "........" */
+ 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 000017A0 "....y..P" */
+ 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 000017A8 "RR0..TMP" */
+ 0x5F,0x70,0x50,0x52,0x51,0x31,0x60,0xA0, /* 000017B0 "_pPRQ1`." */
+ 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 000017B8 "..`..p`T" */
+ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 000017C0 "MP_..p.T" */
+ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000017C8 "MP_.PRR0" */
+ 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 000017D0 ".._SRS.." */
+ 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 000017D8 "h..TMP_p" */
+ 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x31, /* 000017E0 "TMP_PRQ1" */
+ 0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x43, /* 000017E8 "[.N.LNKC" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000017F0 "._HID.A." */
+ 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 000017F8 "..._UID." */
+ 0x03,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 00001800 ".._PRS.." */
+ 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 00001808 "........" */
+ 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 00001810 "........" */
+ 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001818 "...y..._" */
+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00001820 "STA.p..`" */
+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 00001828 "..{..PRQ" */
+ 0x32,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 00001830 "2ap..`.`" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 00001838 ".._DIS.}" */
+ 0x50,0x52,0x51,0x32,0x0A,0x80,0x50,0x52, /* 00001840 "PRQ2..PR" */
+ 0x51,0x32,0x14,0x45,0x04,0x5F,0x43,0x52, /* 00001848 "Q2.E._CR" */
+ 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00001850 "S..PRR0." */
+ 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 00001858 "........" */
+ 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 00001860 "....y..P" */
+ 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 00001868 "RR0..TMP" */
+ 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00001870 "_pPRQ2`." */
+ 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 00001878 "..`..p`T" */
+ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00001880 "MP_..p.T" */
+ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001888 "MP_.PRR0" */
+ 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 00001890 ".._SRS.." */
+ 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 00001898 "h..TMP_p" */
+ 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x32, /* 000018A0 "TMP_PRQ2" */
+ 0x5B,0x82,0x4E,0x0B,0x4C,0x4E,0x4B,0x44, /* 000018A8 "[.N.LNKD" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000018B0 "._HID.A." */
+ 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 000018B8 "..._UID." */
+ 0x04,0x08,0x5F,0x50,0x52,0x53,0x11,0x16, /* 000018C0 ".._PRS.." */
+ 0x0A,0x13,0x89,0x0E,0x00,0x09,0x03,0x05, /* 000018C8 "........" */
+ 0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x0B, /* 000018D0 "........" */
+ 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 000018D8 "...y..._" */
+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000018E0 "STA.p..`" */
+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000018E8 "..{..PRQ" */
+ 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000018F0 "3ap..`.`" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000018F8 ".._DIS.}" */
+ 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 00001900 "PRQ3..PR" */
+ 0x51,0x33,0x14,0x45,0x04,0x5F,0x43,0x52, /* 00001908 "Q3.E._CR" */
+ 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 00001910 "S..PRR0." */
+ 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 00001918 "........" */
+ 0x01,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 00001920 "....y..P" */
+ 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 00001928 "RR0..TMP" */
+ 0x5F,0x70,0x50,0x52,0x51,0x33,0x60,0xA0, /* 00001930 "_pPRQ3`." */
+ 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 00001938 "..`..p`T" */
+ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00001940 "MP_..p.T" */
+ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001948 "MP_.PRR0" */
+ 0x14,0x17,0x5F,0x53,0x52,0x53,0x01,0x8A, /* 00001950 ".._SRS.." */
+ 0x68,0x0A,0x05,0x54,0x4D,0x50,0x5F,0x70, /* 00001958 "h..TMP_p" */
+ 0x54,0x4D,0x50,0x5F,0x50,0x52,0x51,0x33, /* 00001960 "TMP_PRQ3" */
+ 0x5B,0x82,0x4E,0x09,0x4C,0x4E,0x4B,0x53, /* 00001968 "[.N.LNKS" */
+ 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00001970 "._HID.A." */
+ 0x0C,0x0F,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00001978 "..._UID." */
+ 0x05,0x08,0x5F,0x50,0x52,0x53,0x11,0x0E, /* 00001980 ".._PRS.." */
+ 0x0A,0x0B,0x89,0x06,0x00,0x09,0x01,0x09, /* 00001988 "........" */
+ 0x00,0x00,0x00,0x79,0x00,0x14,0x1A,0x5F, /* 00001990 "...y..._" */
+ 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 00001998 "STA.p..`" */
+ 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000019A0 "..{..PRQ" */
+ 0x30,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000019A8 "0ap..`.`" */
+ 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000019B0 ".._DIS.}" */
+ 0x50,0x52,0x51,0x30,0x0A,0x80,0x50,0x52, /* 000019B8 "PRQ0..PR" */
+ 0x51,0x30,0x14,0x45,0x04,0x5F,0x43,0x52, /* 000019C0 "Q0.E._CR" */
+ 0x53,0x00,0x08,0x50,0x52,0x52,0x30,0x11, /* 000019C8 "S..PRR0." */
+ 0x0E,0x0A,0x0B,0x89,0x06,0x00,0x09,0x01, /* 000019D0 "........" */
+ 0x09,0x00,0x00,0x00,0x79,0x00,0x8A,0x50, /* 000019D8 "....y..P" */
+ 0x52,0x52,0x30,0x0A,0x05,0x54,0x4D,0x50, /* 000019E0 "RR0..TMP" */
+ 0x5F,0x70,0x50,0x52,0x51,0x30,0x60,0xA0, /* 000019E8 "_pPRQ0`." */
+ 0x0B,0x95,0x60,0x0A,0x80,0x70,0x60,0x54, /* 000019F0 "..`..p`T" */
+ 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 000019F8 "MP_..p.T" */
+ 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 00001A00 "MP_.PRR0" */
+ 0x08,0x5F,0x53,0x33,0x5F,0x12,0x06,0x04, /* 00001A08 "._S3_..." */
+ 0x01,0x01,0x00,0x00,0x08,0x5F,0x53,0x34, /* 00001A10 "....._S4" */
+ 0x5F,0x12,0x06,0x04,0x00,0x00,0x00,0x00, /* 00001A18 "_......." */
+ 0x08,0x5F,0x53,0x35,0x5F,0x12,0x06,0x04, /* 00001A20 "._S5_..." */
+ 0x00,0x00,0x00,0x00,0x10,0x49,0x0E,0x5F, /* 00001A28 ".....I._" */
+ 0x53,0x42,0x5F,0x14,0x35,0x43,0x50,0x4D, /* 00001A30 "SB_.5CPM" */
+ 0x41,0x01,0x70,0x83,0x88,0x43,0x50,0x4F, /* 00001A38 "A.p..CPO" */
+ 0x4E,0x68,0x00,0x60,0x70,0x11,0x0B,0x0A, /* 00001A40 "Nh.`p..." */
+ 0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00, /* 00001A48 "........" */
+ 0x00,0x61,0x70,0x68,0x88,0x61,0x0A,0x02, /* 00001A50 ".aph.a.." */
+ 0x00,0x70,0x68,0x88,0x61,0x0A,0x03,0x00, /* 00001A58 ".ph.a..." */
+ 0x70,0x60,0x88,0x61,0x0A,0x04,0x00,0xA4, /* 00001A60 "p`.a...." */
+ 0x61,0x14,0x1A,0x43,0x50,0x53,0x54,0x01, /* 00001A68 "a..CPST." */
+ 0x70,0x83,0x88,0x43,0x50,0x4F,0x4E,0x68, /* 00001A70 "p..CPONh" */
+ 0x00,0x60,0xA0,0x05,0x60,0xA4,0x0A,0x0F, /* 00001A78 ".`..`..." */
+ 0xA1,0x03,0xA4,0x00,0x14,0x0A,0x43,0x50, /* 00001A80 "......CP" */
+ 0x45,0x4A,0x02,0x5B,0x22,0x0A,0xC8,0x5B, /* 00001A88 "EJ.["..[" */
+ 0x80,0x50,0x52,0x53,0x54,0x01,0x0B,0x00, /* 00001A90 ".PRST..." */
+ 0xAF,0x0A,0x20,0x5B,0x81,0x0C,0x50,0x52, /* 00001A98 ".. [..PR" */
+ 0x53,0x54,0x01,0x50,0x52,0x53,0x5F,0x40, /* 00001AA0 "ST.PRS_@" */
+ 0x10,0x14,0x4C,0x06,0x50,0x52,0x53,0x43, /* 00001AA8 "..L.PRSC" */
+ 0x00,0x70,0x50,0x52,0x53,0x5F,0x65,0x70, /* 00001AB0 ".pPRS_ep" */
+ 0x00,0x62,0x70,0x00,0x60,0xA2,0x46,0x05, /* 00001AB8 ".bp.`.F." */
+ 0x95,0x60,0x87,0x43,0x50,0x4F,0x4E,0x70, /* 00001AC0 ".`.CPONp" */
+ 0x83,0x88,0x43,0x50,0x4F,0x4E,0x60,0x00, /* 00001AC8 "..CPON`." */
+ 0x61,0xA0,0x0A,0x7B,0x60,0x0A,0x07,0x00, /* 00001AD0 "a..{`..." */
+ 0x7A,0x62,0x01,0x62,0xA1,0x0C,0x70,0x83, /* 00001AD8 "zb.b..p." */
+ 0x88,0x65,0x7A,0x60,0x0A,0x03,0x00,0x00, /* 00001AE0 ".ez`...." */
+ 0x62,0x70,0x7B,0x62,0x01,0x00,0x63,0xA0, /* 00001AE8 "bp{b..c." */
+ 0x22,0x92,0x93,0x61,0x63,0x70,0x63,0x88, /* 00001AF0 ""..acpc." */
+ 0x43,0x50,0x4F,0x4E,0x60,0x00,0xA0,0x0A, /* 00001AF8 "CPON`..." */
+ 0x93,0x63,0x01,0x4E,0x54,0x46,0x59,0x60, /* 00001B00 ".c.NTFY`" */
+ 0x01,0xA1,0x08,0x4E,0x54,0x46,0x59,0x60, /* 00001B08 "...NTFY`" */
+ 0x0A,0x03,0x75,0x60,0xA4,0x01,0x10,0x42, /* 00001B10 "..u`...B" */
+ 0xA7,0x5F,0x47,0x50,0x45,0x08,0x5F,0x48, /* 00001B18 "._GPE._H" */
+ 0x49,0x44,0x0D,0x41,0x43,0x50,0x49,0x30, /* 00001B20 "ID.ACPI0" */
+ 0x30,0x30,0x36,0x00,0x14,0x08,0x5F,0x4C, /* 00001B28 "006..._L" */
+ 0x30,0x30,0x00,0xA4,0x01,0x14,0x4C,0x9C, /* 00001B30 "00....L." */
+ 0x5F,0x4C,0x30,0x31,0x00,0xA0,0x25,0x7B, /* 00001B38 "_L01..%{" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001B40 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0A, /* 00001B48 "CI0PCIU." */
+ 0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001B50 "...\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00001B58 "B_PCI0S1" */
+ 0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F, /* 00001B60 "__..&{\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001B68 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x44,0x0A,0x02,0x00, /* 00001B70 "0PCID..." */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001B78 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x31,0x5F,0x5F, /* 00001B80 "PCI0S1__" */
+ 0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03, /* 00001B88 "...%{\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001B90 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x55,0x0A,0x04,0x00,0x86, /* 00001B98 "PCIU...." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001BA0 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x32,0x5F,0x5F,0x01, /* 00001BA8 "CI0S2__." */
+ 0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001BB0 ".&{\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001BB8 "B_PCI0PC" */
+ 0x49,0x44,0x0A,0x04,0x00,0x86,0x5C,0x2F, /* 00001BC0 "ID....\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001BC8 "._SB_PCI" */
+ 0x30,0x53,0x32,0x5F,0x5F,0x0A,0x03,0xA0, /* 00001BD0 "0S2__..." */
+ 0x25,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001BD8 "%{\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001BE0 "_PCI0PCI" */
+ 0x55,0x0A,0x08,0x00,0x86,0x5C,0x2F,0x03, /* 00001BE8 "U....\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001BF0 "_SB_PCI0" */
+ 0x53,0x33,0x5F,0x5F,0x01,0xA0,0x26,0x7B, /* 00001BF8 "S3__..&{" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001C00 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0A, /* 00001C08 "CI0PCID." */
+ 0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001C10 "...\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x33, /* 00001C18 "B_PCI0S3" */
+ 0x5F,0x5F,0x0A,0x03,0xA0,0x25,0x7B,0x5C, /* 00001C20 "__...%{\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001C28 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x55,0x0A,0x10, /* 00001C30 "I0PCIU.." */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001C38 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x34,0x5F, /* 00001C40 "_PCI0S4_" */
+ 0x5F,0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03, /* 00001C48 "_..&{\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001C50 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x44,0x0A,0x10,0x00,0x86, /* 00001C58 "PCID...." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001C60 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x34,0x5F,0x5F,0x0A, /* 00001C68 "CI0S4__." */
+ 0x03,0xA0,0x25,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001C70 "..%{\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001C78 "SB_PCI0P" */
+ 0x43,0x49,0x55,0x0A,0x20,0x00,0x86,0x5C, /* 00001C80 "CIU. ..\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001C88 "/._SB_PC" */
+ 0x49,0x30,0x53,0x35,0x5F,0x5F,0x01,0xA0, /* 00001C90 "I0S5__.." */
+ 0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001C98 "&{\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001CA0 "_PCI0PCI" */
+ 0x44,0x0A,0x20,0x00,0x86,0x5C,0x2F,0x03, /* 00001CA8 "D. ..\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001CB0 "_SB_PCI0" */
+ 0x53,0x35,0x5F,0x5F,0x0A,0x03,0xA0,0x25, /* 00001CB8 "S5__...%" */
+ 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001CC0 "{\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00001CC8 "PCI0PCIU" */
+ 0x0A,0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00001CD0 ".@..\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00001CD8 "SB_PCI0S" */
+ 0x36,0x5F,0x5F,0x01,0xA0,0x26,0x7B,0x5C, /* 00001CE0 "6__..&{\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001CE8 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x44,0x0A,0x40, /* 00001CF0 "I0PCID.@" */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001CF8 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x36,0x5F, /* 00001D00 "_PCI0S6_" */
+ 0x5F,0x0A,0x03,0xA0,0x25,0x7B,0x5C,0x2F, /* 00001D08 "_...%{\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001D10 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x55,0x0A,0x80,0x00, /* 00001D18 "0PCIU..." */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001D20 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x37,0x5F,0x5F, /* 00001D28 "PCI0S7__" */
+ 0x01,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001D30 "..&{\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001D38 "SB_PCI0P" */
+ 0x43,0x49,0x44,0x0A,0x80,0x00,0x86,0x5C, /* 00001D40 "CID....\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001D48 "/._SB_PC" */
+ 0x49,0x30,0x53,0x37,0x5F,0x5F,0x0A,0x03, /* 00001D50 "I0S7__.." */
+ 0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001D58 ".&{\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001D60 "B_PCI0PC" */
+ 0x49,0x55,0x0B,0x00,0x01,0x00,0x86,0x5C, /* 00001D68 "IU.....\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001D70 "/._SB_PC" */
+ 0x49,0x30,0x53,0x38,0x5F,0x5F,0x01,0xA0, /* 00001D78 "I0S8__.." */
+ 0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001D80 "'{\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001D88 "_PCI0PCI" */
+ 0x44,0x0B,0x00,0x01,0x00,0x86,0x5C,0x2F, /* 00001D90 "D.....\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001D98 "._SB_PCI" */
+ 0x30,0x53,0x38,0x5F,0x5F,0x0A,0x03,0xA0, /* 00001DA0 "0S8__..." */
+ 0x26,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001DA8 "&{\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00001DB0 "_PCI0PCI" */
+ 0x55,0x0B,0x00,0x02,0x00,0x86,0x5C,0x2F, /* 00001DB8 "U.....\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001DC0 "._SB_PCI" */
+ 0x30,0x53,0x39,0x5F,0x5F,0x01,0xA0,0x27, /* 00001DC8 "0S9__..'" */
+ 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001DD0 "{\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44, /* 00001DD8 "PCI0PCID" */
+ 0x0B,0x00,0x02,0x00,0x86,0x5C,0x2F,0x03, /* 00001DE0 ".....\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001DE8 "_SB_PCI0" */
+ 0x53,0x39,0x5F,0x5F,0x0A,0x03,0xA0,0x26, /* 00001DF0 "S9__...&" */
+ 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001DF8 "{\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00001E00 "PCI0PCIU" */
+ 0x0B,0x00,0x04,0x00,0x86,0x5C,0x2F,0x03, /* 00001E08 ".....\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001E10 "_SB_PCI0" */
+ 0x53,0x31,0x30,0x5F,0x01,0xA0,0x27,0x7B, /* 00001E18 "S10_..'{" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001E20 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0B, /* 00001E28 "CI0PCID." */
+ 0x00,0x04,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00001E30 "....\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00001E38 "SB_PCI0S" */
+ 0x31,0x30,0x5F,0x0A,0x03,0xA0,0x26,0x7B, /* 00001E40 "10_...&{" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001E48 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0B, /* 00001E50 "CI0PCIU." */
+ 0x00,0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00001E58 "....\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00001E60 "SB_PCI0S" */
+ 0x31,0x31,0x5F,0x01,0xA0,0x27,0x7B,0x5C, /* 00001E68 "11_..'{\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001E70 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x44,0x0B,0x00, /* 00001E78 "I0PCID.." */
+ 0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001E80 "...\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00001E88 "B_PCI0S1" */
+ 0x31,0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C, /* 00001E90 "1_...&{\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001E98 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x55,0x0B,0x00, /* 00001EA0 "I0PCIU.." */
+ 0x10,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00001EA8 "...\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00001EB0 "B_PCI0S1" */
+ 0x32,0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F, /* 00001EB8 "2_..'{\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001EC0 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x44,0x0B,0x00,0x10, /* 00001EC8 "0PCID..." */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001ED0 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x32, /* 00001ED8 "_PCI0S12" */
+ 0x5F,0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F, /* 00001EE0 "_...&{\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00001EE8 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x55,0x0B,0x00,0x20, /* 00001EF0 "0PCIU.. " */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00001EF8 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x33, /* 00001F00 "_PCI0S13" */
+ 0x5F,0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03, /* 00001F08 "_..'{\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001F10 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x44,0x0B,0x00,0x20,0x00, /* 00001F18 "PCID.. ." */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001F20 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x31,0x33,0x5F, /* 00001F28 "PCI0S13_" */
+ 0x0A,0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03, /* 00001F30 "...&{\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00001F38 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x55,0x0B,0x00,0x40,0x00, /* 00001F40 "PCIU..@." */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001F48 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x31,0x34,0x5F, /* 00001F50 "PCI0S14_" */
+ 0x01,0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001F58 "..'{\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001F60 "SB_PCI0P" */
+ 0x43,0x49,0x44,0x0B,0x00,0x40,0x00,0x86, /* 00001F68 "CID..@.." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001F70 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x31,0x34,0x5F,0x0A, /* 00001F78 "CI0S14_." */
+ 0x03,0xA0,0x26,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001F80 "..&{\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00001F88 "SB_PCI0P" */
+ 0x43,0x49,0x55,0x0B,0x00,0x80,0x00,0x86, /* 00001F90 "CIU....." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00001F98 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x31,0x35,0x5F,0x01, /* 00001FA0 "CI0S15_." */
+ 0xA0,0x27,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001FA8 ".'{\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001FB0 "B_PCI0PC" */
+ 0x49,0x44,0x0B,0x00,0x80,0x00,0x86,0x5C, /* 00001FB8 "ID.....\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00001FC0 "/._SB_PC" */
+ 0x49,0x30,0x53,0x31,0x35,0x5F,0x0A,0x03, /* 00001FC8 "I0S15_.." */
+ 0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00001FD0 ".({\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00001FD8 "B_PCI0PC" */
+ 0x49,0x55,0x0C,0x00,0x00,0x01,0x00,0x00, /* 00001FE0 "IU......" */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00001FE8 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x31,0x36,0x5F, /* 00001FF0 "PCI0S16_" */
+ 0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F, /* 00001FF8 "..){\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00002000 "SB_PCI0P" */
+ 0x43,0x49,0x44,0x0C,0x00,0x00,0x01,0x00, /* 00002008 "CID....." */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002010 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x36, /* 00002018 "_PCI0S16" */
+ 0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F, /* 00002020 "_...({\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002028 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00, /* 00002030 "0PCIU..." */
+ 0x02,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00002038 "....\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00002040 "SB_PCI0S" */
+ 0x31,0x37,0x5F,0x01,0xA0,0x29,0x7B,0x5C, /* 00002048 "17_..){\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002050 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00, /* 00002058 "I0PCID.." */
+ 0x00,0x02,0x00,0x00,0x86,0x5C,0x2F,0x03, /* 00002060 ".....\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002068 "_SB_PCI0" */
+ 0x53,0x31,0x37,0x5F,0x0A,0x03,0xA0,0x28, /* 00002070 "S17_...(" */
+ 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002078 "{\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00002080 "PCI0PCIU" */
+ 0x0C,0x00,0x00,0x04,0x00,0x00,0x86,0x5C, /* 00002088 ".......\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002090 "/._SB_PC" */
+ 0x49,0x30,0x53,0x31,0x38,0x5F,0x01,0xA0, /* 00002098 "I0S18_.." */
+ 0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 000020A0 "){\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 000020A8 "_PCI0PCI" */
+ 0x44,0x0C,0x00,0x00,0x04,0x00,0x00,0x86, /* 000020B0 "D......." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 000020B8 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x31,0x38,0x5F,0x0A, /* 000020C0 "CI0S18_." */
+ 0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F, /* 000020C8 "..({\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 000020D0 "SB_PCI0P" */
+ 0x43,0x49,0x55,0x0C,0x00,0x00,0x08,0x00, /* 000020D8 "CIU....." */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 000020E0 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x31,0x39, /* 000020E8 "_PCI0S19" */
+ 0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03, /* 000020F0 "_..){\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 000020F8 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x08, /* 00002100 "PCID...." */
+ 0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00002108 "...\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x31, /* 00002110 "B_PCI0S1" */
+ 0x39,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C, /* 00002118 "9_...({\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002120 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00, /* 00002128 "I0PCIU.." */
+ 0x00,0x10,0x00,0x00,0x86,0x5C,0x2F,0x03, /* 00002130 ".....\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002138 "_SB_PCI0" */
+ 0x53,0x32,0x30,0x5F,0x01,0xA0,0x29,0x7B, /* 00002140 "S20_..){" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002148 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C, /* 00002150 "CI0PCID." */
+ 0x00,0x00,0x10,0x00,0x00,0x86,0x5C,0x2F, /* 00002158 "......\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002160 "._SB_PCI" */
+ 0x30,0x53,0x32,0x30,0x5F,0x0A,0x03,0xA0, /* 00002168 "0S20_..." */
+ 0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002170 "({\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00002178 "_PCI0PCI" */
+ 0x55,0x0C,0x00,0x00,0x20,0x00,0x00,0x86, /* 00002180 "U... ..." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002188 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x32,0x31,0x5F,0x01, /* 00002190 "CI0S21_." */
+ 0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00002198 ".){\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 000021A0 "B_PCI0PC" */
+ 0x49,0x44,0x0C,0x00,0x00,0x20,0x00,0x00, /* 000021A8 "ID... .." */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 000021B0 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x32,0x31,0x5F, /* 000021B8 "PCI0S21_" */
+ 0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03, /* 000021C0 "...({\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 000021C8 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x40, /* 000021D0 "PCIU...@" */
+ 0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 000021D8 "...\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32, /* 000021E0 "B_PCI0S2" */
+ 0x32,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F, /* 000021E8 "2_..){\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000021F0 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00, /* 000021F8 "0PCID..." */
+ 0x40,0x00,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00002200 "@...\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 00002208 "SB_PCI0S" */
+ 0x32,0x32,0x5F,0x0A,0x03,0xA0,0x28,0x7B, /* 00002210 "22_...({" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002218 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C, /* 00002220 "CI0PCIU." */
+ 0x00,0x00,0x80,0x00,0x00,0x86,0x5C,0x2F, /* 00002228 "......\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002230 "._SB_PCI" */
+ 0x30,0x53,0x32,0x33,0x5F,0x01,0xA0,0x29, /* 00002238 "0S23_..)" */
+ 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002240 "{\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44, /* 00002248 "PCI0PCID" */
+ 0x0C,0x00,0x00,0x80,0x00,0x00,0x86,0x5C, /* 00002250 ".......\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002258 "/._SB_PC" */
+ 0x49,0x30,0x53,0x32,0x33,0x5F,0x0A,0x03, /* 00002260 "I0S23_.." */
+ 0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00002268 ".({\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00002270 "B_PCI0PC" */
+ 0x49,0x55,0x0C,0x00,0x00,0x00,0x01,0x00, /* 00002278 "IU......" */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002280 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x32,0x34,0x5F, /* 00002288 "PCI0S24_" */
+ 0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F, /* 00002290 "..){\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00002298 "SB_PCI0P" */
+ 0x43,0x49,0x44,0x0C,0x00,0x00,0x00,0x01, /* 000022A0 "CID....." */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 000022A8 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x34, /* 000022B0 "_PCI0S24" */
+ 0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F, /* 000022B8 "_...({\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000022C0 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x55,0x0C,0x00,0x00, /* 000022C8 "0PCIU..." */
+ 0x00,0x02,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 000022D0 "....\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 000022D8 "SB_PCI0S" */
+ 0x32,0x35,0x5F,0x01,0xA0,0x29,0x7B,0x5C, /* 000022E0 "25_..){\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 000022E8 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x44,0x0C,0x00, /* 000022F0 "I0PCID.." */
+ 0x00,0x00,0x02,0x00,0x86,0x5C,0x2F,0x03, /* 000022F8 ".....\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002300 "_SB_PCI0" */
+ 0x53,0x32,0x35,0x5F,0x0A,0x03,0xA0,0x28, /* 00002308 "S25_...(" */
+ 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002310 "{\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x55, /* 00002318 "PCI0PCIU" */
+ 0x0C,0x00,0x00,0x00,0x04,0x00,0x86,0x5C, /* 00002320 ".......\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 00002328 "/._SB_PC" */
+ 0x49,0x30,0x53,0x32,0x36,0x5F,0x01,0xA0, /* 00002330 "I0S26_.." */
+ 0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002338 "){\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00002340 "_PCI0PCI" */
+ 0x44,0x0C,0x00,0x00,0x00,0x04,0x00,0x86, /* 00002348 "D......." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002350 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x32,0x36,0x5F,0x0A, /* 00002358 "CI0S26_." */
+ 0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03,0x5F, /* 00002360 "..({\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x50, /* 00002368 "SB_PCI0P" */
+ 0x43,0x49,0x55,0x0C,0x00,0x00,0x00,0x08, /* 00002370 "CIU....." */
+ 0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002378 "..\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x53,0x32,0x37, /* 00002380 "_PCI0S27" */
+ 0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F,0x03, /* 00002388 "_..){\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002390 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x44,0x0C,0x00,0x00,0x00, /* 00002398 "PCID...." */
+ 0x08,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 000023A0 "...\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x32, /* 000023A8 "B_PCI0S2" */
+ 0x37,0x5F,0x0A,0x03,0xA0,0x28,0x7B,0x5C, /* 000023B0 "7_...({\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 000023B8 "/._SB_PC" */
+ 0x49,0x30,0x50,0x43,0x49,0x55,0x0C,0x00, /* 000023C0 "I0PCIU.." */
+ 0x00,0x00,0x10,0x00,0x86,0x5C,0x2F,0x03, /* 000023C8 ".....\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 000023D0 "_SB_PCI0" */
+ 0x53,0x32,0x38,0x5F,0x01,0xA0,0x29,0x7B, /* 000023D8 "S28_..){" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 000023E0 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x44,0x0C, /* 000023E8 "CI0PCID." */
+ 0x00,0x00,0x00,0x10,0x00,0x86,0x5C,0x2F, /* 000023F0 "......\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000023F8 "._SB_PCI" */
+ 0x30,0x53,0x32,0x38,0x5F,0x0A,0x03,0xA0, /* 00002400 "0S28_..." */
+ 0x28,0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42, /* 00002408 "({\/._SB" */
+ 0x5F,0x50,0x43,0x49,0x30,0x50,0x43,0x49, /* 00002410 "_PCI0PCI" */
+ 0x55,0x0C,0x00,0x00,0x00,0x20,0x00,0x86, /* 00002418 "U.... .." */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 00002420 "\/._SB_P" */
+ 0x43,0x49,0x30,0x53,0x32,0x39,0x5F,0x01, /* 00002428 "CI0S29_." */
+ 0xA0,0x29,0x7B,0x5C,0x2F,0x03,0x5F,0x53, /* 00002430 ".){\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x50,0x43, /* 00002438 "B_PCI0PC" */
+ 0x49,0x44,0x0C,0x00,0x00,0x00,0x20,0x00, /* 00002440 "ID.... ." */
+ 0x86,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 00002448 ".\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x53,0x32,0x39,0x5F, /* 00002450 "PCI0S29_" */
+ 0x0A,0x03,0xA0,0x28,0x7B,0x5C,0x2F,0x03, /* 00002458 "...({\/." */
+ 0x5F,0x53,0x42,0x5F,0x50,0x43,0x49,0x30, /* 00002460 "_SB_PCI0" */
+ 0x50,0x43,0x49,0x55,0x0C,0x00,0x00,0x00, /* 00002468 "PCIU...." */
+ 0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F,0x53, /* 00002470 "@..\/._S" */
+ 0x42,0x5F,0x50,0x43,0x49,0x30,0x53,0x33, /* 00002478 "B_PCI0S3" */
+ 0x30,0x5F,0x01,0xA0,0x29,0x7B,0x5C,0x2F, /* 00002480 "0_..){\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 00002488 "._SB_PCI" */
+ 0x30,0x50,0x43,0x49,0x44,0x0C,0x00,0x00, /* 00002490 "0PCID..." */
+ 0x00,0x40,0x00,0x86,0x5C,0x2F,0x03,0x5F, /* 00002498 ".@..\/._" */
+ 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x53, /* 000024A0 "SB_PCI0S" */
+ 0x33,0x30,0x5F,0x0A,0x03,0xA0,0x28,0x7B, /* 000024A8 "30_...({" */
+ 0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50, /* 000024B0 "\/._SB_P" */
+ 0x43,0x49,0x30,0x50,0x43,0x49,0x55,0x0C, /* 000024B8 "CI0PCIU." */
+ 0x00,0x00,0x00,0x80,0x00,0x86,0x5C,0x2F, /* 000024C0 "......\/" */
+ 0x03,0x5F,0x53,0x42,0x5F,0x50,0x43,0x49, /* 000024C8 "._SB_PCI" */
+ 0x30,0x53,0x33,0x31,0x5F,0x01,0xA0,0x29, /* 000024D0 "0S31_..)" */
+ 0x7B,0x5C,0x2F,0x03,0x5F,0x53,0x42,0x5F, /* 000024D8 "{\/._SB_" */
+ 0x50,0x43,0x49,0x30,0x50,0x43,0x49,0x44, /* 000024E0 "PCI0PCID" */
+ 0x0C,0x00,0x00,0x00,0x80,0x00,0x86,0x5C, /* 000024E8 ".......\" */
+ 0x2F,0x03,0x5F,0x53,0x42,0x5F,0x50,0x43, /* 000024F0 "/._SB_PC" */
+ 0x49,0x30,0x53,0x33,0x31,0x5F,0x0A,0x03, /* 000024F8 "I0S31_.." */
+ 0xA4,0x01,0x14,0x11,0x5F,0x4C,0x30,0x32, /* 00002500 "...._L02" */
+ 0x00,0xA4,0x5C,0x2E,0x5F,0x53,0x42,0x5F, /* 00002508 "..\._SB_" */
+ 0x50,0x52,0x53,0x43,0x14,0x08,0x5F,0x4C, /* 00002510 "PRSC.._L" */
+ 0x30,0x33,0x00,0xA4,0x01,0x14,0x08,0x5F, /* 00002518 "03....._" */
+ 0x4C,0x30,0x34,0x00,0xA4,0x01,0x14,0x08, /* 00002520 "L04....." */
+ 0x5F,0x4C,0x30,0x35,0x00,0xA4,0x01,0x14, /* 00002528 "_L05...." */
+ 0x08,0x5F,0x4C,0x30,0x36,0x00,0xA4,0x01, /* 00002530 "._L06..." */
+ 0x14,0x08,0x5F,0x4C,0x30,0x37,0x00,0xA4, /* 00002538 ".._L07.." */
+ 0x01,0x14,0x08,0x5F,0x4C,0x30,0x38,0x00, /* 00002540 "..._L08." */
+ 0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30,0x39, /* 00002548 "...._L09" */
+ 0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C,0x30, /* 00002550 "....._L0" */
+ 0x41,0x00,0xA4,0x01,0x14,0x08,0x5F,0x4C, /* 00002558 "A....._L" */
+ 0x30,0x42,0x00,0xA4,0x01,0x14,0x08,0x5F, /* 00002560 "0B....._" */
+ 0x4C,0x30,0x43,0x00,0xA4,0x01,0x14,0x08, /* 00002568 "L0C....." */
+ 0x5F,0x4C,0x30,0x44,0x00,0xA4,0x01,0x14, /* 00002570 "_L0D...." */
+ 0x08,0x5F,0x4C,0x30,0x45,0x00,0xA4,0x01, /* 00002578 "._L0E..." */
+ 0x14,0x08,0x5F,0x4C,0x30,0x46,0x00,0xA4, /* 00002580 ".._L0F.." */
+ 0x01 /* 00002588 "." */
+};
--- /dev/null
+// Support for generating ACPI tables (on emulators)
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "acpi.h" // struct rsdp_descriptor
+#include "util.h" // memcpy
+#include "pci.h" // pci_find_init_device
+#include "biosvar.h" // GET_EBDA
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "paravirt.h"
+
+/****************************************************/
+/* ACPI tables init */
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+ BSD license) */
+
+struct acpi_table_header /* ACPI common table header */
+{
+ ACPI_TABLE_HEADER_DEF
+} PACKED;
+
+/*
+ * ACPI 1.0 Root System Description Table (RSDT)
+ */
+#define RSDT_SIGNATURE 0x54445352 // RSDT
+struct rsdt_descriptor_rev1
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 table_offset_entry[0]; /* Array of pointers to other */
+ /* ACPI tables */
+} PACKED;
+
+/*
+ * ACPI 1.0 Firmware ACPI Control Structure (FACS)
+ */
+#define FACS_SIGNATURE 0x53434146 // FACS
+struct facs_descriptor_rev1
+{
+ u32 signature; /* ACPI Signature */
+ u32 length; /* Length of structure, in bytes */
+ u32 hardware_signature; /* Hardware configuration signature */
+ u32 firmware_waking_vector; /* ACPI OS waking vector */
+ u32 global_lock; /* Global Lock */
+ u32 S4bios_f : 1; /* Indicates if S4BIOS support is present */
+ u32 reserved1 : 31; /* Must be 0 */
+ u8 resverved3 [40]; /* Reserved - must be zero */
+} PACKED;
+
+
+/*
+ * MADT values and structures
+ */
+
+/* Values for MADT PCATCompat */
+
+#define DUAL_PIC 0
+#define MULTIPLE_APIC 1
+
+
+/* Master MADT */
+
+#define APIC_SIGNATURE 0x43495041 // APIC
+struct multiple_apic_table
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 local_apic_address; /* Physical address of local APIC */
+#if 0
+ u32 PCATcompat : 1; /* A one indicates system also has dual 8259s */
+ u32 reserved1 : 31;
+#else
+ u32 flags;
+#endif
+} PACKED;
+
+
+/* Values for Type in APIC sub-headers */
+
+#define APIC_PROCESSOR 0
+#define APIC_IO 1
+#define APIC_XRUPT_OVERRIDE 2
+#define APIC_NMI 3
+#define APIC_LOCAL_NMI 4
+#define APIC_ADDRESS_OVERRIDE 5
+#define APIC_IO_SAPIC 6
+#define APIC_LOCAL_SAPIC 7
+#define APIC_XRUPT_SOURCE 8
+#define APIC_RESERVED 9 /* 9 and greater are reserved */
+
+/*
+ * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
+ */
+#define ACPI_SUB_HEADER_DEF /* Common ACPI sub-structure header */\
+ u8 type; \
+ u8 length;
+
+/* Sub-structures for MADT */
+
+struct madt_processor_apic
+{
+ ACPI_SUB_HEADER_DEF
+ u8 processor_id; /* ACPI processor id */
+ u8 local_apic_id; /* Processor's local APIC id */
+#if 0
+ u32 processor_enabled: 1; /* Processor is usable if set */
+ u32 reserved2 : 31; /* Reserved, must be zero */
+#else
+ u32 flags;
+#endif
+} PACKED;
+
+struct madt_io_apic
+{
+ ACPI_SUB_HEADER_DEF
+ u8 io_apic_id; /* I/O APIC ID */
+ u8 reserved; /* Reserved - must be zero */
+ u32 address; /* APIC physical address */
+ u32 interrupt; /* Global system interrupt where INTI
+ * lines start */
+} PACKED;
+
+/* IRQs 5,9,10,11 */
+#define PCI_ISA_IRQ_MASK 0x0e20
+
+struct madt_intsrcovr {
+ ACPI_SUB_HEADER_DEF
+ u8 bus;
+ u8 source;
+ u32 gsi;
+ u16 flags;
+} PACKED;
+
+/*
+ * ACPI 2.0 Generic Address Space definition.
+ */
+struct acpi_20_generic_address {
+ u8 address_space_id;
+ u8 register_bit_width;
+ u8 register_bit_offset;
+ u8 reserved;
+ u64 address;
+} PACKED;
+
+/*
+ * HPET Description Table
+ */
+struct acpi_20_hpet {
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 timer_block_id;
+ struct acpi_20_generic_address addr;
+ u8 hpet_number;
+ u16 min_tick;
+ u8 page_protect;
+} PACKED;
+
+#define HPET_ID 0x000
+#define HPET_PERIOD 0x004
+
+/*
+ * SRAT (NUMA topology description) table
+ */
+
+#define SRAT_PROCESSOR 0
+#define SRAT_MEMORY 1
+
+struct system_resource_affinity_table
+{
+ ACPI_TABLE_HEADER_DEF
+ u32 reserved1;
+ u32 reserved2[2];
+} PACKED;
+
+struct srat_processor_affinity
+{
+ ACPI_SUB_HEADER_DEF
+ u8 proximity_lo;
+ u8 local_apic_id;
+ u32 flags;
+ u8 local_sapic_eid;
+ u8 proximity_hi[3];
+ u32 reserved;
+} PACKED;
+
+struct srat_memory_affinity
+{
+ ACPI_SUB_HEADER_DEF
+ u8 proximity[4];
+ u16 reserved1;
+ u32 base_addr_low,base_addr_high;
+ u32 length_low,length_high;
+ u32 reserved2;
+ u32 flags;
+ u32 reserved3[2];
+} PACKED;
+
+#include "acpi-dsdt.hex"
+
+static void
+build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
+{
+ h->signature = sig;
+ h->length = cpu_to_le32(len);
+ h->revision = rev;
+ memcpy(h->oem_id, CONFIG_APPNAME6, 6);
+ memcpy(h->oem_table_id, CONFIG_APPNAME4, 4);
+ memcpy(h->oem_table_id + 4, (void*)&sig, 4);
+ h->oem_revision = cpu_to_le32(1);
+ memcpy(h->asl_compiler_id, CONFIG_APPNAME4, 4);
+ h->asl_compiler_revision = cpu_to_le32(1);
+ h->checksum -= checksum(h, len);
+}
+
+#define PIIX4_ACPI_ENABLE 0xf1
+#define PIIX4_ACPI_DISABLE 0xf0
+#define PIIX4_GPE0_BLK 0xafe0
+#define PIIX4_GPE0_BLK_LEN 4
+
+static void piix4_fadt_init(struct pci_device *pci, void *arg)
+{
+ struct fadt_descriptor_rev1 *fadt = arg;
+ fadt->acpi_enable = PIIX4_ACPI_ENABLE;
+ fadt->acpi_disable = PIIX4_ACPI_DISABLE;
+ fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK);
+ fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN;
+}
+
+static const struct pci_device_id fadt_init_tbl[] = {
+ /* PIIX4 Power Management device (for ACPI) */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ piix4_fadt_init),
+
+ PCI_DEVICE_END
+};
+
+static void *
+build_fadt(struct pci_device *pci)
+{
+ struct fadt_descriptor_rev1 *fadt = malloc_high(sizeof(*fadt));
+ struct facs_descriptor_rev1 *facs = memalign_high(64, sizeof(*facs));
+ void *dsdt = malloc_high(sizeof(AmlCode));
+
+ if (!fadt || !facs || !dsdt) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ /* FACS */
+ memset(facs, 0, sizeof(*facs));
+ facs->signature = FACS_SIGNATURE;
+ facs->length = cpu_to_le32(sizeof(*facs));
+
+ /* DSDT */
+ memcpy(dsdt, AmlCode, sizeof(AmlCode));
+
+ /* FADT */
+ memset(fadt, 0, sizeof(*fadt));
+ fadt->firmware_ctrl = cpu_to_le32((u32)facs);
+ fadt->dsdt = cpu_to_le32((u32)dsdt);
+ fadt->model = 1;
+ fadt->reserved1 = 0;
+
+ if (pci) {
+ int pm_sci_int = pci_config_readb(pci->bdf, PCI_INTERRUPT_LINE);
+
+ fadt->sci_int = cpu_to_le16(pm_sci_int);
+ fadt->smi_cmd = cpu_to_le32(PORT_SMI_CMD);
+ fadt->pm1a_evt_blk = cpu_to_le32(PORT_ACPI_PM_BASE);
+ fadt->pm1a_cnt_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x04);
+ fadt->pm_tmr_blk = cpu_to_le32(PORT_ACPI_PM_BASE + 0x08);
+ fadt->pm1_evt_len = 4;
+ fadt->pm1_cnt_len = 2;
+ fadt->pm_tmr_len = 4;
+
+
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+ pci_init_device(fadt_init_tbl, pci, fadt);
+ } else {
+
+ fadt->sci_int = 0;
+ fadt->smi_cmd = 0;
+ fadt->pm1a_evt_blk = 0;
+ fadt->pm1a_cnt_blk = 0;
+ fadt->pm_tmr_blk = 0;
+ fadt->pm1_evt_len = 0;
+ fadt->pm1_cnt_len = 0;
+ fadt->pm_tmr_len = 0;
+
+
+ fadt->plvl2_lat = cpu_to_le16(0xfff); // C2 state not supported
+ fadt->plvl3_lat = cpu_to_le16(0xfff); // C3 state not supported
+
+ // No PIIX4 to init
+ // pci_init_device(fadt_init_tbl, pci, fadt);
+
+ }
+
+ /* WBINVD + PROC_C1 + SLP_BUTTON + FIX_RTC + RTC_S4 */
+ fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 5) | (1 << 6) | (1 << 7));
+
+ build_header((void*)fadt, FACP_SIGNATURE, sizeof(*fadt), 1);
+
+ return fadt;
+}
+
+static void*
+build_madt(void)
+{
+ int madt_size = (sizeof(struct multiple_apic_table)
+ + sizeof(struct madt_processor_apic) * MaxCountCPUs
+ + sizeof(struct madt_io_apic)
+ + sizeof(struct madt_intsrcovr) * 16);
+ struct multiple_apic_table *madt = malloc_high(madt_size);
+ if (!madt) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(madt, 0, madt_size);
+ madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
+ madt->flags = cpu_to_le32(1);
+ struct madt_processor_apic *apic = (void*)&madt[1];
+ int i;
+ for (i=0; i<MaxCountCPUs; i++) {
+ apic->type = APIC_PROCESSOR;
+ apic->length = sizeof(*apic);
+ apic->processor_id = i;
+ apic->local_apic_id = i;
+ if (i < CountCPUs)
+ apic->flags = cpu_to_le32(1);
+ else
+ apic->flags = cpu_to_le32(0);
+ apic++;
+ }
+ struct madt_io_apic *io_apic = (void*)apic;
+ io_apic->type = APIC_IO;
+ io_apic->length = sizeof(*io_apic);
+ io_apic->io_apic_id = CountCPUs;
+ io_apic->address = cpu_to_le32(BUILD_IOAPIC_ADDR);
+ io_apic->interrupt = cpu_to_le32(0);
+
+ struct madt_intsrcovr *intsrcovr = (void*)&io_apic[1];
+ if (qemu_cfg_irq0_override()) {
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = 0;
+ intsrcovr->gsi = 2;
+ intsrcovr->flags = 0; /* conforms to bus specifications */
+ intsrcovr++;
+ }
+ for (i = 1; i < 16; i++) {
+ if (!(PCI_ISA_IRQ_MASK & (1 << i)))
+ /* No need for a INT source override structure. */
+ continue;
+ memset(intsrcovr, 0, sizeof(*intsrcovr));
+ intsrcovr->type = APIC_XRUPT_OVERRIDE;
+ intsrcovr->length = sizeof(*intsrcovr);
+ intsrcovr->source = i;
+ intsrcovr->gsi = i;
+ intsrcovr->flags = 0xd; /* active high, level triggered */
+ intsrcovr++;
+ }
+
+ build_header((void*)madt, APIC_SIGNATURE, (void*)intsrcovr - (void*)madt, 1);
+ return madt;
+}
+
+// Encode a hex value
+static inline char getHex(u32 val) {
+ val &= 0x0f;
+ return (val <= 9) ? ('0' + val) : ('A' + val - 10);
+}
+
+// Encode a length in an SSDT.
+static u8 *
+encodeLen(u8 *ssdt_ptr, int length, int bytes)
+{
+ switch (bytes) {
+ default:
+ case 4: ssdt_ptr[3] = ((length >> 20) & 0xff);
+ case 3: ssdt_ptr[2] = ((length >> 12) & 0xff);
+ case 2: ssdt_ptr[1] = ((length >> 4) & 0xff);
+ ssdt_ptr[0] = (((bytes-1) & 0x3) << 6) | (length & 0x0f);
+ break;
+ case 1: ssdt_ptr[0] = length & 0x3f;
+ }
+ return ssdt_ptr + bytes;
+}
+
+// AML Processor() object. See src/ssdt-proc.dsl for info.
+static unsigned char ssdt_proc[] = {
+ 0x5b,0x83,0x42,0x05,0x43,0x50,0x41,0x41,
+ 0xaa,0x10,0xb0,0x00,0x00,0x06,0x08,0x49,
+ 0x44,0x5f,0x5f,0x0a,0xaa,0x08,0x5f,0x48,
+ 0x49,0x44,0x0d,0x41,0x43,0x50,0x49,0x30,
+ 0x30,0x30,0x37,0x00,0x14,0x0f,0x5f,0x4d,
+ 0x41,0x54,0x00,0xa4,0x43,0x50,0x4d,0x41,
+ 0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x53,
+ 0x54,0x41,0x00,0xa4,0x43,0x50,0x53,0x54,
+ 0x49,0x44,0x5f,0x5f,0x14,0x0f,0x5f,0x45,
+ 0x4a,0x30,0x01,0x43,0x50,0x45,0x4a,0x49,
+ 0x44,0x5f,0x5f,0x68
+};
+#define SD_OFFSET_CPUHEX 6
+#define SD_OFFSET_CPUID1 8
+#define SD_OFFSET_CPUID2 20
+
+#define SSDT_SIGNATURE 0x54445353 // SSDT
+static void*
+build_ssdt(void)
+{
+ int acpi_cpus = MaxCountCPUs > 0xff ? 0xff : MaxCountCPUs;
+ // length = ScopeOp + procs + NTYF method + CPON package
+ int length = ((1+3+4)
+ + (acpi_cpus * sizeof(ssdt_proc))
+ + (1+2+5+(12*acpi_cpus))
+ + (6+2+1+(1*acpi_cpus)));
+ u8 *ssdt = malloc_high(sizeof(struct acpi_table_header) + length);
+ if (! ssdt) {
+ warn_noalloc();
+ return NULL;
+ }
+ u8 *ssdt_ptr = ssdt + sizeof(struct acpi_table_header);
+
+ // build Scope(_SB_) header
+ *(ssdt_ptr++) = 0x10; // ScopeOp
+ ssdt_ptr = encodeLen(ssdt_ptr, length-1, 3);
+ *(ssdt_ptr++) = '_';
+ *(ssdt_ptr++) = 'S';
+ *(ssdt_ptr++) = 'B';
+ *(ssdt_ptr++) = '_';
+
+ // build Processor object for each processor
+ int i;
+ for (i=0; i<acpi_cpus; i++) {
+ memcpy(ssdt_ptr, ssdt_proc, sizeof(ssdt_proc));
+ ssdt_ptr[SD_OFFSET_CPUHEX] = getHex(i >> 4);
+ ssdt_ptr[SD_OFFSET_CPUHEX+1] = getHex(i);
+ ssdt_ptr[SD_OFFSET_CPUID1] = i;
+ ssdt_ptr[SD_OFFSET_CPUID2] = i;
+ ssdt_ptr += sizeof(ssdt_proc);
+ }
+
+ // build "Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}"
+ *(ssdt_ptr++) = 0x14; // MethodOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 2+5+(12*acpi_cpus), 2);
+ *(ssdt_ptr++) = 'N';
+ *(ssdt_ptr++) = 'T';
+ *(ssdt_ptr++) = 'F';
+ *(ssdt_ptr++) = 'Y';
+ *(ssdt_ptr++) = 0x02;
+ for (i=0; i<acpi_cpus; i++) {
+ *(ssdt_ptr++) = 0xA0; // IfOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 11, 1);
+ *(ssdt_ptr++) = 0x93; // LEqualOp
+ *(ssdt_ptr++) = 0x68; // Arg0Op
+ *(ssdt_ptr++) = 0x0A; // BytePrefix
+ *(ssdt_ptr++) = i;
+ *(ssdt_ptr++) = 0x86; // NotifyOp
+ *(ssdt_ptr++) = 'C';
+ *(ssdt_ptr++) = 'P';
+ *(ssdt_ptr++) = getHex(i >> 4);
+ *(ssdt_ptr++) = getHex(i);
+ *(ssdt_ptr++) = 0x69; // Arg1Op
+ }
+
+ // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
+ *(ssdt_ptr++) = 0x08; // NameOp
+ *(ssdt_ptr++) = 'C';
+ *(ssdt_ptr++) = 'P';
+ *(ssdt_ptr++) = 'O';
+ *(ssdt_ptr++) = 'N';
+ *(ssdt_ptr++) = 0x12; // PackageOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2);
+ *(ssdt_ptr++) = acpi_cpus;
+ for (i=0; i<acpi_cpus; i++)
+ *(ssdt_ptr++) = (i < CountCPUs) ? 0x01 : 0x00;
+
+ build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+
+ //hexdump(ssdt, ssdt_ptr - ssdt);
+
+ return ssdt;
+}
+
+#define HPET_SIGNATURE 0x54455048 // HPET
+static void*
+build_hpet(void)
+{
+ struct acpi_20_hpet *hpet;
+ const void *hpet_base = (void *)BUILD_HPET_ADDRESS;
+ u32 hpet_vendor = readl(hpet_base + HPET_ID) >> 16;
+ u32 hpet_period = readl(hpet_base + HPET_PERIOD);
+
+ if (hpet_vendor == 0 || hpet_vendor == 0xffff ||
+ hpet_period == 0 || hpet_period > 100000000)
+ return NULL;
+
+ hpet = malloc_high(sizeof(*hpet));
+ if (!hpet) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ memset(hpet, 0, sizeof(*hpet));
+ /* Note timer_block_id value must be kept in sync with value advertised by
+ * emulated hpet
+ */
+ hpet->timer_block_id = cpu_to_le32(0x8086a201);
+ hpet->addr.address = cpu_to_le32(BUILD_HPET_ADDRESS);
+ build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1);
+
+ return hpet;
+}
+
+static void
+acpi_build_srat_memory(struct srat_memory_affinity *numamem,
+ u64 base, u64 len, int node, int enabled)
+{
+ numamem->type = SRAT_MEMORY;
+ numamem->length = sizeof(*numamem);
+ memset(numamem->proximity, 0 ,4);
+ numamem->proximity[0] = node;
+ numamem->flags = cpu_to_le32(!!enabled);
+ numamem->base_addr_low = base & 0xFFFFFFFF;
+ numamem->base_addr_high = base >> 32;
+ numamem->length_low = len & 0xFFFFFFFF;
+ numamem->length_high = len >> 32;
+}
+
+#define SRAT_SIGNATURE 0x54415253 // SRAT
+static void *
+build_srat(void)
+{
+ int nb_numa_nodes = qemu_cfg_get_numa_nodes();
+
+ if (nb_numa_nodes == 0)
+ return NULL;
+
+ u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes));
+ if (!numadata) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes);
+
+ struct system_resource_affinity_table *srat;
+ int srat_size = sizeof(*srat) +
+ sizeof(struct srat_processor_affinity) * MaxCountCPUs +
+ sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
+
+ srat = malloc_high(srat_size);
+ if (!srat) {
+ warn_noalloc();
+ free(numadata);
+ return NULL;
+ }
+
+ memset(srat, 0, srat_size);
+ srat->reserved1=1;
+ struct srat_processor_affinity *core = (void*)(srat + 1);
+ int i;
+ u64 curnode;
+
+ for (i = 0; i < MaxCountCPUs; ++i) {
+ core->type = SRAT_PROCESSOR;
+ core->length = sizeof(*core);
+ core->local_apic_id = i;
+ curnode = *numadata++;
+ core->proximity_lo = curnode;
+ memset(core->proximity_hi, 0, 3);
+ core->local_sapic_eid = 0;
+ if (i < CountCPUs)
+ core->flags = cpu_to_le32(1);
+ else
+ core->flags = 0;
+ core++;
+ }
+
+
+ /* the memory map is a bit tricky, it contains at least one hole
+ * from 640k-1M and possibly another one from 3.5G-4G.
+ */
+ struct srat_memory_affinity *numamem = (void*)core;
+ int slots = 0;
+ u64 mem_len, mem_base, next_base = 0;
+
+ acpi_build_srat_memory(numamem, 0, 640*1024, 0, 1);
+ next_base = 1024 * 1024;
+ numamem++;
+ slots++;
+ for (i = 1; i < nb_numa_nodes + 1; ++i) {
+ mem_base = next_base;
+ mem_len = *numadata++;
+ if (i == 1)
+ mem_len -= 1024 * 1024;
+ next_base = mem_base + mem_len;
+
+ /* Cut out the PCI hole */
+ if (mem_base <= RamSize && next_base > RamSize) {
+ mem_len -= next_base - RamSize;
+ if (mem_len > 0) {
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ numamem++;
+ slots++;
+ }
+ mem_base = 1ULL << 32;
+ mem_len = next_base - RamSize;
+ next_base += (1ULL << 32) - RamSize;
+ }
+ acpi_build_srat_memory(numamem, mem_base, mem_len, i-1, 1);
+ numamem++;
+ slots++;
+ }
+ for (; slots < nb_numa_nodes + 2; slots++) {
+ acpi_build_srat_memory(numamem, 0, 0, 0, 0);
+ numamem++;
+ }
+
+ build_header((void*)srat, SRAT_SIGNATURE, srat_size, 1);
+
+ free(numadata);
+ return srat;
+}
+
+static const struct pci_device_id acpi_find_tbl[] = {
+ /* PIIX4 Power Management device. */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL),
+
+ PCI_DEVICE_END,
+};
+
+struct rsdp_descriptor *RsdpAddr;
+
+#define MAX_ACPI_TABLES 20
+void
+acpi_bios_init(void)
+{
+ if (! CONFIG_ACPI)
+ return;
+
+ dprintf(3, "init ACPI tables\n");
+
+ // This code is hardcoded for PIIX4 Power Management device.
+ struct pci_device *pci = pci_find_init_device(acpi_find_tbl, NULL);
+
+ /*
+ if (!pci) {
+ // Device not found
+ return;
+ */
+ if (!pci) {
+ /* JRL: No PIIX4: Disable power management ACPI functions */
+ dprintf(1, "No PIIX4 (v3vee): Disabling ACPI power management functions\n");
+ }
+
+
+ // Build ACPI tables
+ u32 tables[MAX_ACPI_TABLES], tbl_idx = 0;
+
+#define ACPI_INIT_TABLE(X) \
+ do { \
+ tables[tbl_idx] = (u32)(X); \
+ if (tables[tbl_idx]) \
+ tbl_idx++; \
+ } while(0)
+
+ ACPI_INIT_TABLE(build_fadt(pci));
+ ACPI_INIT_TABLE(build_ssdt());
+ ACPI_INIT_TABLE(build_madt());
+ if (pci) {
+ ACPI_INIT_TABLE(build_hpet());
+ }
+ ACPI_INIT_TABLE(build_srat());
+
+ u16 i, external_tables = qemu_cfg_acpi_additional_tables();
+
+ for (i = 0; i < external_tables; i++) {
+ u16 len = qemu_cfg_next_acpi_table_len();
+ void *addr = malloc_high(len);
+ if (!addr) {
+ warn_noalloc();
+ continue;
+ }
+ ACPI_INIT_TABLE(qemu_cfg_next_acpi_table_load(addr, len));
+ if (tbl_idx == MAX_ACPI_TABLES) {
+ warn_noalloc();
+ break;
+ }
+ }
+
+ // Build final rsdt table
+ struct rsdt_descriptor_rev1 *rsdt;
+ size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx;
+ rsdt = malloc_high(rsdt_len);
+ if (!rsdt) {
+ warn_noalloc();
+ return;
+ }
+ memset(rsdt, 0, rsdt_len);
+ memcpy(rsdt->table_offset_entry, tables, sizeof(u32) * tbl_idx);
+ build_header((void*)rsdt, RSDT_SIGNATURE, rsdt_len, 1);
+
+ // Build rsdp pointer table
+ struct rsdp_descriptor *rsdp = malloc_fseg(sizeof(*rsdp));
+ if (!rsdp) {
+ warn_noalloc();
+ return;
+ }
+ memset(rsdp, 0, sizeof(*rsdp));
+ rsdp->signature = RSDP_SIGNATURE;
+ memcpy(rsdp->oem_id, CONFIG_APPNAME6, 6);
+ rsdp->rsdt_physical_address = cpu_to_le32((u32)rsdt);
+ rsdp->checksum -= checksum(rsdp, 20);
+ RsdpAddr = rsdp;
+ dprintf(1, "ACPI tables: RSDP=%p RSDT=%p\n", rsdp, rsdt);
+}
+
+u32
+find_resume_vector(void)
+{
+ dprintf(4, "rsdp=%p\n", RsdpAddr);
+ if (!RsdpAddr || RsdpAddr->signature != RSDP_SIGNATURE)
+ return 0;
+ struct rsdt_descriptor_rev1 *rsdt = (void*)RsdpAddr->rsdt_physical_address;
+ dprintf(4, "rsdt=%p\n", rsdt);
+ if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
+ return 0;
+ void *end = (void*)rsdt + rsdt->length;
+ int i;
+ for (i=0; (void*)&rsdt->table_offset_entry[i] < end; i++) {
+ struct fadt_descriptor_rev1 *fadt = (void*)rsdt->table_offset_entry[i];
+ if (!fadt || fadt->signature != FACP_SIGNATURE)
+ continue;
+ dprintf(4, "fadt=%p\n", fadt);
+ struct facs_descriptor_rev1 *facs = (void*)fadt->firmware_ctrl;
+ dprintf(4, "facs=%p\n", facs);
+ if (! facs || facs->signature != FACS_SIGNATURE)
+ return 0;
+ // Found it.
+ dprintf(4, "resume addr=%d\n", facs->firmware_waking_vector);
+ return facs->firmware_waking_vector;
+ }
+ return 0;
+}
--- /dev/null
+#ifndef __ACPI_H
+#define __ACPI_H
+
+#include "types.h" // u32
+
+void acpi_bios_init(void);
+u32 find_resume_vector(void);
+
+#define RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR "
+
+struct rsdp_descriptor { /* Root System Descriptor Pointer */
+ u64 signature; /* ACPI signature, contains "RSD PTR " */
+ u8 checksum; /* To make sum of struct == 0 */
+ u8 oem_id [6]; /* OEM identification */
+ u8 revision; /* Must be 0 for 1.0, 2 for 2.0 */
+ u32 rsdt_physical_address; /* 32-bit physical address of RSDT */
+ u32 length; /* XSDT Length in bytes including hdr */
+ u64 xsdt_physical_address; /* 64-bit physical address of XSDT */
+ u8 extended_checksum; /* Checksum of entire table */
+ u8 reserved [3]; /* Reserved field must be 0 */
+};
+
+extern struct rsdp_descriptor *RsdpAddr;
+
+/* Table structure from Linux kernel (the ACPI tables are under the
+ BSD license) */
+
+#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
+ u32 signature; /* ACPI signature (4 ASCII characters) */ \
+ u32 length; /* Length of table, in bytes, including header */ \
+ u8 revision; /* ACPI Specification minor version # */ \
+ u8 checksum; /* To make sum of entire table == 0 */ \
+ u8 oem_id [6]; /* OEM identification */ \
+ u8 oem_table_id [8]; /* OEM table identification */ \
+ u32 oem_revision; /* OEM revision number */ \
+ u8 asl_compiler_id [4]; /* ASL compiler vendor ID */ \
+ u32 asl_compiler_revision; /* ASL compiler revision number */
+
+
+/*
+ * ACPI 1.0 Fixed ACPI Description Table (FADT)
+ */
+#define FACP_SIGNATURE 0x50434146 // FACP
+struct fadt_descriptor_rev1
+{
+ ACPI_TABLE_HEADER_DEF /* ACPI common table header */
+ u32 firmware_ctrl; /* Physical address of FACS */
+ u32 dsdt; /* Physical address of DSDT */
+ u8 model; /* System Interrupt Model */
+ u8 reserved1; /* Reserved */
+ u16 sci_int; /* System vector of SCI interrupt */
+ u32 smi_cmd; /* Port address of SMI command port */
+ u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */
+ u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */
+ u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
+ u8 reserved2; /* Reserved - must be zero */
+ u32 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
+ u32 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
+ u32 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
+ u32 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
+ u32 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
+ u32 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
+ u32 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
+ u32 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
+ u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
+ u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
+ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
+ u8 pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
+ u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
+ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
+ u8 gpe1_base; /* Offset in gpe model where gpe1 events start */
+ u8 reserved3; /* Reserved */
+ u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
+ u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
+ u16 flush_size; /* Size of area read to flush caches */
+ u16 flush_stride; /* Stride used in flushing caches */
+ u8 duty_offset; /* Bit location of duty cycle field in p_cnt reg */
+ u8 duty_width; /* Bit width of duty cycle field in p_cnt reg */
+ u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
+ u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
+ u8 century; /* Index to century in RTC CMOS RAM */
+ u8 reserved4; /* Reserved */
+ u8 reserved4a; /* Reserved */
+ u8 reserved4b; /* Reserved */
+#if 0
+ u32 wb_invd : 1; /* The wbinvd instruction works properly */
+ u32 wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
+ u32 proc_c1 : 1; /* All processors support C1 state */
+ u32 plvl2_up : 1; /* C2 state works on MP system */
+ u32 pwr_button : 1; /* Power button is handled as a generic feature */
+ u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
+ u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
+ u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
+ u32 tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
+ u32 reserved5 : 23; /* Reserved - must be zero */
+#else
+ u32 flags;
+#endif
+} PACKED;
+
+#endif // acpi.h
--- /dev/null
+// Low level AHCI disk access
+//
+// Copyright (C) 2010 Gerd Hoffmann <kraxel@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u8
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "boot.h" // add_bcv_hd
+#include "disk.h" // struct ata_s
+#include "ata.h" // ATA_CB_STAT
+#include "ahci.h" // CDB_CMD_READ_10
+#include "blockcmd.h" // CDB_CMD_READ_10
+
+#define AHCI_REQUEST_TIMEOUT 32000 // 32 seconds max for IDE ops
+#define AHCI_RESET_TIMEOUT 500 // 500 miliseconds
+#define AHCI_LINK_TIMEOUT 10 // 10 miliseconds
+
+/****************************************************************
+ * these bits must run in both 16bit and 32bit modes
+ ****************************************************************/
+
+// prepare sata command fis
+static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command)
+{
+ memset_fl(fis, 0, sizeof(*fis));
+ SET_FLATPTR(fis->command, command);
+}
+
+static void sata_prep_readwrite(struct sata_cmd_fis *fis,
+ struct disk_op_s *op, int iswrite)
+{
+ u64 lba = op->lba;
+ u8 command;
+
+ memset_fl(fis, 0, sizeof(*fis));
+
+ if (op->count >= (1<<8) || lba + op->count >= (1<<28)) {
+ SET_FLATPTR(fis->sector_count2, op->count >> 8);
+ SET_FLATPTR(fis->lba_low2, lba >> 24);
+ SET_FLATPTR(fis->lba_mid2, lba >> 32);
+ SET_FLATPTR(fis->lba_high2, lba >> 40);
+ lba &= 0xffffff;
+ command = (iswrite ? ATA_CMD_WRITE_DMA_EXT
+ : ATA_CMD_READ_DMA_EXT);
+ } else {
+ command = (iswrite ? ATA_CMD_WRITE_DMA
+ : ATA_CMD_READ_DMA);
+ }
+ SET_FLATPTR(fis->feature, 1); /* dma */
+ SET_FLATPTR(fis->command, command);
+ SET_FLATPTR(fis->sector_count, op->count);
+ SET_FLATPTR(fis->lba_low, lba);
+ SET_FLATPTR(fis->lba_mid, lba >> 8);
+ SET_FLATPTR(fis->lba_high, lba >> 16);
+ SET_FLATPTR(fis->device, ((lba >> 24) & 0xf) | ATA_CB_DH_LBA);
+}
+
+static void sata_prep_atapi(struct sata_cmd_fis *fis, u16 blocksize)
+{
+ memset_fl(fis, 0, sizeof(*fis));
+ SET_FLATPTR(fis->command, ATA_CMD_PACKET);
+ SET_FLATPTR(fis->feature, 1); /* dma */
+ SET_FLATPTR(fis->lba_mid, blocksize);
+ SET_FLATPTR(fis->lba_high, blocksize >> 8);
+}
+
+// ahci register access helpers
+static u32 ahci_ctrl_readl(struct ahci_ctrl_s *ctrl, u32 reg)
+{
+ u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
+ return pci_readl(addr);
+}
+
+static void ahci_ctrl_writel(struct ahci_ctrl_s *ctrl, u32 reg, u32 val)
+{
+ u32 addr = GET_GLOBALFLAT(ctrl->iobase) + reg;
+ pci_writel(addr, val);
+}
+
+static u32 ahci_port_to_ctrl(u32 pnr, u32 port_reg)
+{
+ u32 ctrl_reg = 0x100;
+ ctrl_reg += pnr * 0x80;
+ ctrl_reg += port_reg;
+ return ctrl_reg;
+}
+
+static u32 ahci_port_readl(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg)
+{
+ u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
+ return ahci_ctrl_readl(ctrl, ctrl_reg);
+}
+
+static void ahci_port_writel(struct ahci_ctrl_s *ctrl, u32 pnr, u32 reg, u32 val)
+{
+ u32 ctrl_reg = ahci_port_to_ctrl(pnr, reg);
+ ahci_ctrl_writel(ctrl, ctrl_reg, val);
+}
+
+// submit ahci command + wait for result
+static int ahci_command(struct ahci_port_s *port, int iswrite, int isatapi,
+ void *buffer, u32 bsize)
+{
+ u32 val, status, success, flags, intbits, error;
+ struct ahci_ctrl_s *ctrl = GET_GLOBAL(port->ctrl);
+ struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
+ struct ahci_fis_s *fis = GET_GLOBAL(port->fis);
+ struct ahci_list_s *list = GET_GLOBAL(port->list);
+ u32 pnr = GET_GLOBAL(port->pnr);
+ u64 end;
+
+ SET_FLATPTR(cmd->fis.reg, 0x27);
+ SET_FLATPTR(cmd->fis.pmp_type, (1 << 7)); /* cmd fis */
+ SET_FLATPTR(cmd->prdt[0].base, ((u32)buffer));
+ SET_FLATPTR(cmd->prdt[0].baseu, 0);
+ SET_FLATPTR(cmd->prdt[0].flags, bsize-1);
+
+ flags = ((1 << 16) | /* one prd entry */
+ (iswrite ? (1 << 6) : 0) |
+ (isatapi ? (1 << 5) : 0) |
+ (5 << 0)); /* fis length (dwords) */
+ SET_FLATPTR(list[0].flags, flags);
+ SET_FLATPTR(list[0].bytes, 0);
+ SET_FLATPTR(list[0].base, ((u32)(cmd)));
+ SET_FLATPTR(list[0].baseu, 0);
+
+ dprintf(2, "AHCI/%d: send cmd ...\n", pnr);
+ intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ if (intbits)
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits);
+ ahci_port_writel(ctrl, pnr, PORT_SCR_ACT, 1);
+ ahci_port_writel(ctrl, pnr, PORT_CMD_ISSUE, 1);
+
+ end = calc_future_tsc(AHCI_REQUEST_TIMEOUT);
+ do {
+ for (;;) {
+ intbits = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ if (intbits) {
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, intbits);
+ if (intbits & 0x02) {
+ status = GET_FLATPTR(fis->psfis[2]);
+ error = GET_FLATPTR(fis->psfis[3]);
+ break;
+ }
+ if (intbits & 0x01) {
+ status = GET_FLATPTR(fis->rfis[2]);
+ error = GET_FLATPTR(fis->rfis[3]);
+ break;
+ }
+ }
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ dprintf(2, "AHCI/%d: ... intbits 0x%x, status 0x%x ...\n",
+ pnr, intbits, status);
+ } while (status & ATA_CB_STAT_BSY);
+
+ success = (0x00 == (status & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF |
+ ATA_CB_STAT_ERR)) &&
+ ATA_CB_STAT_RDY == (status & (ATA_CB_STAT_RDY)));
+ if (success) {
+ dprintf(2, "AHCI/%d: ... finished, status 0x%x, OK\n", pnr,
+ status);
+ } else {
+ dprintf(2, "AHCI/%d: ... finished, status 0x%x, ERROR 0x%x\n", pnr,
+ status, error);
+
+ // non-queued error recovery (AHCI 1.3 section 6.2.2.1)
+ // Clears PxCMD.ST to 0 to reset the PxCI register
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ ahci_port_writel(ctrl, pnr, PORT_CMD, val & ~PORT_CMD_START);
+
+ // waits for PxCMD.CR to clear to 0
+ while (1) {
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ if ((val & PORT_CMD_LIST_ON) == 0)
+ break;
+ yield();
+ }
+
+ // Clears any error bits in PxSERR to enable capturing new errors
+ val = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR);
+ ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, val);
+
+ // Clears status bits in PxIS as appropriate
+ val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
+
+ // If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to 1, issue
+ // a COMRESET to the device to put it in an idle state
+ val = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
+ if (val & (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ)) {
+ dprintf(2, "AHCI/%d: issue comreset\n", pnr);
+ val = ahci_port_readl(ctrl, pnr, PORT_SCR_CTL);
+ // set Device Detection Initialization (DET) to 1 for 1 ms for comreset
+ ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val | 1);
+ mdelay (1);
+ ahci_port_writel(ctrl, pnr, PORT_SCR_CTL, val);
+ }
+
+ // Sets PxCMD.ST to 1 to enable issuing new commands
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ ahci_port_writel(ctrl, pnr, PORT_CMD, val | PORT_CMD_START);
+ }
+ return success ? 0 : -1;
+}
+
+#define CDROM_CDB_SIZE 12
+
+int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (! CONFIG_AHCI)
+ return 0;
+
+ struct ahci_port_s *port = container_of(
+ op->drive_g, struct ahci_port_s, drive);
+ struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
+ u8 *atapi = cdbcmd;
+ int i, rc;
+
+ sata_prep_atapi(&cmd->fis, blocksize);
+ for (i = 0; i < CDROM_CDB_SIZE; i++) {
+ SET_FLATPTR(cmd->atapi[i], atapi[i]);
+ }
+ rc = ahci_command(port, 0, 1, op->buf_fl,
+ op->count * blocksize);
+ if (rc < 0)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+// read/write count blocks from a harddrive, op->buf_fl must be word aligned
+static int
+ahci_disk_readwrite_aligned(struct disk_op_s *op, int iswrite)
+{
+ struct ahci_port_s *port = container_of(
+ op->drive_g, struct ahci_port_s, drive);
+ struct ahci_cmd_s *cmd = GET_GLOBAL(port->cmd);
+ int rc;
+
+ sata_prep_readwrite(&cmd->fis, op, iswrite);
+ rc = ahci_command(port, iswrite, 0, op->buf_fl,
+ op->count * DISK_SECTOR_SIZE);
+ dprintf(2, "ahci disk %s, lba %6x, count %3x, buf %p, rc %d\n",
+ iswrite ? "write" : "read", (u32)op->lba, op->count, op->buf_fl, rc);
+ if (rc < 0)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+// read/write count blocks from a harddrive.
+static int
+ahci_disk_readwrite(struct disk_op_s *op, int iswrite)
+{
+ // if caller's buffer is word aligned, use it directly
+ if (((u32) op->buf_fl & 1) == 0)
+ return ahci_disk_readwrite_aligned(op, iswrite);
+
+ // Use a word aligned buffer for AHCI I/O
+ int rc;
+ struct disk_op_s localop = *op;
+ u8 *alignedbuf_fl = GET_GLOBAL(bounce_buf_fl);
+ u8 *position = op->buf_fl;
+
+ localop.buf_fl = alignedbuf_fl;
+ localop.count = 1;
+
+ if (iswrite) {
+ u16 block;
+ for (block = 0; block < op->count; block++) {
+ memcpy_fl (alignedbuf_fl, position, DISK_SECTOR_SIZE);
+ rc = ahci_disk_readwrite_aligned (&localop, 1);
+ if (rc)
+ return rc;
+ position += DISK_SECTOR_SIZE;
+ localop.lba++;
+ }
+ } else { // read
+ u16 block;
+ for (block = 0; block < op->count; block++) {
+ rc = ahci_disk_readwrite_aligned (&localop, 0);
+ if (rc)
+ return rc;
+ memcpy_fl (position, alignedbuf_fl, DISK_SECTOR_SIZE);
+ position += DISK_SECTOR_SIZE;
+ localop.lba++;
+ }
+ }
+ return DISK_RET_SUCCESS;
+}
+
+// command demuxer
+int process_ahci_op(struct disk_op_s *op)
+{
+ struct ahci_port_s *port;
+ u32 atapi;
+
+ if (!CONFIG_AHCI)
+ return 0;
+
+ port = container_of(op->drive_g, struct ahci_port_s, drive);
+ atapi = GET_GLOBAL(port->atapi);
+
+ if (atapi) {
+ switch (op->command) {
+ case CMD_READ:
+ return cdb_read(op);
+ case CMD_WRITE:
+ case CMD_FORMAT:
+ return DISK_RET_EWRITEPROTECT;
+ case CMD_RESET:
+ /* FIXME: what should we do here? */
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ dprintf(1, "AHCI: unknown cdrom command %d\n", op->command);
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+ } else {
+ switch (op->command) {
+ case CMD_READ:
+ return ahci_disk_readwrite(op, 0);
+ case CMD_WRITE:
+ return ahci_disk_readwrite(op, 1);
+ case CMD_RESET:
+ /* FIXME: what should we do here? */
+ case CMD_FORMAT:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ dprintf(1, "AHCI: unknown disk command %d\n", op->command);
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+ }
+}
+
+/****************************************************************
+ * everything below is pure 32bit code
+ ****************************************************************/
+
+static void
+ahci_port_reset(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+ u32 val;
+ u64 end;
+
+ /* disable FIS + CMD */
+ end = calc_future_tsc(AHCI_RESET_TIMEOUT);
+ for (;;) {
+ val = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ if (!(val & (PORT_CMD_FIS_RX | PORT_CMD_START |
+ PORT_CMD_FIS_ON | PORT_CMD_LIST_ON)))
+ break;
+ val &= ~(PORT_CMD_FIS_RX | PORT_CMD_START);
+ ahci_port_writel(ctrl, pnr, PORT_CMD, val);
+ if (check_tsc(end)) {
+ warn_timeout();
+ break;
+ }
+ yield();
+ }
+
+ /* disable + clear IRQs */
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_MASK, 0);
+ val = ahci_port_readl(ctrl, pnr, PORT_IRQ_STAT);
+ if (val)
+ ahci_port_writel(ctrl, pnr, PORT_IRQ_STAT, val);
+}
+
+static struct ahci_port_s*
+ahci_port_alloc(struct ahci_ctrl_s *ctrl, u32 pnr)
+{
+ struct ahci_port_s *port = malloc_tmp(sizeof(*port));
+
+ if (!port) {
+ warn_noalloc();
+ return NULL;
+ }
+ port->pnr = pnr;
+ port->ctrl = ctrl;
+ port->list = memalign_tmp(1024, 1024);
+ port->fis = memalign_tmp(256, 256);
+ port->cmd = memalign_tmp(256, 256);
+ if (port->list == NULL || port->fis == NULL || port->cmd == NULL) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(port->list, 0, 1024);
+ memset(port->fis, 0, 256);
+ memset(port->cmd, 0, 256);
+
+ ahci_port_writel(ctrl, pnr, PORT_LST_ADDR, (u32)port->list);
+ ahci_port_writel(ctrl, pnr, PORT_FIS_ADDR, (u32)port->fis);
+ return port;
+}
+
+static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port)
+{
+ struct ahci_port_s *tmp;
+ u32 cmd;
+
+ tmp = malloc_fseg(sizeof(*port));
+ *tmp = *port;
+ free(port);
+ port = tmp;
+
+ ahci_port_reset(port->ctrl, port->pnr);
+
+ free(port->list);
+ free(port->fis);
+ free(port->cmd);
+ port->list = memalign_low(1024, 1024);
+ port->fis = memalign_low(256, 256);
+ port->cmd = memalign_low(256, 256);
+
+ ahci_port_writel(port->ctrl, port->pnr, PORT_LST_ADDR, (u32)port->list);
+ ahci_port_writel(port->ctrl, port->pnr, PORT_FIS_ADDR, (u32)port->fis);
+
+ cmd = ahci_port_readl(port->ctrl, port->pnr, PORT_CMD);
+ cmd |= (PORT_CMD_FIS_RX|PORT_CMD_START);
+ ahci_port_writel(port->ctrl, port->pnr, PORT_CMD, cmd);
+
+ return port;
+}
+
+static void ahci_port_release(struct ahci_port_s *port)
+{
+ ahci_port_reset(port->ctrl, port->pnr);
+ free(port->list);
+ free(port->fis);
+ free(port->cmd);
+ free(port);
+}
+
+#define MAXMODEL 40
+
+/* See ahci spec chapter 10.1 "Software Initialization of HBA" */
+static int ahci_port_init(struct ahci_port_s *port)
+{
+ struct ahci_ctrl_s *ctrl = port->ctrl;
+ u32 pnr = port->pnr;
+ char model[MAXMODEL+1];
+ u16 buffer[256];
+ u32 cmd, stat, err, tf;
+ u64 end;
+ int rc;
+
+ /* enable FIS recv */
+ cmd = ahci_port_readl(ctrl, pnr, PORT_CMD);
+ cmd |= PORT_CMD_FIS_RX;
+ ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
+
+ /* spin up */
+ cmd |= PORT_CMD_SPIN_UP;
+ ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
+ end = calc_future_tsc(AHCI_LINK_TIMEOUT);
+ for (;;) {
+ stat = ahci_port_readl(ctrl, pnr, PORT_SCR_STAT);
+ if ((stat & 0x07) == 0x03) {
+ dprintf(1, "AHCI/%d: link up\n", port->pnr);
+ break;
+ }
+ if (check_tsc(end)) {
+ dprintf(1, "AHCI/%d: link down\n", port->pnr);
+ return -1;
+ }
+ yield();
+ }
+
+ /* clear error status */
+ err = ahci_port_readl(ctrl, pnr, PORT_SCR_ERR);
+ if (err)
+ ahci_port_writel(ctrl, pnr, PORT_SCR_ERR, err);
+
+ /* wait for device becoming ready */
+ end = calc_future_tsc(AHCI_REQUEST_TIMEOUT);
+ for (;;) {
+ tf = ahci_port_readl(ctrl, pnr, PORT_TFDATA);
+ if (!(tf & (ATA_CB_STAT_BSY |
+ ATA_CB_STAT_DRQ)))
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ dprintf(1, "AHCI/%d: device not ready (tf 0x%x)\n", port->pnr, tf);
+ return -1;
+ }
+ yield();
+ }
+
+ /* start device */
+ cmd |= PORT_CMD_START;
+ ahci_port_writel(ctrl, pnr, PORT_CMD, cmd);
+
+ sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_PACKET_DEVICE);
+ rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
+ if (rc == 0) {
+ port->atapi = 1;
+ } else {
+ port->atapi = 0;
+ sata_prep_simple(&port->cmd->fis, ATA_CMD_IDENTIFY_DEVICE);
+ rc = ahci_command(port, 0, 0, buffer, sizeof(buffer));
+ if (rc < 0)
+ return -1;
+ }
+
+ port->drive.type = DTYPE_AHCI;
+ port->drive.cntl_id = pnr;
+ port->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
+
+ if (!port->atapi) {
+ // found disk (ata)
+ port->drive.blksize = DISK_SECTOR_SIZE;
+ port->drive.pchs.cylinders = buffer[1];
+ port->drive.pchs.heads = buffer[3];
+ port->drive.pchs.spt = buffer[6];
+
+ u64 sectors;
+ if (buffer[83] & (1 << 10)) // word 83 - lba48 support
+ sectors = *(u64*)&buffer[100]; // word 100-103
+ else
+ sectors = *(u32*)&buffer[60]; // word 60 and word 61
+ port->drive.sectors = sectors;
+ u64 adjsize = sectors >> 11;
+ char adjprefix = 'M';
+ if (adjsize >= (1 << 16)) {
+ adjsize >>= 10;
+ adjprefix = 'G';
+ }
+ port->desc = znprintf(MAXDESCSIZE
+ , "AHCI/%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
+ , port->pnr
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer)
+ , (u32)adjsize, adjprefix);
+ port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0);
+ } else {
+ // found cdrom (atapi)
+ port->drive.blksize = CDROM_SECTOR_SIZE;
+ port->drive.sectors = (u64)-1;
+ u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
+ if (!iscd) {
+ dprintf(1, "AHCI/%d: atapi device is'nt a cdrom\n", port->pnr);
+ return -1;
+ }
+ port->desc = znprintf(MAXDESCSIZE
+ , "DVD/CD [AHCI/%d: %s ATAPI-%d DVD/CD]"
+ , port->pnr
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer));
+ port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0);
+ }
+ return 0;
+}
+
+// Detect any drives attached to a given controller.
+static void
+ahci_port_detect(void *data)
+{
+ struct ahci_port_s *port = data;
+ int rc;
+
+ dprintf(2, "AHCI/%d: probing\n", port->pnr);
+ ahci_port_reset(port->ctrl, port->pnr);
+ rc = ahci_port_init(port);
+ if (rc < 0)
+ ahci_port_release(port);
+ else {
+ port = ahci_port_realloc(port);
+ dprintf(1, "AHCI/%d: registering: \"%s\"\n", port->pnr, port->desc);
+ if (!port->atapi) {
+ // Register with bcv system.
+ boot_add_hd(&port->drive, port->desc, port->prio);
+ } else {
+ // fill cdidmap
+ boot_add_cd(&port->drive, port->desc, port->prio);
+ }
+ }
+}
+
+// Initialize an ata controller and detect its drives.
+static void
+ahci_init_controller(struct pci_device *pci)
+{
+ struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl));
+ struct ahci_port_s *port;
+ u16 bdf = pci->bdf;
+ u32 val, pnr, max;
+
+ if (!ctrl) {
+ warn_noalloc();
+ return;
+ }
+
+ if (bounce_buf_init() < 0) {
+ warn_noalloc();
+ free(ctrl);
+ return;
+ }
+
+ ctrl->pci_tmp = pci;
+ ctrl->pci_bdf = bdf;
+ ctrl->iobase = pci_config_readl(bdf, PCI_BASE_ADDRESS_5);
+ ctrl->irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ dprintf(1, "AHCI controller at %02x.%x, iobase %x, irq %d\n",
+ bdf >> 3, bdf & 7, ctrl->iobase, ctrl->irq);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ val = ahci_ctrl_readl(ctrl, HOST_CTL);
+ ahci_ctrl_writel(ctrl, HOST_CTL, val | HOST_CTL_AHCI_EN);
+
+ ctrl->caps = ahci_ctrl_readl(ctrl, HOST_CAP);
+ ctrl->ports = ahci_ctrl_readl(ctrl, HOST_PORTS_IMPL);
+ dprintf(2, "AHCI: cap 0x%x, ports_impl 0x%x\n",
+ ctrl->caps, ctrl->ports);
+
+ max = ctrl->caps & 0x1f;
+ for (pnr = 0; pnr <= max; pnr++) {
+ if (!(ctrl->ports & (1 << pnr)))
+ continue;
+ port = ahci_port_alloc(ctrl, pnr);
+ if (port == NULL)
+ continue;
+ run_thread(ahci_port_detect, port);
+ }
+}
+
+// Locate and init ahci controllers.
+static void
+ahci_init(void)
+{
+ // Scan PCI bus for ATA adapters
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class != PCI_CLASS_STORAGE_SATA)
+ continue;
+ if (pci->prog_if != 1 /* AHCI rev 1 */)
+ continue;
+ ahci_init_controller(pci);
+ }
+}
+
+void
+ahci_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_AHCI)
+ return;
+
+ dprintf(3, "init ahci\n");
+ ahci_init();
+}
--- /dev/null
+#ifndef __AHCI_H
+#define __AHCI_H
+
+struct sata_cmd_fis {
+ u8 reg;
+ u8 pmp_type;
+ u8 command;
+ u8 feature;
+
+ u8 lba_low;
+ u8 lba_mid;
+ u8 lba_high;
+ u8 device;
+
+ u8 lba_low2;
+ u8 lba_mid2;
+ u8 lba_high2;
+ u8 feature2;
+
+ u8 sector_count;
+ u8 sector_count2;
+ u8 res_1;
+ u8 control;
+
+ u8 res_2[64 - 16];
+};
+
+struct ahci_ctrl_s {
+ struct pci_device *pci_tmp;
+ u16 pci_bdf;
+ u8 irq;
+ u32 iobase;
+ u32 caps;
+ u32 ports;
+};
+
+struct ahci_cmd_s {
+ struct sata_cmd_fis fis;
+ u8 atapi[0x20];
+ u8 res[0x20];
+ struct {
+ u32 base;
+ u32 baseu;
+ u32 res;
+ u32 flags;
+ } prdt[];
+};
+
+/* command list */
+struct ahci_list_s {
+ u32 flags;
+ u32 bytes;
+ u32 base;
+ u32 baseu;
+ u32 res[4];
+};
+
+struct ahci_fis_s {
+ u8 dsfis[0x1c]; /* dma setup */
+ u8 res_1[0x04];
+ u8 psfis[0x14]; /* pio setup */
+ u8 res_2[0x0c];
+ u8 rfis[0x14]; /* d2h register */
+ u8 res_3[0x04];
+ u8 sdbfis[0x08]; /* set device bits */
+ u8 ufis[0x40]; /* unknown */
+ u8 res_4[0x60];
+};
+
+struct ahci_port_s {
+ struct drive_s drive;
+ struct ahci_ctrl_s *ctrl;
+ struct ahci_list_s *list;
+ struct ahci_fis_s *fis;
+ struct ahci_cmd_s *cmd;
+ u32 pnr;
+ u32 atapi;
+ char *desc;
+ int prio;
+};
+
+void ahci_setup(void);
+int process_ahci_op(struct disk_op_s *op);
+int ahci_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+
+#define AHCI_IRQ_ON_SG (1 << 31)
+#define AHCI_CMD_ATAPI (1 << 5)
+#define AHCI_CMD_WRITE (1 << 6)
+#define AHCI_CMD_PREFETCH (1 << 7)
+#define AHCI_CMD_RESET (1 << 8)
+#define AHCI_CMD_CLR_BUSY (1 << 10)
+
+#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
+#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */
+#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */
+
+/* global controller registers */
+#define HOST_CAP 0x00 /* host capabilities */
+#define HOST_CTL 0x04 /* global host control */
+#define HOST_IRQ_STAT 0x08 /* interrupt status */
+#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
+#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */
+
+/* HOST_CTL bits */
+#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */
+#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */
+#define HOST_CTL_AHCI_EN (1 << 31) /* AHCI enabled */
+
+/* HOST_CAP bits */
+#define HOST_CAP_SSC (1 << 14) /* Slumber capable */
+#define HOST_CAP_AHCI (1 << 18) /* AHCI only */
+#define HOST_CAP_CLO (1 << 24) /* Command List Override support */
+#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */
+#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */
+#define HOST_CAP_64 (1 << 31) /* PCI DAC (64-bit DMA) support */
+
+/* registers for each SATA port */
+#define PORT_LST_ADDR 0x00 /* command list DMA addr */
+#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
+#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */
+#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
+#define PORT_IRQ_STAT 0x10 /* interrupt status */
+#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */
+#define PORT_CMD 0x18 /* port command */
+#define PORT_TFDATA 0x20 /* taskfile data */
+#define PORT_SIG 0x24 /* device TF signature */
+#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
+#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
+#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
+#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
+#define PORT_CMD_ISSUE 0x38 /* command issue */
+#define PORT_RESERVED 0x3c /* reserved */
+
+/* PORT_IRQ_{STAT,MASK} bits */
+#define PORT_IRQ_COLD_PRES (1 << 31) /* cold presence detect */
+#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */
+#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
+#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */
+#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */
+#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */
+
+#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */
+#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */
+#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */
+#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
+
+#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \
+ PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \
+ PORT_IRQ_UNK_FIS)
+#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \
+ PORT_IRQ_HBUS_DATA_ERR)
+#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \
+ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \
+ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS)
+
+/* PORT_CMD bits */
+#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */
+#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
+#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */
+#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */
+#define PORT_CMD_CLO (1 << 3) /* Command list override */
+#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
+#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
+#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
+
+#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */
+#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
+#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
+#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
+
+#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */
+#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */
+#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */
+#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */
+#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */
+#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */
+#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */
+#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence
+ Status */
+#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */
+#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier
+ Status */
+#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */
+#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error
+ Status */
+#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */
+#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
+#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
+#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
+#define PORT_IRQ_STAT_CPDS (1 << 31) /* Code Port Detect Status */
+
+#endif // ahci.h
--- /dev/null
+// Basic support for apmbios callbacks.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2005 Struan Bartlett
+// Copyright (C) 2004 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "farptr.h" // GET_VAR
+#include "bregs.h" // struct bregs
+#include "ioport.h" // outb
+#include "util.h" // wait_irq
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+static void
+out_str(const char *str_cs)
+{
+ if (CONFIG_COREBOOT) {
+ dprintf(1, "APM request '%s'\n", str_cs);
+ return;
+ }
+
+ u8 *s = (u8*)str_cs;
+ for (;;) {
+ u8 c = GET_GLOBAL(*s);
+ if (!c)
+ break;
+ outb(c, PORT_BIOS_APM);
+ s++;
+ }
+}
+
+// APM installation check
+static void
+handle_155300(struct bregs *regs)
+{
+ regs->ah = 1; // APM major version
+ regs->al = 2; // APM minor version
+ regs->bh = 'P';
+ regs->bl = 'M';
+ // bit 0 : 16 bit interface supported
+ // bit 1 : 32 bit interface supported
+ regs->cx = 0x03;
+ set_success(regs);
+}
+
+// APM real mode interface connect
+static void
+handle_155301(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// Assembler entry points defined in romlayout.S
+extern void entry_apm16(void);
+extern void entry_apm32(void);
+
+// APM 16 bit protected mode interface connect
+static void
+handle_155302(struct bregs *regs)
+{
+ regs->bx = (u32)entry_apm16;
+ regs->ax = SEG_BIOS; // 16 bit code segment base
+ regs->si = 0xfff0; // 16 bit code segment size
+ regs->cx = SEG_BIOS; // data segment address
+ regs->di = 0xfff0; // data segment length
+ set_success(regs);
+}
+
+// APM 32 bit protected mode interface connect
+static void
+handle_155303(struct bregs *regs)
+{
+ regs->ax = SEG_BIOS; // 32 bit code segment base
+ regs->ebx = (u32)entry_apm32;
+ regs->cx = SEG_BIOS; // 16 bit code segment base
+ // 32 bit code segment size (low 16 bits)
+ // 16 bit code segment size (high 16 bits)
+ regs->esi = 0xfff0fff0;
+ regs->dx = SEG_BIOS; // data segment address
+ regs->di = 0xfff0; // data segment length
+ set_success(regs);
+}
+
+// APM interface disconnect
+static void
+handle_155304(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// APM cpu idle
+static void
+handle_155305(struct bregs *regs)
+{
+ wait_irq();
+ set_success(regs);
+}
+
+// APM cpu busy
+static void
+handle_155306(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+void
+apm_shutdown(void)
+{
+ irq_disable();
+ out_str("Shutdown");
+ for (;;)
+ hlt();
+}
+
+// APM Set Power State
+static void
+handle_155307(struct bregs *regs)
+{
+ if (regs->bx != 1) {
+ set_success(regs);
+ return;
+ }
+ switch (regs->cx) {
+ case 1:
+ out_str("Standby");
+ break;
+ case 2:
+ out_str("Suspend");
+ break;
+ case 3:
+ apm_shutdown();
+ break;
+ }
+ set_success(regs);
+}
+
+static void
+handle_155308(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// Get Power Status
+static void
+handle_15530a(struct bregs *regs)
+{
+ regs->bh = 0x01; // on line
+ regs->bl = 0xff; // unknown battery status
+ regs->ch = 0x80; // no system battery
+ regs->cl = 0xff; // unknown remaining time
+ regs->dx = 0xffff; // unknown remaining time
+ regs->si = 0x00; // zero battery
+ set_success(regs);
+}
+
+#define RET_ENOEVENT 0x80
+
+// Get PM Event
+static void
+handle_15530b(struct bregs *regs)
+{
+ set_code_invalid_silent(regs, RET_ENOEVENT);
+}
+
+// APM Driver Version
+static void
+handle_15530e(struct bregs *regs)
+{
+ regs->ah = 1;
+ regs->al = 2;
+ set_success(regs);
+}
+
+// APM Engage / Disengage
+static void
+handle_15530f(struct bregs *regs)
+{
+ set_success(regs);
+}
+
+// APM Get Capabilities
+static void
+handle_155310(struct bregs *regs)
+{
+ regs->bl = 0;
+ regs->cx = 0;
+ set_success(regs);
+}
+
+static void
+handle_1553XX(struct bregs *regs)
+{
+ set_unimplemented(regs);
+}
+
+void
+handle_1553(struct bregs *regs)
+{
+ if (! CONFIG_APMBIOS) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+
+ //debug_stub(regs);
+ switch (regs->al) {
+ case 0x00: handle_155300(regs); break;
+ case 0x01: handle_155301(regs); break;
+ case 0x02: handle_155302(regs); break;
+ case 0x03: handle_155303(regs); break;
+ case 0x04: handle_155304(regs); break;
+ case 0x05: handle_155305(regs); break;
+ case 0x06: handle_155306(regs); break;
+ case 0x07: handle_155307(regs); break;
+ case 0x08: handle_155308(regs); break;
+ case 0x0a: handle_15530a(regs); break;
+ case 0x0b: handle_15530b(regs); break;
+ case 0x0e: handle_15530e(regs); break;
+ case 0x0f: handle_15530f(regs); break;
+ case 0x10: handle_155310(regs); break;
+ default: handle_1553XX(regs); break;
+ }
+}
+
+void VISIBLE16
+handle_apm16(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_apm);
+ handle_1553(regs);
+}
+
+void VISIBLE32SEG
+handle_apm32(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_apm);
+ handle_1553(regs);
+}
--- /dev/null
+// Generate assembler offsets.
+
+#include "gen-defs.h" // OFFSET
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // struct bios_data_area_s
+
+/* workaround for a warning with -Wmissing-prototypes */
+void foo(void) VISIBLE16;
+
+void foo(void)
+{
+ COMMENT("BREGS");
+ OFFSET(BREGS_es, bregs, es);
+ OFFSET(BREGS_ds, bregs, ds);
+ OFFSET(BREGS_eax, bregs, eax);
+ OFFSET(BREGS_ebx, bregs, ebx);
+ OFFSET(BREGS_ecx, bregs, ecx);
+ OFFSET(BREGS_edx, bregs, edx);
+ OFFSET(BREGS_ebp, bregs, ebp);
+ OFFSET(BREGS_esi, bregs, esi);
+ OFFSET(BREGS_edi, bregs, edi);
+ OFFSET(BREGS_flags, bregs, flags);
+ OFFSET(BREGS_code, bregs, code);
+
+ COMMENT("BDA");
+ OFFSET(BDA_ebda_seg, bios_data_area_s, ebda_seg);
+
+ COMMENT("EBDA");
+ DEFINE(EBDA_OFFSET_TOP_STACK, EBDA_OFFSET_TOP_STACK);
+ DEFINE(EBDA_SEGMENT_START, EBDA_SEGMENT_START);
+}
--- /dev/null
+// Low level ATA disk access
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u8
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "cmos.h" // inb_cmos
+#include "pic.h" // enable_hwirq
+#include "biosvar.h" // GET_EBDA
+#include "pci.h" // foreachpci
+#include "pci_ids.h" // PCI_CLASS_STORAGE_OTHER
+#include "pci_regs.h" // PCI_INTERRUPT_LINE
+#include "boot.h" // boot_add_hd
+#include "disk.h" // struct ata_s
+#include "ata.h" // ATA_CB_STAT
+#include "blockcmd.h" // CDB_CMD_READ_10
+
+#define IDE_TIMEOUT 32000 //32 seconds max for IDE ops
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Wait for the specified ide state
+static inline int
+await_ide(u8 mask, u8 flags, u16 base, u16 timeout)
+{
+ u64 end = calc_future_tsc(timeout);
+ for (;;) {
+ u8 status = inb(base+ATA_CB_STAT);
+ if ((status & mask) == flags)
+ return status;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+// Wait for the device to be not-busy.
+static int
+await_not_bsy(u16 base)
+{
+ return await_ide(ATA_CB_STAT_BSY, 0, base, IDE_TIMEOUT);
+}
+
+// Wait for the device to be ready.
+static int
+await_rdy(u16 base)
+{
+ return await_ide(ATA_CB_STAT_RDY, ATA_CB_STAT_RDY, base, IDE_TIMEOUT);
+}
+
+// Wait for ide state - pauses for one ata cycle first.
+static inline int
+pause_await_not_bsy(u16 iobase1, u16 iobase2)
+{
+ // Wait one PIO transfer cycle.
+ inb(iobase2 + ATA_CB_ASTAT);
+
+ return await_not_bsy(iobase1);
+}
+
+// Wait for ide state - pause for 400ns first.
+static inline int
+ndelay_await_not_bsy(u16 iobase1)
+{
+ ndelay(400);
+ return await_not_bsy(iobase1);
+}
+
+// Reset a drive
+static void
+ata_reset(struct atadrive_s *adrive_g)
+{
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u8 slave = GET_GLOBAL(adrive_g->slave);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ dprintf(6, "ata_reset drive=%p\n", &adrive_g->drive);
+ // Pulse SRST
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN | ATA_CB_DC_SRST, iobase2+ATA_CB_DC);
+ udelay(5);
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC);
+ msleep(2);
+
+ // wait for device to become not busy.
+ int status = await_not_bsy(iobase1);
+ if (status < 0)
+ goto done;
+ if (slave) {
+ // Change device.
+ u64 end = calc_future_tsc(IDE_TIMEOUT);
+ for (;;) {
+ outb(ATA_CB_DH_DEV1, iobase1 + ATA_CB_DH);
+ status = ndelay_await_not_bsy(iobase1);
+ if (status < 0)
+ goto done;
+ if (inb(iobase1 + ATA_CB_DH) == ATA_CB_DH_DEV1)
+ break;
+ // Change drive request failed to take effect - retry.
+ if (check_tsc(end)) {
+ warn_timeout();
+ goto done;
+ }
+ }
+ } else {
+ // QEMU doesn't reset dh on reset, so set it explicitly.
+ outb(ATA_CB_DH_DEV0, iobase1 + ATA_CB_DH);
+ }
+
+ // On a user-reset request, wait for RDY if it is an ATA device.
+ u8 type=GET_GLOBAL(adrive_g->drive.type);
+ if (type == DTYPE_ATA)
+ status = await_rdy(iobase1);
+
+done:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+
+ dprintf(6, "ata_reset exit status=%x\n", status);
+}
+
+// Check for drive RDY for 16bit interface command.
+static int
+isready(struct atadrive_s *adrive_g)
+{
+ // Read the status from controller
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u8 status = inb(iobase1 + ATA_CB_STAT);
+ if ((status & (ATA_CB_STAT_BSY|ATA_CB_STAT_RDY)) == ATA_CB_STAT_RDY)
+ return DISK_RET_SUCCESS;
+ return DISK_RET_ENOTREADY;
+}
+
+// Default 16bit command demuxer for ATA and ATAPI devices.
+static int
+process_ata_misc_op(struct disk_op_s *op)
+{
+ if (!CONFIG_ATA)
+ return 0;
+
+ struct atadrive_s *adrive_g = container_of(
+ op->drive_g, struct atadrive_s, drive);
+ switch (op->command) {
+ case CMD_RESET:
+ ata_reset(adrive_g);
+ return DISK_RET_SUCCESS;
+ case CMD_ISREADY:
+ return isready(adrive_g);
+ case CMD_FORMAT:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+
+/****************************************************************
+ * ATA send command
+ ****************************************************************/
+
+struct ata_pio_command {
+ u8 feature;
+ u8 sector_count;
+ u8 lba_low;
+ u8 lba_mid;
+ u8 lba_high;
+ u8 device;
+ u8 command;
+
+ u8 feature2;
+ u8 sector_count2;
+ u8 lba_low2;
+ u8 lba_mid2;
+ u8 lba_high2;
+};
+
+// Send an ata command to the drive.
+static int
+send_cmd(struct atadrive_s *adrive_g, struct ata_pio_command *cmd)
+{
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u8 slave = GET_GLOBAL(adrive_g->slave);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+
+ // Select device
+ int status = await_not_bsy(iobase1);
+ if (status < 0)
+ return status;
+ u8 newdh = ((cmd->device & ~ATA_CB_DH_DEV1)
+ | (slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0));
+ u8 olddh = inb(iobase1 + ATA_CB_DH);
+ outb(newdh, iobase1 + ATA_CB_DH);
+ if ((olddh ^ newdh) & (1<<4)) {
+ // Was a device change - wait for device to become not busy.
+ status = ndelay_await_not_bsy(iobase1);
+ if (status < 0)
+ return status;
+ }
+
+ // Check for ATA_CMD_(READ|WRITE)_(SECTORS|DMA)_EXT commands.
+ if ((cmd->command & ~0x11) == ATA_CMD_READ_SECTORS_EXT) {
+ outb(cmd->feature2, iobase1 + ATA_CB_FR);
+ outb(cmd->sector_count2, iobase1 + ATA_CB_SC);
+ outb(cmd->lba_low2, iobase1 + ATA_CB_SN);
+ outb(cmd->lba_mid2, iobase1 + ATA_CB_CL);
+ outb(cmd->lba_high2, iobase1 + ATA_CB_CH);
+ }
+ outb(cmd->feature, iobase1 + ATA_CB_FR);
+ outb(cmd->sector_count, iobase1 + ATA_CB_SC);
+ outb(cmd->lba_low, iobase1 + ATA_CB_SN);
+ outb(cmd->lba_mid, iobase1 + ATA_CB_CL);
+ outb(cmd->lba_high, iobase1 + ATA_CB_CH);
+ outb(cmd->command, iobase1 + ATA_CB_CMD);
+
+ return 0;
+}
+
+// Wait for data after calling 'send_cmd'.
+static int
+ata_wait_data(u16 iobase1)
+{
+ int status = ndelay_await_not_bsy(iobase1);
+ if (status < 0)
+ return status;
+
+ if (status & ATA_CB_STAT_ERR) {
+ dprintf(6, "send_cmd : read error (status=%02x err=%02x)\n"
+ , status, inb(iobase1 + ATA_CB_ERR));
+ return -4;
+ }
+ if (!(status & ATA_CB_STAT_DRQ)) {
+ dprintf(6, "send_cmd : DRQ not set (status %02x)\n", status);
+ return -5;
+ }
+
+ return 0;
+}
+
+// Send an ata command that does not transfer any further data.
+int
+ata_cmd_nondata(struct atadrive_s *adrive_g, struct ata_pio_command *cmd)
+{
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ // Disable interrupts
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+ int ret = send_cmd(adrive_g, cmd);
+ if (ret)
+ goto fail;
+ ret = ndelay_await_not_bsy(iobase1);
+ if (ret < 0)
+ goto fail;
+
+ if (ret & ATA_CB_STAT_ERR) {
+ dprintf(6, "nondata cmd : read error (status=%02x err=%02x)\n"
+ , ret, inb(iobase1 + ATA_CB_ERR));
+ ret = -4;
+ goto fail;
+ }
+ if (ret & ATA_CB_STAT_DRQ) {
+ dprintf(6, "nondata cmd : DRQ set (status %02x)\n", ret);
+ ret = -5;
+ goto fail;
+ }
+
+fail:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+
+ return ret;
+}
+
+
+/****************************************************************
+ * ATA PIO transfers
+ ****************************************************************/
+
+// Transfer 'op->count' blocks (of 'blocksize' bytes) to/from drive
+// 'op->drive_g'.
+static int
+ata_pio_transfer(struct disk_op_s *op, int iswrite, int blocksize)
+{
+ dprintf(16, "ata_pio_transfer id=%p write=%d count=%d bs=%d buf=%p\n"
+ , op->drive_g, iswrite, op->count, blocksize, op->buf_fl);
+
+ struct atadrive_s *adrive_g = container_of(
+ op->drive_g, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+ int count = op->count;
+ void *buf_fl = op->buf_fl;
+ int status;
+ for (;;) {
+ if (iswrite) {
+ // Write data to controller
+ dprintf(16, "Write sector id=%p dest=%p\n", op->drive_g, buf_fl);
+ if (CONFIG_ATA_PIO32)
+ outsl_fl(iobase1, buf_fl, blocksize / 4);
+ else
+ outsw_fl(iobase1, buf_fl, blocksize / 2);
+ } else {
+ // Read data from controller
+ dprintf(16, "Read sector id=%p dest=%p\n", op->drive_g, buf_fl);
+ if (CONFIG_ATA_PIO32)
+ insl_fl(iobase1, buf_fl, blocksize / 4);
+ else
+ insw_fl(iobase1, buf_fl, blocksize / 2);
+ }
+ buf_fl += blocksize;
+
+ status = pause_await_not_bsy(iobase1, iobase2);
+ if (status < 0) {
+ // Error
+ op->count -= count;
+ return status;
+ }
+
+ count--;
+ if (!count)
+ break;
+ status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR);
+ if (status != ATA_CB_STAT_DRQ) {
+ dprintf(6, "ata_pio_transfer : more sectors left (status %02x)\n"
+ , status);
+ op->count -= count;
+ return -6;
+ }
+ }
+
+ status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ
+ | ATA_CB_STAT_ERR);
+ if (!iswrite)
+ status &= ~ATA_CB_STAT_DF;
+ if (status != 0) {
+ dprintf(6, "ata_pio_transfer : no sectors left (status %02x)\n", status);
+ return -7;
+ }
+
+ return 0;
+}
+
+
+/****************************************************************
+ * ATA DMA transfers
+ ****************************************************************/
+
+#define BM_CMD 0
+#define BM_CMD_MEMWRITE 0x08
+#define BM_CMD_START 0x01
+#define BM_STATUS 2
+#define BM_STATUS_IRQ 0x04
+#define BM_STATUS_ERROR 0x02
+#define BM_STATUS_ACTIVE 0x01
+#define BM_TABLE 4
+
+struct sff_dma_prd {
+ u32 buf_fl;
+ u32 count;
+};
+
+// Check if DMA available and setup transfer if so.
+static int
+ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize)
+{
+ if (! CONFIG_ATA_DMA)
+ return -1;
+ u32 dest = (u32)op->buf_fl;
+ if (dest & 1)
+ // Need minimum alignment of 1.
+ return -1;
+ struct atadrive_s *adrive_g = container_of(
+ op->drive_g, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster);
+ if (! iomaster)
+ return -1;
+ u32 bytes = op->count * blocksize;
+ if (! bytes)
+ return -1;
+
+ // Build PRD dma structure.
+ struct sff_dma_prd *dma = MAKE_FLATPTR(
+ get_ebda_seg()
+ , (void*)offsetof(struct extended_bios_data_area_s, extra_stack));
+ struct sff_dma_prd *origdma = dma;
+ while (bytes) {
+ if (dma >= &origdma[16])
+ // Too many descriptors..
+ return -1;
+ u32 count = bytes;
+ u32 max = 0x10000 - (dest & 0xffff);
+ if (count > max)
+ count = max;
+
+ SET_FLATPTR(dma->buf_fl, dest);
+ bytes -= count;
+ if (!bytes)
+ // Last descriptor.
+ count |= 1<<31;
+ dprintf(16, "dma@%p: %08x %08x\n", dma, dest, count);
+ dest += count;
+ SET_FLATPTR(dma->count, count);
+ dma++;
+ }
+
+ // Program bus-master controller.
+ outl((u32)origdma, iomaster + BM_TABLE);
+ u8 oldcmd = inb(iomaster + BM_CMD) & ~(BM_CMD_MEMWRITE|BM_CMD_START);
+ outb(oldcmd | (iswrite ? 0x00 : BM_CMD_MEMWRITE), iomaster + BM_CMD);
+ outb(BM_STATUS_ERROR|BM_STATUS_IRQ, iomaster + BM_STATUS);
+
+ return 0;
+}
+
+// Transfer data using DMA.
+static int
+ata_dma_transfer(struct disk_op_s *op)
+{
+ if (! CONFIG_ATA_DMA)
+ return -1;
+ dprintf(16, "ata_dma_transfer id=%p buf=%p\n", op->drive_g, op->buf_fl);
+
+ struct atadrive_s *adrive_g = container_of(
+ op->drive_g, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u16 iomaster = GET_GLOBALFLAT(chan_gf->iomaster);
+
+ // Start bus-master controller.
+ u8 oldcmd = inb(iomaster + BM_CMD);
+ outb(oldcmd | BM_CMD_START, iomaster + BM_CMD);
+
+ u64 end = calc_future_tsc(IDE_TIMEOUT);
+ u8 status;
+ for (;;) {
+ status = inb(iomaster + BM_STATUS);
+ if (status & BM_STATUS_IRQ)
+ break;
+ // Transfer in progress
+ if (check_tsc(end)) {
+ // Timeout.
+ warn_timeout();
+ break;
+ }
+ yield();
+ }
+ outb(oldcmd & ~BM_CMD_START, iomaster + BM_CMD);
+
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+ int idestatus = pause_await_not_bsy(iobase1, iobase2);
+
+ if ((status & (BM_STATUS_IRQ|BM_STATUS_ACTIVE)) == BM_STATUS_IRQ
+ && idestatus >= 0x00
+ && (idestatus & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ
+ | ATA_CB_STAT_ERR)) == 0x00)
+ // Success.
+ return 0;
+
+ dprintf(6, "IDE DMA error (dma=%x ide=%x/%x/%x)\n", status, idestatus
+ , inb(iobase2 + ATA_CB_ASTAT), inb(iobase1 + ATA_CB_ERR));
+ op->count = 0;
+ return -1;
+}
+
+
+/****************************************************************
+ * ATA hard drive functions
+ ****************************************************************/
+
+// Transfer data to harddrive using PIO protocol.
+static int
+ata_pio_cmd_data(struct disk_op_s *op, int iswrite, struct ata_pio_command *cmd)
+{
+ struct atadrive_s *adrive_g = container_of(
+ op->drive_g, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ // Disable interrupts
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+ int ret = send_cmd(adrive_g, cmd);
+ if (ret)
+ goto fail;
+ ret = ata_wait_data(iobase1);
+ if (ret)
+ goto fail;
+ ret = ata_pio_transfer(op, iswrite, DISK_SECTOR_SIZE);
+
+fail:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+ return ret;
+}
+
+// Transfer data to harddrive using DMA protocol.
+static int
+ata_dma_cmd_data(struct disk_op_s *op, struct ata_pio_command *cmd)
+{
+ if (! CONFIG_ATA_DMA)
+ return -1;
+ struct atadrive_s *adrive_g = container_of(
+ op->drive_g, struct atadrive_s, drive);
+ int ret = send_cmd(adrive_g, cmd);
+ if (ret)
+ return ret;
+ return ata_dma_transfer(op);
+}
+
+// Read/write count blocks from a harddrive.
+static int
+ata_readwrite(struct disk_op_s *op, int iswrite)
+{
+ u64 lba = op->lba;
+
+ int usepio = ata_try_dma(op, iswrite, DISK_SECTOR_SIZE);
+
+ struct ata_pio_command cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ if (op->count >= (1<<8) || lba + op->count >= (1<<28)) {
+ cmd.sector_count2 = op->count >> 8;
+ cmd.lba_low2 = lba >> 24;
+ cmd.lba_mid2 = lba >> 32;
+ cmd.lba_high2 = lba >> 40;
+ lba &= 0xffffff;
+
+ if (usepio)
+ cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS_EXT
+ : ATA_CMD_READ_SECTORS_EXT);
+ else
+ cmd.command = (iswrite ? ATA_CMD_WRITE_DMA_EXT
+ : ATA_CMD_READ_DMA_EXT);
+ } else {
+ if (usepio)
+ cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS
+ : ATA_CMD_READ_SECTORS);
+ else
+ cmd.command = (iswrite ? ATA_CMD_WRITE_DMA
+ : ATA_CMD_READ_DMA);
+ }
+
+ cmd.sector_count = op->count;
+ cmd.lba_low = lba;
+ cmd.lba_mid = lba >> 8;
+ cmd.lba_high = lba >> 16;
+ cmd.device = ((lba >> 24) & 0xf) | ATA_CB_DH_LBA;
+
+ int ret;
+ if (usepio)
+ ret = ata_pio_cmd_data(op, iswrite, &cmd);
+ else
+ ret = ata_dma_cmd_data(op, &cmd);
+ if (ret)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+// 16bit command demuxer for ATA harddrives.
+int
+process_ata_op(struct disk_op_s *op)
+{
+ if (!CONFIG_ATA)
+ return 0;
+
+ switch (op->command) {
+ case CMD_READ:
+ return ata_readwrite(op, 0);
+ case CMD_WRITE:
+ return ata_readwrite(op, 1);
+ default:
+ return process_ata_misc_op(op);
+ }
+}
+
+
+/****************************************************************
+ * ATAPI functions
+ ****************************************************************/
+
+#define CDROM_CDB_SIZE 12
+
+// Low-level atapi command transmit function.
+int
+atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (! CONFIG_ATA)
+ return 0;
+
+ struct atadrive_s *adrive_g = container_of(
+ op->drive_g, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u16 iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+
+ struct ata_pio_command cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.lba_mid = blocksize;
+ cmd.lba_high = blocksize >> 8;
+ cmd.command = ATA_CMD_PACKET;
+
+ // Disable interrupts
+ outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC);
+
+ int ret = send_cmd(adrive_g, &cmd);
+ if (ret)
+ goto fail;
+ ret = ata_wait_data(iobase1);
+ if (ret)
+ goto fail;
+
+ // Send command to device
+ outsw_fl(iobase1, MAKE_FLATPTR(GET_SEG(SS), cdbcmd), CDROM_CDB_SIZE / 2);
+
+ int status = pause_await_not_bsy(iobase1, iobase2);
+ if (status < 0) {
+ ret = status;
+ goto fail;
+ }
+
+ if (status & ATA_CB_STAT_ERR) {
+ u8 err = inb(iobase1 + ATA_CB_ERR);
+ // skip "Not Ready"
+ if (err != 0x20)
+ dprintf(6, "send_atapi_cmd : read error (status=%02x err=%02x)\n"
+ , status, err);
+ ret = -2;
+ goto fail;
+ }
+ if (!(status & ATA_CB_STAT_DRQ)) {
+ dprintf(6, "send_atapi_cmd : DRQ not set (status %02x)\n", status);
+ ret = -3;
+ goto fail;
+ }
+
+ ret = ata_pio_transfer(op, 0, blocksize);
+
+fail:
+ // Enable interrupts
+ outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC);
+ if (ret)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+// 16bit command demuxer for ATAPI cdroms.
+int
+process_atapi_op(struct disk_op_s *op)
+{
+ if (!CONFIG_ATA)
+ return 0;
+ switch (op->command) {
+ case CMD_READ:
+ return cdb_read(op);
+ case CMD_FORMAT:
+ case CMD_WRITE:
+ return DISK_RET_EWRITEPROTECT;
+ default:
+ return process_ata_misc_op(op);
+ }
+}
+
+
+/****************************************************************
+ * ATA detect and init
+ ****************************************************************/
+
+// Send an identify device or identify device packet command.
+static int
+send_ata_identity(struct atadrive_s *adrive_g, u16 *buffer, int command)
+{
+ memset(buffer, 0, DISK_SECTOR_SIZE);
+
+ struct disk_op_s dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_g = &adrive_g->drive;
+ dop.count = 1;
+ dop.lba = 1;
+ dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
+
+ struct ata_pio_command cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = command;
+
+ return ata_pio_cmd_data(&dop, 0, &cmd);
+}
+
+// Extract the ATA/ATAPI version info.
+int
+ata_extract_version(u16 *buffer)
+{
+ // Extract ATA/ATAPI version.
+ u16 ataversion = buffer[80];
+ u8 version;
+ for (version=15; version>0; version--)
+ if (ataversion & (1<<version))
+ break;
+ return version;
+}
+
+#define MAXMODEL 40
+
+// Extract the ATA/ATAPI model info.
+char *
+ata_extract_model(char *model, u32 size, u16 *buffer)
+{
+ // Read model name
+ int i;
+ for (i=0; i<size/2; i++)
+ *(u16*)&model[i*2] = ntohs(buffer[27+i]);
+ model[size] = 0x00;
+ nullTrailingSpace(model);
+ return model;
+}
+
+// Common init code between ata and atapi
+static struct atadrive_s *
+init_atadrive(struct atadrive_s *dummy, u16 *buffer)
+{
+ struct atadrive_s *adrive_g = malloc_fseg(sizeof(*adrive_g));
+ if (!adrive_g) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(adrive_g, 0, sizeof(*adrive_g));
+ adrive_g->chan_gf = dummy->chan_gf;
+ adrive_g->slave = dummy->slave;
+ adrive_g->drive.cntl_id = adrive_g->chan_gf->chanid * 2 + dummy->slave;
+ adrive_g->drive.removable = (buffer[0] & 0x80) ? 1 : 0;
+ return adrive_g;
+}
+
+// Detect if the given drive is an atapi - initialize it if so.
+static struct atadrive_s *
+init_drive_atapi(struct atadrive_s *dummy, u16 *buffer)
+{
+ // Send an IDENTIFY_DEVICE_PACKET command to device
+ int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_PACKET_DEVICE);
+ if (ret)
+ return NULL;
+
+ // Success - setup as ATAPI.
+ struct atadrive_s *adrive_g = init_atadrive(dummy, buffer);
+ if (!adrive_g)
+ return NULL;
+ adrive_g->drive.type = DTYPE_ATAPI;
+ adrive_g->drive.blksize = CDROM_SECTOR_SIZE;
+ adrive_g->drive.sectors = (u64)-1;
+ u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05;
+ char model[MAXMODEL+1];
+ char *desc = znprintf(MAXDESCSIZE
+ , "DVD/CD [ata%d-%d: %s ATAPI-%d %s]"
+ , adrive_g->chan_gf->chanid, adrive_g->slave
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer)
+ , (iscd ? "DVD/CD" : "Device"));
+ dprintf(1, "%s\n", desc);
+
+ // fill cdidmap
+ if (iscd) {
+ int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_tmp,
+ adrive_g->chan_gf->chanid,
+ adrive_g->slave);
+ boot_add_cd(&adrive_g->drive, desc, prio);
+ }
+
+ return adrive_g;
+}
+
+// Detect if the given drive is a regular ata drive - initialize it if so.
+static struct atadrive_s *
+init_drive_ata(struct atadrive_s *dummy, u16 *buffer)
+{
+ // Send an IDENTIFY_DEVICE command to device
+ int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_DEVICE);
+ if (ret)
+ return NULL;
+
+ // Success - setup as ATA.
+ struct atadrive_s *adrive_g = init_atadrive(dummy, buffer);
+ if (!adrive_g)
+ return NULL;
+ adrive_g->drive.type = DTYPE_ATA;
+ adrive_g->drive.blksize = DISK_SECTOR_SIZE;
+
+ adrive_g->drive.pchs.cylinders = buffer[1];
+ adrive_g->drive.pchs.heads = buffer[3];
+ adrive_g->drive.pchs.spt = buffer[6];
+
+ u64 sectors;
+ if (buffer[83] & (1 << 10)) // word 83 - lba48 support
+ sectors = *(u64*)&buffer[100]; // word 100-103
+ else
+ sectors = *(u32*)&buffer[60]; // word 60 and word 61
+ adrive_g->drive.sectors = sectors;
+ u64 adjsize = sectors >> 11;
+ char adjprefix = 'M';
+ if (adjsize >= (1 << 16)) {
+ adjsize >>= 10;
+ adjprefix = 'G';
+ }
+ char model[MAXMODEL+1];
+ char *desc = znprintf(MAXDESCSIZE
+ , "ata%d-%d: %s ATA-%d Hard-Disk (%u %ciBytes)"
+ , adrive_g->chan_gf->chanid, adrive_g->slave
+ , ata_extract_model(model, MAXMODEL, buffer)
+ , ata_extract_version(buffer)
+ , (u32)adjsize, adjprefix);
+ dprintf(1, "%s\n", desc);
+
+ int prio = bootprio_find_ata_device(adrive_g->chan_gf->pci_tmp,
+ adrive_g->chan_gf->chanid,
+ adrive_g->slave);
+ // Register with bcv system.
+ boot_add_hd(&adrive_g->drive, desc, prio);
+
+ return adrive_g;
+}
+
+static u64 SpinupEnd;
+
+// Wait for non-busy status and check for "floating bus" condition.
+static int
+powerup_await_non_bsy(u16 base)
+{
+ u8 orstatus = 0;
+ u8 status;
+ for (;;) {
+ status = inb(base+ATA_CB_STAT);
+ if (!(status & ATA_CB_STAT_BSY))
+ break;
+ orstatus |= status;
+ if (orstatus == 0xff) {
+ dprintf(4, "powerup IDE floating\n");
+ return orstatus;
+ }
+ if (check_tsc(SpinupEnd)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ dprintf(6, "powerup iobase=%x st=%x\n", base, status);
+ return status;
+}
+
+// Detect any drives attached to a given controller.
+static void
+ata_detect(void *data)
+{
+ struct ata_channel_s *chan_gf = data;
+ struct atadrive_s dummy;
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.chan_gf = chan_gf;
+ // Device detection
+ int didreset = 0;
+ u8 slave;
+ for (slave=0; slave<=1; slave++) {
+ // Wait for not-bsy.
+ u16 iobase1 = chan_gf->iobase1;
+ int status = powerup_await_non_bsy(iobase1);
+ if (status < 0)
+ continue;
+ u8 newdh = slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0;
+ outb(newdh, iobase1+ATA_CB_DH);
+ ndelay(400);
+ status = powerup_await_non_bsy(iobase1);
+ if (status < 0)
+ continue;
+
+ // Check if ioport registers look valid.
+ outb(newdh, iobase1+ATA_CB_DH);
+ u8 dh = inb(iobase1+ATA_CB_DH);
+ outb(0x55, iobase1+ATA_CB_SC);
+ outb(0xaa, iobase1+ATA_CB_SN);
+ u8 sc = inb(iobase1+ATA_CB_SC);
+ u8 sn = inb(iobase1+ATA_CB_SN);
+ dprintf(6, "ata_detect ata%d-%d: sc=%x sn=%x dh=%x\n"
+ , chan_gf->chanid, slave, sc, sn, dh);
+ if (sc != 0x55 || sn != 0xaa || dh != newdh)
+ continue;
+
+ // Prepare new drive.
+ dummy.slave = slave;
+
+ // reset the channel
+ if (!didreset) {
+ ata_reset(&dummy);
+ didreset = 1;
+ }
+
+ // check for ATAPI
+ u16 buffer[256];
+ struct atadrive_s *adrive_g = init_drive_atapi(&dummy, buffer);
+ if (!adrive_g) {
+ // Didn't find an ATAPI drive - look for ATA drive.
+ u8 st = inb(iobase1+ATA_CB_STAT);
+ if (!st)
+ // Status not set - can't be a valid drive.
+ continue;
+
+ // Wait for RDY.
+ int ret = await_rdy(iobase1);
+ if (ret < 0)
+ continue;
+
+ // check for ATA.
+ adrive_g = init_drive_ata(&dummy, buffer);
+ if (!adrive_g)
+ // No ATA drive found
+ continue;
+ }
+
+ u16 resetresult = buffer[93];
+ dprintf(6, "ata_detect resetresult=%04x\n", resetresult);
+ if (!slave && (resetresult & 0xdf61) == 0x4041)
+ // resetresult looks valid and device 0 is responding to
+ // device 1 requests - device 1 must not be present - skip
+ // detection.
+ break;
+ }
+}
+
+// Initialize an ata controller and detect its drives.
+static void
+init_controller(struct pci_device *pci, int irq
+ , u32 port1, u32 port2, u32 master)
+{
+ static int chanid = 0;
+ struct ata_channel_s *chan_gf = malloc_fseg(sizeof(*chan_gf));
+ if (!chan_gf) {
+ warn_noalloc();
+ return;
+ }
+ chan_gf->chanid = chanid++;
+ chan_gf->irq = irq;
+ chan_gf->pci_bdf = pci ? pci->bdf : -1;
+ chan_gf->pci_tmp = pci;
+ chan_gf->iobase1 = port1;
+ chan_gf->iobase2 = port2;
+ chan_gf->iomaster = master;
+ dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n"
+ , chanid, port1, port2, master, irq, chan_gf->pci_bdf);
+ run_thread(ata_detect, chan_gf);
+}
+
+#define IRQ_ATA1 14
+#define IRQ_ATA2 15
+
+// Handle controllers on an ATA PCI device.
+static void
+init_pciata(struct pci_device *pci, u8 prog_if)
+{
+ pci->have_driver = 1;
+ u16 bdf = pci->bdf;
+ u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ int master = 0;
+ if (CONFIG_ATA_DMA && prog_if & 0x80) {
+ // Check for bus-mastering.
+ u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4);
+ if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+ master = bar & PCI_BASE_ADDRESS_IO_MASK;
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+ }
+ }
+
+ u32 port1, port2, irq;
+ if (prog_if & 1) {
+ port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_0)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_1)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ irq = pciirq;
+ } else {
+ port1 = PORT_ATA1_CMD_BASE;
+ port2 = PORT_ATA1_CTRL_BASE;
+ irq = IRQ_ATA1;
+ }
+ init_controller(pci, irq, port1, port2, master);
+
+ if (prog_if & 4) {
+ port1 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_2)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ port2 = (pci_config_readl(bdf, PCI_BASE_ADDRESS_3)
+ & PCI_BASE_ADDRESS_IO_MASK);
+ irq = pciirq;
+ } else {
+ port1 = PORT_ATA2_CMD_BASE;
+ port2 = PORT_ATA2_CTRL_BASE;
+ irq = IRQ_ATA2;
+ }
+ init_controller(pci, irq, port1, port2, master ? master + 8 : 0);
+}
+
+static void
+found_genericata(struct pci_device *pci, void *arg)
+{
+ init_pciata(pci, pci->prog_if);
+}
+
+static void
+found_compatibleahci(struct pci_device *pci, void *arg)
+{
+ if (CONFIG_AHCI)
+ // Already handled directly via native ahci interface.
+ return;
+ init_pciata(pci, 0x8f);
+}
+
+static const struct pci_device_id pci_ata_tbl[] = {
+ PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE
+ , found_genericata),
+ PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4391, found_compatibleahci),
+ PCI_DEVICE_END,
+};
+
+// Locate and init ata controllers.
+static void
+ata_init(void)
+{
+ if (!CONFIG_COREBOOT && !PCIDevices) {
+ // No PCI devices found - probably a QEMU "-M isapc" machine.
+ // Try using ISA ports for ATA controllers.
+ init_controller(NULL, IRQ_ATA1
+ , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0);
+ init_controller(NULL, IRQ_ATA2
+ , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0);
+ return;
+ }
+
+ // Scan PCI bus for ATA adapters
+ struct pci_device *pci;
+ foreachpci(pci) {
+ pci_init_device(pci_ata_tbl, pci, NULL);
+ }
+}
+
+void
+ata_setup(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_ATA)
+ return;
+
+ dprintf(3, "init hard drives\n");
+
+ SpinupEnd = calc_future_tsc(IDE_TIMEOUT);
+ ata_init();
+
+ SET_BDA(disk_control_byte, 0xc0);
+
+ enable_hwirq(14, FUNC16(entry_76));
+}
--- /dev/null
+#ifndef __ATA_H
+#define __ATA_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_MAX_ATA_INTERFACES
+#include "disk.h" // struct drive_s
+
+struct ata_channel_s {
+ u16 iobase1;
+ u16 iobase2;
+ u16 iomaster;
+ u8 irq;
+ u8 chanid;
+ int pci_bdf;
+ struct pci_device *pci_tmp;
+};
+
+struct atadrive_s {
+ struct drive_s drive;
+ struct ata_channel_s *chan_gf;
+ u8 slave;
+};
+
+// ata.c
+char *ata_extract_model(char *model, u32 size, u16 *buffer);
+int ata_extract_version(u16 *buffer);
+int cdrom_read(struct disk_op_s *op);
+int atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void ata_setup(void);
+int process_ata_op(struct disk_op_s *op);
+int process_atapi_op(struct disk_op_s *op);
+
+// Global defines -- ATA register and register bits.
+// command block & control block regs
+#define ATA_CB_DATA 0 // data reg in/out pio_base_addr1+0
+#define ATA_CB_ERR 1 // error in pio_base_addr1+1
+#define ATA_CB_FR 1 // feature reg out pio_base_addr1+1
+#define ATA_CB_SC 2 // sector count in/out pio_base_addr1+2
+#define ATA_CB_SN 3 // sector number in/out pio_base_addr1+3
+#define ATA_CB_CL 4 // cylinder low in/out pio_base_addr1+4
+#define ATA_CB_CH 5 // cylinder high in/out pio_base_addr1+5
+#define ATA_CB_DH 6 // device head in/out pio_base_addr1+6
+#define ATA_CB_STAT 7 // primary status in pio_base_addr1+7
+#define ATA_CB_CMD 7 // command out pio_base_addr1+7
+
+#define ATA_CB_ASTAT 2 // alternate status in pio_base_addr2+2
+#define ATA_CB_DC 2 // device control out pio_base_addr2+2
+#define ATA_CB_DA 3 // device address in pio_base_addr2+3
+
+#define ATA_CB_ER_ICRC 0x80 // ATA Ultra DMA bad CRC
+#define ATA_CB_ER_BBK 0x80 // ATA bad block
+#define ATA_CB_ER_UNC 0x40 // ATA uncorrected error
+#define ATA_CB_ER_MC 0x20 // ATA media change
+#define ATA_CB_ER_IDNF 0x10 // ATA id not found
+#define ATA_CB_ER_MCR 0x08 // ATA media change request
+#define ATA_CB_ER_ABRT 0x04 // ATA command aborted
+#define ATA_CB_ER_NTK0 0x02 // ATA track 0 not found
+#define ATA_CB_ER_NDAM 0x01 // ATA address mark not found
+
+#define ATA_CB_ER_P_SNSKEY 0xf0 // ATAPI sense key (mask)
+#define ATA_CB_ER_P_MCR 0x08 // ATAPI Media Change Request
+#define ATA_CB_ER_P_ABRT 0x04 // ATAPI command abort
+#define ATA_CB_ER_P_EOM 0x02 // ATAPI End of Media
+#define ATA_CB_ER_P_ILI 0x01 // ATAPI Illegal Length Indication
+
+// ATAPI Interrupt Reason bits in the Sector Count reg (CB_SC)
+#define ATA_CB_SC_P_TAG 0xf8 // ATAPI tag (mask)
+#define ATA_CB_SC_P_REL 0x04 // ATAPI release
+#define ATA_CB_SC_P_IO 0x02 // ATAPI I/O
+#define ATA_CB_SC_P_CD 0x01 // ATAPI C/D
+
+// bits 7-4 of the device/head (CB_DH) reg
+#define ATA_CB_DH_DEV0 0xa0 // select device 0
+#define ATA_CB_DH_DEV1 0xb0 // select device 1
+#define ATA_CB_DH_LBA 0x40 // use LBA
+
+// status reg (CB_STAT and CB_ASTAT) bits
+#define ATA_CB_STAT_BSY 0x80 // busy
+#define ATA_CB_STAT_RDY 0x40 // ready
+#define ATA_CB_STAT_DF 0x20 // device fault
+#define ATA_CB_STAT_WFT 0x20 // write fault (old name)
+#define ATA_CB_STAT_SKC 0x10 // seek complete
+#define ATA_CB_STAT_SERV 0x10 // service
+#define ATA_CB_STAT_DRQ 0x08 // data request
+#define ATA_CB_STAT_CORR 0x04 // corrected
+#define ATA_CB_STAT_IDX 0x02 // index
+#define ATA_CB_STAT_ERR 0x01 // error (ATA)
+#define ATA_CB_STAT_CHK 0x01 // check (ATAPI)
+
+// device control reg (CB_DC) bits
+#define ATA_CB_DC_HD15 0x08 // bit should always be set to one
+#define ATA_CB_DC_SRST 0x04 // soft reset
+#define ATA_CB_DC_NIEN 0x02 // disable interrupts
+
+// Most mandtory and optional ATA commands (from ATA-3),
+#define ATA_CMD_NOP 0x00
+#define ATA_CMD_CFA_REQUEST_EXT_ERR_CODE 0x03
+#define ATA_CMD_DEVICE_RESET 0x08
+#define ATA_CMD_RECALIBRATE 0x10
+#define ATA_CMD_READ_SECTORS 0x20
+#define ATA_CMD_READ_SECTORS_EXT 0x24
+#define ATA_CMD_READ_DMA_EXT 0x25
+#define ATA_CMD_READ_DMA_QUEUED_EXT 0x26
+#define ATA_CMD_READ_NATIVE_MAX_ADDRESS_EXT 0x27
+#define ATA_CMD_READ_MULTIPLE_EXT 0x29
+#define ATA_CMD_READ_LOG_EXT 0x2F
+#define ATA_CMD_WRITE_SECTORS 0x30
+#define ATA_CMD_WRITE_SECTORS_EXT 0x34
+#define ATA_CMD_WRITE_DMA_EXT 0x35
+#define ATA_CMD_WRITE_DMA_QUEUED_EXT 0x36
+#define ATA_CMD_SET_MAX_ADDRESS_EXT 0x37
+#define ATA_CMD_CFA_WRITE_SECTORS_WO_ERASE 0x38
+#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39
+#define ATA_CMD_WRITE_VERIFY 0x3C
+#define ATA_CMD_WRITE_LOG_EXT 0x3F
+#define ATA_CMD_READ_VERIFY_SECTORS 0x40
+#define ATA_CMD_READ_VERIFY_SECTORS_EXT 0x42
+#define ATA_CMD_FORMAT_TRACK 0x50
+#define ATA_CMD_SEEK 0x70
+#define ATA_CMD_CFA_TRANSLATE_SECTOR 0x87
+#define ATA_CMD_EXECUTE_DEVICE_DIAGNOSTIC 0x90
+#define ATA_CMD_INITIALIZE_DEVICE_PARAMETERS 0x91
+#define ATA_CMD_STANDBY_IMMEDIATE2 0x94
+#define ATA_CMD_IDLE_IMMEDIATE2 0x95
+#define ATA_CMD_STANDBY2 0x96
+#define ATA_CMD_IDLE2 0x97
+#define ATA_CMD_CHECK_POWER_MODE2 0x98
+#define ATA_CMD_SLEEP2 0x99
+#define ATA_CMD_PACKET 0xA0
+#define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1
+#define ATA_CMD_CFA_ERASE_SECTORS 0xC0
+#define ATA_CMD_READ_MULTIPLE 0xC4
+#define ATA_CMD_WRITE_MULTIPLE 0xC5
+#define ATA_CMD_SET_MULTIPLE_MODE 0xC6
+#define ATA_CMD_READ_DMA_QUEUED 0xC7
+#define ATA_CMD_READ_DMA 0xC8
+#define ATA_CMD_WRITE_DMA 0xCA
+#define ATA_CMD_WRITE_DMA_QUEUED 0xCC
+#define ATA_CMD_CFA_WRITE_MULTIPLE_WO_ERASE 0xCD
+#define ATA_CMD_STANDBY_IMMEDIATE 0xE0
+#define ATA_CMD_IDLE_IMMEDIATE 0xE1
+#define ATA_CMD_STANDBY 0xE2
+#define ATA_CMD_IDLE 0xE3
+#define ATA_CMD_READ_BUFFER 0xE4
+#define ATA_CMD_CHECK_POWER_MODE 0xE5
+#define ATA_CMD_SLEEP 0xE6
+#define ATA_CMD_FLUSH_CACHE 0xE7
+#define ATA_CMD_WRITE_BUFFER 0xE8
+#define ATA_CMD_IDENTIFY_DEVICE 0xEC
+#define ATA_CMD_SET_FEATURES 0xEF
+#define ATA_CMD_READ_NATIVE_MAX_ADDRESS 0xF8
+#define ATA_CMD_SET_MAX 0xF9
+
+#endif // ata.h
--- /dev/null
+// Coreboot interface support.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "pci.h" // struct pir_header
+#include "acpi.h" // struct rsdp_descriptor
+#include "mptable.h" // MPTABLE_SIGNATURE
+#include "smbios.h" // struct smbios_entry_point
+
+void
+copy_pir(void *pos)
+{
+ struct pir_header *p = pos;
+ if (p->signature != PIR_SIGNATURE)
+ return;
+ if (PirOffset)
+ return;
+ if (p->size < sizeof(*p))
+ return;
+ if (checksum(pos, p->size) != 0)
+ return;
+ void *newpos = malloc_fseg(p->size);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying PIR from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, p->size);
+ PirOffset = (u32)newpos - BUILD_BIOS_ADDR;
+}
+
+void
+copy_mptable(void *pos)
+{
+ struct mptable_floating_s *p = pos;
+ if (p->signature != MPTABLE_SIGNATURE)
+ return;
+ if (!p->physaddr)
+ return;
+ if (checksum(pos, sizeof(*p)) != 0)
+ return;
+ u32 length = p->length * 16;
+ u16 mpclength = ((struct mptable_config_s *)p->physaddr)->length;
+ struct mptable_floating_s *newpos = malloc_fseg(length + mpclength);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying MPTABLE from %p/%x to %p\n", pos, p->physaddr, newpos);
+ memcpy(newpos, pos, length);
+ newpos->physaddr = (u32)newpos + length;
+ newpos->checksum -= checksum(newpos, sizeof(*newpos));
+ memcpy((void*)newpos + length, (void*)p->physaddr, mpclength);
+}
+
+void
+copy_acpi_rsdp(void *pos)
+{
+ if (RsdpAddr)
+ return;
+ struct rsdp_descriptor *p = pos;
+ if (p->signature != RSDP_SIGNATURE)
+ return;
+ u32 length = 20;
+ if (checksum(pos, length) != 0)
+ return;
+ if (p->revision > 1) {
+ length = p->length;
+ if (checksum(pos, length) != 0)
+ return;
+ }
+ void *newpos = malloc_fseg(length);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying ACPI RSDP from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, length);
+ RsdpAddr = newpos;
+}
+
+void
+copy_smbios(void *pos)
+{
+ if (SMBiosAddr)
+ return;
+ struct smbios_entry_point *p = pos;
+ if (memcmp(p->anchor_string, "_SM_", 4))
+ return;
+ if (checksum(pos, 0x10) != 0)
+ return;
+ if (memcmp(p->intermediate_anchor_string, "_DMI_", 5))
+ return;
+ if (checksum(pos+0x10, p->length-0x10) != 0)
+ return;
+ struct smbios_entry_point *newpos = malloc_fseg(p->length);
+ if (!newpos) {
+ warn_noalloc();
+ return;
+ }
+ dprintf(1, "Copying SMBIOS entry point from %p to %p\n", pos, newpos);
+ memcpy(newpos, pos, p->length);
+ SMBiosAddr = newpos;
+}
--- /dev/null
+// Variable layouts of bios.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __BIOSVAR_H
+#define __BIOSVAR_H
+
+#include "types.h" // u8
+#include "farptr.h" // GET_FARVAR
+#include "config.h" // CONFIG_*
+#include "disk.h" // struct chs_s
+
+
+/****************************************************************
+ * Interupt vector table
+ ****************************************************************/
+
+struct rmode_IVT {
+ struct segoff_s ivec[256];
+};
+
+#define GET_IVT(vector) \
+ GET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector])
+#define SET_IVT(vector, segoff) \
+ SET_FARVAR(SEG_IVT, ((struct rmode_IVT *)0)->ivec[vector], segoff)
+
+#define FUNC16(func) ({ \
+ ASSERT32FLAT(); \
+ extern void func (void); \
+ SEGOFF(SEG_BIOS, (u32)func - BUILD_BIOS_ADDR); \
+ })
+
+
+/****************************************************************
+ * Bios Data Area (BDA)
+ ****************************************************************/
+
+struct bios_data_area_s {
+ // 40:00
+ u16 port_com[4];
+ u16 port_lpt[3];
+ u16 ebda_seg;
+ // 40:10
+ u16 equipment_list_flags;
+ u8 pad1;
+ u16 mem_size_kb;
+ u8 pad2;
+ u8 ps2_ctrl_flag;
+ u8 kbd_flag0;
+ u8 kbd_flag1;
+ u8 alt_keypad;
+ u16 kbd_buf_head;
+ u16 kbd_buf_tail;
+ // 40:1e
+ u8 kbd_buf[32];
+ u8 floppy_recalibration_status;
+ u8 floppy_motor_status;
+ // 40:40
+ u8 floppy_motor_counter;
+ u8 floppy_last_status;
+ u8 floppy_return_status[7];
+ u8 video_mode;
+ u16 video_cols;
+ u16 video_pagesize;
+ u16 video_pagestart;
+ // 40:50
+ u16 cursor_pos[8];
+ // 40:60
+ u16 cursor_type;
+ u8 video_page;
+ u16 crtc_address;
+ u8 video_msr;
+ u8 video_pal;
+ struct segoff_s jump;
+ u8 other_6b;
+ u32 timer_counter;
+ // 40:70
+ u8 timer_rollover;
+ u8 break_flag;
+ u16 soft_reset_flag;
+ u8 disk_last_status;
+ u8 hdcount;
+ u8 disk_control_byte;
+ u8 port_disk;
+ u8 lpt_timeout[4];
+ u8 com_timeout[4];
+ // 40:80
+ u16 kbd_buf_start_offset;
+ u16 kbd_buf_end_offset;
+ u8 video_rows;
+ u16 char_height;
+ u8 video_ctl;
+ u8 video_switches;
+ u8 modeset_ctl;
+ u8 dcc_index;
+ u8 floppy_last_data_rate;
+ u8 disk_status_controller;
+ u8 disk_error_controller;
+ u8 disk_interrupt_flag;
+ u8 floppy_harddisk_info;
+ // 40:90
+ u8 floppy_media_state[4];
+ u8 floppy_track[2];
+ u8 kbd_flag2;
+ u8 kbd_led;
+ struct segoff_s user_wait_complete_flag;
+ u32 user_wait_timeout;
+ // 40:A0
+ u8 rtc_wait_flag;
+ u8 other_a1[7];
+ struct segoff_s video_savetable;
+ u8 other_ac[4];
+ // 40:B0
+ u8 other_b0[10];
+ u16 vbe_mode;
+} PACKED;
+
+// BDA floppy_recalibration_status bitdefs
+#define FRS_TIMEOUT (1<<7)
+
+// BDA rtc_wait_flag bitdefs
+#define RWS_WAIT_PENDING (1<<0)
+#define RWS_WAIT_ELAPSED (1<<7)
+
+// BDA floppy_media_state bitdefs
+#define FMS_DRIVE_STATE_MASK (0x07)
+#define FMS_MEDIA_DRIVE_ESTABLISHED (1<<4)
+#define FMS_DOUBLE_STEPPING (1<<5)
+#define FMS_DATA_RATE_MASK (0xc0)
+
+// Accessor functions
+#define GET_BDA(var) \
+ GET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var)
+#define SET_BDA(var, val) \
+ SET_FARVAR(SEG_BDA, ((struct bios_data_area_s *)0)->var, (val))
+#define CLEARBITS_BDA(var, val) do { \
+ typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+ SET_BDA(var, (__val & ~(val))); \
+ } while (0)
+#define SETBITS_BDA(var, val) do { \
+ typeof(((struct bios_data_area_s *)0)->var) __val = GET_BDA(var); \
+ SET_BDA(var, (__val | (val))); \
+ } while (0)
+
+
+/****************************************************************
+ * Extended Bios Data Area (EBDA)
+ ****************************************************************/
+
+// DPTE definition
+struct dpte_s {
+ u16 iobase1;
+ u16 iobase2;
+ u8 prefix;
+ u8 unused;
+ u8 irq;
+ u8 blkcount;
+ u8 dma;
+ u8 pio;
+ u16 options;
+ u16 reserved;
+ u8 revision;
+ u8 checksum;
+};
+
+// ElTorito Device Emulation data
+struct cdemu_s {
+ struct drive_s *emulated_drive_gf;
+ u32 ilba;
+ u16 buffer_segment;
+ u16 load_segment;
+ u16 sector_count;
+ u8 active;
+ u8 media;
+ u8 emulated_extdrive;
+
+ // Virtual device
+ struct chs_s lchs;
+};
+
+struct fdpt_s {
+ u16 cylinders;
+ u8 heads;
+ u8 a0h_signature;
+ u8 phys_sectors;
+ u16 precompensation;
+ u8 reserved;
+ u8 drive_control_byte;
+ u16 phys_cylinders;
+ u8 phys_heads;
+ u16 landing_zone;
+ u8 sectors;
+ u8 checksum;
+} PACKED;
+
+struct usbkeyinfo {
+ union {
+ struct {
+ u8 modifiers;
+ u8 repeatcount;
+ u8 keys[6];
+ };
+ u64 data;
+ };
+};
+
+struct extended_bios_data_area_s {
+ u8 size;
+ u8 reserved1[0x21];
+ struct segoff_s far_call_pointer;
+ u8 mouse_flag1;
+ u8 mouse_flag2;
+ u8 mouse_data[0x08];
+ // 0x30
+ u8 other1[0x0d];
+
+ // 0x3d
+ struct fdpt_s fdpt[2];
+
+ // 0x5d
+ u8 other2[0xC4];
+
+ // 0x121 - Begin custom storage.
+ u8 ps2ctr;
+ struct usbkeyinfo usbkey_last;
+
+ int RTCusers;
+
+ // El Torito Emulation data
+ struct cdemu_s cdemu;
+
+ // Buffer for disk DPTE table
+ struct dpte_s dpte;
+
+ // Locks for removable devices
+ u8 cdrom_locks[CONFIG_MAX_EXTDRIVE];
+
+ u16 boot_sequence;
+
+ // Stack space available for code that needs it.
+ u8 extra_stack[512] __aligned(8);
+} PACKED;
+
+// The initial size and location of EBDA
+#define EBDA_SIZE_START \
+ DIV_ROUND_UP(sizeof(struct extended_bios_data_area_s), 1024)
+#define EBDA_SEGMENT_START \
+ FLATPTR_TO_SEG(BUILD_LOWRAM_END - EBDA_SIZE_START*1024)
+
+// Accessor functions
+static inline u16 get_ebda_seg(void) {
+ return GET_BDA(ebda_seg);
+}
+static inline struct extended_bios_data_area_s *
+get_ebda_ptr(void)
+{
+ ASSERT32FLAT();
+ return MAKE_FLATPTR(get_ebda_seg(), 0);
+}
+#define GET_EBDA2(eseg, var) \
+ GET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var)
+#define SET_EBDA2(eseg, var, val) \
+ SET_FARVAR(eseg, ((struct extended_bios_data_area_s *)0)->var, (val))
+#define GET_EBDA(var) \
+ GET_EBDA2(get_ebda_seg(), var)
+#define SET_EBDA(var, val) \
+ SET_EBDA2(get_ebda_seg(), var, (val))
+
+#define EBDA_OFFSET_TOP_STACK \
+ offsetof(struct extended_bios_data_area_s, extra_stack[ \
+ FIELD_SIZEOF(struct extended_bios_data_area_s \
+ , extra_stack)])
+
+
+/****************************************************************
+ * Global variables
+ ****************************************************************/
+
+#if MODE16 == 0 && MODESEGMENT == 1
+// In 32bit segmented mode %cs may not be readable and the code may be
+// relocated. The entry code sets up %gs with a readable segment and
+// the code offset can be determined by get_global_offset().
+#define GLOBAL_SEGREG GS
+static inline u32 __attribute_const get_global_offset(void) {
+ u32 ret;
+ asm(" calll 1f\n"
+ "1:popl %0\n"
+ " subl $1b, %0"
+ : "=r"(ret));
+ return ret;
+}
+#else
+#define GLOBAL_SEGREG CS
+static inline u32 __attribute_const get_global_offset(void) {
+ return 0;
+}
+#endif
+static inline u16 get_global_seg(void) {
+ return GET_SEG(GLOBAL_SEGREG);
+}
+#define GET_GLOBAL(var) \
+ GET_VAR(GLOBAL_SEGREG, *(typeof(&(var)))((void*)&(var) \
+ + get_global_offset()))
+#define SET_GLOBAL(var, val) do { \
+ ASSERT32FLAT(); \
+ (var) = (val); \
+ } while (0)
+#if MODESEGMENT
+#define GLOBALFLAT2GLOBAL(var) ((typeof(var))((void*)(var) - BUILD_BIOS_ADDR))
+#else
+#define GLOBALFLAT2GLOBAL(var) (var)
+#endif
+// Access a "flat" pointer known to point to the f-segment.
+#define GET_GLOBALFLAT(var) GET_GLOBAL(*GLOBALFLAT2GLOBAL(&(var)))
+
+
+/****************************************************************
+ * Bios Config Table
+ ****************************************************************/
+
+struct bios_config_table_s {
+ u16 size;
+ u8 model;
+ u8 submodel;
+ u8 biosrev;
+ u8 feature1, feature2, feature3, feature4, feature5;
+} PACKED;
+
+extern struct bios_config_table_s BIOS_CONFIG_TABLE __aligned(1);
+
+#endif // __BIOSVAR_H
--- /dev/null
+// Disk setup and access
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // struct ata_s
+#include "biosvar.h" // GET_GLOBAL
+#include "cmos.h" // inb_cmos
+#include "util.h" // dprintf
+#include "ata.h" // process_ata_op
+#include "ahci.h" // process_ahci_op
+#include "usb-msc.h" // process_usb_op
+#include "virtio-blk.h" // process_virtio_op
+
+u8 FloppyCount VAR16VISIBLE;
+u8 CDCount;
+struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE;
+u8 *bounce_buf_fl VAR16VISIBLE;
+
+struct drive_s *
+getDrive(u8 exttype, u8 extdriveoffset)
+{
+ if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
+ return NULL;
+ struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]);
+ if (!drive_gf)
+ return NULL;
+ return GLOBALFLAT2GLOBAL(drive_gf);
+}
+
+int getDriveId(u8 exttype, struct drive_s *drive_g)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
+ if (getDrive(exttype, i) == drive_g)
+ return i;
+ return -1;
+}
+
+int bounce_buf_init(void)
+{
+ if (bounce_buf_fl)
+ return 0;
+
+ u8 *buf = malloc_low(CDROM_SECTOR_SIZE);
+ if (!buf) {
+ warn_noalloc();
+ return -1;
+ }
+ bounce_buf_fl = buf;
+ return 0;
+}
+
+/****************************************************************
+ * Disk geometry translation
+ ****************************************************************/
+
+static u8
+get_translation(struct drive_s *drive_g)
+{
+ u8 type = GET_GLOBAL(drive_g->type);
+ if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
+ // Emulators pass in the translation info via nvram.
+ u8 ataid = GET_GLOBAL(drive_g->cntl_id);
+ u8 channel = ataid / 2;
+ u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
+ translation >>= 2 * (ataid % 4);
+ translation &= 0x03;
+ return translation;
+ }
+
+ // Otherwise use a heuristic to determine translation type.
+ u16 heads = GET_GLOBAL(drive_g->pchs.heads);
+ u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
+ u16 spt = GET_GLOBAL(drive_g->pchs.spt);
+ u64 sectors = GET_GLOBAL(drive_g->sectors);
+ u64 psectors = (u64)heads * cylinders * spt;
+ if (!heads || !cylinders || !spt || psectors > sectors)
+ // pchs doesn't look valid - use LBA.
+ return TRANSLATION_LBA;
+
+ if (cylinders <= 1024 && heads <= 16 && spt <= 63)
+ return TRANSLATION_NONE;
+ if (cylinders * heads <= 131072)
+ return TRANSLATION_LARGE;
+ return TRANSLATION_LBA;
+}
+
+static void
+setup_translation(struct drive_s *drive_g)
+{
+ u8 translation = get_translation(drive_g);
+ SET_GLOBAL(drive_g->translation, translation);
+
+ u16 heads = GET_GLOBAL(drive_g->pchs.heads);
+ u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
+ u16 spt = GET_GLOBAL(drive_g->pchs.spt);
+ u64 sectors = GET_GLOBAL(drive_g->sectors);
+ const char *desc = NULL;
+
+ switch (translation) {
+ default:
+ case TRANSLATION_NONE:
+ desc = "none";
+ break;
+ case TRANSLATION_LBA:
+ desc = "lba";
+ spt = 63;
+ if (sectors > 63*255*1024) {
+ heads = 255;
+ cylinders = 1024;
+ break;
+ }
+ u32 sect = (u32)sectors / 63;
+ heads = sect / 1024;
+ if (heads>128)
+ heads = 255;
+ else if (heads>64)
+ heads = 128;
+ else if (heads>32)
+ heads = 64;
+ else if (heads>16)
+ heads = 32;
+ else
+ heads = 16;
+ cylinders = sect / heads;
+ break;
+ case TRANSLATION_RECHS:
+ desc = "r-echs";
+ // Take care not to overflow
+ if (heads==16) {
+ if (cylinders>61439)
+ cylinders=61439;
+ heads=15;
+ cylinders = (u16)((u32)(cylinders)*16/15);
+ }
+ // then go through the large bitshift process
+ case TRANSLATION_LARGE:
+ if (translation == TRANSLATION_LARGE)
+ desc = "large";
+ while (cylinders > 1024) {
+ cylinders >>= 1;
+ heads <<= 1;
+
+ // If we max out the head count
+ if (heads > 127)
+ break;
+ }
+ break;
+ }
+ // clip to 1024 cylinders in lchs
+ if (cylinders > 1024)
+ cylinders = 1024;
+ dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n"
+ , drive_g
+ , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt
+ , desc
+ , cylinders, heads, spt
+ , (u32)sectors);
+
+ SET_GLOBAL(drive_g->lchs.heads, heads);
+ SET_GLOBAL(drive_g->lchs.cylinders, cylinders);
+ SET_GLOBAL(drive_g->lchs.spt, spt);
+}
+
+
+/****************************************************************
+ * Drive mapping
+ ****************************************************************/
+
+// Fill in Fixed Disk Parameter Table (located in ebda).
+static void
+fill_fdpt(struct drive_s *drive_g, int hdid)
+{
+ if (hdid > 1)
+ return;
+
+ u16 nlc = GET_GLOBAL(drive_g->lchs.cylinders);
+ u16 nlh = GET_GLOBAL(drive_g->lchs.heads);
+ u16 nlspt = GET_GLOBAL(drive_g->lchs.spt);
+
+ u16 npc = GET_GLOBAL(drive_g->pchs.cylinders);
+ u16 nph = GET_GLOBAL(drive_g->pchs.heads);
+ u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
+
+ struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
+ fdpt->precompensation = 0xffff;
+ fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
+ fdpt->landing_zone = npc;
+ fdpt->cylinders = nlc;
+ fdpt->heads = nlh;
+ fdpt->sectors = nlspt;
+
+ if (nlc != npc || nlh != nph || nlspt != npspt) {
+ // Logical mapping present - use extended structure.
+
+ // complies with Phoenix style Translated Fixed Disk Parameter
+ // Table (FDPT)
+ fdpt->phys_cylinders = npc;
+ fdpt->phys_heads = nph;
+ fdpt->phys_sectors = npspt;
+ fdpt->a0h_signature = 0xa0;
+
+ // Checksum structure.
+ fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
+ }
+
+ if (hdid == 0)
+ SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
+ struct extended_bios_data_area_s, fdpt[0])));
+ else
+ SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
+ struct extended_bios_data_area_s, fdpt[1])));
+}
+
+// Find spot to add a drive
+static void
+add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive_g)
+{
+ if (*count >= ARRAY_SIZE(IDMap[0])) {
+ warn_noalloc();
+ return;
+ }
+ idmap[*count] = drive_g;
+ *count = *count + 1;
+}
+
+// Map a hard drive
+void
+map_hd_drive(struct drive_s *drive_g)
+{
+ ASSERT32FLAT();
+ struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
+ int hdid = bda->hdcount;
+ dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdid);
+ add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);
+
+ // Setup disk geometry translation.
+ setup_translation(drive_g);
+
+ // Fill "fdpt" structure.
+ fill_fdpt(drive_g, hdid);
+}
+
+// Map a cd
+void
+map_cd_drive(struct drive_s *drive_g)
+{
+ dprintf(3, "Mapping cd drive %p\n", drive_g);
+ add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g);
+}
+
+// Map a floppy
+void
+map_floppy_drive(struct drive_s *drive_g)
+{
+ dprintf(3, "Mapping floppy drive %p\n", drive_g);
+ add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g);
+
+ // Update equipment word bits for floppy
+ if (FloppyCount == 1) {
+ // 1 drive, ready for boot
+ SETBITS_BDA(equipment_list_flags, 0x01);
+ SET_BDA(floppy_harddisk_info, 0x07);
+ } else if (FloppyCount >= 2) {
+ // 2 drives, ready for boot
+ SETBITS_BDA(equipment_list_flags, 0x41);
+ SET_BDA(floppy_harddisk_info, 0x77);
+ }
+}
+
+
+/****************************************************************
+ * 16bit calling interface
+ ****************************************************************/
+
+// Execute a disk_op request.
+int
+process_op(struct disk_op_s *op)
+{
+ ASSERT16();
+ u8 type = GET_GLOBAL(op->drive_g->type);
+ switch (type) {
+ case DTYPE_FLOPPY:
+ return process_floppy_op(op);
+ case DTYPE_ATA:
+ return process_ata_op(op);
+ case DTYPE_ATAPI:
+ return process_atapi_op(op);
+ case DTYPE_RAMDISK:
+ return process_ramdisk_op(op);
+ case DTYPE_CDEMU:
+ return process_cdemu_op(op);
+ case DTYPE_USB:
+ return process_usb_op(op);
+ case DTYPE_VIRTIO:
+ return process_virtio_op(op);
+ case DTYPE_AHCI:
+ return process_ahci_op(op);
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+// Execute a "disk_op_s" request - this runs on a stack in the ebda.
+static int
+__send_disk_op(struct disk_op_s *op_far, u16 op_seg)
+{
+ struct disk_op_s dop;
+ memcpy_far(GET_SEG(SS), &dop
+ , op_seg, op_far
+ , sizeof(dop));
+
+ dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
+ , dop.drive_g, (u32)dop.lba, dop.buf_fl
+ , dop.count, dop.command);
+
+ int status = process_op(&dop);
+
+ // Update count with total sectors transferred.
+ SET_FARVAR(op_seg, op_far->count, dop.count);
+
+ return status;
+}
+
+// Execute a "disk_op_s" request by jumping to a stack in the ebda.
+int
+send_disk_op(struct disk_op_s *op)
+{
+ ASSERT16();
+ if (! CONFIG_DRIVES)
+ return -1;
+
+ return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
+}
--- /dev/null
+// Support for several common scsi like command data block requests
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // htonl
+#include "disk.h" // struct disk_op_s
+#include "blockcmd.h" // struct cdb_request_sense
+#include "ata.h" // atapi_cmd_data
+#include "ahci.h" // atapi_cmd_data
+#include "usb-msc.h" // usb_cmd_data
+
+// Route command to low-level handler.
+static int
+cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ u8 type = GET_GLOBAL(op->drive_g->type);
+ switch (type) {
+ case DTYPE_ATAPI:
+ return atapi_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_USB:
+ return usb_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_AHCI:
+ return ahci_cmd_data(op, cdbcmd, blocksize);
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+int
+cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
+{
+ struct cdb_request_sense cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_INQUIRY;
+ cmd.length = sizeof(*data);
+ op->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// Request SENSE
+int
+cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
+{
+ struct cdb_request_sense cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_REQUEST_SENSE;
+ cmd.length = sizeof(*data);
+ op->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// Request capacity
+int
+cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data)
+{
+ struct cdb_read_capacity cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_READ_CAPACITY;
+ op->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
+// Read sectors.
+int
+cdb_read(struct disk_op_s *op)
+{
+ struct cdb_rwdata_10 cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_READ_10;
+ cmd.lba = htonl(op->lba);
+ cmd.count = htons(op->count);
+ return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
+}
--- /dev/null
+// Definitions for SCSI style command data blocks.
+#ifndef __BLOCKCMD_H
+#define __BLOCKCMD_H
+
+#include "types.h" // u8
+
+#define CDB_CMD_READ_10 0x28
+#define CDB_CMD_VERIFY_10 0x2f
+#define CDB_CMD_WRITE_10 0x2a
+
+struct cdb_rwdata_10 {
+ u8 command;
+ u8 flags;
+ u32 lba;
+ u8 resreved_06;
+ u16 count;
+ u8 reserved_09;
+ u8 pad[6];
+} PACKED;
+
+#define CDB_CMD_READ_CAPACITY 0x25
+
+struct cdb_read_capacity {
+ u8 command;
+ u8 flags;
+ u8 resreved_02[8];
+ u8 pad[6];
+} PACKED;
+
+struct cdbres_read_capacity {
+ u32 sectors;
+ u32 blksize;
+} PACKED;
+
+#define CDB_CMD_INQUIRY 0x12
+#define CDB_CMD_REQUEST_SENSE 0x03
+
+struct cdb_request_sense {
+ u8 command;
+ u8 flags;
+ u16 reserved_02;
+ u8 length;
+ u8 reserved_05;
+ u8 pad[10];
+} PACKED;
+
+struct cdbres_request_sense {
+ u8 errcode;
+ u8 segment;
+ u8 flags;
+ u32 info;
+ u8 additional;
+ u32 specific;
+ u8 asc;
+ u8 ascq;
+ u32 reserved_0e;
+} PACKED;
+
+struct cdbres_inquiry {
+ u8 pdt;
+ u8 removable;
+ u8 reserved_02[2];
+ u8 additional;
+ u8 reserved_05[3];
+ char vendor[8];
+ char product[16];
+ char rev[4];
+} PACKED;
+
+// blockcmd.c
+int cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
+int cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data);
+int cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data);
+int cdb_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
+int cdb_read(struct disk_op_s *op);
+
+#endif // blockcmd.h
--- /dev/null
+/*
+* Basic BMP data process and Raw picture data handle functions.
+* Could be used to adjust pixel data format, get infomation, etc.
+*
+* Copyright (C) 2011 Wayne Xia <xiawenc@cn.ibm.com>
+*
+* This work is licensed under the terms of the GNU LGPLv3.
+*/
+#include "util.h"
+#include "bmp.h"
+
+#define bmp_load4byte(addr) (*(u32 *)(addr))
+#define bmp_load2byte(addr) (*(u16 *)(addr))
+
+typedef struct tagBITMAPFILEHEADER {
+ u8 bfType[2];
+ u8 bfSize[4];
+ u8 bfReserved1[2];
+ u8 bfReserved2[2];
+ u8 bfOffBits[4];
+} BITMAPFILEHEADER, tagBITMAPFILEHEADER;
+
+typedef struct tagBITMAPINFOHEADER {
+ u8 biSize[4];
+ u8 biWidth[4];
+ u8 biHeight[4];
+ u8 biPlanes[2];
+ u8 biBitCount[2];
+ u8 biCompression[4];
+ u8 biSizeImage[4];
+ u8 biXPelsPerMeter[4];
+ u8 biYPelsPerMeter[4];
+ u8 biClrUsed[4];
+ u8 biClrImportant[4];
+} BITMAPINFOHEADER, tagBITMAPINFOHEADER;
+
+typedef struct tagRGBQUAD {
+ u8 rgbBlue;
+ u8 rgbGreen;
+ u8 rgbRed;
+ u8 rgbReserved;
+} RGBQUAD, tagRGBQUAD;
+
+/* flat picture data adjusting function
+* description:
+* switch the vertical line sequence
+* arrange horizontal pixel data, add extra space in the dest buffer
+* for every line
+*/
+static void raw_data_format_adjust_24bpp(u8 *src, u8 *dest, int width,
+ int height, int bytes_per_line_dest)
+{
+ int bytes_per_line_src = 3 * width;
+ int i;
+ for (i = 0 ; i < height ; i++) {
+ memcpy(dest + i * bytes_per_line_dest,
+ src + (height - 1 - i) * bytes_per_line_src, bytes_per_line_src);
+ }
+}
+
+struct bmp_decdata *bmp_alloc(void)
+{
+ struct bmp_decdata *bmp = malloc_tmphigh(sizeof(*bmp));
+ return bmp;
+}
+
+int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size)
+{
+ if (data_size < 54)
+ return 1;
+
+ u16 bmp_filehead = bmp_load2byte(data + 0);
+ if (bmp_filehead != 0x4d42)
+ return 2;
+ u32 bmp_recordsize = bmp_load4byte(data + 2);
+ if (bmp_recordsize != data_size)
+ return 3;
+ u32 bmp_dataoffset = bmp_load4byte(data + 10);
+ bmp->datap = (unsigned char *)data + bmp_dataoffset;
+ bmp->width = bmp_load4byte(data + 18);
+ bmp->height = bmp_load4byte(data + 22);
+ bmp->bpp = bmp_load2byte(data + 28);
+ return 0;
+}
+
+void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height)
+{
+ *width = bmp->width;
+ *height = bmp->height;
+}
+
+
+int bmp_show(struct bmp_decdata *bmp, unsigned char *pic, int width
+ , int height, int depth, int bytes_per_line_dest)
+{
+ if (bmp->datap == pic)
+ return 0;
+ /* now only support 24bpp bmp file */
+ if ((depth == 24) && (bmp->bpp == 24)) {
+ raw_data_format_adjust_24bpp(bmp->datap, pic, width, height,
+ bytes_per_line_dest);
+ return 0;
+ }
+ return 1;
+}
--- /dev/null
+#ifndef BMP_H
+#define BMP_H
+#include "types.h"
+
+struct bmp_decdata {
+ struct tagRGBQUAD *quadp;
+ unsigned char *datap;
+ int width;
+ int height;
+ int bpp;
+};
+
+/* allocate decdata struct */
+struct bmp_decdata *bmp_alloc(void);
+
+/* extract information from bmp file data */
+int bmp_decode(struct bmp_decdata *bmp, unsigned char *data, int data_size);
+
+/* get bmp properties */
+void bmp_get_size(struct bmp_decdata *bmp, int *width, int *height);
+
+/* flush flat picture data to *pc */
+int bmp_show(struct bmp_decdata *bmp, unsigned char *pic, int width
+ , int height, int depth, int bytes_per_line_dest);
+#endif
--- /dev/null
+// Code to load disk image and start system boot.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "config.h" // CONFIG_*
+#include "disk.h" // cdrom_boot
+#include "bregs.h" // struct bregs
+#include "boot.h" // func defs
+#include "cmos.h" // inb_cmos
+#include "paravirt.h" // romfile_loadfile
+#include "pci.h" //pci_bdf_to_*
+
+
+/****************************************************************
+ * Boot priority ordering
+ ****************************************************************/
+
+static char **Bootorder;
+static int BootorderCount;
+
+static void
+loadBootOrder(void)
+{
+ if (!CONFIG_BOOTORDER)
+ return;
+
+ char *f = romfile_loadfile("bootorder", NULL);
+ if (!f)
+ return;
+
+ int i = 0;
+ BootorderCount = 1;
+ while (f[i]) {
+ if (f[i] == '\n')
+ BootorderCount++;
+ i++;
+ }
+ Bootorder = malloc_tmphigh(BootorderCount*sizeof(char*));
+ if (!Bootorder) {
+ warn_noalloc();
+ free(f);
+ BootorderCount = 0;
+ return;
+ }
+
+ dprintf(3, "boot order:\n");
+ i = 0;
+ do {
+ Bootorder[i] = f;
+ f = strchr(f, '\n');
+ if (f)
+ *(f++) = '\0';
+ nullTrailingSpace(Bootorder[i]);
+ dprintf(3, "%d: %s\n", i+1, Bootorder[i]);
+ i++;
+ } while (f);
+}
+
+// See if 'str' starts with 'glob' - if glob contains an '*' character
+// it will match any number of characters in str that aren't a '/' or
+// the next glob character.
+static char *
+glob_prefix(const char *glob, const char *str)
+{
+ for (;;) {
+ if (!*glob && (!*str || *str == '/'))
+ return (char*)str;
+ if (*glob == '*') {
+ if (!*str || *str == '/' || *str == glob[1])
+ glob++;
+ else
+ str++;
+ continue;
+ }
+ if (*glob != *str)
+ return NULL;
+ glob++;
+ str++;
+ }
+}
+
+// Search the bootorder list for the given glob pattern.
+static int
+find_prio(const char *glob)
+{
+ dprintf(1, "Searching bootorder for: %s\n", glob);
+ int i;
+ for (i = 0; i < BootorderCount; i++)
+ if (glob_prefix(glob, Bootorder[i]))
+ return i+1;
+ return -1;
+}
+
+#define FW_PCI_DOMAIN "/pci@i0cf8"
+
+static char *
+build_pci_path(char *buf, int max, const char *devname, struct pci_device *pci)
+{
+ // Build the string path of a bdf - for example: /pci@i0cf8/isa@1,2
+ char *p = buf;
+ if (pci->parent) {
+ p = build_pci_path(p, max, "pci-bridge", pci->parent);
+ } else {
+ if (pci->rootbus)
+ p += snprintf(p, max, "/pci-root@%x", pci->rootbus);
+ p += snprintf(p, buf+max-p, "%s", FW_PCI_DOMAIN);
+ }
+
+ int dev = pci_bdf_to_dev(pci->bdf), fn = pci_bdf_to_fn(pci->bdf);
+ p += snprintf(p, buf+max-p, "/%s@%x", devname, dev);
+ if (fn)
+ p += snprintf(p, buf+max-p, ",%x", fn);
+ return p;
+}
+
+int bootprio_find_pci_device(struct pci_device *pci)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find pci device - for example: /pci@i0cf8/ethernet@5
+ char desc[256];
+ build_pci_path(desc, sizeof(desc), "*", pci);
+ return find_prio(desc);
+}
+
+int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ // Find ata drive - for example: /pci@i0cf8/ide@1,1/drive@1/disk@0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "*", pci);
+ snprintf(p, desc+sizeof(desc)-p, "/drive@%x/disk@%x", chanid, slave);
+ return find_prio(desc);
+}
+
+int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ if (!pci)
+ // support only pci machine for now
+ return -1;
+ // Find floppy - for example: /pci@i0cf8/isa@1/fdc@03f1/floppy@0
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "isa", pci);
+ snprintf(p, desc+sizeof(desc)-p, "/fdc@%04x/floppy@%x", port, fdid);
+ return find_prio(desc);
+}
+
+int bootprio_find_pci_rom(struct pci_device *pci, int instance)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find pci rom - for example: /pci@i0cf8/scsi@3:rom2
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "*", pci);
+ if (instance)
+ snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
+ return find_prio(desc);
+}
+
+int bootprio_find_named_rom(const char *name, int instance)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find named rom - for example: /rom@genroms/linuxboot.bin
+ char desc[256], *p;
+ p = desc + snprintf(desc, sizeof(desc), "/rom@%s", name);
+ if (instance)
+ snprintf(p, desc+sizeof(desc)-p, ":rom%d", instance);
+ return find_prio(desc);
+}
+
+int bootprio_find_usb(struct pci_device *pci, u64 path)
+{
+ if (!CONFIG_BOOTORDER)
+ return -1;
+ // Find usb - for example: /pci@i0cf8/usb@1,2/hub@1/network@0/ethernet@0
+ int i;
+ char desc[256], *p;
+ p = build_pci_path(desc, sizeof(desc), "usb", pci);
+ for (i=56; i>0; i-=8) {
+ int port = (path >> i) & 0xff;
+ if (port != 0xff)
+ p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port);
+ }
+ snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff));
+ return find_prio(desc);
+}
+
+
+/****************************************************************
+ * Boot setup
+ ****************************************************************/
+
+static int CheckFloppySig = 1;
+
+#define DEFAULT_PRIO 9999
+
+static int DefaultFloppyPrio = 101;
+static int DefaultCDPrio = 102;
+static int DefaultHDPrio = 103;
+static int DefaultBEVPrio = 104;
+
+void
+boot_setup(void)
+{
+ if (! CONFIG_BOOT)
+ return;
+
+ SET_EBDA(boot_sequence, 0xffff);
+
+ if (!CONFIG_COREBOOT) {
+ // On emulators, get boot order from nvram.
+ if (inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1)
+ CheckFloppySig = 0;
+ u32 bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2)
+ | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4));
+ DefaultFloppyPrio = DefaultCDPrio = DefaultHDPrio
+ = DefaultBEVPrio = DEFAULT_PRIO;
+ int i;
+ for (i=101; i<104; i++) {
+ u32 val = bootorder & 0x0f;
+ bootorder >>= 4;
+ switch (val) {
+ case 1: DefaultFloppyPrio = i; break;
+ case 2: DefaultHDPrio = i; break;
+ case 3: DefaultCDPrio = i; break;
+ case 4: DefaultBEVPrio = i; break;
+ }
+ }
+ }
+
+ loadBootOrder();
+}
+
+
+/****************************************************************
+ * BootList handling
+ ****************************************************************/
+
+struct bootentry_s {
+ int type;
+ union {
+ u32 data;
+ struct segoff_s vector;
+ struct drive_s *drive;
+ };
+ int priority;
+ const char *description;
+ struct bootentry_s *next;
+};
+static struct bootentry_s *BootList;
+
+#define IPL_TYPE_FLOPPY 0x01
+#define IPL_TYPE_HARDDISK 0x02
+#define IPL_TYPE_CDROM 0x03
+#define IPL_TYPE_CBFS 0x20
+#define IPL_TYPE_BEV 0x80
+#define IPL_TYPE_BCV 0x81
+
+static void
+bootentry_add(int type, int prio, u32 data, const char *desc)
+{
+ if (! CONFIG_BOOT)
+ return;
+ struct bootentry_s *be = malloc_tmp(sizeof(*be));
+ if (!be) {
+ warn_noalloc();
+ return;
+ }
+ be->type = type;
+ be->priority = prio;
+ be->data = data;
+ be->description = desc ?: "?";
+ dprintf(3, "Registering bootable: %s (type:%d prio:%d data:%x)\n"
+ , be->description, type, prio, data);
+
+ // Add entry in sorted order.
+ struct bootentry_s **pprev;
+ for (pprev = &BootList; *pprev; pprev = &(*pprev)->next) {
+ struct bootentry_s *pos = *pprev;
+ if (be->priority < pos->priority)
+ break;
+ if (be->priority > pos->priority)
+ continue;
+ if (be->type < pos->type)
+ break;
+ if (be->type > pos->type)
+ continue;
+ if (be->type <= IPL_TYPE_CDROM
+ && (be->drive->type < pos->drive->type
+ || (be->drive->type == pos->drive->type
+ && be->drive->cntl_id < pos->drive->cntl_id)))
+ break;
+ }
+ be->next = *pprev;
+ *pprev = be;
+}
+
+// Return the given priority if it's set - defaultprio otherwise.
+static inline int defPrio(int priority, int defaultprio) {
+ return (priority < 0) ? defaultprio : priority;
+}
+
+// Add a BEV vector for a given pnp compatible option rom.
+void
+boot_add_bev(u16 seg, u16 bev, u16 desc, int prio)
+{
+ bootentry_add(IPL_TYPE_BEV, defPrio(prio, DefaultBEVPrio)
+ , SEGOFF(seg, bev).segoff
+ , desc ? MAKE_FLATPTR(seg, desc) : "Unknown");
+ DefaultBEVPrio = DEFAULT_PRIO;
+}
+
+// Add a bcv entry for an expansion card harddrive or legacy option rom
+void
+boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio)
+{
+ bootentry_add(IPL_TYPE_BCV, defPrio(prio, DEFAULT_PRIO)
+ , SEGOFF(seg, ip).segoff
+ , desc ? MAKE_FLATPTR(seg, desc) : "Legacy option rom");
+}
+
+void
+boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_FLOPPY, defPrio(prio, DefaultFloppyPrio)
+ , (u32)drive_g, desc);
+}
+
+void
+boot_add_hd(struct drive_s *drive_g, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_HARDDISK, defPrio(prio, DefaultHDPrio)
+ , (u32)drive_g, desc);
+}
+
+void
+boot_add_cd(struct drive_s *drive_g, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_CDROM, defPrio(prio, DefaultCDPrio)
+ , (u32)drive_g, desc);
+}
+
+// Add a CBFS payload entry
+void
+boot_add_cbfs(void *data, const char *desc, int prio)
+{
+ bootentry_add(IPL_TYPE_CBFS, defPrio(prio, DEFAULT_PRIO), (u32)data, desc);
+}
+
+
+/****************************************************************
+ * Boot menu and BCV execution
+ ****************************************************************/
+
+#define DEFAULT_BOOTMENU_WAIT 2500
+
+// Show IPL option menu.
+static void
+interactive_bootmenu(void)
+{
+ if (! CONFIG_BOOTMENU || ! qemu_cfg_show_boot_menu())
+ return;
+
+ while (get_keystroke(0) >= 0)
+ ;
+
+ printf("Press F12 for boot menu.\n\n");
+
+ u32 menutime = romfile_loadint("etc/boot-menu-wait", DEFAULT_BOOTMENU_WAIT);
+ enable_bootsplash();
+ int scan_code = get_keystroke(menutime);
+ disable_bootsplash();
+ if (scan_code != 0x86)
+ /* not F12 */
+ return;
+
+ while (get_keystroke(0) >= 0)
+ ;
+
+ printf("Select boot device:\n\n");
+ wait_threads();
+
+ // Show menu items
+ struct bootentry_s *pos = BootList;
+ int maxmenu = 0;
+ while (pos) {
+ char desc[60];
+ maxmenu++;
+ printf("%d. %s\n", maxmenu
+ , strtcpy(desc, pos->description, ARRAY_SIZE(desc)));
+ pos = pos->next;
+ }
+
+ // Get key press
+ for (;;) {
+ scan_code = get_keystroke(1000);
+ if (scan_code >= 1 && scan_code <= maxmenu+1)
+ break;
+ }
+ printf("\n");
+ if (scan_code == 0x01)
+ // ESC
+ return;
+
+ // Find entry and make top priority.
+ int choice = scan_code - 1;
+ struct bootentry_s **pprev = &BootList;
+ while (--choice)
+ pprev = &(*pprev)->next;
+ pos = *pprev;
+ *pprev = pos->next;
+ pos->next = BootList;
+ BootList = pos;
+ pos->priority = 0;
+}
+
+// BEV (Boot Execution Vector) list
+struct bev_s {
+ int type;
+ u32 vector;
+};
+static struct bev_s BEV[20];
+static int BEVCount;
+static int HaveHDBoot, HaveFDBoot;
+
+static void
+add_bev(int type, u32 vector)
+{
+ if (type == IPL_TYPE_HARDDISK && HaveHDBoot++)
+ return;
+ if (type == IPL_TYPE_FLOPPY && HaveFDBoot++)
+ return;
+ if (BEVCount >= ARRAY_SIZE(BEV))
+ return;
+ struct bev_s *bev = &BEV[BEVCount++];
+ bev->type = type;
+ bev->vector = vector;
+}
+
+// Prepare for boot - show menu and run bcvs.
+void
+boot_prep(void)
+{
+ if (! CONFIG_BOOT) {
+ wait_threads();
+ return;
+ }
+
+ // XXX - show available drives?
+
+ // Allow user to modify BCV/IPL order.
+ interactive_bootmenu();
+ wait_threads();
+
+ // Map drives and populate BEV list
+ struct bootentry_s *pos = BootList;
+ while (pos) {
+ switch (pos->type) {
+ case IPL_TYPE_BCV:
+ call_bcv(pos->vector.seg, pos->vector.offset);
+ add_bev(IPL_TYPE_HARDDISK, 0);
+ break;
+ case IPL_TYPE_FLOPPY:
+ map_floppy_drive(pos->drive);
+ add_bev(IPL_TYPE_FLOPPY, 0);
+ break;
+ case IPL_TYPE_HARDDISK:
+ map_hd_drive(pos->drive);
+ add_bev(IPL_TYPE_HARDDISK, 0);
+ break;
+ case IPL_TYPE_CDROM:
+ map_cd_drive(pos->drive);
+ // NO BREAK
+ default:
+ add_bev(pos->type, pos->data);
+ break;
+ }
+ pos = pos->next;
+ }
+
+ // If nothing added a floppy/hd boot - add it manually.
+ add_bev(IPL_TYPE_FLOPPY, 0);
+ add_bev(IPL_TYPE_HARDDISK, 0);
+}
+
+
+/****************************************************************
+ * Boot code (int 18/19)
+ ****************************************************************/
+
+// Jump to a bootup entry point.
+static void
+call_boot_entry(struct segoff_s bootsegip, u8 bootdrv)
+{
+ dprintf(1, "Booting from %04x:%04x\n", bootsegip.seg, bootsegip.offset);
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.code = bootsegip;
+ // Set the magic number in ax and the boot drive in dl.
+ br.dl = bootdrv;
+ br.ax = 0xaa55;
+ call16(&br);
+}
+
+// Boot from a disk (either floppy or harddrive)
+static void
+boot_disk(u8 bootdrv, int checksig)
+{
+ u16 bootseg = 0x07c0;
+
+ // Read sector
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.dl = bootdrv;
+ br.es = bootseg;
+ br.ah = 2;
+ br.al = 1;
+ br.cl = 1;
+ call16_int(0x13, &br);
+
+ if (br.flags & F_CF) {
+ printf("Boot failed: could not read the boot disk\n\n");
+ return;
+ }
+
+ if (checksig) {
+ struct mbr_s *mbr = (void*)0;
+ if (GET_FARVAR(bootseg, mbr->signature) != MBR_SIGNATURE) {
+ printf("Boot failed: not a bootable disk\n\n");
+ return;
+ }
+ }
+
+ /* Canonicalize bootseg:bootip */
+ u16 bootip = (bootseg & 0x0fff) << 4;
+ bootseg &= 0xf000;
+
+ call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
+}
+
+// Boot from a CD-ROM
+static void
+boot_cdrom(struct drive_s *drive_g)
+{
+ if (! CONFIG_CDROM_BOOT)
+ return;
+ printf("Booting from DVD/CD...\n");
+
+ int status = cdrom_boot(drive_g);
+ if (status) {
+ printf("Boot failed: Could not read from CDROM (code %04x)\n", status);
+ return;
+ }
+
+ u16 ebda_seg = get_ebda_seg();
+ u8 bootdrv = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+ u16 bootseg = GET_EBDA2(ebda_seg, cdemu.load_segment);
+ /* Canonicalize bootseg:bootip */
+ u16 bootip = (bootseg & 0x0fff) << 4;
+ bootseg &= 0xf000;
+
+ call_boot_entry(SEGOFF(bootseg, bootip), bootdrv);
+}
+
+// Boot from a CBFS payload
+static void
+boot_cbfs(struct cbfs_file *file)
+{
+ if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+ return;
+ printf("Booting from CBFS...\n");
+ cbfs_run_payload(file);
+}
+
+// Boot from a BEV entry on an optionrom.
+static void
+boot_rom(u32 vector)
+{
+ printf("Booting from ROM...\n");
+ struct segoff_s so;
+ so.segoff = vector;
+ call_boot_entry(so, 0);
+}
+
+// Determine next boot method and attempt a boot using it.
+static void
+do_boot(u16 seq_nr)
+{
+ if (! CONFIG_BOOT)
+ panic("Boot support not compiled in.\n");
+
+ if (seq_nr >= BEVCount) {
+ printf("No bootable device.\n");
+ // Loop with irqs enabled - this allows ctrl+alt+delete to work.
+ for (;;)
+ wait_irq();
+ }
+
+ // Boot the given BEV type.
+ struct bev_s *ie = &BEV[seq_nr];
+ switch (ie->type) {
+ case IPL_TYPE_FLOPPY:
+ printf("Booting from Floppy...\n");
+ boot_disk(0x00, CheckFloppySig);
+ break;
+ case IPL_TYPE_HARDDISK:
+ printf("Booting from Hard Disk...\n");
+ boot_disk(0x80, 1);
+ break;
+ case IPL_TYPE_CDROM:
+ boot_cdrom((void*)ie->vector);
+ break;
+ case IPL_TYPE_CBFS:
+ boot_cbfs((void*)ie->vector);
+ break;
+ case IPL_TYPE_BEV:
+ boot_rom(ie->vector);
+ break;
+ }
+
+ // Boot failed: invoke the boot recovery function
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x18, &br);
+}
+
+// Boot Failure recovery: try the next device.
+void VISIBLE32FLAT
+handle_18(void)
+{
+ debug_serial_setup();
+ debug_enter(NULL, DEBUG_HDL_18);
+ u16 ebda_seg = get_ebda_seg();
+ u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
+ SET_EBDA2(ebda_seg, boot_sequence, seq);
+ do_boot(seq);
+}
+
+// INT 19h Boot Load Service Entry Point
+void VISIBLE32FLAT
+handle_19(void)
+{
+ debug_serial_setup();
+ debug_enter(NULL, DEBUG_HDL_19);
+ SET_EBDA(boot_sequence, 0);
+ do_boot(0);
+}
--- /dev/null
+// Storage for boot definitions.
+#ifndef __BOOT_H
+#define __BOOT_H
+
+// boot.c
+void boot_setup(void);
+void boot_add_bev(u16 seg, u16 bev, u16 desc, int prio);
+void boot_add_bcv(u16 seg, u16 ip, u16 desc, int prio);
+struct drive_s;
+void boot_add_floppy(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_hd(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_cd(struct drive_s *drive_g, const char *desc, int prio);
+void boot_add_cbfs(void *data, const char *desc, int prio);
+void boot_prep(void);
+struct pci_device;
+int bootprio_find_pci_device(struct pci_device *pci);
+int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave);
+int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid);
+int bootprio_find_pci_rom(struct pci_device *pci, int instance);
+int bootprio_find_named_rom(const char *name, int instance);
+int bootprio_find_usb(struct pci_device *pci, u64 path);
+
+#endif // __BOOT_H
--- /dev/null
+// Option rom scanning code.
+//
+// Copyright (C) 2009-2010 coresystems GmbH
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "farptr.h" // FLATPTR_TO_SEG
+#include "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "jpeg.h" // splash
+#include "biosvar.h" // SET_EBDA
+#include "paravirt.h" // romfile_find
+#include "bmp.h"
+
+/****************************************************************
+ * VESA structures
+ ****************************************************************/
+
+struct vesa_info {
+ u32 vesa_signature;
+ u16 vesa_version;
+ struct segoff_s oem_string_ptr;
+ u8 capabilities[4];
+ struct segoff_s video_mode_ptr;
+ u16 total_memory;
+ u16 oem_software_rev;
+ struct segoff_s oem_vendor_name_ptr;
+ struct segoff_s oem_product_name_ptr;
+ struct segoff_s oem_product_rev_ptr;
+ u8 reserved[222];
+ u8 oem_data[256];
+} PACKED;
+
+#define VESA_SIGNATURE 0x41534556 // VESA
+#define VBE2_SIGNATURE 0x32454256 // VBE2
+
+struct vesa_mode_info {
+ u16 mode_attributes;
+ u8 win_a_attributes;
+ u8 win_b_attributes;
+ u16 win_granularity;
+ u16 win_size;
+ u16 win_a_segment;
+ u16 win_b_segment;
+ u32 win_func_ptr;
+ u16 bytes_per_scanline;
+ u16 x_resolution;
+ u16 y_resolution;
+ u8 x_charsize;
+ u8 y_charsize;
+ u8 number_of_planes;
+ u8 bits_per_pixel;
+ u8 number_of_banks;
+ u8 memory_model;
+ u8 bank_size;
+ u8 number_of_image_pages;
+ u8 reserved_page;
+ u8 red_mask_size;
+ u8 red_mask_pos;
+ u8 green_mask_size;
+ u8 green_mask_pos;
+ u8 blue_mask_size;
+ u8 blue_mask_pos;
+ u8 reserved_mask_size;
+ u8 reserved_mask_pos;
+ u8 direct_color_mode_info;
+ void *phys_base_ptr;
+ u32 offscreen_mem_offset;
+ u16 offscreen_mem_size;
+ u8 reserved[206];
+} PACKED;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Call int10 vga handler.
+static void
+call16_int10(struct bregs *br)
+{
+ br->flags = F_IF;
+ start_preempt();
+ call16_int(0x10, br);
+ finish_preempt();
+}
+
+
+/****************************************************************
+ * VGA text / graphics console
+ ****************************************************************/
+
+void
+enable_vga_console(void)
+{
+ dprintf(1, "Turning on vga text mode console\n");
+ struct bregs br;
+
+ /* Enable VGA text mode */
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x0003;
+ call16_int10(&br);
+
+ // Write to screen.
+ printf("SeaBIOS (version %s)\n\n", VERSION);
+}
+
+static int
+find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info
+ , int width, int height, int bpp_req)
+{
+ dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height);
+ u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode_ptr);
+ for (;; videomodes++) {
+ u16 videomode = *videomodes;
+ if (videomode == 0xffff) {
+ dprintf(1, "Unable to find vesa video mode dimensions %d/%d\n"
+ , width, height);
+ return -1;
+ }
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x4f01;
+ br.cx = (1 << 14) | videomode;
+ br.di = FLATPTR_TO_OFFSET(mode_info);
+ br.es = FLATPTR_TO_SEG(mode_info);
+ call16_int10(&br);
+ if (br.ax != 0x4f) {
+ dprintf(1, "get_mode failed.\n");
+ continue;
+ }
+ if (mode_info->x_resolution != width
+ || mode_info->y_resolution != height)
+ continue;
+ u8 depth = mode_info->bits_per_pixel;
+ if (bpp_req == 0) {
+ if (depth != 16 && depth != 24 && depth != 32)
+ continue;
+ } else {
+ if (depth != bpp_req)
+ continue;
+ }
+ return videomode;
+ }
+}
+
+static int BootsplashActive;
+
+void
+enable_bootsplash(void)
+{
+ if (!CONFIG_BOOTSPLASH)
+ return;
+ /* splash picture can be bmp or jpeg file */
+ dprintf(3, "Checking for bootsplash\n");
+ u8 type = 0; /* 0 means jpg, 1 means bmp, default is 0=jpg */
+ int filesize;
+ u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize);
+ if (!filedata) {
+ filedata = romfile_loadfile("bootsplash.bmp", &filesize);
+ if (!filedata)
+ return;
+ type = 1;
+ }
+ dprintf(3, "start showing bootsplash\n");
+
+ u8 *picture = NULL; /* data buff used to be flushed to the video buf */
+ struct jpeg_decdata *jpeg = NULL;
+ struct bmp_decdata *bmp = NULL;
+ struct vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info));
+ struct vesa_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info));
+ if (!vesa_info || !mode_info) {
+ warn_noalloc();
+ goto done;
+ }
+
+ /* Check whether we have a VESA 2.0 compliant BIOS */
+ memset(vesa_info, 0, sizeof(struct vesa_info));
+ vesa_info->vesa_signature = VBE2_SIGNATURE;
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x4f00;
+ br.di = FLATPTR_TO_OFFSET(vesa_info);
+ br.es = FLATPTR_TO_SEG(vesa_info);
+ call16_int10(&br);
+ if (vesa_info->vesa_signature != VESA_SIGNATURE) {
+ dprintf(1,"No VBE2 found.\n");
+ goto done;
+ }
+
+ /* Print some debugging information about our card. */
+ char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr);
+ char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr);
+ dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
+ vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff,
+ vendor, product);
+
+ int ret, width, height;
+ int bpp_require = 0;
+ if (type == 0) {
+ jpeg = jpeg_alloc();
+ if (!jpeg) {
+ warn_noalloc();
+ goto done;
+ }
+ /* Parse jpeg and get image size. */
+ dprintf(5, "Decoding bootsplash.jpg\n");
+ ret = jpeg_decode(jpeg, filedata);
+ if (ret) {
+ dprintf(1, "jpeg_decode failed with return code %d...\n", ret);
+ goto done;
+ }
+ jpeg_get_size(jpeg, &width, &height);
+ } else {
+ bmp = bmp_alloc();
+ if (!bmp) {
+ warn_noalloc();
+ goto done;
+ }
+ /* Parse bmp and get image size. */
+ dprintf(5, "Decoding bootsplash.bmp\n");
+ ret = bmp_decode(bmp, filedata, filesize);
+ if (ret) {
+ dprintf(1, "bmp_decode failed with return code %d...\n", ret);
+ goto done;
+ }
+ bmp_get_size(bmp, &width, &height);
+ bpp_require = 24;
+ }
+ /* jpeg would use 16 or 24 bpp video mode, BMP use 24bpp mode only */
+
+ // Try to find a graphics mode with the corresponding dimensions.
+ int videomode = find_videomode(vesa_info, mode_info, width, height,
+ bpp_require);
+ if (videomode < 0) {
+ dprintf(1, "failed to find a videomode with %dx%d %dbpp (0=any).\n",
+ width, height, bpp_require);
+ goto done;
+ }
+ void *framebuffer = mode_info->phys_base_ptr;
+ int depth = mode_info->bits_per_pixel;
+ dprintf(3, "mode: %04x\n", videomode);
+ dprintf(3, "framebuffer: %p\n", framebuffer);
+ dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline);
+ dprintf(3, "bits per pixel: %d\n", depth);
+
+ // Allocate space for image and decompress it.
+ int imagesize = height * mode_info->bytes_per_scanline;
+ picture = malloc_tmphigh(imagesize);
+ if (!picture) {
+ warn_noalloc();
+ goto done;
+ }
+
+ if (type == 0) {
+ dprintf(5, "Decompressing bootsplash.jpg\n");
+ ret = jpeg_show(jpeg, picture, width, height, depth,
+ mode_info->bytes_per_scanline);
+ if (ret) {
+ dprintf(1, "jpeg_show failed with return code %d...\n", ret);
+ goto done;
+ }
+ } else {
+ dprintf(5, "Decompressing bootsplash.bmp\n");
+ ret = bmp_show(bmp, picture, width, height, depth,
+ mode_info->bytes_per_scanline);
+ if (ret) {
+ dprintf(1, "bmp_show failed with return code %d...\n", ret);
+ goto done;
+ }
+ }
+
+ /* Switch to graphics mode */
+ dprintf(5, "Switching to graphics mode\n");
+ memset(&br, 0, sizeof(br));
+ br.ax = 0x4f02;
+ br.bx = (1 << 14) | videomode;
+ call16_int10(&br);
+ if (br.ax != 0x4f) {
+ dprintf(1, "set_mode failed.\n");
+ goto done;
+ }
+
+ /* Show the picture */
+ dprintf(5, "Showing bootsplash picture\n");
+ iomemcpy(framebuffer, picture, imagesize);
+ dprintf(5, "Bootsplash copy complete\n");
+ BootsplashActive = 1;
+
+done:
+ free(filedata);
+ free(picture);
+ free(vesa_info);
+ free(mode_info);
+ free(jpeg);
+ free(bmp);
+ return;
+}
+
+void
+disable_bootsplash(void)
+{
+ if (!CONFIG_BOOTSPLASH || !BootsplashActive)
+ return;
+ BootsplashActive = 0;
+ enable_vga_console();
+}
--- /dev/null
+// Structure layout of cpu registers the the bios uses.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#ifndef __BREGS_H
+#define __BREGS_H
+
+// CPU flag bitdefs
+#define F_CF (1<<0)
+#define F_ZF (1<<6)
+#define F_IF (1<<9)
+
+// CR0 flags
+#define CR0_PG (1<<31) // Paging
+#define CR0_CD (1<<30) // Cache disable
+#define CR0_NW (1<<29) // Not Write-through
+#define CR0_PE (1<<0) // Protection enable
+
+
+#ifndef __ASSEMBLY__
+
+#include "farptr.h" // struct segoff_s
+
+/****************************************************************
+ * Registers saved/restored in romlayout.S
+ ****************************************************************/
+
+#include "types.h" // u16
+
+#define UREG(ER, R, RH, RL) union { u32 ER; struct { u16 R; u16 R ## _hi; }; struct { u8 RL; u8 RH; u8 R ## _hilo; u8 R ## _hihi; }; }
+
+// Layout of registers passed in to irq handlers. Note that this
+// layout corresponds to code in romlayout.S - don't change it here
+// without also updating the assembler code.
+struct bregs {
+ u16 ds;
+ u16 es;
+ UREG(edi, di, di8u, di8l);
+ UREG(esi, si, si8u, si8l);
+ UREG(ebp, bp, bp8u, bp8l);
+ UREG(ebx, bx, bh, bl);
+ UREG(edx, dx, dh, dl);
+ UREG(ecx, cx, ch, cl);
+ UREG(eax, ax, ah, al);
+ struct segoff_s code;
+ u16 flags;
+} PACKED;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static inline void
+set_cf(struct bregs *regs, int cond)
+{
+ if (cond)
+ regs->flags |= F_CF;
+ else
+ regs->flags &= ~F_CF;
+}
+
+// Frequently used return codes
+#define RET_EUNSUPPORTED 0x86
+
+static inline void
+set_success(struct bregs *regs)
+{
+ set_cf(regs, 0);
+}
+
+static inline void
+set_code_success(struct bregs *regs)
+{
+ regs->ah = 0;
+ set_cf(regs, 0);
+}
+
+static inline void
+set_invalid_silent(struct bregs *regs)
+{
+ set_cf(regs, 1);
+}
+
+static inline void
+set_code_invalid_silent(struct bregs *regs, u8 code)
+{
+ regs->ah = code;
+ set_cf(regs, 1);
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // bregs.h
--- /dev/null
+// Support for booting from cdroms (the "El Torito" spec).
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // cdrom_13
+#include "util.h" // memset
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_EBDA
+#include "ata.h" // ATA_CMD_REQUEST_SENSE
+#include "blockcmd.h" // CDB_CMD_REQUEST_SENSE
+
+
+/****************************************************************
+ * CD emulation
+ ****************************************************************/
+
+struct drive_s *cdemu_drive_gf VAR16VISIBLE;
+
+static int
+cdemu_read(struct disk_op_s *op)
+{
+ u16 ebda_seg = get_ebda_seg();
+ struct drive_s *drive_g;
+ drive_g = GLOBALFLAT2GLOBAL(GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf));
+ struct disk_op_s dop;
+ dop.drive_g = drive_g;
+ dop.command = op->command;
+ dop.lba = GET_EBDA2(ebda_seg, cdemu.ilba) + op->lba / 4;
+
+ int count = op->count;
+ op->count = 0;
+ u8 *cdbuf_fl = GET_GLOBAL(bounce_buf_fl);
+
+ if (op->lba & 3) {
+ // Partial read of first block.
+ dop.count = 1;
+ dop.buf_fl = cdbuf_fl;
+ int ret = process_op(&dop);
+ if (ret)
+ return ret;
+ u8 thiscount = 4 - (op->lba & 3);
+ if (thiscount > count)
+ thiscount = count;
+ count -= thiscount;
+ memcpy_fl(op->buf_fl, cdbuf_fl + (op->lba & 3) * 512, thiscount * 512);
+ op->buf_fl += thiscount * 512;
+ op->count += thiscount;
+ dop.lba++;
+ }
+
+ if (count > 3) {
+ // Read n number of regular blocks.
+ dop.count = count / 4;
+ dop.buf_fl = op->buf_fl;
+ int ret = process_op(&dop);
+ op->count += dop.count * 4;
+ if (ret)
+ return ret;
+ u8 thiscount = count & ~3;
+ count &= 3;
+ op->buf_fl += thiscount * 512;
+ dop.lba += thiscount / 4;
+ }
+
+ if (count) {
+ // Partial read on last block.
+ dop.count = 1;
+ dop.buf_fl = cdbuf_fl;
+ int ret = process_op(&dop);
+ if (ret)
+ return ret;
+ u8 thiscount = count;
+ memcpy_fl(op->buf_fl, cdbuf_fl, thiscount * 512);
+ op->count += thiscount;
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+int
+process_cdemu_op(struct disk_op_s *op)
+{
+ if (!CONFIG_CDROM_EMU)
+ return 0;
+
+ switch (op->command) {
+ case CMD_READ:
+ return cdemu_read(op);
+ case CMD_WRITE:
+ case CMD_FORMAT:
+ return DISK_RET_EWRITEPROTECT;
+ case CMD_VERIFY:
+ case CMD_RESET:
+ case CMD_SEEK:
+ case CMD_ISREADY:
+ return DISK_RET_SUCCESS;
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+void
+cdemu_setup(void)
+{
+ if (!CONFIG_CDROM_EMU)
+ return;
+ if (!CDCount)
+ return;
+ if (bounce_buf_init() < 0)
+ return;
+
+ struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g));
+ if (!drive_g) {
+ warn_noalloc();
+ free(drive_g);
+ return;
+ }
+ cdemu_drive_gf = drive_g;
+ memset(drive_g, 0, sizeof(*drive_g));
+ drive_g->type = DTYPE_CDEMU;
+ drive_g->blksize = DISK_SECTOR_SIZE;
+ drive_g->sectors = (u64)-1;
+}
+
+struct eltorito_s {
+ u8 size;
+ u8 media;
+ u8 emulated_drive;
+ u8 controller_index;
+ u32 ilba;
+ u16 device_spec;
+ u16 buffer_segment;
+ u16 load_segment;
+ u16 sector_count;
+ u8 cylinders;
+ u8 sectors;
+ u8 heads;
+};
+
+#define SET_INT13ET(regs,var,val) \
+ SET_FARVAR((regs)->ds, ((struct eltorito_s*)((regs)->si+0))->var, (val))
+
+// ElTorito - Terminate disk emu
+void
+cdemu_134b(struct bregs *regs)
+{
+ // FIXME ElTorito Hardcoded
+ u16 ebda_seg = get_ebda_seg();
+ SET_INT13ET(regs, size, 0x13);
+ SET_INT13ET(regs, media, GET_EBDA2(ebda_seg, cdemu.media));
+ SET_INT13ET(regs, emulated_drive
+ , GET_EBDA2(ebda_seg, cdemu.emulated_extdrive));
+ struct drive_s *drive_gf = GET_EBDA2(ebda_seg, cdemu.emulated_drive_gf);
+ u8 cntl_id = 0;
+ if (drive_gf)
+ cntl_id = GET_GLOBALFLAT(drive_gf->cntl_id);
+ SET_INT13ET(regs, controller_index, cntl_id / 2);
+ SET_INT13ET(regs, device_spec, cntl_id % 2);
+ SET_INT13ET(regs, ilba, GET_EBDA2(ebda_seg, cdemu.ilba));
+ SET_INT13ET(regs, buffer_segment, GET_EBDA2(ebda_seg, cdemu.buffer_segment));
+ SET_INT13ET(regs, load_segment, GET_EBDA2(ebda_seg, cdemu.load_segment));
+ SET_INT13ET(regs, sector_count, GET_EBDA2(ebda_seg, cdemu.sector_count));
+ SET_INT13ET(regs, cylinders, GET_EBDA2(ebda_seg, cdemu.lchs.cylinders));
+ SET_INT13ET(regs, sectors, GET_EBDA2(ebda_seg, cdemu.lchs.spt));
+ SET_INT13ET(regs, heads, GET_EBDA2(ebda_seg, cdemu.lchs.heads));
+
+ // If we have to terminate emulation
+ if (regs->al == 0x00) {
+ // FIXME ElTorito Various. Should be handled accordingly to spec
+ SET_EBDA2(ebda_seg, cdemu.active, 0x00); // bye bye
+
+ // XXX - update floppy/hd count.
+ }
+
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+
+/****************************************************************
+ * CD booting
+ ****************************************************************/
+
+static int
+atapi_is_ready(struct disk_op_s *op)
+{
+ dprintf(6, "atapi_is_ready (drive=%p)\n", op->drive_g);
+
+ /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is
+ * reported by the device. If the device reports "IN PROGRESS",
+ * 30 seconds is added. */
+ struct cdbres_read_capacity info;
+ int in_progress = 0;
+ u64 end = calc_future_tsc(5000);
+ for (;;) {
+ if (check_tsc(end)) {
+ dprintf(1, "read capacity failed\n");
+ return -1;
+ }
+
+ int ret = cdb_read_capacity(op, &info);
+ if (!ret)
+ // Success
+ break;
+
+ struct cdbres_request_sense sense;
+ ret = cdb_get_sense(op, &sense);
+ if (ret)
+ // Error - retry.
+ continue;
+
+ // Sense succeeded.
+ if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */
+ dprintf(1, "Device reports MEDIUM NOT PRESENT\n");
+ return -1;
+ }
+
+ if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) {
+ /* IN PROGRESS OF BECOMING READY */
+ printf("Waiting for device to detect medium... ");
+ /* Allow 30 seconds more */
+ end = calc_future_tsc(30000);
+ in_progress = 1;
+ }
+ }
+
+ u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
+ if (blksize != GET_GLOBAL(op->drive_g->blksize)) {
+ printf("Unsupported sector size %u\n", blksize);
+ return -1;
+ }
+
+ dprintf(6, "sectors=%u\n", sectors);
+ printf("%dMB medium detected\n", sectors>>(20-11));
+ return 0;
+}
+
+int
+cdrom_boot(struct drive_s *drive_g)
+{
+ struct disk_op_s dop;
+ int cdid = getDriveId(EXTTYPE_CD, drive_g);
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_g = drive_g;
+ if (!dop.drive_g || cdid < 0)
+ return 1;
+
+ int ret = atapi_is_ready(&dop);
+ if (ret)
+ dprintf(1, "atapi_is_ready returned %d\n", ret);
+
+ // Read the Boot Record Volume Descriptor
+ u8 buffer[2048];
+ dop.lba = 0x11;
+ dop.count = 1;
+ dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer);
+ ret = cdb_read(&dop);
+ if (ret)
+ return 3;
+
+ // Validity checks
+ if (buffer[0])
+ return 4;
+ if (strcmp((char*)&buffer[1], "CD001\001EL TORITO SPECIFICATION") != 0)
+ return 5;
+
+ // ok, now we calculate the Boot catalog address
+ u32 lba = *(u32*)&buffer[0x47];
+
+ // And we read the Boot Catalog
+ dop.lba = lba;
+ dop.count = 1;
+ ret = cdb_read(&dop);
+ if (ret)
+ return 7;
+
+ // Validation entry
+ if (buffer[0x00] != 0x01)
+ return 8; // Header
+ if (buffer[0x01] != 0x00)
+ return 9; // Platform
+ if (buffer[0x1E] != 0x55)
+ return 10; // key 1
+ if (buffer[0x1F] != 0xAA)
+ return 10; // key 2
+
+ // Initial/Default Entry
+ if (buffer[0x20] != 0x88)
+ return 11; // Bootable
+
+ u16 ebda_seg = get_ebda_seg();
+ u8 media = buffer[0x21];
+ SET_EBDA2(ebda_seg, cdemu.media, media);
+
+ SET_EBDA2(ebda_seg, cdemu.emulated_drive_gf, dop.drive_g);
+
+ u16 boot_segment = *(u16*)&buffer[0x22];
+ if (!boot_segment)
+ boot_segment = 0x07C0;
+ SET_EBDA2(ebda_seg, cdemu.load_segment, boot_segment);
+ SET_EBDA2(ebda_seg, cdemu.buffer_segment, 0x0000);
+
+ u16 nbsectors = *(u16*)&buffer[0x26];
+ SET_EBDA2(ebda_seg, cdemu.sector_count, nbsectors);
+
+ lba = *(u32*)&buffer[0x28];
+ SET_EBDA2(ebda_seg, cdemu.ilba, lba);
+
+ // And we read the image in memory
+ dop.lba = lba;
+ dop.count = DIV_ROUND_UP(nbsectors, 4);
+ dop.buf_fl = MAKE_FLATPTR(boot_segment, 0);
+ ret = cdb_read(&dop);
+ if (ret)
+ return 12;
+
+ if (media == 0) {
+ // No emulation requested - return success.
+ SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, EXTSTART_CD + cdid);
+ return 0;
+ }
+
+ // Emulation of a floppy/harddisk requested
+ if (! CONFIG_CDROM_EMU || !cdemu_drive_gf)
+ return 13;
+
+ // Set emulated drive id and increase bios installed hardware
+ // number of devices
+ if (media < 4) {
+ // Floppy emulation
+ SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x00);
+ // XXX - get and set actual floppy count.
+ SETBITS_BDA(equipment_list_flags, 0x41);
+
+ switch (media) {
+ case 0x01: // 1.2M floppy
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, 15);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+ break;
+ case 0x02: // 1.44M floppy
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, 18);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+ break;
+ case 0x03: // 2.88M floppy
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, 36);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders, 80);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, 2);
+ break;
+ }
+ } else {
+ // Harddrive emulation
+ SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, 0x80);
+ SET_BDA(hdcount, GET_BDA(hdcount) + 1);
+
+ // Peak at partition table to get chs.
+ struct mbr_s *mbr = (void*)0;
+ u8 sptcyl = GET_FARVAR(boot_segment, mbr->partitions[0].last.sptcyl);
+ u8 cyllow = GET_FARVAR(boot_segment, mbr->partitions[0].last.cyllow);
+ u8 heads = GET_FARVAR(boot_segment, mbr->partitions[0].last.heads);
+
+ SET_EBDA2(ebda_seg, cdemu.lchs.spt, sptcyl & 0x3f);
+ SET_EBDA2(ebda_seg, cdemu.lchs.cylinders
+ , ((sptcyl<<2)&0x300) + cyllow + 1);
+ SET_EBDA2(ebda_seg, cdemu.lchs.heads, heads + 1);
+ }
+
+ // everything is ok, so from now on, the emulation is active
+ SET_EBDA2(ebda_seg, cdemu.active, 0x01);
+ dprintf(6, "cdemu media=%d\n", media);
+
+ return 0;
+}
--- /dev/null
+// 16bit code to handle system clocks.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "util.h" // debug_enter
+#include "disk.h" // floppy_tick
+#include "cmos.h" // inb_cmos
+#include "pic.h" // eoi_pic1
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_GLOBAL
+#include "usb-hid.h" // usb_check_event
+
+// RTC register flags
+#define RTC_A_UIP 0x80
+
+#define RTC_B_SET 0x80
+#define RTC_B_PIE 0x40
+#define RTC_B_AIE 0x20
+#define RTC_B_UIE 0x10
+#define RTC_B_BIN 0x04
+#define RTC_B_24HR 0x02
+#define RTC_B_DSE 0x01
+
+
+// Bits for PORT_PS2_CTRLB
+#define PPCB_T2GATE (1<<0)
+#define PPCB_SPKR (1<<1)
+#define PPCB_T2OUT (1<<5)
+
+// Bits for PORT_PIT_MODE
+#define PM_SEL_TIMER0 (0<<6)
+#define PM_SEL_TIMER1 (1<<6)
+#define PM_SEL_TIMER2 (2<<6)
+#define PM_SEL_READBACK (3<<6)
+#define PM_ACCESS_LATCH (0<<4)
+#define PM_ACCESS_LOBYTE (1<<4)
+#define PM_ACCESS_HIBYTE (2<<4)
+#define PM_ACCESS_WORD (3<<4)
+#define PM_MODE0 (0<<1)
+#define PM_MODE1 (1<<1)
+#define PM_MODE2 (2<<1)
+#define PM_MODE3 (3<<1)
+#define PM_MODE4 (4<<1)
+#define PM_MODE5 (5<<1)
+#define PM_CNT_BINARY (0<<0)
+#define PM_CNT_BCD (1<<0)
+
+
+/****************************************************************
+ * TSC timer
+ ****************************************************************/
+
+#define CALIBRATE_COUNT 0x800 // Approx 1.7ms
+
+u32 cpu_khz VAR16VISIBLE;
+
+static void
+calibrate_tsc(void)
+{
+ // Setup "timer2"
+ u8 orig = inb(PORT_PS2_CTRLB);
+ outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB);
+ /* binary, mode 0, LSB/MSB, Ch 2 */
+ outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE);
+ /* LSB of ticks */
+ outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2);
+ /* MSB of ticks */
+ outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2);
+
+ u64 start = rdtscll();
+ while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0)
+ ;
+ u64 end = rdtscll();
+
+ // Restore PORT_PS2_CTRLB
+ outb(orig, PORT_PS2_CTRLB);
+
+ // Store calibrated cpu khz.
+ u64 diff = end - start;
+ dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n"
+ , (u32)start, (u32)end, (u32)diff);
+ u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT;
+ SET_GLOBAL(cpu_khz, hz / 1000);
+
+ dprintf(1, "CPU Mhz=%u\n", hz / 1000000);
+}
+
+static void
+tscdelay(u64 diff)
+{
+ u64 start = rdtscll();
+ u64 end = start + diff;
+ while (!check_tsc(end))
+ cpu_relax();
+}
+
+static void
+tscsleep(u64 diff)
+{
+ u64 start = rdtscll();
+ u64 end = start + diff;
+ while (!check_tsc(end))
+ yield();
+}
+
+void ndelay(u32 count) {
+ tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void udelay(u32 count) {
+ tscdelay(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void mdelay(u32 count) {
+ tscdelay(count * GET_GLOBAL(cpu_khz));
+}
+
+void nsleep(u32 count) {
+ tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000);
+}
+void usleep(u32 count) {
+ tscsleep(count * GET_GLOBAL(cpu_khz) / 1000);
+}
+void msleep(u32 count) {
+ tscsleep(count * GET_GLOBAL(cpu_khz));
+}
+
+// Return the TSC value that is 'msecs' time in the future.
+u64
+calc_future_tsc(u32 msecs)
+{
+ u32 khz = GET_GLOBAL(cpu_khz);
+ return rdtscll() + ((u64)khz * msecs);
+}
+u64
+calc_future_tsc_usec(u32 usecs)
+{
+ u32 khz = GET_GLOBAL(cpu_khz);
+ return rdtscll() + ((u64)(khz/1000) * usecs);
+}
+
+
+/****************************************************************
+ * Init
+ ****************************************************************/
+
+static int
+rtc_updating(void)
+{
+ // This function checks to see if the update-in-progress bit
+ // is set in CMOS Status Register A. If not, it returns 0.
+ // If it is set, it tries to wait until there is a transition
+ // to 0, and will return 0 if such a transition occurs. A -1
+ // is returned only after timing out. The maximum period
+ // that this bit should be set is constrained to (1984+244)
+ // useconds, but we wait for longer just to be sure.
+
+ if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+ return 0;
+ u64 end = calc_future_tsc(15);
+ for (;;) {
+ if ((inb_cmos(CMOS_STATUS_A) & RTC_A_UIP) == 0)
+ return 0;
+ if (check_tsc(end))
+ // update-in-progress never transitioned to 0
+ return -1;
+ yield();
+ }
+}
+
+static void
+pit_setup(void)
+{
+ // timer0: binary count, 16bit count, mode 2
+ outb(PM_SEL_TIMER0|PM_ACCESS_WORD|PM_MODE2|PM_CNT_BINARY, PORT_PIT_MODE);
+ // maximum count of 0000H = 18.2Hz
+ outb(0x0, PORT_PIT_COUNTER0);
+ outb(0x0, PORT_PIT_COUNTER0);
+}
+
+static void
+init_rtc(void)
+{
+ outb_cmos(0x26, CMOS_STATUS_A); // 32,768Khz src, 976.5625us updates
+ u8 regB = inb_cmos(CMOS_STATUS_B);
+ outb_cmos((regB & RTC_B_DSE) | RTC_B_24HR, CMOS_STATUS_B);
+ inb_cmos(CMOS_STATUS_C);
+ inb_cmos(CMOS_STATUS_D);
+}
+
+static u32
+bcd2bin(u8 val)
+{
+ return (val & 0xf) + ((val >> 4) * 10);
+}
+
+void
+timer_setup(void)
+{
+ dprintf(3, "init timer\n");
+ calibrate_tsc();
+ pit_setup();
+
+ init_rtc();
+ rtc_updating();
+ u32 seconds = bcd2bin(inb_cmos(CMOS_RTC_SECONDS));
+ u32 minutes = bcd2bin(inb_cmos(CMOS_RTC_MINUTES));
+ u32 hours = bcd2bin(inb_cmos(CMOS_RTC_HOURS));
+ u32 ticks = (hours * 60 + minutes) * 60 + seconds;
+ ticks = ((u64)ticks * PIT_TICK_RATE) / PIT_TICK_INTERVAL;
+ SET_BDA(timer_counter, ticks);
+
+ enable_hwirq(0, FUNC16(entry_08));
+ enable_hwirq(8, FUNC16(entry_70));
+}
+
+
+/****************************************************************
+ * Standard clock functions
+ ****************************************************************/
+
+#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL)
+
+// Calculate the timer value at 'count' number of full timer ticks in
+// the future.
+u32
+calc_future_timer_ticks(u32 count)
+{
+ return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY;
+}
+
+// Return the timer value that is 'msecs' time in the future.
+u32
+calc_future_timer(u32 msecs)
+{
+ if (!msecs)
+ return GET_BDA(timer_counter);
+ u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL);
+ u32 ticks = DIV_ROUND_UP(kticks, 1000);
+ return calc_future_timer_ticks(ticks);
+}
+
+// Check if the given timer value has passed.
+int
+check_timer(u32 end)
+{
+ return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY)
+ < (TICKS_PER_DAY/2));
+}
+
+// get current clock count
+static void
+handle_1a00(struct bregs *regs)
+{
+ yield();
+ u32 ticks = GET_BDA(timer_counter);
+ regs->cx = ticks >> 16;
+ regs->dx = ticks;
+ regs->al = GET_BDA(timer_rollover);
+ SET_BDA(timer_rollover, 0); // reset flag
+ set_success(regs);
+}
+
+// Set Current Clock Count
+static void
+handle_1a01(struct bregs *regs)
+{
+ u32 ticks = (regs->cx << 16) | regs->dx;
+ SET_BDA(timer_counter, ticks);
+ SET_BDA(timer_rollover, 0); // reset flag
+ // XXX - should use set_code_success()?
+ regs->ah = 0;
+ set_success(regs);
+}
+
+// Read CMOS Time
+static void
+handle_1a02(struct bregs *regs)
+{
+ if (rtc_updating()) {
+ set_invalid(regs);
+ return;
+ }
+
+ regs->dh = inb_cmos(CMOS_RTC_SECONDS);
+ regs->cl = inb_cmos(CMOS_RTC_MINUTES);
+ regs->ch = inb_cmos(CMOS_RTC_HOURS);
+ regs->dl = inb_cmos(CMOS_STATUS_B) & RTC_B_DSE;
+ regs->ah = 0;
+ regs->al = regs->ch;
+ set_success(regs);
+}
+
+// Set CMOS Time
+static void
+handle_1a03(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3
+ // before 1111 1101 0111 1101 0000 0000
+ // after 0110 0010 0110 0010 0000 0010
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = ((RegB & 01100000b) | 00000010b)
+ if (rtc_updating()) {
+ init_rtc();
+ // fall through as if an update were not in progress
+ }
+ outb_cmos(regs->dh, CMOS_RTC_SECONDS);
+ outb_cmos(regs->cl, CMOS_RTC_MINUTES);
+ outb_cmos(regs->ch, CMOS_RTC_HOURS);
+ // Set Daylight Savings time enabled bit to requested value
+ u8 val8 = ((inb_cmos(CMOS_STATUS_B) & (RTC_B_PIE|RTC_B_AIE))
+ | RTC_B_24HR | (regs->dl & RTC_B_DSE));
+ outb_cmos(val8, CMOS_STATUS_B);
+ regs->ah = 0;
+ regs->al = val8; // val last written to Reg B
+ set_success(regs);
+}
+
+// Read CMOS Date
+static void
+handle_1a04(struct bregs *regs)
+{
+ regs->ah = 0;
+ if (rtc_updating()) {
+ set_invalid(regs);
+ return;
+ }
+ regs->cl = inb_cmos(CMOS_RTC_YEAR);
+ regs->dh = inb_cmos(CMOS_RTC_MONTH);
+ regs->dl = inb_cmos(CMOS_RTC_DAY_MONTH);
+ if (CONFIG_COREBOOT) {
+ if (regs->cl > 0x80)
+ regs->ch = 0x19;
+ else
+ regs->ch = 0x20;
+ } else {
+ regs->ch = inb_cmos(CMOS_CENTURY);
+ }
+ regs->al = regs->ch;
+ set_success(regs);
+}
+
+// Set CMOS Date
+static void
+handle_1a05(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3 try#4
+ // before 1111 1101 0111 1101 0000 0010 0000 0000
+ // after 0110 1101 0111 1101 0000 0010 0000 0000
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = (RegB & 01111111b)
+ if (rtc_updating()) {
+ init_rtc();
+ set_invalid(regs);
+ return;
+ }
+ outb_cmos(regs->cl, CMOS_RTC_YEAR);
+ outb_cmos(regs->dh, CMOS_RTC_MONTH);
+ outb_cmos(regs->dl, CMOS_RTC_DAY_MONTH);
+ if (!CONFIG_COREBOOT)
+ outb_cmos(regs->ch, CMOS_CENTURY);
+ // clear halt-clock bit
+ u8 val8 = inb_cmos(CMOS_STATUS_B) & ~RTC_B_SET;
+ outb_cmos(val8, CMOS_STATUS_B);
+ regs->ah = 0;
+ regs->al = val8; // AL = val last written to Reg B
+ set_success(regs);
+}
+
+// Set Alarm Time in CMOS
+static void
+handle_1a06(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3
+ // before 1101 1111 0101 1111 0000 0000
+ // after 0110 1111 0111 1111 0010 0000
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = ((RegB & 01111111b) | 00100000b)
+ u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
+ regs->ax = 0;
+ if (val8 & RTC_B_AIE) {
+ // Alarm interrupt enabled already
+ set_invalid(regs);
+ return;
+ }
+ if (rtc_updating()) {
+ init_rtc();
+ // fall through as if an update were not in progress
+ }
+ outb_cmos(regs->dh, CMOS_RTC_SECONDS_ALARM);
+ outb_cmos(regs->cl, CMOS_RTC_MINUTES_ALARM);
+ outb_cmos(regs->ch, CMOS_RTC_HOURS_ALARM);
+ // enable Status Reg B alarm bit, clear halt clock bit
+ outb_cmos((val8 & ~RTC_B_SET) | RTC_B_AIE, CMOS_STATUS_B);
+ set_success(regs);
+}
+
+// Turn off Alarm
+static void
+handle_1a07(struct bregs *regs)
+{
+ // Using a debugger, I notice the following masking/setting
+ // of bits in Status Register B, by setting Reg B to
+ // a few values and getting its value after INT 1A was called.
+ //
+ // try#1 try#2 try#3 try#4
+ // before 1111 1101 0111 1101 0010 0000 0010 0010
+ // after 0100 0101 0101 0101 0000 0000 0000 0010
+ //
+ // Bit4 in try#1 flipped in hardware (forced low) due to bit7=1
+ // My assumption: RegB = (RegB & 01010111b)
+ u8 val8 = inb_cmos(CMOS_STATUS_B); // Get Status Reg B
+ // clear clock-halt bit, disable alarm bit
+ outb_cmos(val8 & ~(RTC_B_SET|RTC_B_AIE), CMOS_STATUS_B);
+ regs->ah = 0;
+ regs->al = val8; // val last written to Reg B
+ set_success(regs);
+}
+
+// Unsupported
+static void
+handle_1aXX(struct bregs *regs)
+{
+ set_unimplemented(regs);
+}
+
+// INT 1Ah Time-of-day Service Entry Point
+void VISIBLE16
+handle_1a(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_1a);
+ switch (regs->ah) {
+ case 0x00: handle_1a00(regs); break;
+ case 0x01: handle_1a01(regs); break;
+ case 0x02: handle_1a02(regs); break;
+ case 0x03: handle_1a03(regs); break;
+ case 0x04: handle_1a04(regs); break;
+ case 0x05: handle_1a05(regs); break;
+ case 0x06: handle_1a06(regs); break;
+ case 0x07: handle_1a07(regs); break;
+ case 0xb1: handle_1ab1(regs); break;
+ default: handle_1aXX(regs); break;
+ }
+}
+
+// INT 08h System Timer ISR Entry Point
+void VISIBLE16
+handle_08(void)
+{
+ debug_isr(DEBUG_ISR_08);
+
+ floppy_tick();
+
+ u32 counter = GET_BDA(timer_counter);
+ counter++;
+ // compare to one days worth of timer ticks at 18.2 hz
+ if (counter >= TICKS_PER_DAY) {
+ // there has been a midnight rollover at this point
+ counter = 0;
+ SET_BDA(timer_rollover, GET_BDA(timer_rollover) + 1);
+ }
+
+ SET_BDA(timer_counter, counter);
+
+ usb_check_event();
+
+ // chain to user timer tick INT #0x1c
+ u32 eax=0, flags;
+ call16_simpint(0x1c, &eax, &flags);
+
+ eoi_pic1();
+}
+
+
+/****************************************************************
+ * Periodic timer
+ ****************************************************************/
+
+void
+useRTC(void)
+{
+ u16 ebda_seg = get_ebda_seg();
+ int count = GET_EBDA2(ebda_seg, RTCusers);
+ SET_EBDA2(ebda_seg, RTCusers, count+1);
+ if (count)
+ return;
+ // Turn on the Periodic Interrupt timer
+ u8 bRegister = inb_cmos(CMOS_STATUS_B);
+ outb_cmos(bRegister | RTC_B_PIE, CMOS_STATUS_B);
+}
+
+void
+releaseRTC(void)
+{
+ u16 ebda_seg = get_ebda_seg();
+ int count = GET_EBDA2(ebda_seg, RTCusers);
+ SET_EBDA2(ebda_seg, RTCusers, count-1);
+ if (count != 1)
+ return;
+ // Clear the Periodic Interrupt.
+ u8 bRegister = inb_cmos(CMOS_STATUS_B);
+ outb_cmos(bRegister & ~RTC_B_PIE, CMOS_STATUS_B);
+}
+
+static int
+set_usertimer(u32 usecs, u16 seg, u16 offset)
+{
+ if (GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING)
+ return -1;
+
+ // Interval not already set.
+ SET_BDA(rtc_wait_flag, RWS_WAIT_PENDING); // Set status byte.
+ SET_BDA(user_wait_complete_flag, SEGOFF(seg, offset));
+ SET_BDA(user_wait_timeout, usecs);
+ useRTC();
+ return 0;
+}
+
+static void
+clear_usertimer(void)
+{
+ if (!(GET_BDA(rtc_wait_flag) & RWS_WAIT_PENDING))
+ return;
+ // Turn off status byte.
+ SET_BDA(rtc_wait_flag, 0);
+ releaseRTC();
+}
+
+#define RET_ECLOCKINUSE 0x83
+
+// Wait for CX:DX microseconds
+void
+handle_1586(struct bregs *regs)
+{
+ // Use the rtc to wait for the specified time.
+ u8 statusflag = 0;
+ u32 count = (regs->cx << 16) | regs->dx;
+ int ret = set_usertimer(count, GET_SEG(SS), (u32)&statusflag);
+ if (ret) {
+ set_code_invalid(regs, RET_ECLOCKINUSE);
+ return;
+ }
+ while (!statusflag)
+ wait_irq();
+ set_success(regs);
+}
+
+// Set Interval requested.
+static void
+handle_158300(struct bregs *regs)
+{
+ int ret = set_usertimer((regs->cx << 16) | regs->dx, regs->es, regs->bx);
+ if (ret)
+ // Interval already set.
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ else
+ set_success(regs);
+}
+
+// Clear interval requested
+static void
+handle_158301(struct bregs *regs)
+{
+ clear_usertimer();
+ set_success(regs);
+}
+
+static void
+handle_1583XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+ regs->al--;
+}
+
+void
+handle_1583(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_158300(regs); break;
+ case 0x01: handle_158301(regs); break;
+ default: handle_1583XX(regs); break;
+ }
+}
+
+#define USEC_PER_RTC DIV_ROUND_CLOSEST(1000000, 1024)
+
+// int70h: IRQ8 - CMOS RTC
+void VISIBLE16
+handle_70(void)
+{
+ debug_isr(DEBUG_ISR_70);
+
+ // Check which modes are enabled and have occurred.
+ u8 registerB = inb_cmos(CMOS_STATUS_B);
+ u8 registerC = inb_cmos(CMOS_STATUS_C);
+
+ if (!(registerB & (RTC_B_PIE|RTC_B_AIE)))
+ goto done;
+ if (registerC & RTC_B_AIE) {
+ // Handle Alarm Interrupt.
+ u32 eax=0, flags;
+ call16_simpint(0x4a, &eax, &flags);
+ }
+ if (!(registerC & RTC_B_PIE))
+ goto done;
+
+ // Handle Periodic Interrupt.
+
+ check_preempt();
+
+ if (!GET_BDA(rtc_wait_flag))
+ goto done;
+
+ // Wait Interval (Int 15, AH=83) active.
+ u32 time = GET_BDA(user_wait_timeout); // Time left in microseconds.
+ if (time < USEC_PER_RTC) {
+ // Done waiting - write to specified flag byte.
+ struct segoff_s segoff = GET_BDA(user_wait_complete_flag);
+ u16 ptr_seg = segoff.seg;
+ u8 *ptr_far = (u8*)(segoff.offset+0);
+ u8 oldval = GET_FARVAR(ptr_seg, *ptr_far);
+ SET_FARVAR(ptr_seg, *ptr_far, oldval | 0x80);
+
+ clear_usertimer();
+ } else {
+ // Continue waiting.
+ time -= USEC_PER_RTC;
+ SET_BDA(user_wait_timeout, time);
+ }
+
+done:
+ eoi_pic2();
+}
--- /dev/null
+// Definitions for X86 CMOS non-volatile memory access.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __CMOS_H
+#define __CMOS_H
+
+#define CMOS_RTC_SECONDS 0x00
+#define CMOS_RTC_SECONDS_ALARM 0x01
+#define CMOS_RTC_MINUTES 0x02
+#define CMOS_RTC_MINUTES_ALARM 0x03
+#define CMOS_RTC_HOURS 0x04
+#define CMOS_RTC_HOURS_ALARM 0x05
+#define CMOS_RTC_DAY_WEEK 0x06
+#define CMOS_RTC_DAY_MONTH 0x07
+#define CMOS_RTC_MONTH 0x08
+#define CMOS_RTC_YEAR 0x09
+#define CMOS_STATUS_A 0x0a
+#define CMOS_STATUS_B 0x0b
+#define CMOS_STATUS_C 0x0c
+#define CMOS_STATUS_D 0x0d
+#define CMOS_RESET_CODE 0x0f
+#define CMOS_FLOPPY_DRIVE_TYPE 0x10
+#define CMOS_DISK_DATA 0x12
+#define CMOS_EQUIPMENT_INFO 0x14
+#define CMOS_DISK_DRIVE1_TYPE 0x19
+#define CMOS_DISK_DRIVE2_TYPE 0x1a
+#define CMOS_DISK_DRIVE1_CYL 0x1b
+#define CMOS_DISK_DRIVE2_CYL 0x24
+#define CMOS_MEM_EXTMEM_LOW 0x30
+#define CMOS_MEM_EXTMEM_HIGH 0x31
+#define CMOS_CENTURY 0x32
+#define CMOS_MEM_EXTMEM2_LOW 0x34
+#define CMOS_MEM_EXTMEM2_HIGH 0x35
+#define CMOS_BIOS_BOOTFLAG1 0x38
+#define CMOS_BIOS_DISKTRANSFLAG 0x39
+#define CMOS_BIOS_BOOTFLAG2 0x3d
+#define CMOS_MEM_HIGHMEM_LOW 0x5b
+#define CMOS_MEM_HIGHMEM_MID 0x5c
+#define CMOS_MEM_HIGHMEM_HIGH 0x5d
+#define CMOS_BIOS_SMP_COUNT 0x5f
+
+// CMOS_FLOPPY_DRIVE_TYPE bitdefs
+#define CFD_NO_DRIVE 0
+#define CFD_360KB 1
+#define CFD_12MB 2
+#define CFD_720KB 3
+#define CFD_144MB 4
+#define CFD_288MB 5
+
+#ifndef __ASSEMBLY__
+
+#include "ioport.h" // inb, outb
+
+static inline u8
+inb_cmos(u8 reg)
+{
+ reg |= NMI_DISABLE_BIT;
+ outb(reg, PORT_CMOS_INDEX);
+ return inb(PORT_CMOS_DATA);
+}
+
+static inline void
+outb_cmos(u8 val, u8 reg)
+{
+ reg |= NMI_DISABLE_BIT;
+ outb(reg, PORT_CMOS_INDEX);
+ outb(val, PORT_CMOS_DATA);
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // cmos.h
--- /dev/null
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include "autoconf.h"
+
+// Configuration definitions.
+
+//#define CONFIG_APPNAME "QEMU"
+//#define CONFIG_CPUNAME8 "QEMUCPU "
+//#define CONFIG_APPNAME6 "QEMU "
+//#define CONFIG_APPNAME4 "QEMU"
+#define CONFIG_APPNAME "Bochs"
+#define CONFIG_CPUNAME8 "BOCHSCPU"
+#define CONFIG_APPNAME6 "BOCHS "
+#define CONFIG_APPNAME4 "BXPC"
+
+// Maximum number of map entries in the e820 map
+#define CONFIG_MAX_E820 32
+// Space to reserve in f-segment for dynamic allocations
+#define CONFIG_MAX_BIOSTABLE 2048
+// Space to reserve in high-memory for tables
+#define CONFIG_MAX_HIGHTABLE (64*1024)
+// Largest supported externaly facing drive id
+#define CONFIG_MAX_EXTDRIVE 16
+// Number of bytes the smbios may be and still live in the f-segment
+#define BUILD_MAX_SMBIOS_FSEG 600
+
+#define CONFIG_MODEL_ID 0xFC
+#define CONFIG_SUBMODEL_ID 0x00
+#define CONFIG_BIOS_REVISION 0x01
+
+// Various memory addresses used by the code.
+#define BUILD_STACK_ADDR 0x7000
+#define BUILD_S3RESUME_STACK_ADDR 0x1000
+#define BUILD_AP_BOOT_ADDR 0x10000
+#define BUILD_EBDA_MINIMUM 0x90000
+#define BUILD_LOWRAM_END 0xa0000
+#define BUILD_ROM_START 0xc0000
+#define BUILD_BIOS_ADDR 0xf0000
+#define BUILD_BIOS_SIZE 0x10000
+// 32KB for shadow ram copying (works around emulator deficiencies)
+#define BUILD_BIOS_TMP_ADDR 0x30000
+#define BUILD_SMM_INIT_ADDR 0x38000
+#define BUILD_SMM_ADDR 0xa8000
+#define BUILD_SMM_SIZE 0x8000
+#define BUILD_MAX_HIGHMEM 0xe0000000
+
+#define BUILD_PCIMEM_START 0xe0000000
+#define BUILD_PCIMEM_END 0xfec00000 /* IOAPIC is mapped at */
+
+#define BUILD_IOAPIC_ADDR 0xfec00000
+#define BUILD_HPET_ADDRESS 0xfed00000
+#define BUILD_APIC_ADDR 0xfee00000
+
+// Important real-mode segments
+#define SEG_IVT 0x0000
+#define SEG_BDA 0x0040
+#define SEG_BIOS 0xf000
+
+// Segment definitions in protected mode (see rombios32_gdt in misc.c)
+#define SEG32_MODE32_CS (1 << 3)
+#define SEG32_MODE32_DS (2 << 3)
+#define SEG32_MODE16_CS (3 << 3)
+#define SEG32_MODE16_DS (4 << 3)
+#define SEG32_MODE16BIG_CS (5 << 3)
+#define SEG32_MODE16BIG_DS (6 << 3)
+
+// Debugging levels. If non-zero and CONFIG_DEBUG_LEVEL is greater
+// than the specified value, then the corresponding irq handler will
+// report every enter event.
+#define DEBUG_ISR_02 1
+#define DEBUG_HDL_05 1
+#define DEBUG_ISR_08 20
+#define DEBUG_ISR_09 9
+#define DEBUG_ISR_0e 9
+#define DEBUG_HDL_10 20
+#define DEBUG_HDL_11 2
+#define DEBUG_HDL_12 2
+#define DEBUG_HDL_13 10
+#define DEBUG_HDL_14 2
+#define DEBUG_HDL_15 9
+#define DEBUG_HDL_16 9
+#define DEBUG_HDL_17 2
+#define DEBUG_HDL_18 1
+#define DEBUG_HDL_19 1
+#define DEBUG_HDL_1a 9
+#define DEBUG_HDL_40 1
+#define DEBUG_ISR_70 9
+#define DEBUG_ISR_74 9
+#define DEBUG_ISR_75 1
+#define DEBUG_ISR_76 10
+#define DEBUG_ISR_hwpic1 5
+#define DEBUG_ISR_hwpic2 5
+#define DEBUG_HDL_pnp 1
+#define DEBUG_HDL_pmm 1
+#define DEBUG_HDL_pcibios32 9
+#define DEBUG_HDL_apm 9
+
+#define DEBUG_unimplemented 2
+#define DEBUG_invalid 3
+#define DEBUG_thread 2
+
+#endif // config.h
--- /dev/null
+// Coreboot interface support.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "memmap.h" // add_e820
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "lzmadecode.h" // LzmaDecode
+#include "smbios.h" // smbios_init
+#include "boot.h" // boot_add_cbfs
+
+
+/****************************************************************
+ * Memory map
+ ****************************************************************/
+
+struct cb_header {
+ u32 signature;
+ u32 header_bytes;
+ u32 header_checksum;
+ u32 table_bytes;
+ u32 table_checksum;
+ u32 table_entries;
+};
+
+#define CB_SIGNATURE 0x4f49424C // "LBIO"
+
+struct cb_memory_range {
+ u64 start;
+ u64 size;
+ u32 type;
+};
+
+#define CB_MEM_TABLE 16
+
+struct cb_memory {
+ u32 tag;
+ u32 size;
+ struct cb_memory_range map[0];
+};
+
+#define CB_TAG_MEMORY 0x01
+
+#define MEM_RANGE_COUNT(_rec) \
+ (((_rec)->size - sizeof(*(_rec))) / sizeof((_rec)->map[0]))
+
+struct cb_mainboard {
+ u32 tag;
+ u32 size;
+ u8 vendor_idx;
+ u8 part_idx;
+ char strings[0];
+};
+
+#define CB_TAG_MAINBOARD 0x0003
+
+struct cb_forward {
+ u32 tag;
+ u32 size;
+ u64 forward;
+};
+
+#define CB_TAG_FORWARD 0x11
+
+static u16
+ipchksum(char *buf, int count)
+{
+ u16 *p = (u16*)buf;
+ u32 sum = 0;
+ while (count > 1) {
+ sum += *p++;
+ count -= 2;
+ }
+ if (count)
+ sum += *(u8*)p;
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ~sum;
+}
+
+// Try to locate the coreboot header in a given address range.
+static struct cb_header *
+find_cb_header(char *addr, int len)
+{
+ char *end = addr + len;
+ for (; addr < end; addr += 16) {
+ struct cb_header *cbh = (struct cb_header *)addr;
+ if (cbh->signature != CB_SIGNATURE)
+ continue;
+ if (! cbh->table_bytes)
+ continue;
+ if (ipchksum(addr, sizeof(*cbh)) != 0)
+ continue;
+ if (ipchksum(addr + sizeof(*cbh), cbh->table_bytes)
+ != cbh->table_checksum)
+ continue;
+ return cbh;
+ }
+ return NULL;
+}
+
+// Try to find the coreboot memory table in the given coreboot table.
+static void *
+find_cb_subtable(struct cb_header *cbh, u32 tag)
+{
+ char *tbl = (char *)cbh + sizeof(*cbh);
+ int i;
+ for (i=0; i<cbh->table_entries; i++) {
+ struct cb_memory *cbm = (struct cb_memory *)tbl;
+ tbl += cbm->size;
+ if (cbm->tag == tag)
+ return cbm;
+ }
+ return NULL;
+}
+
+static struct cb_memory *CBMemTable;
+const char *CBvendor, *CBpart;
+
+// Populate max ram and e820 map info by scanning for a coreboot table.
+static void
+coreboot_fill_map(void)
+{
+ dprintf(3, "Attempting to find coreboot table\n");
+
+ // Find coreboot table.
+ struct cb_header *cbh = find_cb_header(0, 0x1000);
+ if (!cbh)
+ goto fail;
+ struct cb_forward *cbf = find_cb_subtable(cbh, CB_TAG_FORWARD);
+ if (cbf) {
+ dprintf(3, "Found coreboot table forwarder.\n");
+ cbh = find_cb_header((char *)((u32)cbf->forward), 0x100);
+ if (!cbh)
+ goto fail;
+ }
+ dprintf(3, "Now attempting to find coreboot memory map\n");
+ struct cb_memory *cbm = CBMemTable = find_cb_subtable(cbh, CB_TAG_MEMORY);
+ if (!cbm)
+ goto fail;
+
+ u64 maxram = 0, maxram_over4G = 0;
+ int i, count = MEM_RANGE_COUNT(cbm);
+ for (i=0; i<count; i++) {
+ struct cb_memory_range *m = &cbm->map[i];
+ u32 type = m->type;
+ if (type == CB_MEM_TABLE) {
+ type = E820_RESERVED;
+ } else if (type == E820_ACPI || type == E820_RAM) {
+ u64 end = m->start + m->size;
+ if (end > 0x100000000ull) {
+ end -= 0x100000000ull;
+ if (end > maxram_over4G)
+ maxram_over4G = end;
+ } else if (end > maxram)
+ maxram = end;
+ }
+ add_e820(m->start, m->size, type);
+ }
+
+ RamSize = maxram;
+ RamSizeOver4G = maxram_over4G;
+
+ // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this
+ // confuses grub. So, override it.
+ add_e820(0, 16*1024, E820_RAM);
+
+ struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD);
+ if (cbmb) {
+ CBvendor = &cbmb->strings[cbmb->vendor_idx];
+ CBpart = &cbmb->strings[cbmb->part_idx];
+ dprintf(1, "Found mainboard %s %s\n", CBvendor, CBpart);
+ }
+
+ return;
+
+fail:
+ // No table found.. Use 16Megs as a dummy value.
+ dprintf(1, "Unable to find coreboot table!\n");
+ RamSize = 16*1024*1024;
+ RamSizeOver4G = 0;
+ add_e820(0, 16*1024*1024, E820_RAM);
+ return;
+}
+
+
+/****************************************************************
+ * BIOS table copying
+ ****************************************************************/
+
+// Attempt to find (and relocate) any standard bios tables found in a
+// given address range.
+static void
+scan_tables(u32 start, u32 size)
+{
+ void *p = (void*)ALIGN(start, 16);
+ void *end = (void*)start + size;
+ for (; p<end; p += 16) {
+ copy_pir(p);
+ copy_mptable(p);
+ copy_acpi_rsdp(p);
+ copy_smbios(p);
+ }
+}
+
+void
+coreboot_copy_biostable(void)
+{
+ struct cb_memory *cbm = CBMemTable;
+ if (! CONFIG_COREBOOT || !cbm)
+ return;
+
+ dprintf(3, "Relocating coreboot bios tables\n");
+
+ // Scan CB_MEM_TABLE areas for bios tables.
+ int i, count = MEM_RANGE_COUNT(cbm);
+ for (i=0; i<count; i++) {
+ struct cb_memory_range *m = &cbm->map[i];
+ if (m->type == CB_MEM_TABLE)
+ scan_tables(m->start, m->size);
+ }
+
+ // XXX - create a dummy smbios table for now.
+ if (!SMBiosAddr)
+ smbios_init();
+}
+
+
+/****************************************************************
+ * ulzma
+ ****************************************************************/
+
+// Uncompress data in flash to an area of memory.
+static int
+ulzma(u8 *dst, u32 maxlen, const u8 *src, u32 srclen)
+{
+ dprintf(3, "Uncompressing data %d@%p to %d@%p\n", srclen, src, maxlen, dst);
+ CLzmaDecoderState state;
+ int ret = LzmaDecodeProperties(&state.Properties, src, LZMA_PROPERTIES_SIZE);
+ if (ret != LZMA_RESULT_OK) {
+ dprintf(1, "LzmaDecodeProperties error - %d\n", ret);
+ return -1;
+ }
+ u8 scratch[15980];
+ int need = (LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
+ if (need > sizeof(scratch)) {
+ dprintf(1, "LzmaDecode need %d have %d\n", need, (unsigned int)sizeof(scratch));
+ return -1;
+ }
+ state.Probs = (CProb *)scratch;
+
+ u32 dstlen = *(u32*)(src + LZMA_PROPERTIES_SIZE);
+ if (dstlen > maxlen) {
+ dprintf(1, "LzmaDecode too large (max %d need %d)\n", maxlen, dstlen);
+ return -1;
+ }
+ u32 inProcessed, outProcessed;
+ ret = LzmaDecode(&state, src + LZMA_PROPERTIES_SIZE + 8, srclen
+ , &inProcessed, dst, dstlen, &outProcessed);
+ if (ret) {
+ dprintf(1, "LzmaDecode returned %d\n", ret);
+ return -1;
+ }
+ return dstlen;
+}
+
+
+/****************************************************************
+ * Coreboot flash format
+ ****************************************************************/
+
+#define CBFS_HEADER_MAGIC 0x4F524243
+#define CBFS_HEADPTR_ADDR 0xFFFFFFFc
+#define CBFS_VERSION1 0x31313131
+
+struct cbfs_header {
+ u32 magic;
+ u32 version;
+ u32 romsize;
+ u32 bootblocksize;
+ u32 align;
+ u32 offset;
+ u32 pad[2];
+} PACKED;
+
+static struct cbfs_header *CBHDR;
+
+static void
+cbfs_setup(void)
+{
+ if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+ return;
+
+ CBHDR = *(void **)CBFS_HEADPTR_ADDR;
+ if (CBHDR->magic != htonl(CBFS_HEADER_MAGIC)) {
+ dprintf(1, "Unable to find CBFS (ptr=%p; got %x not %x)\n"
+ , CBHDR, CBHDR->magic, htonl(CBFS_HEADER_MAGIC));
+ CBHDR = NULL;
+ return;
+ }
+
+ dprintf(1, "Found CBFS header at %p\n", CBHDR);
+}
+
+#define CBFS_FILE_MAGIC 0x455649484352414cLL // LARCHIVE
+
+struct cbfs_file {
+ u64 magic;
+ u32 len;
+ u32 type;
+ u32 checksum;
+ u32 offset;
+ char filename[0];
+} PACKED;
+
+// Verify a cbfs entry looks valid.
+static struct cbfs_file *
+cbfs_verify(struct cbfs_file *file)
+{
+ if (file < (struct cbfs_file *)(0xFFFFFFFF - ntohl(CBHDR->romsize)))
+ return NULL;
+ u64 magic = file->magic;
+ if (magic == CBFS_FILE_MAGIC) {
+ dprintf(5, "Found CBFS file %s\n", file->filename);
+ return file;
+ }
+ return NULL;
+}
+
+// Return the first file in the CBFS archive
+static struct cbfs_file *
+cbfs_getfirst(void)
+{
+ if (! CBHDR)
+ return NULL;
+ return cbfs_verify((void *)(0 - ntohl(CBHDR->romsize) + ntohl(CBHDR->offset)));
+}
+
+// Return the file after the given file.
+static struct cbfs_file *
+cbfs_getnext(struct cbfs_file *file)
+{
+ file = (void*)file + ALIGN(ntohl(file->len) + ntohl(file->offset), ntohl(CBHDR->align));
+ return cbfs_verify(file);
+}
+
+// Find the file with the given filename.
+struct cbfs_file *
+cbfs_findfile(const char *fname)
+{
+ dprintf(3, "Searching CBFS for %s\n", fname);
+ struct cbfs_file *file;
+ for (file = cbfs_getfirst(); file; file = cbfs_getnext(file))
+ if (strcmp(fname, file->filename) == 0)
+ return file;
+ return NULL;
+}
+
+// Find next file with the given filename prefix.
+struct cbfs_file *
+cbfs_findprefix(const char *prefix, struct cbfs_file *last)
+{
+ if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH)
+ return NULL;
+
+ dprintf(3, "Searching CBFS for prefix %s\n", prefix);
+ int len = strlen(prefix);
+ struct cbfs_file *file;
+ if (! last)
+ file = cbfs_getfirst();
+ else
+ file = cbfs_getnext(last);
+ for (; file; file = cbfs_getnext(file))
+ if (memcmp(prefix, file->filename, len) == 0)
+ return file;
+ return NULL;
+}
+
+// Find a file with the given filename (possibly with ".lzma" extension).
+struct cbfs_file *
+cbfs_finddatafile(const char *fname)
+{
+ int fnlen = strlen(fname);
+ struct cbfs_file *file = NULL;
+ for (;;) {
+ file = cbfs_findprefix(fname, file);
+ if (!file)
+ return NULL;
+ if (file->filename[fnlen] == '\0'
+ || strcmp(&file->filename[fnlen], ".lzma") == 0)
+ return file;
+ }
+}
+
+// Determine whether the file has a ".lzma" extension.
+static int
+cbfs_iscomp(struct cbfs_file *file)
+{
+ int fnamelen = strlen(file->filename);
+ return fnamelen > 5 && strcmp(&file->filename[fnamelen-5], ".lzma") == 0;
+}
+
+// Return the filename of a given file.
+const char *
+cbfs_filename(struct cbfs_file *file)
+{
+ return file->filename;
+}
+
+// Determine the uncompressed size of a datafile.
+u32
+cbfs_datasize(struct cbfs_file *file)
+{
+ void *src = (void*)file + ntohl(file->offset);
+ if (cbfs_iscomp(file))
+ return *(u32*)(src + LZMA_PROPERTIES_SIZE);
+ return ntohl(file->len);
+}
+
+// Copy a file to memory (uncompressing if necessary)
+int
+cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen)
+{
+ if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file)
+ return -1;
+
+ u32 size = ntohl(file->len);
+ void *src = (void*)file + ntohl(file->offset);
+ if (cbfs_iscomp(file)) {
+ // Compressed - copy to temp ram and uncompress it.
+ void *temp = malloc_tmphigh(size);
+ if (!temp)
+ return -1;
+ iomemcpy(temp, src, size);
+ int ret = ulzma(dst, maxlen, temp, size);
+ yield();
+ free(temp);
+ return ret;
+ }
+
+ // Not compressed.
+ dprintf(3, "Copying data %d@%p to %d@%p\n", size, src, maxlen, dst);
+ if (size > maxlen) {
+ warn_noalloc();
+ return -1;
+ }
+ iomemcpy(dst, src, size);
+ return size;
+}
+
+struct cbfs_payload_segment {
+ u32 type;
+ u32 compression;
+ u32 offset;
+ u64 load_addr;
+ u32 len;
+ u32 mem_len;
+} PACKED;
+
+#define PAYLOAD_SEGMENT_BSS 0x20535342
+#define PAYLOAD_SEGMENT_ENTRY 0x52544E45
+
+#define CBFS_COMPRESS_NONE 0
+#define CBFS_COMPRESS_LZMA 1
+
+struct cbfs_payload {
+ struct cbfs_payload_segment segments[1];
+};
+
+void
+cbfs_run_payload(struct cbfs_file *file)
+{
+ if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !file)
+ return;
+ dprintf(1, "Run %s\n", file->filename);
+ struct cbfs_payload *pay = (void*)file + ntohl(file->offset);
+ struct cbfs_payload_segment *seg = pay->segments;
+ for (;;) {
+ void *src = (void*)pay + ntohl(seg->offset);
+ void *dest = (void*)ntohl((u32)seg->load_addr);
+ u32 src_len = ntohl(seg->len);
+ u32 dest_len = ntohl(seg->mem_len);
+ switch (seg->type) {
+ case PAYLOAD_SEGMENT_BSS:
+ dprintf(3, "BSS segment %d@%p\n", dest_len, dest);
+ memset(dest, 0, dest_len);
+ break;
+ case PAYLOAD_SEGMENT_ENTRY: {
+ dprintf(1, "Calling addr %p\n", dest);
+ void (*func)() = dest;
+ func();
+ return;
+ }
+ default:
+ dprintf(3, "Segment %x %d@%p -> %d@%p\n"
+ , seg->type, src_len, src, dest_len, dest);
+ if (seg->compression == htonl(CBFS_COMPRESS_NONE)) {
+ if (src_len > dest_len)
+ src_len = dest_len;
+ memcpy(dest, src, src_len);
+ } else if (CONFIG_LZMA
+ && seg->compression == htonl(CBFS_COMPRESS_LZMA)) {
+ int ret = ulzma(dest, dest_len, src, src_len);
+ if (ret < 0)
+ return;
+ src_len = ret;
+ } else {
+ dprintf(1, "No support for compression type %x\n"
+ , seg->compression);
+ return;
+ }
+ if (dest_len > src_len)
+ memset(dest + src_len, 0, dest_len - src_len);
+ break;
+ }
+ seg++;
+ }
+}
+
+// Register payloads in "img/" directory with boot system.
+void
+cbfs_payload_setup(void)
+{
+ struct cbfs_file *file = NULL;
+ for (;;) {
+ file = cbfs_findprefix("img/", file);
+ if (!file)
+ break;
+ const char *filename = cbfs_filename(file);
+ char *desc = znprintf(MAXDESCSIZE, "Payload [%s]", &filename[4]);
+ boot_add_cbfs(file, desc, bootprio_find_named_rom(filename, 0));
+ }
+}
+
+void
+coreboot_setup(void)
+{
+ coreboot_fill_map();
+ cbfs_setup();
+}
--- /dev/null
+// 16bit code to access hard drives.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // floppy_13
+#include "biosvar.h" // SET_BDA
+#include "config.h" // CONFIG_*
+#include "util.h" // debug_enter
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+#include "pci.h" // pci_bdf_to_bus
+#include "ata.h" // ATA_CB_DC
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+void
+__disk_ret(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ if (regs->dl < EXTSTART_HD)
+ SET_BDA(floppy_last_status, code);
+ else
+ SET_BDA(disk_last_status, code);
+ if (code)
+ __set_code_invalid(regs, linecode, fname);
+ else
+ set_code_success(regs);
+}
+
+void
+__disk_ret_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ if (regs->dl < EXTSTART_HD)
+ SET_BDA(floppy_last_status, code);
+ else
+ SET_BDA(disk_last_status, code);
+ __set_code_unimplemented(regs, linecode, fname);
+}
+
+static void
+__disk_stub(struct bregs *regs, int lineno, const char *fname)
+{
+ __warn_unimplemented(regs, lineno, fname);
+ __disk_ret(regs, DISK_RET_SUCCESS | (lineno << 8), fname);
+}
+
+#define DISK_STUB(regs) \
+ __disk_stub((regs), __LINE__, __func__)
+
+// Get the cylinders/heads/sectors for the given drive.
+static void
+fillLCHS(struct drive_s *drive_g, u16 *nlc, u16 *nlh, u16 *nlspt)
+{
+ if (CONFIG_CDROM_EMU
+ && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf))) {
+ // Emulated drive - get info from ebda. (It's not possible to
+ // populate the geometry directly in the driveid because the
+ // geometry is only known after the bios segment is made
+ // read-only).
+ u16 ebda_seg = get_ebda_seg();
+ *nlc = GET_EBDA2(ebda_seg, cdemu.lchs.cylinders);
+ *nlh = GET_EBDA2(ebda_seg, cdemu.lchs.heads);
+ *nlspt = GET_EBDA2(ebda_seg, cdemu.lchs.spt);
+ return;
+ }
+ *nlc = GET_GLOBAL(drive_g->lchs.cylinders);
+ *nlh = GET_GLOBAL(drive_g->lchs.heads);
+ *nlspt = GET_GLOBAL(drive_g->lchs.spt);
+}
+
+// Perform read/write/verify using old-style chs accesses
+static void
+basic_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
+{
+ struct disk_op_s dop;
+ dop.drive_g = drive_g;
+ dop.command = command;
+
+ u8 count = regs->al;
+ u16 cylinder = regs->ch | ((((u16)regs->cl) << 2) & 0x300);
+ u16 sector = regs->cl & 0x3f;
+ u16 head = regs->dh;
+
+ if (count > 128 || count == 0 || sector == 0) {
+ warn_invalid(regs);
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+ dop.count = count;
+
+ u16 nlc, nlh, nlspt;
+ fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+ // sanity check on cyl heads, sec
+ if (cylinder >= nlc || head >= nlh || sector > nlspt) {
+ warn_invalid(regs);
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ // translate lchs to lba
+ dop.lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
+ + (u32)sector - 1);
+
+ dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
+
+ int status = send_disk_op(&dop);
+
+ regs->al = dop.count;
+
+ disk_ret(regs, status);
+}
+
+// Perform read/write/verify using new-style "int13ext" accesses.
+static void
+extended_access(struct bregs *regs, struct drive_s *drive_g, u16 command)
+{
+ struct disk_op_s dop;
+ // Get lba and check.
+ dop.lba = GET_INT13EXT(regs, lba);
+ dop.command = command;
+ dop.drive_g = drive_g;
+ if (dop.lba >= GET_GLOBAL(drive_g->sectors)) {
+ warn_invalid(regs);
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ dop.buf_fl = SEGOFF_TO_FLATPTR(GET_INT13EXT(regs, data));
+ dop.count = GET_INT13EXT(regs, count);
+
+ int status = send_disk_op(&dop);
+
+ SET_INT13EXT(regs, count, dop.count);
+
+ disk_ret(regs, status);
+}
+
+
+/****************************************************************
+ * Hard Drive functions
+ ****************************************************************/
+
+// disk controller reset
+static void
+disk_1300(struct bregs *regs, struct drive_s *drive_g)
+{
+ struct disk_op_s dop;
+ dop.drive_g = drive_g;
+ dop.command = CMD_RESET;
+ int status = send_disk_op(&dop);
+ disk_ret(regs, status);
+}
+
+// read disk status
+static void
+disk_1301(struct bregs *regs, struct drive_s *drive_g)
+{
+ u8 v;
+ if (regs->dl < EXTSTART_HD)
+ // Floppy
+ v = GET_BDA(floppy_last_status);
+ else
+ v = GET_BDA(disk_last_status);
+ regs->ah = v;
+ set_cf(regs, v);
+ // XXX - clear disk_last_status?
+}
+
+// read disk sectors
+static void
+disk_1302(struct bregs *regs, struct drive_s *drive_g)
+{
+ basic_access(regs, drive_g, CMD_READ);
+}
+
+// write disk sectors
+static void
+disk_1303(struct bregs *regs, struct drive_s *drive_g)
+{
+ basic_access(regs, drive_g, CMD_WRITE);
+}
+
+// verify disk sectors
+static void
+disk_1304(struct bregs *regs, struct drive_s *drive_g)
+{
+ basic_access(regs, drive_g, CMD_VERIFY);
+}
+
+// format disk track
+static void
+disk_1305(struct bregs *regs, struct drive_s *drive_g)
+{
+ debug_stub(regs);
+
+ u16 nlc, nlh, nlspt;
+ fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+ u8 num_sectors = regs->al;
+ u8 head = regs->dh;
+
+ if (head >= nlh || num_sectors == 0 || num_sectors > nlspt) {
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ struct disk_op_s dop;
+ dop.drive_g = drive_g;
+ dop.command = CMD_FORMAT;
+ dop.lba = head;
+ dop.count = num_sectors;
+ dop.buf_fl = MAKE_FLATPTR(regs->es, regs->bx);
+ int status = send_disk_op(&dop);
+ disk_ret(regs, status);
+}
+
+// read disk drive parameters
+static void
+disk_1308(struct bregs *regs, struct drive_s *drive_g)
+{
+ u16 ebda_seg = get_ebda_seg();
+ // Get logical geometry from table
+ u16 nlc, nlh, nlspt;
+ fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+ nlc--;
+ nlh--;
+ u8 count;
+ if (regs->dl < EXTSTART_HD) {
+ // Floppy
+ count = GET_GLOBAL(FloppyCount);
+
+ if (CONFIG_CDROM_EMU
+ && drive_g == GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf)))
+ regs->bx = GET_EBDA2(ebda_seg, cdemu.media) * 2;
+ else
+ regs->bx = GET_GLOBAL(drive_g->floppy_type);
+
+ // set es & di to point to 11 byte diskette param table in ROM
+ regs->es = SEG_BIOS;
+ regs->di = (u32)&diskette_param_table2;
+ } else if (regs->dl < EXTSTART_CD) {
+ // Hard drive
+ count = GET_BDA(hdcount);
+ nlc--; // last sector reserved
+ } else {
+ // Not supported on CDROM
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ if (CONFIG_CDROM_EMU && GET_EBDA2(ebda_seg, cdemu.active)) {
+ u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+ if (((emudrive ^ regs->dl) & 0x80) == 0)
+ // Note extra drive due to emulation.
+ count++;
+ if (regs->dl < EXTSTART_HD && count > 2)
+ // Max of two floppy drives.
+ count = 2;
+ }
+
+ regs->al = 0;
+ regs->ch = nlc & 0xff;
+ regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
+ regs->dh = nlh;
+
+ disk_ret(regs, DISK_RET_SUCCESS);
+ regs->dl = count;
+}
+
+// initialize drive parameters
+static void
+disk_1309(struct bregs *regs, struct drive_s *drive_g)
+{
+ DISK_STUB(regs);
+}
+
+// seek to specified cylinder
+static void
+disk_130c(struct bregs *regs, struct drive_s *drive_g)
+{
+ DISK_STUB(regs);
+}
+
+// alternate disk reset
+static void
+disk_130d(struct bregs *regs, struct drive_s *drive_g)
+{
+ DISK_STUB(regs);
+}
+
+// check drive ready
+static void
+disk_1310(struct bregs *regs, struct drive_s *drive_g)
+{
+ // should look at 40:8E also???
+
+ struct disk_op_s dop;
+ dop.drive_g = drive_g;
+ dop.command = CMD_ISREADY;
+ int status = send_disk_op(&dop);
+ disk_ret(regs, status);
+}
+
+// recalibrate
+static void
+disk_1311(struct bregs *regs, struct drive_s *drive_g)
+{
+ DISK_STUB(regs);
+}
+
+// controller internal diagnostic
+static void
+disk_1314(struct bregs *regs, struct drive_s *drive_g)
+{
+ DISK_STUB(regs);
+}
+
+// read disk drive size
+static void
+disk_1315(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+ if (regs->dl < EXTSTART_HD || regs->dl >= EXTSTART_CD) {
+ // Floppy or cdrom
+ regs->ah = 1;
+ return;
+ }
+ // Hard drive
+
+ // Get logical geometry from table
+ u16 nlc, nlh, nlspt;
+ fillLCHS(drive_g, &nlc, &nlh, &nlspt);
+
+ // Compute sector count seen by int13
+ u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
+ regs->cx = lba >> 16;
+ regs->dx = lba & 0xffff;
+ regs->ah = 3; // hard disk accessible
+}
+
+static void
+disk_1316(struct bregs *regs, struct drive_s *drive_g)
+{
+ if (regs->dl >= EXTSTART_HD) {
+ // Hard drive
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+ disk_ret(regs, DISK_RET_ECHANGED);
+}
+
+// IBM/MS installation check
+static void
+disk_1341(struct bregs *regs, struct drive_s *drive_g)
+{
+ regs->bx = 0xaa55; // install check
+ regs->cx = 0x0007; // ext disk access and edd, removable supported
+ disk_ret(regs, DISK_RET_SUCCESS);
+ regs->ah = 0x30; // EDD 3.0
+}
+
+// IBM/MS extended read
+static void
+disk_1342(struct bregs *regs, struct drive_s *drive_g)
+{
+ extended_access(regs, drive_g, CMD_READ);
+}
+
+// IBM/MS extended write
+static void
+disk_1343(struct bregs *regs, struct drive_s *drive_g)
+{
+ extended_access(regs, drive_g, CMD_WRITE);
+}
+
+// IBM/MS verify
+static void
+disk_1344(struct bregs *regs, struct drive_s *drive_g)
+{
+ extended_access(regs, drive_g, CMD_VERIFY);
+}
+
+// lock
+static void
+disk_134500(struct bregs *regs, struct drive_s *drive_g)
+{
+ u16 ebda_seg = get_ebda_seg();
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
+ if (locks == 0xff) {
+ regs->al = 1;
+ disk_ret(regs, DISK_RET_ETOOMANYLOCKS);
+ return;
+ }
+ SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks + 1);
+ regs->al = 1;
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// unlock
+static void
+disk_134501(struct bregs *regs, struct drive_s *drive_g)
+{
+ u16 ebda_seg = get_ebda_seg();
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_EBDA2(ebda_seg, cdrom_locks[cdid]);
+ if (locks == 0x00) {
+ regs->al = 0;
+ disk_ret(regs, DISK_RET_ENOTLOCKED);
+ return;
+ }
+ locks--;
+ SET_EBDA2(ebda_seg, cdrom_locks[cdid], locks);
+ regs->al = (locks ? 1 : 0);
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// status
+static void
+disk_134502(struct bregs *regs, struct drive_s *drive_g)
+{
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_EBDA(cdrom_locks[cdid]);
+ regs->al = (locks ? 1 : 0);
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_1345XX(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS lock/unlock drive
+static void
+disk_1345(struct bregs *regs, struct drive_s *drive_g)
+{
+ if (regs->dl < EXTSTART_CD) {
+ // Always success for HD
+ disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x00: disk_134500(regs, drive_g); break;
+ case 0x01: disk_134501(regs, drive_g); break;
+ case 0x02: disk_134502(regs, drive_g); break;
+ default: disk_1345XX(regs, drive_g); break;
+ }
+}
+
+// IBM/MS eject media
+static void
+disk_1346(struct bregs *regs, struct drive_s *drive_g)
+{
+ if (regs->dl < EXTSTART_CD) {
+ // Volume Not Removable
+ disk_ret(regs, DISK_RET_ENOTREMOVABLE);
+ return;
+ }
+
+ int cdid = regs->dl - EXTSTART_CD;
+ u8 locks = GET_EBDA(cdrom_locks[cdid]);
+ if (locks != 0) {
+ disk_ret(regs, DISK_RET_ELOCKED);
+ return;
+ }
+
+ // FIXME should handle 0x31 no media in device
+ // FIXME should handle 0xb5 valid request failed
+
+ // Call removable media eject
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.ah = 0x52;
+ br.dl = regs->dl;
+ call16_int(0x15, &br);
+
+ if (br.ah || br.flags & F_CF) {
+ disk_ret(regs, DISK_RET_ELOCKED);
+ return;
+ }
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// IBM/MS extended seek
+static void
+disk_1347(struct bregs *regs, struct drive_s *drive_g)
+{
+ extended_access(regs, drive_g, CMD_SEEK);
+}
+
+// IBM/MS get drive parameters
+static void
+disk_1348(struct bregs *regs, struct drive_s *drive_g)
+{
+ u16 size = GET_INT13DPT(regs, size);
+ u16 t13 = size == 74;
+
+ // Buffer is too small
+ if (size < 26) {
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ // EDD 1.x
+
+ u8 type = GET_GLOBAL(drive_g->type);
+ u16 npc = GET_GLOBAL(drive_g->pchs.cylinders);
+ u16 nph = GET_GLOBAL(drive_g->pchs.heads);
+ u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
+ u64 lba = GET_GLOBAL(drive_g->sectors);
+ u16 blksize = GET_GLOBAL(drive_g->blksize);
+
+ dprintf(DEBUG_HDL_13, "disk_1348 size=%d t=%d chs=%d,%d,%d lba=%d bs=%d\n"
+ , size, type, npc, nph, npspt, (u32)lba, blksize);
+
+ SET_INT13DPT(regs, size, 26);
+ if (type == DTYPE_ATAPI) {
+ // 0x74 = removable, media change, lockable, max values
+ SET_INT13DPT(regs, infos, 0x74);
+ SET_INT13DPT(regs, cylinders, 0xffffffff);
+ SET_INT13DPT(regs, heads, 0xffffffff);
+ SET_INT13DPT(regs, spt, 0xffffffff);
+ SET_INT13DPT(regs, sector_count, (u64)-1);
+ } else {
+ if (lba > (u64)npspt*nph*0x3fff) {
+ SET_INT13DPT(regs, infos, 0x00); // geometry is invalid
+ SET_INT13DPT(regs, cylinders, 0x3fff);
+ } else {
+ SET_INT13DPT(regs, infos, 0x02); // geometry is valid
+ SET_INT13DPT(regs, cylinders, (u32)npc);
+ }
+ SET_INT13DPT(regs, heads, (u32)nph);
+ SET_INT13DPT(regs, spt, (u32)npspt);
+ SET_INT13DPT(regs, sector_count, lba);
+ }
+ SET_INT13DPT(regs, blksize, blksize);
+
+ if (size < 30 ||
+ (type != DTYPE_ATA && type != DTYPE_ATAPI && type != DTYPE_VIRTIO)) {
+ disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+ }
+
+ // EDD 2.x
+
+ int bdf;
+ u16 iobase1 = 0;
+ u64 device_path = 0;
+ u8 channel = 0;
+ SET_INT13DPT(regs, size, 30);
+ if (type == DTYPE_ATA || type == DTYPE_ATAPI) {
+ u16 ebda_seg = get_ebda_seg();
+
+ SET_INT13DPT(regs, dpte_segment, ebda_seg);
+ SET_INT13DPT(regs, dpte_offset
+ , offsetof(struct extended_bios_data_area_s, dpte));
+
+ // Fill in dpte
+ struct atadrive_s *adrive_g = container_of(
+ drive_g, struct atadrive_s, drive);
+ struct ata_channel_s *chan_gf = GET_GLOBAL(adrive_g->chan_gf);
+ u8 slave = GET_GLOBAL(adrive_g->slave);
+ u16 iobase2 = GET_GLOBALFLAT(chan_gf->iobase2);
+ u8 irq = GET_GLOBALFLAT(chan_gf->irq);
+ iobase1 = GET_GLOBALFLAT(chan_gf->iobase1);
+ bdf = GET_GLOBALFLAT(chan_gf->pci_bdf);
+ device_path = slave;
+ channel = GET_GLOBALFLAT(chan_gf->chanid);
+
+ u16 options = 0;
+ if (type == DTYPE_ATA) {
+ u8 translation = GET_GLOBAL(drive_g->translation);
+ if (translation != TRANSLATION_NONE) {
+ options |= 1<<3; // CHS translation
+ if (translation == TRANSLATION_LBA)
+ options |= 1<<9;
+ if (translation == TRANSLATION_RECHS)
+ options |= 3<<9;
+ }
+ } else {
+ // ATAPI
+ options |= 1<<5; // removable device
+ options |= 1<<6; // atapi device
+ }
+ options |= 1<<4; // lba translation
+ if (CONFIG_ATA_PIO32)
+ options |= 1<<7;
+
+ SET_EBDA2(ebda_seg, dpte.iobase1, iobase1);
+ SET_EBDA2(ebda_seg, dpte.iobase2, iobase2 + ATA_CB_DC);
+ SET_EBDA2(ebda_seg, dpte.prefix, ((slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0)
+ | ATA_CB_DH_LBA));
+ SET_EBDA2(ebda_seg, dpte.unused, 0xcb);
+ SET_EBDA2(ebda_seg, dpte.irq, irq);
+ SET_EBDA2(ebda_seg, dpte.blkcount, 1);
+ SET_EBDA2(ebda_seg, dpte.dma, 0);
+ SET_EBDA2(ebda_seg, dpte.pio, 0);
+ SET_EBDA2(ebda_seg, dpte.options, options);
+ SET_EBDA2(ebda_seg, dpte.reserved, 0);
+ SET_EBDA2(ebda_seg, dpte.revision, 0x11);
+
+ u8 sum = checksum_far(
+ ebda_seg, (void*)offsetof(struct extended_bios_data_area_s, dpte), 15);
+ SET_EBDA2(ebda_seg, dpte.checksum, -sum);
+ } else {
+ SET_INT13DPT(regs, dpte_segment, 0);
+ SET_INT13DPT(regs, dpte_offset, 0);
+ bdf = GET_GLOBAL(drive_g->cntl_id);
+ }
+
+ if (size < 66) {
+ disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+ }
+
+ // EDD 3.x
+ SET_INT13DPT(regs, key, 0xbedd);
+ SET_INT13DPT(regs, dpi_length, t13 ? 44 : 36);
+ SET_INT13DPT(regs, reserved1, 0);
+ SET_INT13DPT(regs, reserved2, 0);
+
+ if (bdf != -1) {
+ SET_INT13DPT(regs, host_bus[0], 'P');
+ SET_INT13DPT(regs, host_bus[1], 'C');
+ SET_INT13DPT(regs, host_bus[2], 'I');
+ SET_INT13DPT(regs, host_bus[3], ' ');
+
+ u32 path = (pci_bdf_to_bus(bdf) | (pci_bdf_to_dev(bdf) << 8)
+ | (pci_bdf_to_fn(bdf) << 16));
+ if (t13)
+ path |= channel << 24;
+
+ SET_INT13DPT(regs, iface_path, path);
+ } else {
+ // ISA
+ SET_INT13DPT(regs, host_bus[0], 'I');
+ SET_INT13DPT(regs, host_bus[1], 'S');
+ SET_INT13DPT(regs, host_bus[2], 'A');
+ SET_INT13DPT(regs, host_bus[3], ' ');
+
+ SET_INT13DPT(regs, iface_path, iobase1);
+ }
+
+ if (type != DTYPE_VIRTIO) {
+ SET_INT13DPT(regs, iface_type[0], 'A');
+ SET_INT13DPT(regs, iface_type[1], 'T');
+ SET_INT13DPT(regs, iface_type[2], 'A');
+ SET_INT13DPT(regs, iface_type[3], ' ');
+ } else {
+ SET_INT13DPT(regs, iface_type[0], 'S');
+ SET_INT13DPT(regs, iface_type[1], 'C');
+ SET_INT13DPT(regs, iface_type[2], 'S');
+ SET_INT13DPT(regs, iface_type[3], 'I');
+ }
+ SET_INT13DPT(regs, iface_type[4], ' ');
+ SET_INT13DPT(regs, iface_type[5], ' ');
+ SET_INT13DPT(regs, iface_type[6], ' ');
+ SET_INT13DPT(regs, iface_type[7], ' ');
+
+ if (t13) {
+ SET_INT13DPT(regs, t13.device_path[0], device_path);
+ SET_INT13DPT(regs, t13.device_path[1], 0);
+
+ SET_INT13DPT(regs, t13.checksum
+ , -checksum_far(regs->ds, (void*)(regs->si+30), 43));
+ } else {
+ SET_INT13DPT(regs, phoenix.device_path, device_path);
+
+ SET_INT13DPT(regs, phoenix.checksum
+ , -checksum_far(regs->ds, (void*)(regs->si+30), 35));
+ }
+
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+// IBM/MS extended media change
+static void
+disk_1349(struct bregs *regs, struct drive_s *drive_g)
+{
+ if (regs->dl < EXTSTART_CD) {
+ // Always success for HD
+ disk_ret(regs, DISK_RET_SUCCESS);
+ return;
+ }
+ set_invalid(regs);
+ // always send changed ??
+ regs->ah = DISK_RET_ECHANGED;
+}
+
+static void
+disk_134e01(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e03(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e04(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134e06(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret(regs, DISK_RET_SUCCESS);
+}
+
+static void
+disk_134eXX(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret(regs, DISK_RET_EPARAM);
+}
+
+// IBM/MS set hardware configuration
+static void
+disk_134e(struct bregs *regs, struct drive_s *drive_g)
+{
+ switch (regs->al) {
+ case 0x01: disk_134e01(regs, drive_g); break;
+ case 0x03: disk_134e03(regs, drive_g); break;
+ case 0x04: disk_134e04(regs, drive_g); break;
+ case 0x06: disk_134e06(regs, drive_g); break;
+ default: disk_134eXX(regs, drive_g); break;
+ }
+}
+
+static void
+disk_13XX(struct bregs *regs, struct drive_s *drive_g)
+{
+ disk_ret_unimplemented(regs, DISK_RET_EPARAM);
+}
+
+static void
+disk_13(struct bregs *regs, struct drive_s *drive_g)
+{
+ //debug_stub(regs);
+
+ // clear completion flag
+ SET_BDA(disk_interrupt_flag, 0);
+
+ switch (regs->ah) {
+ case 0x00: disk_1300(regs, drive_g); break;
+ case 0x01: disk_1301(regs, drive_g); break;
+ case 0x02: disk_1302(regs, drive_g); break;
+ case 0x03: disk_1303(regs, drive_g); break;
+ case 0x04: disk_1304(regs, drive_g); break;
+ case 0x05: disk_1305(regs, drive_g); break;
+ case 0x08: disk_1308(regs, drive_g); break;
+ case 0x09: disk_1309(regs, drive_g); break;
+ case 0x0c: disk_130c(regs, drive_g); break;
+ case 0x0d: disk_130d(regs, drive_g); break;
+ case 0x10: disk_1310(regs, drive_g); break;
+ case 0x11: disk_1311(regs, drive_g); break;
+ case 0x14: disk_1314(regs, drive_g); break;
+ case 0x15: disk_1315(regs, drive_g); break;
+ case 0x16: disk_1316(regs, drive_g); break;
+ case 0x41: disk_1341(regs, drive_g); break;
+ case 0x42: disk_1342(regs, drive_g); break;
+ case 0x43: disk_1343(regs, drive_g); break;
+ case 0x44: disk_1344(regs, drive_g); break;
+ case 0x45: disk_1345(regs, drive_g); break;
+ case 0x46: disk_1346(regs, drive_g); break;
+ case 0x47: disk_1347(regs, drive_g); break;
+ case 0x48: disk_1348(regs, drive_g); break;
+ case 0x49: disk_1349(regs, drive_g); break;
+ case 0x4e: disk_134e(regs, drive_g); break;
+ default: disk_13XX(regs, drive_g); break;
+ }
+}
+
+static void
+floppy_13(struct bregs *regs, struct drive_s *drive_g)
+{
+ // Only limited commands are supported on floppies.
+ switch (regs->ah) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x08:
+ case 0x15:
+ case 0x16:
+ disk_13(regs, drive_g);
+ break;
+ default: disk_13XX(regs, drive_g); break;
+ }
+}
+
+
+/****************************************************************
+ * Entry points
+ ****************************************************************/
+
+static void
+handle_legacy_disk(struct bregs *regs, u8 extdrive)
+{
+ if (! CONFIG_DRIVES) {
+ // XXX - support handle_1301 anyway?
+ disk_ret(regs, DISK_RET_EPARAM);
+ return;
+ }
+
+ if (extdrive < EXTSTART_HD) {
+ struct drive_s *drive_g = getDrive(EXTTYPE_FLOPPY, extdrive);
+ if (!drive_g)
+ goto fail;
+ floppy_13(regs, drive_g);
+ return;
+ }
+
+ struct drive_s *drive_g;
+ if (extdrive >= EXTSTART_CD)
+ drive_g = getDrive(EXTTYPE_CD, extdrive - EXTSTART_CD);
+ else
+ drive_g = getDrive(EXTTYPE_HD, extdrive - EXTSTART_HD);
+ if (!drive_g)
+ goto fail;
+ disk_13(regs, drive_g);
+ return;
+
+fail:
+ // XXX - support 1301/1308/1315 anyway?
+ disk_ret(regs, DISK_RET_EPARAM);
+}
+
+void VISIBLE16
+handle_40(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_40);
+ handle_legacy_disk(regs, regs->dl);
+}
+
+// INT 13h Fixed Disk Services Entry Point
+void VISIBLE16
+handle_13(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_13);
+ u8 extdrive = regs->dl;
+
+ if (CONFIG_CDROM_EMU) {
+ if (regs->ah == 0x4b) {
+ cdemu_134b(regs);
+ return;
+ }
+ u16 ebda_seg = get_ebda_seg();
+ if (GET_EBDA2(ebda_seg, cdemu.active)) {
+ u8 emudrive = GET_EBDA2(ebda_seg, cdemu.emulated_extdrive);
+ if (extdrive == emudrive) {
+ // Access to an emulated drive.
+ struct drive_s *cdemu_g;
+ cdemu_g = GLOBALFLAT2GLOBAL(GET_GLOBAL(cdemu_drive_gf));
+ if (regs->ah > 0x16) {
+ // Only old-style commands supported.
+ disk_13XX(regs, cdemu_g);
+ return;
+ }
+ disk_13(regs, cdemu_g);
+ return;
+ }
+ if (extdrive < EXTSTART_CD && ((emudrive ^ extdrive) & 0x80) == 0)
+ // Adjust id to make room for emulated drive.
+ extdrive--;
+ }
+ }
+ handle_legacy_disk(regs, extdrive);
+}
+
+// record completion in BIOS task complete flag
+void VISIBLE16
+handle_76(void)
+{
+ debug_isr(DEBUG_ISR_76);
+ SET_BDA(disk_interrupt_flag, 0xff);
+ eoi_pic2();
+}
+
+// Old Fixed Disk Parameter Table (newer tables are in the ebda).
+struct fdpt_s OldFDPT VAR16FIXED(0xe401);
--- /dev/null
+// Definitions for X86 bios disks.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __DISK_H
+#define __DISK_H
+
+#include "types.h" // u8
+#include "config.h" // CONFIG_*
+#include "farptr.h" // struct segoff_s
+
+#define DISK_RET_SUCCESS 0x00
+#define DISK_RET_EPARAM 0x01
+#define DISK_RET_EADDRNOTFOUND 0x02
+#define DISK_RET_EWRITEPROTECT 0x03
+#define DISK_RET_ECHANGED 0x06
+#define DISK_RET_EBOUNDARY 0x09
+#define DISK_RET_EBADTRACK 0x0c
+#define DISK_RET_ECONTROLLER 0x20
+#define DISK_RET_ETIMEOUT 0x80
+#define DISK_RET_ENOTLOCKED 0xb0
+#define DISK_RET_ELOCKED 0xb1
+#define DISK_RET_ENOTREMOVABLE 0xb2
+#define DISK_RET_ETOOMANYLOCKS 0xb4
+#define DISK_RET_EMEDIA 0xC0
+#define DISK_RET_ENOTREADY 0xAA
+
+
+/****************************************************************
+ * Interface structs
+ ****************************************************************/
+
+// Bios disk structures.
+struct int13ext_s {
+ u8 size;
+ u8 reserved;
+ u16 count;
+ struct segoff_s data;
+ u64 lba;
+} PACKED;
+
+#define GET_INT13EXT(regs,var) \
+ GET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var)
+#define SET_INT13EXT(regs,var,val) \
+ SET_FARVAR((regs)->ds, ((struct int13ext_s*)((regs)->si+0))->var, (val))
+
+// Disk Physical Table definition
+struct int13dpt_s {
+ u16 size;
+ u16 infos;
+ u32 cylinders;
+ u32 heads;
+ u32 spt;
+ u64 sector_count;
+ u16 blksize;
+ u16 dpte_offset;
+ u16 dpte_segment;
+ u16 key;
+ u8 dpi_length;
+ u8 reserved1;
+ u16 reserved2;
+ u8 host_bus[4];
+ u8 iface_type[8];
+ u64 iface_path;
+ union {
+ struct {
+ u64 device_path;
+ u8 reserved3;
+ u8 checksum;
+ } phoenix;
+ struct {
+ u64 device_path[2];
+ u8 reserved3;
+ u8 checksum;
+ } t13;
+ };
+} PACKED;
+
+#define GET_INT13DPT(regs,var) \
+ GET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var)
+#define SET_INT13DPT(regs,var,val) \
+ SET_FARVAR((regs)->ds, ((struct int13dpt_s*)((regs)->si+0))->var, (val))
+
+// Floppy "Disk Base Table"
+struct floppy_dbt_s {
+ u8 specify1;
+ u8 specify2;
+ u8 shutoff_ticks;
+ u8 bps_code;
+ u8 sectors;
+ u8 interblock_len;
+ u8 data_len;
+ u8 gap_len;
+ u8 fill_byte;
+ u8 settle_time;
+ u8 startup_time;
+} PACKED;
+
+struct floppy_ext_dbt_s {
+ struct floppy_dbt_s dbt;
+ // Extra fields
+ u8 max_track;
+ u8 data_rate;
+ u8 drive_type;
+} PACKED;
+
+// Helper function for setting up a return code.
+struct bregs;
+void __disk_ret(struct bregs *regs, u32 linecode, const char *fname);
+#define disk_ret(regs, code) \
+ __disk_ret((regs), (code) | (__LINE__ << 8), __func__)
+void __disk_ret_unimplemented(struct bregs *regs, u32 linecode
+ , const char *fname);
+#define disk_ret_unimplemented(regs, code) \
+ __disk_ret_unimplemented((regs), (code) | (__LINE__ << 8), __func__)
+
+
+/****************************************************************
+ * Master boot record
+ ****************************************************************/
+
+struct packed_chs_s {
+ u8 heads;
+ u8 sptcyl;
+ u8 cyllow;
+};
+
+struct partition_s {
+ u8 status;
+ struct packed_chs_s first;
+ u8 type;
+ struct packed_chs_s last;
+ u32 lba;
+ u32 count;
+} PACKED;
+
+struct mbr_s {
+ u8 code[440];
+ // 0x01b8
+ u32 diskseg;
+ // 0x01bc
+ u16 null;
+ // 0x01be
+ struct partition_s partitions[4];
+ // 0x01fe
+ u16 signature;
+} PACKED;
+
+#define MBR_SIGNATURE 0xaa55
+
+
+/****************************************************************
+ * Disk command request
+ ****************************************************************/
+
+struct disk_op_s {
+ u64 lba;
+ void *buf_fl;
+ struct drive_s *drive_g;
+ u16 count;
+ u8 command;
+};
+
+#define CMD_RESET 0x00
+#define CMD_READ 0x02
+#define CMD_WRITE 0x03
+#define CMD_VERIFY 0x04
+#define CMD_FORMAT 0x05
+#define CMD_SEEK 0x07
+#define CMD_ISREADY 0x10
+
+
+/****************************************************************
+ * Global storage
+ ****************************************************************/
+
+struct chs_s {
+ u16 heads; // # heads
+ u16 cylinders; // # cylinders
+ u16 spt; // # sectors / track
+};
+
+struct drive_s {
+ u8 type; // Driver type (DTYPE_*)
+ u8 floppy_type; // Type of floppy (only for floppy drives).
+ struct chs_s lchs; // Logical CHS
+ u64 sectors; // Total sectors count
+ u32 cntl_id; // Unique id for a given driver type.
+ u8 removable; // Is media removable (currently unused)
+
+ // Info for EDD calls
+ u8 translation; // type of translation
+ u16 blksize; // block size
+ struct chs_s pchs; // Physical CHS
+};
+
+#define DISK_SECTOR_SIZE 512
+#define CDROM_SECTOR_SIZE 2048
+
+#define DTYPE_NONE 0x00
+#define DTYPE_FLOPPY 0x01
+#define DTYPE_ATA 0x02
+#define DTYPE_ATAPI 0x03
+#define DTYPE_RAMDISK 0x04
+#define DTYPE_CDEMU 0x05
+#define DTYPE_USB 0x06
+#define DTYPE_VIRTIO 0x07
+#define DTYPE_AHCI 0x08
+
+#define MAXDESCSIZE 80
+
+#define TRANSLATION_NONE 0
+#define TRANSLATION_LBA 1
+#define TRANSLATION_LARGE 2
+#define TRANSLATION_RECHS 3
+
+#define EXTTYPE_FLOPPY 0
+#define EXTTYPE_HD 1
+#define EXTTYPE_CD 2
+
+#define EXTSTART_HD 0x80
+#define EXTSTART_CD 0xE0
+
+
+/****************************************************************
+ * Function defs
+ ****************************************************************/
+
+// block.c
+extern u8 FloppyCount, CDCount;
+extern u8 *bounce_buf_fl;
+struct drive_s *getDrive(u8 exttype, u8 extdriveoffset);
+int getDriveId(u8 exttype, struct drive_s *drive_g);
+void map_floppy_drive(struct drive_s *drive_g);
+void map_hd_drive(struct drive_s *drive_g);
+void map_cd_drive(struct drive_s *drive_g);
+int process_op(struct disk_op_s *op);
+int send_disk_op(struct disk_op_s *op);
+int bounce_buf_init(void);
+
+// floppy.c
+extern struct floppy_ext_dbt_s diskette_param_table2;
+void floppy_setup(void);
+struct drive_s *init_floppy(int floppyid, int ftype);
+int find_floppy_type(u32 size);
+int process_floppy_op(struct disk_op_s *op);
+void floppy_tick(void);
+
+// cdrom.c
+extern struct drive_s *cdemu_drive_gf;
+int process_cdemu_op(struct disk_op_s *op);
+void cdemu_setup(void);
+void cdemu_134b(struct bregs *regs);
+int cdrom_boot(struct drive_s *drive_g);
+
+// ramdisk.c
+void ramdisk_setup(void);
+int process_ramdisk_op(struct disk_op_s *op);
+
+#endif // disk.h
--- /dev/null
+// Macros for entering C code
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Entry macros
+ ****************************************************************/
+
+ // Call a C function - this does the minimal work necessary to
+ // call into C. It sets up %ds, backs up %es, and backs up
+ // those registers that are call clobbered by the C compiler.
+ .macro ENTRY cfunc
+ cli // In case something far-calls instead of using "int"
+ cld
+ pushl %eax // Save registers clobbered by C code
+ pushl %ecx
+ pushl %edx
+ pushw %es
+ pushw %ds
+ movw %ss, %ax // Move %ss to %ds
+ movw %ax, %ds
+ pushl %esp // Backup %esp, then clear high bits
+ movzwl %sp, %esp
+ calll \cfunc
+ popl %esp // Restore %esp (including high bits)
+ popw %ds // Restore registers saved above
+ popw %es
+ popl %edx
+ popl %ecx
+ popl %eax
+ .endm
+
+ // As above, but get calling function from stack.
+ .macro ENTRY_ST
+ cli
+ cld
+ pushl %ecx
+ pushl %edx
+ pushw %es
+ pushw %ds
+ movw %ss, %cx // Move %ss to %ds
+ movw %cx, %ds
+ pushl %esp // Backup %esp, then clear high bits
+ movzwl %sp, %esp
+ movl 16(%esp), %ecx // Get calling function
+ movl %eax, 16(%esp) // Save %eax
+ calll *%ecx
+ popl %esp // Restore %esp (including high bits)
+ popw %ds // Restore registers saved above
+ popw %es
+ popl %edx
+ popl %ecx
+ popl %eax
+ .endm
+
+ // Call a C function with current register list as an
+ // argument. This backs up the registers and sets %eax
+ // to point to the backup. On return, the registers are
+ // restored from the structure.
+ .macro ENTRY_ARG cfunc
+ cli
+ cld
+ pushl %eax // Save registers (matches struct bregs)
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushw %es
+ pushw %ds
+ movw %ss, %ax // Move %ss to %ds
+ movw %ax, %ds
+ movl %esp, %ebx // Backup %esp, then zero high bits
+ movzwl %sp, %esp
+ movl %esp, %eax // First arg is pointer to struct bregs
+ calll \cfunc
+ movl %ebx, %esp // Restore %esp (including high bits)
+ popw %ds // Restore registers (from struct bregs)
+ popw %es
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
+ popl %edx
+ popl %ecx
+ popl %eax
+ .endm
+
+ // As above, but get calling function from stack.
+ .macro ENTRY_ARG_ST
+ cli
+ cld
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushw %es
+ pushw %ds
+ movw %ss, %cx // Move %ss to %ds
+ movw %cx, %ds
+ movl %esp, %ebx // Backup %esp, then zero high bits
+ movzwl %sp, %esp
+ movl 28(%esp), %ecx // Get calling function
+ movl %eax, 28(%esp) // Save %eax
+ movl %esp, %eax // First arg is pointer to struct bregs
+ calll *%ecx
+ movl %ebx, %esp // Restore %esp (including high bits)
+ popw %ds // Restore registers (from struct bregs)
+ popw %es
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
+ popl %edx
+ popl %ecx
+ popl %eax
+ .endm
+
+ // Same as ENTRY_ARG, but don't mangle %esp
+ .macro ENTRY_ARG_ESP cfunc
+ cli
+ cld
+ pushl %eax // Save registers (matches struct bregs)
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
+ pushw %es
+ pushw %ds
+ movw %ss, %ax // Move %ss to %ds
+ movw %ax, %ds
+ movl %esp, %eax // First arg is pointer to struct bregs
+ calll \cfunc
+ popw %ds // Restore registers (from struct bregs)
+ popw %es
+ popl %edi
+ popl %esi
+ popl %ebp
+ popl %ebx
+ popl %edx
+ popl %ecx
+ popl %eax
+ .endm
+
+ // Reset stack, transition to 32bit mode, and call a C function.
+ // Clobbers %ax
+ .macro ENTRY_INTO32 cfunc
+ xorw %ax, %ax
+ movw %ax, %ss
+ movl $ BUILD_STACK_ADDR , %esp
+ movl $ \cfunc , %edx
+ jmp transition32
+ .endm
+
+ // Declare a function
+ .macro DECLFUNC func
+ .section .text.asm.\func
+ .global \func
+ .endm
+
+ // Declare an exported function
+ .macro EXPORTFUNC func
+ .section .text.asm.export.\func
+ .global \func
+ .endm
--- /dev/null
+// Code to access multiple segments within gcc.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __FARPTR_H
+#define __FARPTR_H
+
+#include "ioport.h" // insb
+
+// Dummy definitions used to make sure gcc understands dependencies
+// between SET_SEG and GET/READ/WRITE_SEG macros.
+extern u16 __segment_ES, __segment_CS, __segment_DS, __segment_SS;
+extern u16 __segment_FS, __segment_GS;
+
+// Low level macros for reading/writing memory via a segment selector.
+#define READ8_SEG(prefix, SEG, value, var) \
+ __asm__(prefix "movb %%" #SEG ":%1, %b0" : "=Qi"(value) \
+ : "m"(var), "m"(__segment_ ## SEG))
+#define READ16_SEG(prefix, SEG, value, var) \
+ __asm__(prefix "movw %%" #SEG ":%1, %w0" : "=ri"(value) \
+ : "m"(var), "m"(__segment_ ## SEG))
+#define READ32_SEG(prefix, SEG, value, var) \
+ __asm__(prefix "movl %%" #SEG ":%1, %0" : "=ri"(value) \
+ : "m"(var), "m"(__segment_ ## SEG))
+#define READ64_SEG(prefix, SEG, value, var) do { \
+ union u64_u32_u __value; \
+ union u64_u32_u *__r64_ptr = (union u64_u32_u *)&(var); \
+ READ32_SEG(prefix, SEG, __value.hi, __r64_ptr->hi); \
+ READ32_SEG(prefix, SEG, __value.lo, __r64_ptr->lo); \
+ *(u64*)&(value) = __value.val; \
+ } while (0)
+#define WRITE8_SEG(prefix, SEG, var, value) \
+ __asm__(prefix "movb %b1, %%" #SEG ":%0" : "=m"(var) \
+ : "Q"(value), "m"(__segment_ ## SEG))
+#define WRITE16_SEG(prefix, SEG, var, value) \
+ __asm__(prefix "movw %w1, %%" #SEG ":%0" : "=m"(var) \
+ : "r"(value), "m"(__segment_ ## SEG))
+#define WRITE32_SEG(prefix, SEG, var, value) \
+ __asm__(prefix "movl %1, %%" #SEG ":%0" : "=m"(var) \
+ : "r"(value), "m"(__segment_ ## SEG))
+#define WRITE64_SEG(prefix, SEG, var, value) do { \
+ union u64_u32_u __value; \
+ union u64_u32_u *__w64_ptr = (union u64_u32_u *)&(var); \
+ typeof(var) __value_tmp = (value); \
+ __value.val = *(u64*)&__value_tmp; \
+ WRITE32_SEG(prefix, SEG, __w64_ptr->hi, __value.hi); \
+ WRITE32_SEG(prefix, SEG, __w64_ptr->lo, __value.lo); \
+ } while (0)
+
+// Macros for automatically choosing the appropriate memory size
+// access method.
+extern void __force_link_error__unknown_type(void);
+
+#define __GET_VAR(prefix, seg, var) ({ \
+ typeof(var) __val; \
+ if (sizeof(__val) == 1) \
+ READ8_SEG(prefix, seg, __val, var); \
+ else if (sizeof(__val) == 2) \
+ READ16_SEG(prefix, seg, __val, var); \
+ else if (sizeof(__val) == 4) \
+ READ32_SEG(prefix, seg, __val, var); \
+ else if (sizeof(__val) == 8) \
+ READ64_SEG(prefix, seg, __val, var); \
+ else \
+ __force_link_error__unknown_type(); \
+ __val; })
+
+#define __SET_VAR(prefix, seg, var, val) do { \
+ if (sizeof(var) == 1) \
+ WRITE8_SEG(prefix, seg, var, (val)); \
+ else if (sizeof(var) == 2) \
+ WRITE16_SEG(prefix, seg, var, (val)); \
+ else if (sizeof(var) == 4) \
+ WRITE32_SEG(prefix, seg, var, (val)); \
+ else if (sizeof(var) == 8) \
+ WRITE64_SEG(prefix, seg, var, (val)); \
+ else \
+ __force_link_error__unknown_type(); \
+ } while (0)
+
+// Low level macros for getting/setting a segment register.
+#define __SET_SEG(SEG, value) \
+ __asm__("movw %w1, %%" #SEG : "=m"(__segment_ ## SEG) \
+ : "rm"(value))
+#define __GET_SEG(SEG) ({ \
+ u16 __seg; \
+ __asm__("movw %%" #SEG ", %w0" : "=rm"(__seg) \
+ : "m"(__segment_ ## SEG)); \
+ __seg;})
+
+// Macros for accessing a variable in another segment. (They
+// automatically update the %es segment and then make the appropriate
+// access.)
+#define __GET_FARVAR(seg, var) ({ \
+ SET_SEG(ES, (seg)); \
+ GET_VAR(ES, (var)); })
+#define __SET_FARVAR(seg, var, val) do { \
+ typeof(var) __sfv_val = (val); \
+ SET_SEG(ES, (seg)); \
+ SET_VAR(ES, (var), __sfv_val); \
+ } while (0)
+
+// Macros for accesssing a 32bit flat mode pointer from 16bit real
+// mode. (They automatically update the %es segment, break the
+// pointer into segment/offset, and then make the access.)
+#define __GET_FLATPTR(ptr) ({ \
+ typeof(&(ptr)) __ptr = &(ptr); \
+ GET_FARVAR(FLATPTR_TO_SEG(__ptr) \
+ , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr)); })
+#define __SET_FLATPTR(ptr, val) do { \
+ typeof (&(ptr)) __ptr = &(ptr); \
+ SET_FARVAR(FLATPTR_TO_SEG(__ptr) \
+ , *(typeof(__ptr))FLATPTR_TO_OFFSET(__ptr) \
+ , (val)); \
+ } while (0)
+
+// Macros for converting to/from 32bit flat mode pointers to their
+// equivalent 16bit segment/offset values.
+#define FLATPTR_TO_SEG(p) (((u32)(p)) >> 4)
+#define FLATPTR_TO_OFFSET(p) (((u32)(p)) & 0xf)
+#define MAKE_FLATPTR(seg,off) ((void*)(((u32)(seg)<<4)+(u32)(off)))
+
+
+#if MODESEGMENT == 1
+
+// Definitions when using segmented mode.
+#define GET_FARVAR(seg, var) __GET_FARVAR((seg), (var))
+#define SET_FARVAR(seg, var, val) __SET_FARVAR((seg), (var), (val))
+#define GET_VAR(seg, var) __GET_VAR("", seg, (var))
+#define SET_VAR(seg, var, val) __SET_VAR("", seg, (var), (val))
+#define SET_SEG(SEG, value) __SET_SEG(SEG, (value))
+#define GET_SEG(SEG) __GET_SEG(SEG)
+#define GET_FLATPTR(ptr) __GET_FLATPTR(ptr)
+#define SET_FLATPTR(ptr, val) __SET_FLATPTR((ptr), (val))
+
+static inline void insb_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ insb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void insw_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ insw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void insl_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ insl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsb_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ outsb(port, (u8*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsw_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ outsw(port, (u16*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+static inline void outsl_fl(u16 port, void *ptr_fl, u16 count) {
+ SET_SEG(ES, FLATPTR_TO_SEG(ptr_fl));
+ outsl(port, (u32*)FLATPTR_TO_OFFSET(ptr_fl), count);
+}
+
+#else
+
+// In 32-bit flat mode there is no need to mess with the segments.
+#define GET_FARVAR(seg, var) \
+ (*((typeof(&(var)))MAKE_FLATPTR((seg), &(var))))
+#define SET_FARVAR(seg, var, val) \
+ do { GET_FARVAR((seg), (var)) = (val); } while (0)
+#define GET_VAR(seg, var) (var)
+#define SET_VAR(seg, var, val) do { (var) = (val); } while (0)
+#define SET_SEG(SEG, value) ((void)(value))
+#define GET_SEG(SEG) 0
+#define GET_FLATPTR(ptr) (ptr)
+#define SET_FLATPTR(ptr, val) do { (ptr) = (val); } while (0)
+
+#define insb_fl(port, ptr_fl, count) insb(port, ptr_fl, count)
+#define insw_fl(port, ptr_fl, count) insw(port, ptr_fl, count)
+#define insl_fl(port, ptr_fl, count) insl(port, ptr_fl, count)
+#define outsb_fl(port, ptr_fl, count) outsb(port, ptr_fl, count)
+#define outsw_fl(port, ptr_fl, count) outsw(port, ptr_fl, count)
+#define outsl_fl(port, ptr_fl, count) outsl(port, ptr_fl, count)
+
+#endif
+
+// Definition for common 16bit segment/offset pointers.
+struct segoff_s {
+ union {
+ struct {
+ u16 offset;
+ u16 seg;
+ };
+ u32 segoff;
+ };
+};
+#define SEGOFF(s,o) ({struct segoff_s __so; __so.offset=(o); __so.seg=(s); __so;})
+
+static inline struct segoff_s FLATPTR_TO_SEGOFF(void *p) {
+ return SEGOFF(FLATPTR_TO_SEG(p), FLATPTR_TO_OFFSET(p));
+}
+static inline void *SEGOFF_TO_FLATPTR(struct segoff_s so) {
+ return MAKE_FLATPTR(so.seg, so.offset);
+}
+
+#endif // farptr.h
--- /dev/null
+// 16bit code to access floppy drives.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u8
+#include "disk.h" // DISK_RET_SUCCESS
+#include "config.h" // CONFIG_FLOPPY
+#include "biosvar.h" // SET_BDA
+#include "util.h" // wait_irq
+#include "cmos.h" // inb_cmos
+#include "pic.h" // eoi_pic1
+#include "bregs.h" // struct bregs
+#include "boot.h" // boot_add_floppy
+#include "pci.h" // pci_to_bdf
+#include "pci_ids.h" // PCI_CLASS_BRIDGE_ISA
+
+#define FLOPPY_SIZE_CODE 0x02 // 512 byte sectors
+#define FLOPPY_DATALEN 0xff // Not used - because size code is 0x02
+#define FLOPPY_MOTOR_TICKS 37 // ~2 seconds
+#define FLOPPY_FILLBYTE 0xf6
+#define FLOPPY_GAPLEN 0x1B
+#define FLOPPY_FORMAT_GAPLEN 0x6c
+
+// New diskette parameter table adding 3 parameters from IBM
+// Since no provisions are made for multiple drive types, most
+// values in this table are ignored. I set parameters for 1.44M
+// floppy here
+struct floppy_ext_dbt_s diskette_param_table2 VAR16VISIBLE = {
+ .dbt = {
+ .specify1 = 0xAF, // step rate 12ms, head unload 240ms
+ .specify2 = 0x02, // head load time 4ms, DMA used
+ .shutoff_ticks = FLOPPY_MOTOR_TICKS, // ~2 seconds
+ .bps_code = FLOPPY_SIZE_CODE,
+ .sectors = 18,
+ .interblock_len = FLOPPY_GAPLEN,
+ .data_len = FLOPPY_DATALEN,
+ .gap_len = FLOPPY_FORMAT_GAPLEN,
+ .fill_byte = FLOPPY_FILLBYTE,
+ .settle_time = 0x0F, // 15ms
+ .startup_time = 0x08, // 1 second
+ },
+ .max_track = 79, // maximum track
+ .data_rate = 0, // data transfer rate
+ .drive_type = 4, // drive type in cmos
+};
+
+// Since no provisions are made for multiple drive types, most
+// values in this table are ignored. I set parameters for 1.44M
+// floppy here
+struct floppy_dbt_s diskette_param_table VAR16FIXED(0xefc7) = {
+ .specify1 = 0xAF,
+ .specify2 = 0x02,
+ .shutoff_ticks = FLOPPY_MOTOR_TICKS,
+ .bps_code = FLOPPY_SIZE_CODE,
+ .sectors = 18,
+ .interblock_len = FLOPPY_GAPLEN,
+ .data_len = FLOPPY_DATALEN,
+ .gap_len = FLOPPY_FORMAT_GAPLEN,
+ .fill_byte = FLOPPY_FILLBYTE,
+ .settle_time = 0x0F,
+ .startup_time = 0x08,
+};
+
+struct floppyinfo_s {
+ struct chs_s chs;
+ u8 config_data;
+ u8 media_state;
+};
+
+struct floppyinfo_s FloppyInfo[] VAR16VISIBLE = {
+ // Unknown
+ { {0, 0, 0}, 0x00, 0x00},
+ // 1 - 360KB, 5.25" - 2 heads, 40 tracks, 9 sectors
+ { {2, 40, 9}, 0x00, 0x25},
+ // 2 - 1.2MB, 5.25" - 2 heads, 80 tracks, 15 sectors
+ { {2, 80, 15}, 0x00, 0x25},
+ // 3 - 720KB, 3.5" - 2 heads, 80 tracks, 9 sectors
+ { {2, 80, 9}, 0x00, 0x17},
+ // 4 - 1.44MB, 3.5" - 2 heads, 80 tracks, 18 sectors
+ { {2, 80, 18}, 0x00, 0x17},
+ // 5 - 2.88MB, 3.5" - 2 heads, 80 tracks, 36 sectors
+ { {2, 80, 36}, 0xCC, 0xD7},
+ // 6 - 160k, 5.25" - 1 heads, 40 tracks, 8 sectors
+ { {1, 40, 8}, 0x00, 0x27},
+ // 7 - 180k, 5.25" - 1 heads, 40 tracks, 9 sectors
+ { {1, 40, 9}, 0x00, 0x27},
+ // 8 - 320k, 5.25" - 2 heads, 40 tracks, 8 sectors
+ { {2, 40, 8}, 0x00, 0x27},
+};
+
+struct drive_s *
+init_floppy(int floppyid, int ftype)
+{
+ if (ftype <= 0 || ftype >= ARRAY_SIZE(FloppyInfo)) {
+ dprintf(1, "Bad floppy type %d\n", ftype);
+ return NULL;
+ }
+
+ struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g));
+ if (!drive_g) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(drive_g, 0, sizeof(*drive_g));
+ drive_g->cntl_id = floppyid;
+ drive_g->type = DTYPE_FLOPPY;
+ drive_g->blksize = DISK_SECTOR_SIZE;
+ drive_g->floppy_type = ftype;
+ drive_g->sectors = (u64)-1;
+
+ memcpy(&drive_g->lchs, &FloppyInfo[ftype].chs
+ , sizeof(FloppyInfo[ftype].chs));
+ return drive_g;
+}
+
+static void
+addFloppy(int floppyid, int ftype)
+{
+ struct drive_s *drive_g = init_floppy(floppyid, ftype);
+ if (!drive_g)
+ return;
+ char *desc = znprintf(MAXDESCSIZE, "Floppy [drive %c]", 'A' + floppyid);
+ struct pci_device *pci = pci_find_class(PCI_CLASS_BRIDGE_ISA); /* isa-to-pci bridge */
+ int prio = bootprio_find_fdc_device(pci, PORT_FD_BASE, floppyid);
+ boot_add_floppy(drive_g, desc, prio);
+}
+
+void
+floppy_setup(void)
+{
+ if (! CONFIG_FLOPPY)
+ return;
+ dprintf(3, "init floppy drives\n");
+
+ if (CONFIG_COREBOOT) {
+ // XXX - disable floppies on coreboot for now.
+ } else {
+ u8 type = inb_cmos(CMOS_FLOPPY_DRIVE_TYPE);
+ if (type & 0xf0)
+ addFloppy(0, type >> 4);
+ if (type & 0x0f)
+ addFloppy(1, type & 0x0f);
+ }
+
+ outb(0x02, PORT_DMA1_MASK_REG);
+
+ enable_hwirq(6, FUNC16(entry_0e));
+}
+
+// Find a floppy type that matches a given image size.
+int
+find_floppy_type(u32 size)
+{
+ int i;
+ for (i=1; i<ARRAY_SIZE(FloppyInfo); i++) {
+ struct chs_s *c = &FloppyInfo[i].chs;
+ if (c->cylinders * c->heads * c->spt * DISK_SECTOR_SIZE == size)
+ return i;
+ }
+ return -1;
+}
+
+
+/****************************************************************
+ * Low-level floppy IO
+ ****************************************************************/
+
+static void
+floppy_reset_controller(void)
+{
+ // Reset controller
+ u8 val8 = inb(PORT_FD_DOR);
+ outb(val8 & ~0x04, PORT_FD_DOR);
+ outb(val8 | 0x04, PORT_FD_DOR);
+
+ // Wait for controller to come out of reset
+ while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+ ;
+}
+
+static int
+wait_floppy_irq(void)
+{
+ ASSERT16();
+ u8 v;
+ for (;;) {
+ if (!GET_BDA(floppy_motor_counter))
+ return -1;
+ v = GET_BDA(floppy_recalibration_status);
+ if (v & FRS_TIMEOUT)
+ break;
+ // Could use wait_irq() here, but that causes issues on
+ // bochs, so use yield() instead.
+ yield();
+ }
+
+ v &= ~FRS_TIMEOUT;
+ SET_BDA(floppy_recalibration_status, v);
+ return 0;
+}
+
+static void
+floppy_prepare_controller(u8 floppyid)
+{
+ CLEARBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+
+ // turn on motor of selected drive, DMA & int enabled, normal operation
+ u8 prev_reset = inb(PORT_FD_DOR) & 0x04;
+ u8 dor = 0x10;
+ if (floppyid)
+ dor = 0x20;
+ dor |= 0x0c;
+ dor |= floppyid;
+ outb(dor, PORT_FD_DOR);
+
+ // reset the disk motor timeout value of INT 08
+ SET_BDA(floppy_motor_counter, FLOPPY_MOTOR_TICKS);
+
+ // wait for drive readiness
+ while ((inb(PORT_FD_STATUS) & 0xc0) != 0x80)
+ ;
+
+ if (!prev_reset)
+ wait_floppy_irq();
+}
+
+static int
+floppy_pio(u8 *cmd, u8 cmdlen)
+{
+ floppy_prepare_controller(cmd[1] & 1);
+
+ // send command to controller
+ u8 i;
+ for (i=0; i<cmdlen; i++)
+ outb(cmd[i], PORT_FD_DATA);
+
+ int ret = wait_floppy_irq();
+ if (ret) {
+ floppy_reset_controller();
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+floppy_cmd(struct disk_op_s *op, u16 count, u8 *cmd, u8 cmdlen)
+{
+ // es:bx = pointer to where to place information from diskette
+ u32 addr = (u32)op->buf_fl;
+
+ // check for 64K boundary overrun
+ u16 end = count - 1;
+ u32 last_addr = addr + end;
+ if ((addr >> 16) != (last_addr >> 16))
+ return DISK_RET_EBOUNDARY;
+
+ u8 mode_register = 0x4a; // single mode, increment, autoinit disable,
+ if (cmd[0] == 0xe6)
+ // read
+ mode_register = 0x46;
+
+ //DEBUGF("floppy dma c2\n");
+ outb(0x06, PORT_DMA1_MASK_REG);
+ outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+ outb(addr, PORT_DMA_ADDR_2);
+ outb(addr>>8, PORT_DMA_ADDR_2);
+ outb(0x00, PORT_DMA1_CLEAR_FF_REG); // clear flip-flop
+ outb(end, PORT_DMA_CNT_2);
+ outb(end>>8, PORT_DMA_CNT_2);
+
+ // port 0b: DMA-1 Mode Register
+ // transfer type=write, channel 2
+ outb(mode_register, PORT_DMA1_MODE_REG);
+
+ // port 81: DMA-1 Page Register, channel 2
+ outb(addr>>16, PORT_DMA_PAGE_2);
+
+ outb(0x02, PORT_DMA1_MASK_REG); // unmask channel 2
+
+ int ret = floppy_pio(cmd, cmdlen);
+ if (ret)
+ return DISK_RET_ETIMEOUT;
+
+ // check port 3f4 for accessibility to status bytes
+ if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+ return DISK_RET_ECONTROLLER;
+
+ // read 7 return status bytes from controller
+ u8 i;
+ for (i=0; i<7; i++) {
+ u8 v = inb(PORT_FD_DATA);
+ cmd[i] = v;
+ SET_BDA(floppy_return_status[i], v);
+ }
+
+ return DISK_RET_SUCCESS;
+}
+
+
+/****************************************************************
+ * Floppy media sense
+ ****************************************************************/
+
+static inline void
+set_diskette_current_cyl(u8 floppyid, u8 cyl)
+{
+ SET_BDA(floppy_track[floppyid], cyl);
+}
+
+static void
+floppy_drive_recal(u8 floppyid)
+{
+ // send Recalibrate command (2 bytes) to controller
+ u8 data[12];
+ data[0] = 0x07; // 07: Recalibrate
+ data[1] = floppyid; // 0=drive0, 1=drive1
+ floppy_pio(data, 2);
+
+ SETBITS_BDA(floppy_recalibration_status, 1<<floppyid);
+ set_diskette_current_cyl(floppyid, 0);
+}
+
+static int
+floppy_media_sense(struct drive_s *drive_g)
+{
+ // for now cheat and get drive type from CMOS,
+ // assume media is same as drive type
+
+ // ** config_data **
+ // Bitfields for diskette media control:
+ // Bit(s) Description (Table M0028)
+ // 7-6 last data rate set by controller
+ // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+ // 5-4 last diskette drive step rate selected
+ // 00=0Ch, 01=0Dh, 10=0Eh, 11=0Ah
+ // 3-2 {data rate at start of operation}
+ // 1-0 reserved
+
+ // ** media_state **
+ // Bitfields for diskette drive media state:
+ // Bit(s) Description (Table M0030)
+ // 7-6 data rate
+ // 00=500kbps, 01=300kbps, 10=250kbps, 11=1Mbps
+ // 5 double stepping required (e.g. 360kB in 1.2MB)
+ // 4 media type established
+ // 3 drive capable of supporting 4MB media
+ // 2-0 on exit from BIOS, contains
+ // 000 trying 360kB in 360kB
+ // 001 trying 360kB in 1.2MB
+ // 010 trying 1.2MB in 1.2MB
+ // 011 360kB in 360kB established
+ // 100 360kB in 1.2MB established
+ // 101 1.2MB in 1.2MB established
+ // 110 reserved
+ // 111 all other formats/drives
+
+ u8 ftype = GET_GLOBAL(drive_g->floppy_type);
+ SET_BDA(floppy_last_data_rate, GET_GLOBAL(FloppyInfo[ftype].config_data));
+ u8 floppyid = GET_GLOBAL(drive_g->cntl_id);
+ SET_BDA(floppy_media_state[floppyid]
+ , GET_GLOBAL(FloppyInfo[ftype].media_state));
+ return DISK_RET_SUCCESS;
+}
+
+static int
+check_recal_drive(struct drive_s *drive_g)
+{
+ u8 floppyid = GET_GLOBAL(drive_g->cntl_id);
+ if ((GET_BDA(floppy_recalibration_status) & (1<<floppyid))
+ && (GET_BDA(floppy_media_state[floppyid]) & FMS_MEDIA_DRIVE_ESTABLISHED))
+ // Media is known.
+ return DISK_RET_SUCCESS;
+
+ // Recalibrate drive.
+ floppy_drive_recal(floppyid);
+
+ // Sense media.
+ return floppy_media_sense(drive_g);
+}
+
+
+/****************************************************************
+ * Floppy handlers
+ ****************************************************************/
+
+static void
+lba2chs(struct disk_op_s *op, u8 *track, u8 *sector, u8 *head)
+{
+ u32 lba = op->lba;
+
+ u32 tmp = lba + 1;
+ u16 nlspt = GET_GLOBAL(op->drive_g->lchs.spt);
+ *sector = tmp % nlspt;
+
+ tmp /= nlspt;
+ u16 nlh = GET_GLOBAL(op->drive_g->lchs.heads);
+ *head = tmp % nlh;
+
+ tmp /= nlh;
+ *track = tmp;
+}
+
+// diskette controller reset
+static int
+floppy_reset(struct disk_op_s *op)
+{
+ u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+ set_diskette_current_cyl(floppyid, 0); // current cylinder
+ return DISK_RET_SUCCESS;
+}
+
+// Read Diskette Sectors
+static int
+floppy_read(struct disk_op_s *op)
+{
+ int res = check_recal_drive(op->drive_g);
+ if (res)
+ goto fail;
+
+ u8 track, sector, head;
+ lba2chs(op, &track, §or, &head);
+
+ // send read-normal-data command (9 bytes) to controller
+ u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+ u8 data[12];
+ data[0] = 0xe6; // e6: read normal data
+ data[1] = (head << 2) | floppyid; // HD DR1 DR2
+ data[2] = track;
+ data[3] = head;
+ data[4] = sector;
+ data[5] = FLOPPY_SIZE_CODE;
+ data[6] = sector + op->count - 1; // last sector to read on track
+ data[7] = FLOPPY_GAPLEN;
+ data[8] = FLOPPY_DATALEN;
+
+ res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9);
+ if (res)
+ goto fail;
+
+ if (data[0] & 0xc0) {
+ res = DISK_RET_ECONTROLLER;
+ goto fail;
+ }
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(floppyid, track);
+ return DISK_RET_SUCCESS;
+fail:
+ op->count = 0; // no sectors read
+ return res;
+}
+
+// Write Diskette Sectors
+static int
+floppy_write(struct disk_op_s *op)
+{
+ int res = check_recal_drive(op->drive_g);
+ if (res)
+ goto fail;
+
+ u8 track, sector, head;
+ lba2chs(op, &track, §or, &head);
+
+ // send write-normal-data command (9 bytes) to controller
+ u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+ u8 data[12];
+ data[0] = 0xc5; // c5: write normal data
+ data[1] = (head << 2) | floppyid; // HD DR1 DR2
+ data[2] = track;
+ data[3] = head;
+ data[4] = sector;
+ data[5] = FLOPPY_SIZE_CODE;
+ data[6] = sector + op->count - 1; // last sector to write on track
+ data[7] = FLOPPY_GAPLEN;
+ data[8] = FLOPPY_DATALEN;
+
+ res = floppy_cmd(op, op->count * DISK_SECTOR_SIZE, data, 9);
+ if (res)
+ goto fail;
+
+ if (data[0] & 0xc0) {
+ if (data[1] & 0x02)
+ res = DISK_RET_EWRITEPROTECT;
+ else
+ res = DISK_RET_ECONTROLLER;
+ goto fail;
+ }
+
+ // ??? should track be new val from return_status[3] ?
+ set_diskette_current_cyl(floppyid, track);
+ return DISK_RET_SUCCESS;
+fail:
+ op->count = 0; // no sectors read
+ return res;
+}
+
+// Verify Diskette Sectors
+static int
+floppy_verify(struct disk_op_s *op)
+{
+ int res = check_recal_drive(op->drive_g);
+ if (res)
+ goto fail;
+
+ u8 track, sector, head;
+ lba2chs(op, &track, §or, &head);
+
+ // ??? should track be new val from return_status[3] ?
+ u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+ set_diskette_current_cyl(floppyid, track);
+ return DISK_RET_SUCCESS;
+fail:
+ op->count = 0; // no sectors read
+ return res;
+}
+
+// format diskette track
+static int
+floppy_format(struct disk_op_s *op)
+{
+ int ret = check_recal_drive(op->drive_g);
+ if (ret)
+ return ret;
+
+ u8 head = op->lba;
+
+ // send format-track command (6 bytes) to controller
+ u8 floppyid = GET_GLOBAL(op->drive_g->cntl_id);
+ u8 data[12];
+ data[0] = 0x4d; // 4d: format track
+ data[1] = (head << 2) | floppyid; // HD DR1 DR2
+ data[2] = FLOPPY_SIZE_CODE;
+ data[3] = op->count; // number of sectors per track
+ data[4] = FLOPPY_FORMAT_GAPLEN;
+ data[5] = FLOPPY_FILLBYTE;
+
+ ret = floppy_cmd(op, op->count * 4, data, 6);
+ if (ret)
+ return ret;
+
+ if (data[0] & 0xc0) {
+ if (data[1] & 0x02)
+ return DISK_RET_EWRITEPROTECT;
+ return DISK_RET_ECONTROLLER;
+ }
+
+ set_diskette_current_cyl(floppyid, 0);
+ return DISK_RET_SUCCESS;
+}
+
+int
+process_floppy_op(struct disk_op_s *op)
+{
+ if (!CONFIG_FLOPPY)
+ return 0;
+
+ switch (op->command) {
+ case CMD_RESET:
+ return floppy_reset(op);
+ case CMD_READ:
+ return floppy_read(op);
+ case CMD_WRITE:
+ return floppy_write(op);
+ case CMD_VERIFY:
+ return floppy_verify(op);
+ case CMD_FORMAT:
+ return floppy_format(op);
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+
+/****************************************************************
+ * HW irqs
+ ****************************************************************/
+
+// INT 0Eh Diskette Hardware ISR Entry Point
+void VISIBLE16
+handle_0e(void)
+{
+ debug_isr(DEBUG_ISR_0e);
+ if (! CONFIG_FLOPPY)
+ goto done;
+
+ if ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0) {
+ outb(0x08, PORT_FD_DATA); // sense interrupt status
+ while ((inb(PORT_FD_STATUS) & 0xc0) != 0xc0)
+ ;
+ do {
+ inb(PORT_FD_DATA);
+ } while ((inb(PORT_FD_STATUS) & 0xc0) == 0xc0);
+ }
+ // diskette interrupt has occurred
+ SETBITS_BDA(floppy_recalibration_status, FRS_TIMEOUT);
+
+done:
+ eoi_pic1();
+}
+
+// Called from int08 handler.
+void
+floppy_tick(void)
+{
+ if (! CONFIG_FLOPPY)
+ return;
+
+ // time to turn off drive(s)?
+ u8 fcount = GET_BDA(floppy_motor_counter);
+ if (fcount) {
+ fcount--;
+ SET_BDA(floppy_motor_counter, fcount);
+ if (fcount == 0)
+ // turn motor(s) off
+ outb(inb(PORT_FD_DOR) & 0xcf, PORT_FD_DOR);
+ }
+}
--- /dev/null
+#include "types.h" // u8
+
+// Character Font for 320x200 & 640x200 Graphics (lower 128 characters)
+
+/*
+ * This font comes from the fntcol16.zip package (c) by Joseph Gil
+ * found at ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * This font is public domain
+ */
+u8 vgafont8[128*8] VAR16FIXED(0xfa6e) = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+};
--- /dev/null
+// Tool for building defintions accessible from assembler code. This
+// is based on code from the Linux Kernel.
+#ifndef __GEN_DEFS_H
+#define __GEN_DEFS_H
+
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() \
+ asm volatile("\n->" : : )
+
+#define OFFSET(sym, str, mem) \
+ DEFINE(sym, offsetof(struct str, mem))
+
+#define COMMENT(x) \
+ asm volatile("\n->#" x)
+
+#endif // gen-defs.h
--- /dev/null
+// Definitions for X86 IO port access.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __IOPORT_H
+#define __IOPORT_H
+
+#define PORT_DMA_ADDR_2 0x0004
+#define PORT_DMA_CNT_2 0x0005
+#define PORT_DMA1_MASK_REG 0x000a
+#define PORT_DMA1_MODE_REG 0x000b
+#define PORT_DMA1_CLEAR_FF_REG 0x000c
+#define PORT_DMA1_MASTER_CLEAR 0x000d
+#define PORT_PIC1_CMD 0x0020
+#define PORT_PIC1_DATA 0x0021
+#define PORT_PIT_COUNTER0 0x0040
+#define PORT_PIT_COUNTER1 0x0041
+#define PORT_PIT_COUNTER2 0x0042
+#define PORT_PIT_MODE 0x0043
+#define PORT_PS2_DATA 0x0060
+#define PORT_PS2_CTRLB 0x0061
+#define PORT_PS2_STATUS 0x0064
+#define PORT_CMOS_INDEX 0x0070
+#define PORT_CMOS_DATA 0x0071
+#define PORT_DIAG 0x0080
+#define PORT_DMA_PAGE_2 0x0081
+#define PORT_A20 0x0092
+#define PORT_PIC2_CMD 0x00a0
+#define PORT_PIC2_DATA 0x00a1
+#define PORT_SMI_CMD 0x00b2
+#define PORT_SMI_STATUS 0x00b3
+#define PORT_DMA2_MASK_REG 0x00d4
+#define PORT_DMA2_MODE_REG 0x00d6
+#define PORT_DMA2_MASTER_CLEAR 0x00da
+#define PORT_MATH_CLEAR 0x00f0
+#define PORT_ATA2_CMD_BASE 0x0170
+#define PORT_ATA1_CMD_BASE 0x01f0
+#define PORT_LPT2 0x0278
+#define PORT_SERIAL4 0x02e8
+#define PORT_SERIAL2 0x02f8
+#define PORT_ATA2_CTRL_BASE 0x0374
+#define PORT_LPT1 0x0378
+#define PORT_SERIAL3 0x03e8
+#define PORT_ATA1_CTRL_BASE 0x03f4
+#define PORT_FD_BASE 0x03f0
+#define PORT_FD_DOR 0x03f2
+#define PORT_FD_STATUS 0x03f4
+#define PORT_FD_DATA 0x03f5
+#define PORT_HD_DATA 0x03f6
+#define PORT_FD_DIR 0x03f7
+#define PORT_SERIAL1 0x03f8
+#define PORT_PCI_CMD 0x0cf8
+#define PORT_PCI_REBOOT 0x0cf9
+#define PORT_PCI_DATA 0x0cfc
+#define PORT_BIOS_DEBUG 0x0402
+#define PORT_QEMU_CFG_CTL 0x0510
+#define PORT_QEMU_CFG_DATA 0x0511
+#define PORT_ACPI_PM_BASE 0xb000
+#define PORT_SMB_BASE 0xb100
+#define PORT_BIOS_APM 0x8900
+
+// Serial port offsets
+#define SEROFF_DATA 0
+#define SEROFF_DLL 0
+#define SEROFF_IER 1
+#define SEROFF_DLH 1
+#define SEROFF_IIR 2
+#define SEROFF_LCR 3
+#define SEROFF_LSR 5
+#define SEROFF_MSR 6
+
+// PORT_A20 bitdefs
+#define A20_ENABLE_BIT 0x02
+
+// PORT_CMOS_INDEX nmi disable bit
+#define NMI_DISABLE_BIT 0x80
+
+#ifndef __ASSEMBLY__
+
+#include "types.h" // u8
+
+static inline void outb(u8 value, u16 port) {
+ __asm__ __volatile__("outb %b0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline void outw(u16 value, u16 port) {
+ __asm__ __volatile__("outw %w0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline void outl(u32 value, u16 port) {
+ __asm__ __volatile__("outl %0, %w1" : : "a"(value), "Nd"(port));
+}
+static inline u8 inb(u16 port) {
+ u8 value;
+ __asm__ __volatile__("inb %w1, %b0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+static inline u16 inw(u16 port) {
+ u16 value;
+ __asm__ __volatile__("inw %w1, %w0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+static inline u32 inl(u16 port) {
+ u32 value;
+ __asm__ __volatile__("inl %w1, %0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+
+static inline void insb(u16 port, u8 *data, u32 count) {
+ asm volatile("rep insb (%%dx), %%es:(%%edi)"
+ : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+static inline void insw(u16 port, u16 *data, u32 count) {
+ asm volatile("rep insw (%%dx), %%es:(%%edi)"
+ : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+static inline void insl(u16 port, u32 *data, u32 count) {
+ asm volatile("rep insl (%%dx), %%es:(%%edi)"
+ : "+c"(count), "+D"(data) : "d"(port) : "memory");
+}
+// XXX - outs not limited to es segment
+static inline void outsb(u16 port, u8 *data, u32 count) {
+ asm volatile("rep outsb %%es:(%%esi), (%%dx)"
+ : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+static inline void outsw(u16 port, u16 *data, u32 count) {
+ asm volatile("rep outsw %%es:(%%esi), (%%dx)"
+ : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+static inline void outsl(u16 port, u32 *data, u32 count) {
+ asm volatile("rep outsl %%es:(%%esi), (%%dx)"
+ : "+c"(count), "+S"(data) : "d"(port) : "memory");
+}
+
+#endif // !__ASSEMBLY__
+
+#endif // ioport.h
--- /dev/null
+/*
+ * Copyright (C) 2001, Novell Inc.
+ * Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Novell nor the names of the contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*
+ * a tiny jpeg decoder.
+ *
+ * written in August 2001 by Michael Schroeder <mls@suse.de>
+ *
+ */
+
+#define __LITTLE_ENDIAN
+#include "util.h"
+#include "jpeg.h"
+#define ISHIFT 11
+
+#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5))
+#define IMULT(a, b) (((a) * (b)) >> ISHIFT)
+#define ITOINT(a) ((a) >> ISHIFT)
+
+#ifndef __P
+# define __P(x) x
+#endif
+
+/* special markers */
+#define M_BADHUFF -1
+#define M_EOF 0x80
+
+struct in {
+ unsigned char *p;
+ unsigned int bits;
+ int left;
+ int marker;
+
+ int (*func) __P((void *));
+ void *data;
+};
+
+/*********************************/
+struct dec_hufftbl;
+struct enc_hufftbl;
+
+union hufftblp {
+ struct dec_hufftbl *dhuff;
+ struct enc_hufftbl *ehuff;
+};
+
+struct scan {
+ int dc; /* old dc value */
+
+ union hufftblp hudc;
+ union hufftblp huac;
+ int next; /* when to switch to next scan */
+
+ int cid; /* component id */
+ int hv; /* horiz/vert, copied from comp */
+ int tq; /* quant tbl, copied from comp */
+};
+
+/*********************************/
+
+#define DECBITS 10 /* seems to be the optimum */
+
+struct dec_hufftbl {
+ int maxcode[17];
+ int valptr[16];
+ unsigned char vals[256];
+ unsigned int llvals[1 << DECBITS];
+};
+
+static void decode_mcus __P((struct in *, int *, int, struct scan *, int *));
+static int dec_readmarker __P((struct in *));
+static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *));
+
+static void setinput __P((struct in *, unsigned char *));
+/*********************************/
+
+#undef PREC
+#define PREC int
+
+static void idctqtab __P((unsigned char *, PREC *));
+static void idct __P((int *, int *, PREC *, PREC, int));
+static void scaleidctqtab __P((PREC *, PREC));
+
+/*********************************/
+
+static void initcol __P((PREC[][64]));
+
+static void col221111 __P((int *, unsigned char *, int));
+static void col221111_16 __P((int *, unsigned char *, int));
+static void col221111_32 __P((int *, unsigned char *, int));
+
+/*********************************/
+
+#define ERR_NO_SOI 1
+#define ERR_NOT_8BIT 2
+#define ERR_HEIGHT_MISMATCH 3
+#define ERR_WIDTH_MISMATCH 4
+#define ERR_BAD_WIDTH_OR_HEIGHT 5
+#define ERR_TOO_MANY_COMPPS 6
+#define ERR_ILLEGAL_HV 7
+#define ERR_QUANT_TABLE_SELECTOR 8
+#define ERR_NOT_YCBCR_221111 9
+#define ERR_UNKNOWN_CID_IN_SCAN 10
+#define ERR_NOT_SEQUENTIAL_DCT 11
+#define ERR_WRONG_MARKER 12
+#define ERR_NO_EOI 13
+#define ERR_BAD_TABLES 14
+#define ERR_DEPTH_MISMATCH 15
+
+/*********************************/
+
+#define M_SOI 0xd8
+#define M_APP0 0xe0
+#define M_DQT 0xdb
+#define M_SOF0 0xc0
+#define M_DHT 0xc4
+#define M_DRI 0xdd
+#define M_SOS 0xda
+#define M_RST0 0xd0
+#define M_EOI 0xd9
+#define M_COM 0xfe
+
+struct comp {
+ int cid;
+ int hv;
+ int tq;
+};
+
+#define MAXCOMP 4
+struct jpginfo {
+ int nc; /* number of components */
+ int ns; /* number of scans */
+ int dri; /* restart interval */
+ int nm; /* mcus til next marker */
+ int rm; /* next restart marker */
+};
+
+struct jpeg_decdata {
+ int dcts[6 * 64 + 16];
+ int out[64 * 6];
+ int dquant[3][64];
+
+ unsigned char *datap;
+ struct jpginfo info;
+ struct comp comps[MAXCOMP];
+ struct scan dscans[MAXCOMP];
+ unsigned char quant[4][64];
+ struct dec_hufftbl dhuff[4];
+ struct in in;
+
+ int height, width;
+};
+
+static int getbyte(struct jpeg_decdata *jpeg)
+{
+ return *jpeg->datap++;
+}
+
+static int getword(struct jpeg_decdata *jpeg)
+{
+ int c1, c2;
+ c1 = *jpeg->datap++;
+ c2 = *jpeg->datap++;
+ return c1 << 8 | c2;
+}
+
+static int readtables(struct jpeg_decdata *jpeg, int till)
+{
+ int m, l, i, j, lq, pq, tq;
+ int tc, th, tt;
+
+ for (;;) {
+ if (getbyte(jpeg) != 0xff)
+ return -1;
+ if ((m = getbyte(jpeg)) == till)
+ break;
+
+ switch (m) {
+ case 0xc2:
+ return 0;
+
+ case M_DQT:
+ lq = getword(jpeg);
+ while (lq > 2) {
+ pq = getbyte(jpeg);
+ tq = pq & 15;
+ if (tq > 3)
+ return -1;
+ pq >>= 4;
+ if (pq != 0)
+ return -1;
+ for (i = 0; i < 64; i++)
+ jpeg->quant[tq][i] = getbyte(jpeg);
+ lq -= 64 + 1;
+ }
+ break;
+
+ case M_DHT:
+ l = getword(jpeg);
+ while (l > 2) {
+ int hufflen[16], k;
+ unsigned char huffvals[256];
+
+ tc = getbyte(jpeg);
+ th = tc & 15;
+ tc >>= 4;
+ tt = tc * 2 + th;
+ if (tc > 1 || th > 1)
+ return -1;
+ for (i = 0; i < 16; i++)
+ hufflen[i] = getbyte(jpeg);
+ l -= 1 + 16;
+ k = 0;
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < hufflen[i]; j++)
+ huffvals[k++] = getbyte(jpeg);
+ l -= hufflen[i];
+ }
+ dec_makehuff(jpeg->dhuff + tt, hufflen, huffvals);
+ }
+ break;
+
+ case M_DRI:
+ l = getword(jpeg);
+ jpeg->info.dri = getword(jpeg);
+ break;
+
+ default:
+ l = getword(jpeg);
+ while (l-- > 2)
+ getbyte(jpeg);
+ break;
+ }
+ }
+ return 0;
+}
+
+static void dec_initscans(struct jpeg_decdata *jpeg)
+{
+ int i;
+
+ jpeg->info.nm = jpeg->info.dri + 1;
+ jpeg->info.rm = M_RST0;
+ for (i = 0; i < jpeg->info.ns; i++)
+ jpeg->dscans[i].dc = 0;
+}
+
+static int dec_checkmarker(struct jpeg_decdata *jpeg)
+{
+ int i;
+
+ if (dec_readmarker(&jpeg->in) != jpeg->info.rm)
+ return -1;
+ jpeg->info.nm = jpeg->info.dri;
+ jpeg->info.rm = (jpeg->info.rm + 1) & ~0x08;
+ for (i = 0; i < jpeg->info.ns; i++)
+ jpeg->dscans[i].dc = 0;
+ return 0;
+}
+
+struct jpeg_decdata *jpeg_alloc(void)
+{
+ struct jpeg_decdata *jpeg = malloc_tmphigh(sizeof(*jpeg));
+ return jpeg;
+}
+
+int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf)
+{
+ int i, j, m, tac, tdc;
+
+ if (!jpeg || !buf)
+ return -1;
+ jpeg->datap = buf;
+ if (getbyte(jpeg) != 0xff)
+ return ERR_NO_SOI;
+ if (getbyte(jpeg) != M_SOI)
+ return ERR_NO_SOI;
+ if (readtables(jpeg, M_SOF0))
+ return ERR_BAD_TABLES;
+ getword(jpeg);
+ i = getbyte(jpeg);
+ if (i != 8)
+ return ERR_NOT_8BIT;
+ jpeg->height = getword(jpeg);
+ jpeg->width = getword(jpeg);
+ if ((jpeg->height & 15) || (jpeg->width & 15))
+ return ERR_BAD_WIDTH_OR_HEIGHT;
+ jpeg->info.nc = getbyte(jpeg);
+ if (jpeg->info.nc > MAXCOMP)
+ return ERR_TOO_MANY_COMPPS;
+ for (i = 0; i < jpeg->info.nc; i++) {
+ int h, v;
+ jpeg->comps[i].cid = getbyte(jpeg);
+ jpeg->comps[i].hv = getbyte(jpeg);
+ v = jpeg->comps[i].hv & 15;
+ h = jpeg->comps[i].hv >> 4;
+ jpeg->comps[i].tq = getbyte(jpeg);
+ if (h > 3 || v > 3)
+ return ERR_ILLEGAL_HV;
+ if (jpeg->comps[i].tq > 3)
+ return ERR_QUANT_TABLE_SELECTOR;
+ }
+ if (readtables(jpeg, M_SOS))
+ return ERR_BAD_TABLES;
+ getword(jpeg);
+ jpeg->info.ns = getbyte(jpeg);
+ if (jpeg->info.ns != 3)
+ return ERR_NOT_YCBCR_221111;
+ for (i = 0; i < 3; i++) {
+ jpeg->dscans[i].cid = getbyte(jpeg);
+ tdc = getbyte(jpeg);
+ tac = tdc & 15;
+ tdc >>= 4;
+ if (tdc > 1 || tac > 1)
+ return ERR_QUANT_TABLE_SELECTOR;
+ for (j = 0; j < jpeg->info.nc; j++)
+ if (jpeg->comps[j].cid == jpeg->dscans[i].cid)
+ break;
+ if (j == jpeg->info.nc)
+ return ERR_UNKNOWN_CID_IN_SCAN;
+ jpeg->dscans[i].hv = jpeg->comps[j].hv;
+ jpeg->dscans[i].tq = jpeg->comps[j].tq;
+ jpeg->dscans[i].hudc.dhuff = &jpeg->dhuff[tdc];
+ jpeg->dscans[i].huac.dhuff = &jpeg->dhuff[2 + tac];
+ }
+
+ i = getbyte(jpeg);
+ j = getbyte(jpeg);
+ m = getbyte(jpeg);
+
+ if (i != 0 || j != 63 || m != 0)
+ return ERR_NOT_SEQUENTIAL_DCT;
+
+ if (jpeg->dscans[0].cid != 1 || jpeg->dscans[1].cid != 2
+ || jpeg->dscans[2].cid != 3)
+ return ERR_NOT_YCBCR_221111;
+
+ if (jpeg->dscans[0].hv != 0x22 || jpeg->dscans[1].hv != 0x11
+ || jpeg->dscans[2].hv != 0x11)
+ return ERR_NOT_YCBCR_221111;
+
+ idctqtab(jpeg->quant[jpeg->dscans[0].tq], jpeg->dquant[0]);
+ idctqtab(jpeg->quant[jpeg->dscans[1].tq], jpeg->dquant[1]);
+ idctqtab(jpeg->quant[jpeg->dscans[2].tq], jpeg->dquant[2]);
+ initcol(jpeg->dquant);
+ setinput(&jpeg->in, jpeg->datap);
+
+#if 0
+ /* landing zone */
+ img[len] = 0;
+ img[len + 1] = 0xff;
+ img[len + 2] = M_EOF;
+#endif
+
+ dec_initscans(jpeg);
+
+ return 0;
+}
+
+void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height)
+{
+ *width = jpeg->width;
+ *height = jpeg->height;
+}
+
+int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width
+ , int height, int depth, int bytes_per_line_dest)
+{
+ int m, mcusx, mcusy, mx, my, mloffset, jpgbpl;
+ int max[6];
+
+ if (jpeg->height != height)
+ return ERR_HEIGHT_MISMATCH;
+ if (jpeg->width != width)
+ return ERR_WIDTH_MISMATCH;
+
+ jpgbpl = width * depth / 8;
+ mloffset = bytes_per_line_dest > jpgbpl ? bytes_per_line_dest : jpgbpl;
+
+ mcusx = jpeg->width >> 4;
+ mcusy = jpeg->height >> 4;
+
+ jpeg->dscans[0].next = 6 - 4;
+ jpeg->dscans[1].next = 6 - 4 - 1;
+ jpeg->dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */
+ for (my = 0; my < mcusy; my++) {
+ for (mx = 0; mx < mcusx; mx++) {
+ if (jpeg->info.dri && !--jpeg->info.nm)
+ if (dec_checkmarker(jpeg))
+ return ERR_WRONG_MARKER;
+
+ decode_mcus(&jpeg->in, jpeg->dcts, 6, jpeg->dscans, max);
+ idct(jpeg->dcts, jpeg->out, jpeg->dquant[0],
+ IFIX(128.5), max[0]);
+ idct(jpeg->dcts + 64, jpeg->out + 64, jpeg->dquant[0],
+ IFIX(128.5), max[1]);
+ idct(jpeg->dcts + 128, jpeg->out + 128, jpeg->dquant[0],
+ IFIX(128.5), max[2]);
+ idct(jpeg->dcts + 192, jpeg->out + 192, jpeg->dquant[0],
+ IFIX(128.5), max[3]);
+ idct(jpeg->dcts + 256, jpeg->out + 256, jpeg->dquant[1],
+ IFIX(0.5), max[4]);
+ idct(jpeg->dcts + 320, jpeg->out + 320, jpeg->dquant[2],
+ IFIX(0.5), max[5]);
+
+ switch (depth) {
+ case 32:
+ col221111_32(jpeg->out,
+ pic + (my * 16 * mloffset + mx * 16 * 4),
+ mloffset);
+ break;
+ case 24:
+ col221111(jpeg->out,
+ pic + (my * 16 * mloffset + mx * 16 * 3),
+ mloffset);
+ break;
+ case 16:
+ col221111_16(jpeg->out,
+ pic + (my * 16 * mloffset + mx * 16 * 2),
+ mloffset);
+ break;
+ default:
+ return ERR_DEPTH_MISMATCH;
+ break;
+ }
+ }
+ }
+
+ m = dec_readmarker(&jpeg->in);
+ if (m != M_EOI)
+ return ERR_NO_EOI;
+
+ return 0;
+}
+
+/****************************************************************/
+/************** huffman decoder ***************/
+/****************************************************************/
+
+static int fillbits __P((struct in *, int, unsigned int));
+static int dec_rec2 __P((struct in *, struct dec_hufftbl *, int *, int, int));
+
+static void setinput(struct in *in, unsigned char *p)
+{
+ in->p = p;
+ in->left = 0;
+ in->bits = 0;
+ in->marker = 0;
+}
+
+static int fillbits(struct in *in, int le, unsigned int bi)
+{
+ int b, m;
+
+ if (in->marker) {
+ if (le <= 16)
+ in->bits = bi << 16, le += 16;
+ return le;
+ }
+ while (le <= 24) {
+ b = *in->p++;
+ if (b == 0xff && (m = *in->p++) != 0) {
+ if (m == M_EOF) {
+ if (in->func && (m = in->func(in->data)) == 0)
+ continue;
+ }
+ in->marker = m;
+ if (le <= 16)
+ bi = bi << 16, le += 16;
+ break;
+ }
+ bi = bi << 8 | b;
+ le += 8;
+ }
+ in->bits = bi; /* tmp... 2 return values needed */
+ return le;
+}
+
+static int dec_readmarker(struct in *in)
+{
+ int m;
+
+ in->left = fillbits(in, in->left, in->bits);
+ if ((m = in->marker) == 0)
+ return 0;
+ in->left = 0;
+ in->marker = 0;
+ return m;
+}
+
+#define LEBI_DCL int le, bi
+#define LEBI_GET(in) (le = in->left, bi = in->bits)
+#define LEBI_PUT(in) (in->left = le, in->bits = bi)
+
+#define GETBITS(in, n) ( \
+ (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \
+ (le -= (n)), \
+ bi >> le & ((1 << (n)) - 1) \
+)
+
+#define UNGETBITS(in, n) ( \
+ le += (n) \
+)
+
+
+static int dec_rec2(struct in *in, struct dec_hufftbl *hu, int *runp,
+ int c, int i)
+{
+ LEBI_DCL;
+
+ LEBI_GET(in);
+ if (i) {
+ UNGETBITS(in, i & 127);
+ *runp = i >> 8 & 15;
+ i >>= 16;
+ } else {
+ for (i = DECBITS;
+ (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++);
+ if (i >= 16) {
+ in->marker = M_BADHUFF;
+ return 0;
+ }
+ i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2];
+ *runp = i >> 4;
+ i &= 15;
+ }
+ if (i == 0) { /* sigh, 0xf0 is 11 bit */
+ LEBI_PUT(in);
+ return 0;
+ }
+ /* receive part */
+ c = GETBITS(in, i);
+ if (c < (1 << (i - 1)))
+ c += (-1 << i) + 1;
+ LEBI_PUT(in);
+ return c;
+}
+
+#define DEC_REC(in, hu, r, i) ( \
+ r = GETBITS(in, DECBITS), \
+ i = hu->llvals[r], \
+ i & 128 ? \
+ ( \
+ UNGETBITS(in, i & 127), \
+ r = i >> 8 & 15, \
+ i >> 16 \
+ ) \
+ : \
+ ( \
+ LEBI_PUT(in), \
+ i = dec_rec2(in, hu, &r, r, i), \
+ LEBI_GET(in), \
+ i \
+ ) \
+)
+
+static void decode_mcus(struct in *in, int *dct, int n, struct scan *sc,
+ int *maxp)
+{
+ struct dec_hufftbl *hu;
+ int i, r, t;
+ LEBI_DCL;
+
+ memset(dct, 0, n * 64 * sizeof(*dct));
+ LEBI_GET(in);
+ while (n-- > 0) {
+ hu = sc->hudc.dhuff;
+ *dct++ = (sc->dc += DEC_REC(in, hu, r, t));
+
+ hu = sc->huac.dhuff;
+ i = 63;
+ while (i > 0) {
+ t = DEC_REC(in, hu, r, t);
+ if (t == 0 && r == 0) {
+ dct += i;
+ break;
+ }
+ dct += r;
+ *dct++ = t;
+ i -= r + 1;
+ }
+ *maxp++ = 64 - i;
+ if (n == sc->next)
+ sc++;
+ }
+ LEBI_PUT(in);
+}
+
+static void dec_makehuff(struct dec_hufftbl *hu, int *hufflen,
+ unsigned char *huffvals)
+{
+ int code, k, i, j, d, x, c, v;
+ for (i = 0; i < (1 << DECBITS); i++)
+ hu->llvals[i] = 0;
+
+ /*
+ * llvals layout:
+ *
+ * value v already known, run r, backup u bits:
+ * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu
+ * value unknown, size b bits, run r, backup u bits:
+ * 000000000000bbbb 0000 rrrr 0 uuuuuuu
+ * value and size unknown:
+ * 0000000000000000 0000 0000 0 0000000
+ */
+
+ code = 0;
+ k = 0;
+ for (i = 0; i < 16; i++, code <<= 1) { /* sizes */
+ hu->valptr[i] = k;
+ for (j = 0; j < hufflen[i]; j++) {
+ hu->vals[k] = *huffvals++;
+ if (i < DECBITS) {
+ c = code << (DECBITS - 1 - i);
+ v = hu->vals[k] & 0x0f; /* size */
+ for (d = 1 << (DECBITS - 1 - i); --d >= 0;) {
+ if (v + i < DECBITS) { /* both fit in table */
+ x = d >> (DECBITS - 1 - v - i);
+ if (v && x < (1 << (v - 1)))
+ x += (-1 << v) + 1;
+ x = x << 16 | (hu->vals[k] & 0xf0) << 4 |
+ (DECBITS - (i + 1 + v)) | 128;
+ } else
+ x = v << 16 | (hu->vals[k] & 0xf0) << 4 |
+ (DECBITS - (i + 1));
+ hu->llvals[c | d] = x;
+ }
+ }
+ code++;
+ k++;
+ }
+ hu->maxcode[i] = code;
+ }
+ hu->maxcode[16] = 0x20000; /* always terminate decode */
+}
+
+/****************************************************************/
+/************** idct ***************/
+/****************************************************************/
+
+#define ONE ((PREC)IFIX(1.))
+#define S2 ((PREC)IFIX(0.382683432))
+#define C2 ((PREC)IFIX(0.923879532))
+#define C4 ((PREC)IFIX(0.707106781))
+
+#define S22 ((PREC)IFIX(2 * 0.382683432))
+#define C22 ((PREC)IFIX(2 * 0.923879532))
+#define IC4 ((PREC)IFIX(1 / 0.707106781))
+
+#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */
+#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */
+#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */
+
+#define XPP(a,b) (t = a + b, b = a - b, a = t)
+#define XMP(a,b) (t = a - b, b = a + b, a = t)
+#define XPM(a,b) (t = a + b, b = b - a, a = t)
+
+#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \
+ a = IMULT(a, c - s) + t, \
+ b = IMULT(b, c + s) - t)
+
+#define IDCT \
+( \
+ XPP(t0, t1), \
+ XMP(t2, t3), \
+ t2 = IMULT(t2, IC4) - t3, \
+ XPP(t0, t3), \
+ XPP(t1, t2), \
+ XMP(t4, t7), \
+ XPP(t5, t6), \
+ XMP(t5, t7), \
+ t5 = IMULT(t5, IC4), \
+ ROT(t4, t6, S22, C22), \
+ t6 -= t7, \
+ t5 -= t6, \
+ t4 -= t5, \
+ XPP(t0, t7), \
+ XPP(t1, t6), \
+ XPP(t2, t5), \
+ XPP(t3, t4) \
+)
+
+static unsigned char zig2[64] = {
+ 0, 2, 3, 9, 10, 20, 21, 35,
+ 14, 16, 25, 31, 39, 46, 50, 57,
+ 5, 7, 12, 18, 23, 33, 37, 48,
+ 27, 29, 41, 44, 52, 55, 59, 62,
+ 15, 26, 30, 40, 45, 51, 56, 58,
+ 1, 4, 8, 11, 19, 22, 34, 36,
+ 28, 42, 43, 53, 54, 60, 61, 63,
+ 6, 13, 17, 24, 32, 38, 47, 49
+};
+
+static void idct(int *in, int *out, PREC * quant, PREC off, int max)
+{
+ PREC t0, t1, t2, t3, t4, t5, t6, t7, t;
+ PREC tmp[64], *tmpp;
+ int i, j;
+ unsigned char *zig2p;
+
+ t0 = off;
+ if (max == 1) {
+ t0 += in[0] * quant[0];
+ for (i = 0; i < 64; i++)
+ out[i] = ITOINT(t0);
+ return;
+ }
+ zig2p = zig2;
+ tmpp = tmp;
+ for (i = 0; i < 8; i++) {
+ j = *zig2p++;
+ t0 += in[j] * quant[j];
+ j = *zig2p++;
+ t5 = in[j] * quant[j];
+ j = *zig2p++;
+ t2 = in[j] * quant[j];
+ j = *zig2p++;
+ t7 = in[j] * quant[j];
+ j = *zig2p++;
+ t1 = in[j] * quant[j];
+ j = *zig2p++;
+ t4 = in[j] * quant[j];
+ j = *zig2p++;
+ t3 = in[j] * quant[j];
+ j = *zig2p++;
+ t6 = in[j] * quant[j];
+ IDCT;
+ tmpp[0 * 8] = t0;
+ tmpp[1 * 8] = t1;
+ tmpp[2 * 8] = t2;
+ tmpp[3 * 8] = t3;
+ tmpp[4 * 8] = t4;
+ tmpp[5 * 8] = t5;
+ tmpp[6 * 8] = t6;
+ tmpp[7 * 8] = t7;
+ tmpp++;
+ t0 = 0;
+ }
+ for (i = 0; i < 8; i++) {
+ t0 = tmp[8 * i + 0];
+ t1 = tmp[8 * i + 1];
+ t2 = tmp[8 * i + 2];
+ t3 = tmp[8 * i + 3];
+ t4 = tmp[8 * i + 4];
+ t5 = tmp[8 * i + 5];
+ t6 = tmp[8 * i + 6];
+ t7 = tmp[8 * i + 7];
+ IDCT;
+ out[8 * i + 0] = ITOINT(t0);
+ out[8 * i + 1] = ITOINT(t1);
+ out[8 * i + 2] = ITOINT(t2);
+ out[8 * i + 3] = ITOINT(t3);
+ out[8 * i + 4] = ITOINT(t4);
+ out[8 * i + 5] = ITOINT(t5);
+ out[8 * i + 6] = ITOINT(t6);
+ out[8 * i + 7] = ITOINT(t7);
+ }
+}
+
+static unsigned char zig[64] = {
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+static PREC aaidct[8] = {
+ IFIX(0.3535533906), IFIX(0.4903926402),
+ IFIX(0.4619397663), IFIX(0.4157348062),
+ IFIX(0.3535533906), IFIX(0.2777851165),
+ IFIX(0.1913417162), IFIX(0.0975451610)
+};
+
+
+static void idctqtab(unsigned char *qin, PREC * qout)
+{
+ int i, j;
+
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 8; j++)
+ qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] *
+ IMULT(aaidct[i], aaidct[j]);
+}
+
+static void scaleidctqtab(PREC * q, PREC sc)
+{
+ int i;
+
+ for (i = 0; i < 64; i++)
+ q[i] = IMULT(q[i], sc);
+}
+
+/****************************************************************/
+/************** color decoder ***************/
+/****************************************************************/
+
+#define ROUND
+
+/*
+ * YCbCr Color transformation:
+ *
+ * y:0..255 Cb:-128..127 Cr:-128..127
+ *
+ * R = Y + 1.40200 * Cr
+ * G = Y - 0.34414 * Cb - 0.71414 * Cr
+ * B = Y + 1.77200 * Cb
+ *
+ * =>
+ * Cr *= 1.40200;
+ * Cb *= 1.77200;
+ * Cg = 0.19421 * Cb + .50937 * Cr;
+ * R = Y + Cr;
+ * G = Y - Cg;
+ * B = Y + Cb;
+ *
+ * =>
+ * Cg = (50 * Cb + 130 * Cr + 128) >> 8;
+ */
+
+static void initcol(PREC q[][64])
+{
+ scaleidctqtab(q[1], IFIX(1.77200));
+ scaleidctqtab(q[2], IFIX(1.40200));
+}
+
+/* This is optimized for the stupid sun SUNWspro compiler. */
+#define STORECLAMP(a,x) \
+( \
+ (a) = (x), \
+ (unsigned int)(x) >= 256 ? \
+ ((a) = (x) < 0 ? 0 : 255) \
+ : \
+ 0 \
+)
+
+#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x))
+
+#ifdef ROUND
+
+#define CBCRCG(yin, xin) \
+( \
+ cb = outc[0 +yin*8+xin], \
+ cr = outc[64+yin*8+xin], \
+ cg = (50 * cb + 130 * cr + 128) >> 8 \
+)
+
+#else
+
+#define CBCRCG(yin, xin) \
+( \
+ cb = outc[0 +yin*8+xin], \
+ cr = outc[64+yin*8+xin], \
+ cg = (3 * cb + 8 * cr) >> 4 \
+)
+
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define PIC(yin, xin, p, xout) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ STORECLAMP(p[(xout) * 3 + 2], y + cr), \
+ STORECLAMP(p[(xout) * 3 + 1], y - cg), \
+ STORECLAMP(p[(xout) * 3 + 0], y + cb) \
+)
+#else
+#define PIC(yin, xin, p, xout) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ STORECLAMP(p[(xout) * 3 + 0], y + cr), \
+ STORECLAMP(p[(xout) * 3 + 1], y - cg), \
+ STORECLAMP(p[(xout) * 3 + 2], y + cb) \
+)
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define PIC_16(yin, xin, p, xout, add) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
+ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
+ p[(xout) * 2 + 0] = y & 0xff, \
+ p[(xout) * 2 + 1] = y >> 8 \
+)
+#else
+#ifdef CONFIG_PPC
+#define PIC_16(yin, xin, p, xout, add) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \
+ ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
+ p[(xout) * 2 + 0] = y >> 8, \
+ p[(xout) * 2 + 1] = y & 0xff \
+)
+#else
+#define PIC_16(yin, xin, p, xout, add) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
+ ((CLAMP(y - cg + add ) & 0xfc) << 3) | \
+ ((CLAMP(y + cb + add*2+1) ) >> 3), \
+ p[(xout) * 2 + 0] = y >> 8, \
+ p[(xout) * 2 + 1] = y & 0xff \
+)
+#endif
+#endif
+
+#define PIC_32(yin, xin, p, xout) \
+( \
+ y = outy[(yin) * 8 + xin], \
+ STORECLAMP(p[(xout) * 4 + 0], y + cr), \
+ STORECLAMP(p[(xout) * 4 + 1], y - cg), \
+ STORECLAMP(p[(xout) * 4 + 2], y + cb), \
+ p[(xout) * 4 + 3] = 0 \
+)
+
+#define PIC221111(xin) \
+( \
+ CBCRCG(0, xin), \
+ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
+ PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
+ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
+ PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
+)
+
+#define PIC221111_16(xin) \
+( \
+ CBCRCG(0, xin), \
+ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \
+ PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \
+ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \
+ PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \
+)
+
+#define PIC221111_32(xin) \
+( \
+ CBCRCG(0, xin), \
+ PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
+ PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
+ PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
+ PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
+)
+
+static void col221111(int *out, unsigned char *pic, int width)
+{
+ int i, j, k;
+ unsigned char *pic0, *pic1;
+ int *outy, *outc;
+ int cr, cg, cb, y;
+
+ pic0 = pic;
+ pic1 = pic + width;
+ outy = out;
+ outc = out + 64 * 4;
+ for (i = 2; i > 0; i--) {
+ for (j = 4; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ PIC221111(k);
+ }
+ outc += 8;
+ outy += 16;
+ pic0 += 2 * width;
+ pic1 += 2 * width;
+ }
+ outy += 64 * 2 - 16 * 4;
+ }
+}
+
+static void col221111_16(int *out, unsigned char *pic, int width)
+{
+ int i, j, k;
+ unsigned char *pic0, *pic1;
+ int *outy, *outc;
+ int cr, cg, cb, y;
+
+ pic0 = pic;
+ pic1 = pic + width;
+ outy = out;
+ outc = out + 64 * 4;
+ for (i = 2; i > 0; i--) {
+ for (j = 4; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ PIC221111_16(k);
+ }
+ outc += 8;
+ outy += 16;
+ pic0 += 2 * width;
+ pic1 += 2 * width;
+ }
+ outy += 64 * 2 - 16 * 4;
+ }
+}
+
+static void col221111_32(int *out, unsigned char *pic, int width)
+{
+ int i, j, k;
+ unsigned char *pic0, *pic1;
+ int *outy, *outc;
+ int cr, cg, cb, y;
+
+ pic0 = pic;
+ pic1 = pic + width;
+ outy = out;
+ outc = out + 64 * 4;
+ for (i = 2; i > 0; i--) {
+ for (j = 4; j > 0; j--) {
+ for (k = 0; k < 8; k++) {
+ PIC221111_32(k);
+ }
+ outc += 8;
+ outy += 16;
+ pic0 += 2 * width;
+ pic1 += 2 * width;
+ }
+ outy += 64 * 2 - 16 * 4;
+ }
+}
--- /dev/null
+#ifndef __JPEG_H
+#define __JPEG_H
+
+struct jpeg_decdata;
+struct jpeg_decdata *jpeg_alloc(void);
+int jpeg_decode(struct jpeg_decdata *jpeg, unsigned char *buf);
+void jpeg_get_size(struct jpeg_decdata *jpeg, int *width, int *height);
+int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width
+ , int height, int depth, int bytes_per_line_dest);
+
+#endif
--- /dev/null
+// 16bit code to handle keyboard requests.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "util.h" // debug_enter
+#include "config.h" // CONFIG_*
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // ps2_kbd_command
+#include "usb-hid.h" // usb_kbd_command
+
+// Bit definitions for BDA kbd_flag[012]
+#define KF0_RSHIFT (1<<0)
+#define KF0_LSHIFT (1<<1)
+#define KF0_CTRLACTIVE (1<<2)
+#define KF0_ALTACTIVE (1<<3)
+#define KF0_SCROLLACTIVE (1<<4)
+#define KF0_NUMACTIVE (1<<5)
+#define KF0_CAPSACTIVE (1<<6)
+
+#define KF1_LCTRL (1<<0)
+#define KF1_LALT (1<<1)
+#define KF1_PAUSEACTIVE (1<<3)
+#define KF1_SCROLL (1<<4)
+#define KF1_NUM (1<<5)
+#define KF1_CAPS (1<<6)
+
+#define KF2_LAST_E1 (1<<0)
+#define KF2_LAST_E0 (1<<1)
+#define KF2_RCTRL (1<<2)
+#define KF2_RALT (1<<3)
+#define KF2_101KBD (1<<4)
+
+void
+kbd_setup(void)
+{
+ dprintf(3, "init keyboard\n");
+ u16 x = offsetof(struct bios_data_area_s, kbd_buf);
+ SET_BDA(kbd_flag2, KF2_101KBD);
+ SET_BDA(kbd_buf_head, x);
+ SET_BDA(kbd_buf_tail, x);
+ SET_BDA(kbd_buf_start_offset, x);
+
+ SET_BDA(kbd_buf_end_offset
+ , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf));
+}
+
+static u8
+enqueue_key(u8 scan_code, u8 ascii_code)
+{
+ u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+ u16 buffer_end = GET_BDA(kbd_buf_end_offset);
+
+ u16 buffer_head = GET_BDA(kbd_buf_head);
+ u16 buffer_tail = GET_BDA(kbd_buf_tail);
+
+ u16 temp_tail = buffer_tail;
+ buffer_tail += 2;
+ if (buffer_tail >= buffer_end)
+ buffer_tail = buffer_start;
+
+ if (buffer_tail == buffer_head)
+ return 0;
+
+ SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+0), ascii_code);
+ SET_FARVAR(SEG_BDA, *(u8*)(temp_tail+1), scan_code);
+ SET_BDA(kbd_buf_tail, buffer_tail);
+ return 1;
+}
+
+static void
+dequeue_key(struct bregs *regs, int incr, int extended)
+{
+ yield();
+ u16 buffer_head;
+ u16 buffer_tail;
+ for (;;) {
+ buffer_head = GET_BDA(kbd_buf_head);
+ buffer_tail = GET_BDA(kbd_buf_tail);
+
+ if (buffer_head != buffer_tail)
+ break;
+ if (!incr) {
+ regs->flags |= F_ZF;
+ return;
+ }
+ wait_irq();
+ }
+
+ u8 ascii_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+0));
+ u8 scan_code = GET_FARVAR(SEG_BDA, *(u8*)(buffer_head+1));
+ if ((ascii_code == 0xF0 && scan_code != 0)
+ || (ascii_code == 0xE0 && !extended))
+ ascii_code = 0;
+ regs->ax = (scan_code << 8) | ascii_code;
+
+ if (!incr) {
+ regs->flags &= ~F_ZF;
+ return;
+ }
+ u16 buffer_start = GET_BDA(kbd_buf_start_offset);
+ u16 buffer_end = GET_BDA(kbd_buf_end_offset);
+
+ buffer_head += 2;
+ if (buffer_head >= buffer_end)
+ buffer_head = buffer_start;
+ SET_BDA(kbd_buf_head, buffer_head);
+}
+
+static inline int
+kbd_command(int command, u8 *param)
+{
+ if (usb_kbd_active())
+ return usb_kbd_command(command, param);
+ return ps2_kbd_command(command, param);
+}
+
+// read keyboard input
+static void
+handle_1600(struct bregs *regs)
+{
+ dequeue_key(regs, 1, 0);
+}
+
+// check keyboard status
+static void
+handle_1601(struct bregs *regs)
+{
+ dequeue_key(regs, 0, 0);
+}
+
+// get shift flag status
+static void
+handle_1602(struct bregs *regs)
+{
+ yield();
+ regs->al = GET_BDA(kbd_flag0);
+}
+
+// store key-stroke into buffer
+static void
+handle_1605(struct bregs *regs)
+{
+ regs->al = !enqueue_key(regs->ch, regs->cl);
+}
+
+// GET KEYBOARD FUNCTIONALITY
+static void
+handle_1609(struct bregs *regs)
+{
+ // bit Bochs Description
+ // 7 0 reserved
+ // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support)
+ // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support)
+ // 4 1 INT 16/AH=0Ah supported
+ // 3 0 INT 16/AX=0306h supported
+ // 2 0 INT 16/AX=0305h supported
+ // 1 0 INT 16/AX=0304h supported
+ // 0 0 INT 16/AX=0300h supported
+ //
+ regs->al = 0x30;
+}
+
+// GET KEYBOARD ID
+static void
+handle_160a(struct bregs *regs)
+{
+ u8 param[2];
+ int ret = kbd_command(ATKBD_CMD_GETID, param);
+ if (ret) {
+ regs->bx = 0;
+ return;
+ }
+ regs->bx = (param[1] << 8) | param[0];
+}
+
+// read MF-II keyboard input
+static void
+handle_1610(struct bregs *regs)
+{
+ dequeue_key(regs, 1, 1);
+}
+
+// check MF-II keyboard status
+static void
+handle_1611(struct bregs *regs)
+{
+ dequeue_key(regs, 0, 1);
+}
+
+// get extended keyboard status
+static void
+handle_1612(struct bregs *regs)
+{
+ yield();
+ regs->al = GET_BDA(kbd_flag0);
+ regs->ah = ((GET_BDA(kbd_flag1) & ~(KF2_RCTRL|KF2_RALT))
+ | (GET_BDA(kbd_flag2) & (KF2_RCTRL|KF2_RALT)));
+ //BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX);
+}
+
+static void
+handle_166f(struct bregs *regs)
+{
+ if (regs->al == 0x08)
+ // unsupported, aka normal keyboard
+ regs->ah = 2;
+}
+
+// keyboard capability check called by DOS 5.0+ keyb
+static void
+handle_1692(struct bregs *regs)
+{
+ // function int16 ah=0x10-0x12 supported
+ regs->ah = 0x80;
+}
+
+// 122 keys capability check called by DOS 5.0+ keyb
+static void
+handle_16a2(struct bregs *regs)
+{
+ // don't change AH : function int16 ah=0x20-0x22 NOT supported
+}
+
+static void
+handle_16XX(struct bregs *regs)
+{
+ warn_unimplemented(regs);
+}
+
+static void
+set_leds(void)
+{
+ u8 shift_flags = (GET_BDA(kbd_flag0) >> 4) & 0x07;
+ u8 kbd_led = GET_BDA(kbd_led);
+ u8 led_flags = kbd_led & 0x07;
+ if (shift_flags == led_flags)
+ return;
+
+ int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags);
+ if (ret)
+ // Error
+ return;
+ kbd_led = (kbd_led & ~0x07) | shift_flags;
+ SET_BDA(kbd_led, kbd_led);
+}
+
+// INT 16h Keyboard Service Entry Point
+void VISIBLE16
+handle_16(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_16);
+ if (! CONFIG_KEYBOARD)
+ return;
+
+ // XXX - set_leds should be called from irq handler
+ set_leds();
+
+ switch (regs->ah) {
+ case 0x00: handle_1600(regs); break;
+ case 0x01: handle_1601(regs); break;
+ case 0x02: handle_1602(regs); break;
+ case 0x05: handle_1605(regs); break;
+ case 0x09: handle_1609(regs); break;
+ case 0x0a: handle_160a(regs); break;
+ case 0x10: handle_1610(regs); break;
+ case 0x11: handle_1611(regs); break;
+ case 0x12: handle_1612(regs); break;
+ case 0x92: handle_1692(regs); break;
+ case 0xa2: handle_16a2(regs); break;
+ case 0x6f: handle_166f(regs); break;
+ default: handle_16XX(regs); break;
+ }
+}
+
+#define none 0
+#define MNUM KF0_NUMACTIVE
+#define MCAP KF0_CAPSACTIVE
+
+static struct scaninfo {
+ u16 normal;
+ u16 shift;
+ u16 control;
+ u16 alt;
+ u8 lock_flags;
+} scan_to_scanascii[] VAR16 = {
+ { none, none, none, none, none },
+ { 0x011b, 0x011b, 0x011b, 0x0100, none }, /* escape */
+ { 0x0231, 0x0221, none, 0x7800, none }, /* 1! */
+ { 0x0332, 0x0340, 0x0300, 0x7900, none }, /* 2@ */
+ { 0x0433, 0x0423, none, 0x7a00, none }, /* 3# */
+ { 0x0534, 0x0524, none, 0x7b00, none }, /* 4$ */
+ { 0x0635, 0x0625, none, 0x7c00, none }, /* 5% */
+ { 0x0736, 0x075e, 0x071e, 0x7d00, none }, /* 6^ */
+ { 0x0837, 0x0826, none, 0x7e00, none }, /* 7& */
+ { 0x0938, 0x092a, none, 0x7f00, none }, /* 8* */
+ { 0x0a39, 0x0a28, none, 0x8000, none }, /* 9( */
+ { 0x0b30, 0x0b29, none, 0x8100, none }, /* 0) */
+ { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200, none }, /* -_ */
+ { 0x0d3d, 0x0d2b, none, 0x8300, none }, /* =+ */
+ { 0x0e08, 0x0e08, 0x0e7f, none, none }, /* backspace */
+ { 0x0f09, 0x0f00, none, none, none }, /* tab */
+ { 0x1071, 0x1051, 0x1011, 0x1000, MCAP }, /* Q */
+ { 0x1177, 0x1157, 0x1117, 0x1100, MCAP }, /* W */
+ { 0x1265, 0x1245, 0x1205, 0x1200, MCAP }, /* E */
+ { 0x1372, 0x1352, 0x1312, 0x1300, MCAP }, /* R */
+ { 0x1474, 0x1454, 0x1414, 0x1400, MCAP }, /* T */
+ { 0x1579, 0x1559, 0x1519, 0x1500, MCAP }, /* Y */
+ { 0x1675, 0x1655, 0x1615, 0x1600, MCAP }, /* U */
+ { 0x1769, 0x1749, 0x1709, 0x1700, MCAP }, /* I */
+ { 0x186f, 0x184f, 0x180f, 0x1800, MCAP }, /* O */
+ { 0x1970, 0x1950, 0x1910, 0x1900, MCAP }, /* P */
+ { 0x1a5b, 0x1a7b, 0x1a1b, none, none }, /* [{ */
+ { 0x1b5d, 0x1b7d, 0x1b1d, none, none }, /* ]} */
+ { 0x1c0d, 0x1c0d, 0x1c0a, none, none }, /* Enter */
+ { none, none, none, none, none }, /* L Ctrl */
+ { 0x1e61, 0x1e41, 0x1e01, 0x1e00, MCAP }, /* A */
+ { 0x1f73, 0x1f53, 0x1f13, 0x1f00, MCAP }, /* S */
+ { 0x2064, 0x2044, 0x2004, 0x2000, MCAP }, /* D */
+ { 0x2166, 0x2146, 0x2106, 0x2100, MCAP }, /* F */
+ { 0x2267, 0x2247, 0x2207, 0x2200, MCAP }, /* G */
+ { 0x2368, 0x2348, 0x2308, 0x2300, MCAP }, /* H */
+ { 0x246a, 0x244a, 0x240a, 0x2400, MCAP }, /* J */
+ { 0x256b, 0x254b, 0x250b, 0x2500, MCAP }, /* K */
+ { 0x266c, 0x264c, 0x260c, 0x2600, MCAP }, /* L */
+ { 0x273b, 0x273a, none, none, none }, /* ;: */
+ { 0x2827, 0x2822, none, none, none }, /* '" */
+ { 0x2960, 0x297e, none, none, none }, /* `~ */
+ { none, none, none, none, none }, /* L shift */
+ { 0x2b5c, 0x2b7c, 0x2b1c, none, none }, /* |\ */
+ { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00, MCAP }, /* Z */
+ { 0x2d78, 0x2d58, 0x2d18, 0x2d00, MCAP }, /* X */
+ { 0x2e63, 0x2e43, 0x2e03, 0x2e00, MCAP }, /* C */
+ { 0x2f76, 0x2f56, 0x2f16, 0x2f00, MCAP }, /* V */
+ { 0x3062, 0x3042, 0x3002, 0x3000, MCAP }, /* B */
+ { 0x316e, 0x314e, 0x310e, 0x3100, MCAP }, /* N */
+ { 0x326d, 0x324d, 0x320d, 0x3200, MCAP }, /* M */
+ { 0x332c, 0x333c, none, none, none }, /* ,< */
+ { 0x342e, 0x343e, none, none, none }, /* .> */
+ { 0x352f, 0x353f, none, none, none }, /* /? */
+ { none, none, none, none, none }, /* R Shift */
+ { 0x372a, 0x372a, none, none, none }, /* * */
+ { none, none, none, none, none }, /* L Alt */
+ { 0x3920, 0x3920, 0x3920, 0x3920, none }, /* space */
+ { none, none, none, none, none }, /* caps lock */
+ { 0x3b00, 0x5400, 0x5e00, 0x6800, none }, /* F1 */
+ { 0x3c00, 0x5500, 0x5f00, 0x6900, none }, /* F2 */
+ { 0x3d00, 0x5600, 0x6000, 0x6a00, none }, /* F3 */
+ { 0x3e00, 0x5700, 0x6100, 0x6b00, none }, /* F4 */
+ { 0x3f00, 0x5800, 0x6200, 0x6c00, none }, /* F5 */
+ { 0x4000, 0x5900, 0x6300, 0x6d00, none }, /* F6 */
+ { 0x4100, 0x5a00, 0x6400, 0x6e00, none }, /* F7 */
+ { 0x4200, 0x5b00, 0x6500, 0x6f00, none }, /* F8 */
+ { 0x4300, 0x5c00, 0x6600, 0x7000, none }, /* F9 */
+ { 0x4400, 0x5d00, 0x6700, 0x7100, none }, /* F10 */
+ { none, none, none, none, none }, /* Num Lock */
+ { none, none, none, none, none }, /* Scroll Lock */
+ { 0x4700, 0x4737, 0x7700, none, MNUM }, /* 7 Home */
+ { 0x4800, 0x4838, none, none, MNUM }, /* 8 UP */
+ { 0x4900, 0x4939, 0x8400, none, MNUM }, /* 9 PgUp */
+ { 0x4a2d, 0x4a2d, none, none, none }, /* - */
+ { 0x4b00, 0x4b34, 0x7300, none, MNUM }, /* 4 Left */
+ { 0x4c00, 0x4c35, none, none, MNUM }, /* 5 */
+ { 0x4d00, 0x4d36, 0x7400, none, MNUM }, /* 6 Right */
+ { 0x4e2b, 0x4e2b, none, none, none }, /* + */
+ { 0x4f00, 0x4f31, 0x7500, none, MNUM }, /* 1 End */
+ { 0x5000, 0x5032, none, none, MNUM }, /* 2 Down */
+ { 0x5100, 0x5133, 0x7600, none, MNUM }, /* 3 PgDn */
+ { 0x5200, 0x5230, none, none, MNUM }, /* 0 Ins */
+ { 0x5300, 0x532e, none, none, MNUM }, /* Del */
+ { none, none, none, none, none },
+ { none, none, none, none, none },
+ { 0x565c, 0x567c, none, none, none }, /* \| */
+ { 0x8500, 0x8700, 0x8900, 0x8b00, none }, /* F11 */
+ { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
+};
+
+// Handle a scancode read from the ps2 port. Note that "noinline" is
+// used to make sure the call to call16_simpint in process_key doesn't
+// have the overhead of this function's stack.
+static void noinline
+__process_key(u8 scancode)
+{
+ u8 flags0 = GET_BDA(kbd_flag0);
+ u8 flags1 = GET_BDA(kbd_flag1);
+ u8 flags2 = GET_BDA(kbd_flag2);
+
+ if (flags2 & KF2_LAST_E1) {
+ // Part of "pause" key (sequence is e1 1d 45 e1 9d c5)
+ if ((scancode & ~0x80) == 0x1d)
+ // Second key of sequence
+ return;
+ // Third key of sequence - clear flag.
+ flags2 &= ~KF2_LAST_E1;
+ SET_BDA(kbd_flag2, flags2);
+
+ if (scancode == 0xc5) {
+ // Final key in sequence.
+
+ // XXX - do actual pause.
+ }
+ return;
+ }
+
+ // XXX - PrtScr should cause int 0x05
+ // XXX - Ctrl+Break should cause int 0x1B
+ // XXX - SysReq should cause int 0x15/0x85
+
+ switch (scancode) {
+ case 0x00:
+ dprintf(1, "KBD: int09 handler: AL=0\n");
+ return;
+
+ case 0x3a: /* Caps Lock press */
+ flags0 ^= KF0_CAPSACTIVE;
+ flags1 |= KF1_CAPS;
+ break;
+ case 0xba: /* Caps Lock release */
+ flags1 &= ~KF1_CAPS;
+ break;
+
+ case 0x2a: /* L Shift press */
+ flags0 |= KF0_LSHIFT;
+ break;
+ case 0xaa: /* L Shift release */
+ flags0 &= ~KF0_LSHIFT;
+ break;
+
+ case 0x36: /* R Shift press */
+ flags0 |= KF0_RSHIFT;
+ break;
+ case 0xb6: /* R Shift release */
+ flags0 &= ~KF0_RSHIFT;
+ break;
+
+ case 0x1d: /* Ctrl press */
+ flags0 |= KF0_CTRLACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 |= KF2_RCTRL;
+ else
+ flags1 |= KF1_LCTRL;
+ break;
+ case 0x9d: /* Ctrl release */
+ flags0 &= ~KF0_CTRLACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 &= ~KF2_RCTRL;
+ else
+ flags1 &= ~KF1_LCTRL;
+ break;
+
+ case 0x38: /* Alt press */
+ flags0 |= KF0_ALTACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 |= KF2_RALT;
+ else
+ flags1 |= KF1_LALT;
+ break;
+ case 0xb8: /* Alt release */
+ flags0 &= ~KF0_ALTACTIVE;
+ if (flags2 & KF2_LAST_E0)
+ flags2 &= ~KF2_RALT;
+ else
+ flags1 &= ~KF1_LALT;
+ break;
+
+ case 0x45: /* Num Lock press */
+ flags1 |= KF1_NUM;
+ flags0 ^= KF0_NUMACTIVE;
+ break;
+ case 0xc5: /* Num Lock release */
+ flags1 &= ~KF1_NUM;
+ break;
+
+ case 0x46: /* Scroll Lock press */
+ flags1 |= KF1_SCROLL;
+ flags0 ^= KF0_SCROLLACTIVE;
+ break;
+ case 0xc6: /* Scroll Lock release */
+ flags1 &= ~KF1_SCROLL;
+ break;
+
+ case 0xe0:
+ // Extended key
+ flags2 |= KF2_LAST_E0;
+ SET_BDA(kbd_flag2, flags2);
+ return;
+ case 0xe1:
+ // Start of pause key sequence
+ flags2 |= KF2_LAST_E1;
+ break;
+
+ default:
+ if (scancode & 0x80)
+ // toss key releases
+ break;
+ if (scancode == 0x53
+ && ((flags0 & (KF0_CTRLACTIVE|KF0_ALTACTIVE))
+ == (KF0_CTRLACTIVE|KF0_ALTACTIVE))) {
+ // Ctrl+alt+del - reset machine.
+ SET_BDA(soft_reset_flag, 0x1234);
+ reset_vector();
+ }
+ if (scancode >= ARRAY_SIZE(scan_to_scanascii)) {
+ dprintf(1, "KBD: int09h_handler(): unknown scancode read: 0x%02x!\n"
+ , scancode);
+ return;
+ }
+ u8 asciicode;
+ struct scaninfo *info = &scan_to_scanascii[scancode];
+ if (flags0 & KF0_ALTACTIVE) {
+ asciicode = GET_GLOBAL(info->alt);
+ scancode = GET_GLOBAL(info->alt) >> 8;
+ } else if (flags0 & KF0_CTRLACTIVE) {
+ asciicode = GET_GLOBAL(info->control);
+ scancode = GET_GLOBAL(info->control) >> 8;
+ } else if (flags2 & KF2_LAST_E0
+ && scancode >= 0x47 && scancode <= 0x53) {
+ /* extended keys handling */
+ asciicode = 0xe0;
+ scancode = GET_GLOBAL(info->normal) >> 8;
+ } else if (flags0 & (KF0_RSHIFT|KF0_LSHIFT)) {
+ /* check if lock state should be ignored because a SHIFT
+ * key is pressed */
+
+ if (flags0 & GET_GLOBAL(info->lock_flags)) {
+ asciicode = GET_GLOBAL(info->normal);
+ scancode = GET_GLOBAL(info->normal) >> 8;
+ } else {
+ asciicode = GET_GLOBAL(info->shift);
+ scancode = GET_GLOBAL(info->shift) >> 8;
+ }
+ } else {
+ /* check if lock is on */
+ if (flags0 & GET_GLOBAL(info->lock_flags)) {
+ asciicode = GET_GLOBAL(info->shift);
+ scancode = GET_GLOBAL(info->shift) >> 8;
+ } else {
+ asciicode = GET_GLOBAL(info->normal);
+ scancode = GET_GLOBAL(info->normal) >> 8;
+ }
+ }
+ if (scancode==0 && asciicode==0)
+ dprintf(1, "KBD: scancode & asciicode are zero?\n");
+ enqueue_key(scancode, asciicode);
+ break;
+ }
+ flags2 &= ~KF2_LAST_E0;
+
+ SET_BDA(kbd_flag0, flags0);
+ SET_BDA(kbd_flag1, flags1);
+ SET_BDA(kbd_flag2, flags2);
+}
+
+void
+process_key(u8 key)
+{
+ if (!CONFIG_KEYBOARD)
+ return;
+
+ if (CONFIG_KBD_CALL_INT15_4F) {
+ // allow for keyboard intercept
+ u32 eax = (0x4f << 8) | key;
+ u32 flags;
+ call16_simpint(0x15, &eax, &flags);
+ if (!(flags & F_CF))
+ return;
+ key = eax;
+ }
+ __process_key(key);
+}
--- /dev/null
+/*
+ LzmaDecode.c
+ LZMA Decoder (optimized for Speed version)
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this Code, expressly permits you to
+ statically or dynamically link your Code (or bind by name) to the
+ interfaces of this file without subjecting your linked Code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "lzmadecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+ { UpdateBit0(p); mi <<= 1; A0; } else \
+ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
+
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+ { int i = numLevels; res = 1; \
+ do { CProb *cp = probs + res; RC_GET_BIT(cp, res) } while(--i != 0); \
+ res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+ CProb *p = vs->Probs;
+ SizeT nowPos = 0;
+ Byte previousByte = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+
+
+ int state = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ int len = 0;
+ const Byte *Buffer;
+ const Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+
+ *inSizeProcessed = 0;
+ *outSizeProcessed = 0;
+
+ {
+ UInt32 i;
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ }
+
+ RC_INIT(inStream, inSize);
+
+
+ while(nowPos < outSize)
+ {
+ CProb *prob;
+ UInt32 bound;
+ int posState = (int)(
+ (nowPos
+ )
+ & posStateMask);
+
+ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ int symbol = 1;
+ UpdateBit0(prob)
+ prob = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ int matchByte;
+ matchByte = outStream[nowPos - rep0];
+ do
+ {
+ int bit;
+ CProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & 0x100);
+ probLit = prob + 0x100 + bit + symbol;
+ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+ }
+ while (symbol < 0x100);
+ }
+ while (symbol < 0x100)
+ {
+ CProb *probLit = prob + symbol;
+ RC_GET_BIT(probLit, symbol)
+ }
+ previousByte = (Byte)symbol;
+
+ outStream[nowPos++] = previousByte;
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRep + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < kNumLitStates ? 0 : 3;
+ prob = p + LenCoder;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG0 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+
+ if (nowPos == 0)
+ return LZMA_RESULT_DATA_ERROR;
+
+ state = state < kNumLitStates ? 9 : 11;
+ previousByte = outStream[nowPos - rep0];
+ outStream[nowPos++] = previousByte;
+
+ continue;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ UpdateBit1(prob);
+ prob = p + IsRepG1 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG2 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = p + RepLenCoder;
+ }
+ {
+ int numBits, offset;
+ CProb *probLen = prob + LenChoice;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ numBits = kLenNumLowBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenChoice2;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ numBits = kLenNumMidBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ numBits = kLenNumHighBits;
+ }
+ }
+ RangeDecoderBitTreeDecode(probLen, numBits, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ int posSlot;
+ state += kNumLitStates;
+ prob = p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = (2 | ((UInt32)posSlot & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 <<= numDirectBits;
+ prob = p + SpecPos + rep0 - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ RC_NORMALIZE
+ Range >>= 1;
+ rep0 <<= 1;
+ if (Code >= Range)
+ {
+ Code -= Range;
+ rep0 |= 1;
+ }
+ }
+ while (--numDirectBits != 0);
+ prob = p + Align;
+ rep0 <<= kNumAlignBits;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ int i = 1;
+ int mi = 1;
+ do
+ {
+ CProb *prob3 = prob + mi;
+ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+ i <<= 1;
+ }
+ while(--numDirectBits != 0);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ if (rep0 > nowPos)
+ return LZMA_RESULT_DATA_ERROR;
+
+
+ do
+ {
+ previousByte = outStream[nowPos - rep0];
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+ RC_NORMALIZE;
+
+
+ *inSizeProcessed = (SizeT)(Buffer - inStream);
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
--- /dev/null
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+typedef unsigned char Byte;
+typedef unsigned short UInt16;
+typedef unsigned int UInt32;
+typedef UInt32 SizeT;
+
+#define CProb UInt16
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+ int lc;
+ int lp;
+ int pb;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+ CLzmaProperties Properties;
+ CProb *Probs;
+
+
+} CLzmaDecoderState;
+
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
--- /dev/null
+// Support for building memory maps suitable for int 15 e820 calls.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "memmap.h" // struct e820entry
+#include "util.h" // dprintf.h
+#include "biosvar.h" // SET_EBDA
+
+
+/****************************************************************
+ * e820 memory map
+ ****************************************************************/
+
+// Remove an entry from the e820_list.
+static void
+remove_e820(int i)
+{
+ e820_count--;
+ memmove(&e820_list[i], &e820_list[i+1]
+ , sizeof(e820_list[0]) * (e820_count - i));
+}
+
+// Insert an entry in the e820_list at the given position.
+static void
+insert_e820(int i, u64 start, u64 size, u32 type)
+{
+ if (e820_count >= CONFIG_MAX_E820) {
+ warn_noalloc();
+ return;
+ }
+
+ memmove(&e820_list[i+1], &e820_list[i]
+ , sizeof(e820_list[0]) * (e820_count - i));
+ e820_count++;
+ struct e820entry *e = &e820_list[i];
+ e->start = start;
+ e->size = size;
+ e->type = type;
+}
+
+static const char *
+e820_type_name(u32 type)
+{
+ switch (type) {
+ case E820_RAM: return "RAM";
+ case E820_RESERVED: return "RESERVED";
+ case E820_ACPI: return "ACPI";
+ case E820_NVS: return "NVS";
+ case E820_UNUSABLE: return "UNUSABLE";
+ case E820_HOLE: return "HOLE";
+ default: return "UNKNOWN";
+ }
+}
+
+// Show the current e820_list.
+static void
+dump_map(void)
+{
+ dprintf(1, "e820 map has %d items:\n", e820_count);
+ int i;
+ for (i=0; i<e820_count; i++) {
+ struct e820entry *e = &e820_list[i];
+ u64 e_end = e->start + e->size;
+ dprintf(1, " %d: %08x%08x - %08x%08x = %d %s\n", i
+ , (u32)(e->start >> 32), (u32)e->start
+ , (u32)(e_end >> 32), (u32)e_end
+ , e->type, e820_type_name(e->type));
+ }
+}
+
+// Add a new entry to the list. This scans for overlaps and keeps the
+// list sorted.
+void
+add_e820(u64 start, u64 size, u32 type)
+{
+ dprintf(8, "Add to e820 map: %08x %08x %d\n", (u32)start, (u32)size, type);
+
+ if (! size)
+ // Huh? Nothing to do.
+ return;
+
+ // Find position of new item (splitting existing item if needed).
+ u64 end = start + size;
+ int i;
+ for (i=0; i<e820_count; i++) {
+ struct e820entry *e = &e820_list[i];
+ u64 e_end = e->start + e->size;
+ if (start > e_end)
+ continue;
+ // Found position - check if an existing item needs to be split.
+ if (start > e->start) {
+ if (type == e->type) {
+ // Same type - merge them.
+ size += start - e->start;
+ start = e->start;
+ } else {
+ // Split existing item.
+ e->size = start - e->start;
+ i++;
+ if (e_end > end)
+ insert_e820(i, end, e_end - end, e->type);
+ }
+ }
+ break;
+ }
+ // Remove/adjust existing items that are overlapping.
+ while (i<e820_count) {
+ struct e820entry *e = &e820_list[i];
+ if (end < e->start)
+ // No overlap - done.
+ break;
+ u64 e_end = e->start + e->size;
+ if (end >= e_end) {
+ // Existing item completely overlapped - remove it.
+ remove_e820(i);
+ continue;
+ }
+ // Not completely overlapped - adjust its start.
+ e->start = end;
+ e->size = e_end - end;
+ if (type == e->type) {
+ // Same type - merge them.
+ size += e->size;
+ remove_e820(i);
+ }
+ break;
+ }
+ // Insert new item.
+ if (type != E820_HOLE)
+ insert_e820(i, start, size, type);
+ //dump_map();
+}
+
+// Report on final memory locations.
+void
+memmap_finalize(void)
+{
+ dump_map();
+}
--- /dev/null
+#ifndef __E820MAP_H
+#define __E820MAP_H
+
+#include "types.h" // u64
+
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+#define E820_HOLE ((u32)-1) // Useful for removing entries
+
+struct e820entry {
+ u64 start;
+ u64 size;
+ u32 type;
+};
+
+void add_e820(u64 start, u64 size, u32 type);
+void memmap_finalize(void);
+
+// A typical OS page size
+#define PAGE_SIZE 4096
+
+// e820 map storage (defined in system.c)
+extern struct e820entry e820_list[];
+extern int e820_count;
+
+// Space for exported bios tables (defined in misc.c)
+extern char BiosTableSpace[];
+
+#endif // e820map.h
--- /dev/null
+// Code for misc 16bit handlers and variables.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_BDA
+#include "util.h" // debug_enter
+#include "pic.h" // enable_hwirq
+
+// Amount of continuous ram under 4Gig
+u32 RamSize VAR16VISIBLE;
+// Amount of continuous ram >4Gig
+u64 RamSizeOver4G;
+// Space for bios tables built an run-time.
+char BiosTableSpace[CONFIG_MAX_BIOSTABLE] __aligned(MALLOC_MIN_ALIGN) VAR16VISIBLE;
+
+
+/****************************************************************
+ * Misc 16bit ISRs
+ ****************************************************************/
+
+// INT 12h Memory Size Service Entry Point
+void VISIBLE16
+handle_12(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_12);
+ regs->ax = GET_BDA(mem_size_kb);
+}
+
+// INT 11h Equipment List Service Entry Point
+void VISIBLE16
+handle_11(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_11);
+ regs->ax = GET_BDA(equipment_list_flags);
+}
+
+// INT 05h Print Screen Service Entry Point
+void VISIBLE16
+handle_05(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_05);
+}
+
+// INT 10h Video Support Service Entry Point
+void VISIBLE16
+handle_10(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_10);
+ // dont do anything, since the VGA BIOS handles int10h requests
+}
+
+// NMI handler
+void VISIBLE16
+handle_02(void)
+{
+ debug_isr(DEBUG_ISR_02);
+}
+
+void
+mathcp_setup(void)
+{
+ dprintf(3, "math cp init\n");
+ // 80x87 coprocessor installed
+ SETBITS_BDA(equipment_list_flags, 0x02);
+ enable_hwirq(13, FUNC16(entry_75));
+}
+
+// INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
+void VISIBLE16
+handle_75(void)
+{
+ debug_isr(DEBUG_ISR_75);
+
+ // clear irq13
+ outb(0, PORT_MATH_CLEAR);
+ // clear interrupt
+ eoi_pic2();
+ // legacy nmi call
+ u32 eax=0, flags;
+ call16_simpint(0x02, &eax, &flags);
+}
+
+
+/****************************************************************
+ * BIOS_CONFIG_TABLE
+ ****************************************************************/
+
+// DMA channel 3 used by hard disk BIOS
+#define CBT_F1_DMA3USED (1<<7)
+// 2nd interrupt controller (8259) installed
+#define CBT_F1_2NDPIC (1<<6)
+// Real-Time Clock installed
+#define CBT_F1_RTC (1<<5)
+// INT 15/AH=4Fh called upon INT 09h
+#define CBT_F1_INT154F (1<<4)
+// wait for external event (INT 15/AH=41h) supported
+#define CBT_F1_WAITEXT (1<<3)
+// extended BIOS area allocated (usually at top of RAM)
+#define CBT_F1_EBDA (1<<2)
+// bus is Micro Channel instead of ISA
+#define CBT_F1_MCA (1<<1)
+// system has dual bus (Micro Channel + ISA)
+#define CBT_F1_MCAISA (1<<0)
+
+// INT 16/AH=09h (keyboard functionality) supported
+#define CBT_F2_INT1609 (1<<6)
+
+struct bios_config_table_s BIOS_CONFIG_TABLE VAR16FIXED(0xe6f5) = {
+ .size = sizeof(BIOS_CONFIG_TABLE) - 2,
+ .model = CONFIG_MODEL_ID,
+ .submodel = CONFIG_SUBMODEL_ID,
+ .biosrev = CONFIG_BIOS_REVISION,
+ .feature1 = (
+ CBT_F1_2NDPIC | CBT_F1_RTC | CBT_F1_EBDA
+ | (CONFIG_KBD_CALL_INT15_4F ? CBT_F1_INT154F : 0)),
+ .feature2 = CBT_F2_INT1609,
+ .feature3 = 0,
+ .feature4 = 0,
+ .feature5 = 0,
+};
+
+
+/****************************************************************
+ * GDT and IDT tables
+ ****************************************************************/
+
+// Real mode IDT descriptor
+struct descloc_s rmode_IDT_info VAR16VISIBLE = {
+ .length = sizeof(struct rmode_IVT) - 1,
+ .addr = (u32)MAKE_FLATPTR(SEG_IVT, 0),
+};
+
+// Dummy IDT that forces a machine shutdown if an irq happens in
+// protected mode.
+u8 dummy_IDT VAR16VISIBLE;
+
+// Protected mode IDT descriptor
+struct descloc_s pmode_IDT_info VAR16VISIBLE = {
+ .length = sizeof(dummy_IDT) - 1,
+ .addr = (u32)MAKE_FLATPTR(SEG_BIOS, &dummy_IDT),
+};
+
+// GDT
+u64 rombios32_gdt[] VAR16VISIBLE __aligned(8) = {
+ // First entry can't be used.
+ 0x0000000000000000LL,
+ // 32 bit flat code segment (SEG32_MODE32_CS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_B,
+ // 32 bit flat data segment (SEG32_MODE32_DS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_DATA | GDT_B,
+ // 16 bit code segment base=0xf0000 limit=0xffff (SEG32_MODE16_CS)
+ GDT_LIMIT(BUILD_BIOS_SIZE-1) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR),
+ // 16 bit data segment base=0x0 limit=0xffff (SEG32_MODE16_DS)
+ GDT_LIMIT(0x0ffff) | GDT_DATA,
+ // 16 bit code segment base=0xf0000 limit=0xffffffff (SEG32_MODE16BIG_CS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_CODE | GDT_BASE(BUILD_BIOS_ADDR),
+ // 16 bit data segment base=0 limit=0xffffffff (SEG32_MODE16BIG_DS)
+ GDT_GRANLIMIT(0xffffffff) | GDT_DATA,
+};
+
+// GDT descriptor
+struct descloc_s rombios32_gdt_48 VAR16VISIBLE = {
+ .length = sizeof(rombios32_gdt) - 1,
+ .addr = (u32)MAKE_FLATPTR(SEG_BIOS, rombios32_gdt),
+};
+
+
+/****************************************************************
+ * Misc fixed vars
+ ****************************************************************/
+
+char BiosCopyright[] VAR16FIXED(0xff00) =
+ "(c) 2002 MandrakeSoft S.A. Written by Kevin Lawton & the Bochs team.";
+
+// BIOS build date
+char BiosDate[] VAR16FIXED(0xfff5) = "06/23/99";
+
+u8 BiosModelId VAR16FIXED(0xfffe) = CONFIG_MODEL_ID;
+
+u8 BiosChecksum VAR16FIXED(0xffff);
+
+// XXX - Initial Interrupt Vector Offsets Loaded by POST
+u8 InitVectors[13] VAR16FIXED(0xfef3);
+
+// XXX - INT 1D - SYSTEM DATA - VIDEO PARAMETER TABLES
+u8 VideoParams[88] VAR16FIXED(0xf0a4);
--- /dev/null
+// 16bit code to handle mouse events.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_EBDA
+#include "util.h" // debug_isr
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+#include "ps2port.h" // ps2_mouse_command
+#include "usb-hid.h" // usb_mouse_command
+
+void
+mouse_setup(void)
+{
+ if (! CONFIG_MOUSE)
+ return;
+ dprintf(3, "init mouse\n");
+ // pointing device installed
+ SETBITS_BDA(equipment_list_flags, 0x04);
+}
+
+static inline int
+mouse_command(int command, u8 *param)
+{
+ if (usb_mouse_active())
+ return usb_mouse_command(command, param);
+ return ps2_mouse_command(command, param);
+}
+
+#define RET_SUCCESS 0x00
+#define RET_EINVFUNCTION 0x01
+#define RET_EINVINPUT 0x02
+#define RET_EINTERFACE 0x03
+#define RET_ENEEDRESEND 0x04
+#define RET_ENOHANDLER 0x05
+
+// Disable Mouse
+static void
+mouse_15c20000(struct bregs *regs)
+{
+ int ret = mouse_command(PSMOUSE_CMD_DISABLE, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Enable Mouse
+static void
+mouse_15c20001(struct bregs *regs)
+{
+ u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
+ if ((mouse_flags_2 & 0x80) == 0) {
+ set_code_invalid(regs, RET_ENOHANDLER);
+ return;
+ }
+
+ int ret = mouse_command(PSMOUSE_CMD_ENABLE, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+static void
+mouse_15c200XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+// Disable/Enable Mouse
+static void
+mouse_15c200(struct bregs *regs)
+{
+ switch (regs->bh) {
+ case 0x00: mouse_15c20000(regs); break;
+ case 0x01: mouse_15c20001(regs); break;
+ default: mouse_15c200XX(regs); break;
+ }
+}
+
+// Reset Mouse
+static void
+mouse_15c201(struct bregs *regs)
+{
+ u8 param[2];
+ int ret = mouse_command(PSMOUSE_CMD_RESET_BAT, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bl = param[0];
+ regs->bh = param[1];
+ set_code_success(regs);
+}
+
+// Set Sample Rate
+static void
+mouse_15c202(struct bregs *regs)
+{
+ static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
+ if (regs->bh >= ARRAY_SIZE(sample_rates)) {
+ set_code_invalid(regs, RET_EINVINPUT);
+ return;
+ }
+ u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]);
+ int ret = mouse_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Set Resolution
+static void
+mouse_15c203(struct bregs *regs)
+{
+ // BH:
+ // 0 = 25 dpi, 1 count per millimeter
+ // 1 = 50 dpi, 2 counts per millimeter
+ // 2 = 100 dpi, 4 counts per millimeter
+ // 3 = 200 dpi, 8 counts per millimeter
+ if (regs->bh >= 4) {
+ set_code_invalid(regs, RET_EINVINPUT);
+ return;
+ }
+ u8 param = regs->bh;
+ int ret = mouse_command(PSMOUSE_CMD_SETRES, ¶m);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Get Device ID
+static void
+mouse_15c204(struct bregs *regs)
+{
+ u8 param[2];
+ int ret = mouse_command(PSMOUSE_CMD_GETID, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bh = param[0];
+ set_code_success(regs);
+}
+
+// Initialize Mouse
+static void
+mouse_15c205(struct bregs *regs)
+{
+ if (regs->bh != 3) {
+ set_code_invalid(regs, RET_EINTERFACE);
+ return;
+ }
+ u16 ebda_seg = get_ebda_seg();
+ SET_EBDA2(ebda_seg, mouse_flag1, 0x00);
+ SET_EBDA2(ebda_seg, mouse_flag2, regs->bh);
+
+ // Reset Mouse
+ mouse_15c201(regs);
+}
+
+// Return Status
+static void
+mouse_15c20600(struct bregs *regs)
+{
+ u8 param[3];
+ int ret = mouse_command(PSMOUSE_CMD_GETINFO, param);
+ if (ret) {
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ return;
+ }
+ regs->bl = param[0];
+ regs->cl = param[1];
+ regs->dl = param[2];
+ set_code_success(regs);
+}
+
+// Set Scaling Factor to 1:1
+static void
+mouse_15c20601(struct bregs *regs)
+{
+ int ret = mouse_command(PSMOUSE_CMD_SETSCALE11, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+// Set Scaling Factor to 2:1
+static void
+mouse_15c20602(struct bregs *regs)
+{
+ int ret = mouse_command(PSMOUSE_CMD_SETSCALE21, NULL);
+ if (ret)
+ set_code_invalid(regs, RET_ENEEDRESEND);
+ else
+ set_code_success(regs);
+}
+
+static void
+mouse_15c206XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+// Return Status & Set Scaling Factor...
+static void
+mouse_15c206(struct bregs *regs)
+{
+ switch (regs->bh) {
+ case 0x00: mouse_15c20600(regs); break;
+ case 0x01: mouse_15c20601(regs); break;
+ case 0x02: mouse_15c20602(regs); break;
+ default: mouse_15c206XX(regs); break;
+ }
+}
+
+// Set Mouse Handler Address
+static void
+mouse_15c207(struct bregs *regs)
+{
+ struct segoff_s farptr = SEGOFF(regs->es, regs->bx);
+ u16 ebda_seg = get_ebda_seg();
+ u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
+ if (! farptr.segoff) {
+ /* remove handler */
+ if ((mouse_flags_2 & 0x80) != 0) {
+ mouse_flags_2 &= ~0x80;
+ mouse_command(PSMOUSE_CMD_DISABLE, NULL);
+ }
+ } else {
+ /* install handler */
+ mouse_flags_2 |= 0x80;
+ }
+ SET_EBDA2(ebda_seg, mouse_flag2, mouse_flags_2);
+ SET_EBDA2(ebda_seg, far_call_pointer, farptr);
+ set_code_success(regs);
+}
+
+static void
+mouse_15c2XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EINVFUNCTION);
+}
+
+void
+handle_15c2(struct bregs *regs)
+{
+ //debug_stub(regs);
+
+ if (! CONFIG_MOUSE) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x00: mouse_15c200(regs); break;
+ case 0x01: mouse_15c201(regs); break;
+ case 0x02: mouse_15c202(regs); break;
+ case 0x03: mouse_15c203(regs); break;
+ case 0x04: mouse_15c204(regs); break;
+ case 0x05: mouse_15c205(regs); break;
+ case 0x06: mouse_15c206(regs); break;
+ case 0x07: mouse_15c207(regs); break;
+ default: mouse_15c2XX(regs); break;
+ }
+}
+
+void noinline
+process_mouse(u8 data)
+{
+ if (!CONFIG_MOUSE)
+ return;
+
+ u16 ebda_seg = get_ebda_seg();
+ u8 mouse_flags_1 = GET_EBDA2(ebda_seg, mouse_flag1);
+ u8 mouse_flags_2 = GET_EBDA2(ebda_seg, mouse_flag2);
+
+ if (! (mouse_flags_2 & 0x80))
+ // far call handler not installed
+ return;
+
+ u8 package_count = mouse_flags_2 & 0x07;
+ u8 index = mouse_flags_1 & 0x07;
+ SET_EBDA2(ebda_seg, mouse_data[index], data);
+
+ if ((index+1) < package_count) {
+ mouse_flags_1++;
+ SET_EBDA2(ebda_seg, mouse_flag1, mouse_flags_1);
+ return;
+ }
+
+ u16 status = GET_EBDA2(ebda_seg, mouse_data[0]);
+ u16 X = GET_EBDA2(ebda_seg, mouse_data[1]);
+ u16 Y = GET_EBDA2(ebda_seg, mouse_data[2]);
+ SET_EBDA2(ebda_seg, mouse_flag1, 0);
+
+ struct segoff_s func = GET_EBDA2(ebda_seg, far_call_pointer);
+ dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n"
+ , status, X, Y, func.seg, func.offset);
+
+ asm volatile(
+ "pushl %%ebp\n"
+ "sti\n"
+
+ "pushl %0\n"
+ "pushw %w1\n" // status
+ "pushw %w2\n" // X
+ "pushw %w3\n" // Y
+ "pushw $0\n" // Z
+ "lcallw *8(%%esp)\n"
+ "addl $12, %%esp\n"
+
+ "cli\n"
+ "cld\n"
+ "popl %%ebp"
+ : "+a"(func.segoff), "+c"(status), "+d"(X), "+b"(Y)
+ :
+ : "edi", "esi", "cc", "memory");
+}
--- /dev/null
+// MPTable generation (on emulators)
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "mptable.h" // MPTABLE_SIGNATURE
+#include "paravirt.h" // qemu_cfg_irq0_override
+#include "pci.h"
+#include "pci_regs.h"
+
+void
+mptable_init(void)
+{
+ if (! CONFIG_MPTABLE)
+ return;
+
+ dprintf(3, "init MPTable\n");
+
+ // Config structure in temp area.
+ struct mptable_config_s *config = malloc_tmp(32*1024);
+ if (!config) {
+ warn_noalloc();
+ return;
+ }
+ memset(config, 0, sizeof(*config));
+ config->signature = MPCONFIG_SIGNATURE;
+ config->spec = 4;
+ memcpy(config->oemid, CONFIG_CPUNAME8, sizeof(config->oemid));
+ memcpy(config->productid, "0.1 ", sizeof(config->productid));
+ config->lapic = BUILD_APIC_ADDR;
+
+ // Detect cpu info
+ u32 cpuid_signature, ebx, ecx, cpuid_features;
+ cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+ if (! cpuid_signature) {
+ // Use default values.
+ cpuid_signature = 0x600;
+ cpuid_features = 0x201;
+ }
+ int pkgcpus = 1;
+ if (cpuid_features & (1 << 28)) {
+ /* Only populate the MPS tables with the first logical CPU in
+ each package */
+ pkgcpus = (ebx >> 16) & 0xff;
+ pkgcpus = 1 << (__fls(pkgcpus - 1) + 1); /* round up to power of 2 */
+ }
+ u8 apic_version = readl((u8*)BUILD_APIC_ADDR + 0x30) & 0xff;
+
+ // CPU definitions.
+ struct mpt_cpu *cpus = (void*)&config[1], *cpu = cpus;
+ int i;
+ for (i = 0; i < MaxCountCPUs; i+=pkgcpus) {
+ memset(cpu, 0, sizeof(*cpu));
+ cpu->type = MPT_TYPE_CPU;
+ cpu->apicid = i;
+ cpu->apicver = apic_version;
+ /* cpu flags: enabled, bootstrap cpu */
+ cpu->cpuflag = ((i<CountCPUs) ? 0x01 : 0x00) | ((i==0) ? 0x02 : 0x00);
+ cpu->cpusignature = cpuid_signature;
+ cpu->featureflag = cpuid_features;
+ cpu++;
+ }
+ int entrycount = cpu - cpus;
+
+ // PCI buses
+ struct mpt_bus *buses = (void*)cpu, *bus = buses;
+ int lastbus = -1;
+ struct pci_device *pci;
+ foreachpci(pci) {
+ int curbus = pci_bdf_to_bus(pci->bdf);
+ if (curbus == lastbus)
+ continue;
+ lastbus = curbus;
+ memset(bus, 0, sizeof(*bus));
+ bus->type = MPT_TYPE_BUS;
+ bus->busid = curbus;
+ memcpy(bus->bustype, "PCI ", sizeof(bus->bustype));
+ bus++;
+ }
+
+ /* isa bus */
+ int isabusid;
+ memset(bus, 0, sizeof(*bus));
+ bus->type = MPT_TYPE_BUS;
+ isabusid = bus->busid = lastbus + 1;
+ memcpy(bus->bustype, "ISA ", sizeof(bus->bustype));
+ bus++;
+ entrycount += bus - buses;
+
+ /* ioapic */
+ u8 ioapic_id = CountCPUs;
+ struct mpt_ioapic *ioapic = (void*)bus;
+ memset(ioapic, 0, sizeof(*ioapic));
+ ioapic->type = MPT_TYPE_IOAPIC;
+ ioapic->apicid = ioapic_id;
+ ioapic->apicver = 0x11;
+ ioapic->flags = 1; // enable
+ ioapic->apicaddr = BUILD_IOAPIC_ADDR;
+ entrycount++;
+
+ /* irqs */
+ struct mpt_intsrc *intsrcs = (void*)&ioapic[1], *intsrc = intsrcs;
+ int dev = -1;
+ unsigned short mask = 0, pinmask = 0;
+
+ foreachpci(pci) {
+ u16 bdf = pci->bdf;
+ int pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+ int irq = pci_config_readb(bdf, PCI_INTERRUPT_LINE);
+ if (pin == 0)
+ continue;
+ if (dev != pci_bdf_to_busdev(bdf)) {
+ dev = pci_bdf_to_busdev(bdf);
+ pinmask = 0;
+ }
+ if (pinmask & (1 << pin)) /* pin was seen already */
+ continue;
+ pinmask |= (1 << pin);
+ mask |= (1 << irq);
+ memset(intsrc, 0, sizeof(*intsrc));
+ intsrc->type = MPT_TYPE_INTSRC;
+ intsrc->irqtype = 0; /* INT */
+ intsrc->irqflag = 1; /* active high */
+ intsrc->srcbus = pci_bdf_to_bus(bdf); /* PCI bus */
+ intsrc->srcbusirq = (pci_bdf_to_dev(bdf) << 2) | (pin - 1);
+ intsrc->dstapic = ioapic_id;
+ intsrc->dstirq = irq;
+ intsrc++;
+ }
+
+ for (i = 0; i < 16; i++) {
+ memset(intsrc, 0, sizeof(*intsrc));
+ if (mask & (1 << i))
+ continue;
+ intsrc->type = MPT_TYPE_INTSRC;
+ intsrc->irqtype = 0; /* INT */
+ intsrc->irqflag = 0; /* conform to bus spec */
+ intsrc->srcbus = isabusid; /* ISA bus */
+ intsrc->srcbusirq = i;
+ intsrc->dstapic = ioapic_id;
+ intsrc->dstirq = i;
+ if (qemu_cfg_irq0_override()) {
+ /* Destination 2 is covered by irq0->inti2 override (i ==
+ 0). Source IRQ 2 is unused */
+ if (i == 0)
+ intsrc->dstirq = 2;
+ else if (i == 2)
+ intsrc--;
+ }
+ intsrc++;
+ }
+
+ /* Local interrupt assignment */
+ intsrc->type = MPT_TYPE_LOCAL_INT;
+ intsrc->irqtype = 3; /* ExtINT */
+ intsrc->irqflag = 0; /* PO, EL default */
+ intsrc->srcbus = isabusid; /* ISA */
+ intsrc->srcbusirq = 0;
+ intsrc->dstapic = 0; /* BSP == APIC #0 */
+ intsrc->dstirq = 0; /* LINTIN0 */
+ intsrc++;
+
+ intsrc->type = MPT_TYPE_LOCAL_INT;
+ intsrc->irqtype = 1; /* NMI */
+ intsrc->irqflag = 0; /* PO, EL default */
+ intsrc->srcbus = isabusid; /* ISA */
+ intsrc->srcbusirq = 0;
+ intsrc->dstapic = 0; /* BSP == APIC #0 */
+ intsrc->dstirq = 1; /* LINTIN1 */
+ intsrc++;
+ entrycount += intsrc - intsrcs;
+
+ // Finalize config structure.
+ int length = (void*)intsrc - (void*)config;
+ config->entrycount = entrycount;
+ config->length = length;
+ config->checksum -= checksum(config, length);
+
+ // Allocate final memory locations. (In theory the config
+ // structure can go in high memory, but Linux kernels before
+ // v2.6.30 crash with that.)
+ struct mptable_config_s *finalconfig = malloc_fseg(length);
+ struct mptable_floating_s *floating = malloc_fseg(sizeof(*floating));
+ if (!finalconfig || !floating) {
+ warn_noalloc();
+ free(config);
+ free(finalconfig);
+ free(floating);
+ return;
+ }
+ memcpy(finalconfig, config, length);
+ free(config);
+
+ /* floating pointer structure */
+ memset(floating, 0, sizeof(*floating));
+ floating->signature = MPTABLE_SIGNATURE;
+ floating->physaddr = (u32)finalconfig;
+ floating->length = 1;
+ floating->spec_rev = 4;
+ floating->checksum -= checksum(floating, sizeof(*floating));
+
+ dprintf(1, "MP table addr=%p MPC table addr=%p size=%d\n",
+ floating, finalconfig, length);
+}
--- /dev/null
+#ifndef __MPTABLE_H
+#define __MPTABLE_H
+
+#include "types.h" // u32
+
+#define MPTABLE_SIGNATURE 0x5f504d5f // "_MP_"
+
+struct mptable_floating_s {
+ u32 signature;
+ u32 physaddr;
+ u8 length;
+ u8 spec_rev;
+ u8 checksum;
+ u8 feature1;
+ u8 feature2;
+ u8 reserved[3];
+};
+
+#define MPCONFIG_SIGNATURE 0x504d4350 // "PCMP"
+
+struct mptable_config_s {
+ u32 signature;
+ u16 length;
+ u8 spec;
+ u8 checksum;
+ char oemid[8];
+ char productid[12];
+ u32 oemptr;
+ u16 oemsize;
+ u16 entrycount;
+ u32 lapic;
+ u16 exttable_length;
+ u8 exttable_checksum;
+ u8 reserved;
+} PACKED;
+
+#define MPT_TYPE_CPU 0
+#define MPT_TYPE_BUS 1
+#define MPT_TYPE_IOAPIC 2
+#define MPT_TYPE_INTSRC 3
+#define MPT_TYPE_LOCAL_INT 4
+
+struct mpt_cpu {
+ u8 type;
+ u8 apicid;
+ u8 apicver;
+ u8 cpuflag;
+ u32 cpusignature;
+ u32 featureflag;
+ u32 reserved[2];
+} PACKED;
+
+struct mpt_bus {
+ u8 type;
+ u8 busid;
+ char bustype[6];
+} PACKED;
+
+struct mpt_ioapic {
+ u8 type;
+ u8 apicid;
+ u8 apicver;
+ u8 flags;
+ u32 apicaddr;
+} PACKED;
+
+struct mpt_intsrc {
+ u8 type;
+ u8 irqtype;
+ u16 irqflag;
+ u8 srcbus;
+ u8 srcbusirq;
+ u8 dstapic;
+ u8 dstirq;
+} PACKED;
+
+// mptable.c
+void mptable_init(void);
+
+#endif // mptable.h
--- /dev/null
+// Initialize MTRRs - mostly useful on KVM.
+//
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "xen.h" // usingXen
+
+#define MSR_MTRRcap 0x000000fe
+#define MSR_MTRRfix64K_00000 0x00000250
+#define MSR_MTRRfix16K_80000 0x00000258
+#define MSR_MTRRfix16K_A0000 0x00000259
+#define MSR_MTRRfix4K_C0000 0x00000268
+#define MSR_MTRRfix4K_C8000 0x00000269
+#define MSR_MTRRfix4K_D0000 0x0000026a
+#define MSR_MTRRfix4K_D8000 0x0000026b
+#define MSR_MTRRfix4K_E0000 0x0000026c
+#define MSR_MTRRfix4K_E8000 0x0000026d
+#define MSR_MTRRfix4K_F0000 0x0000026e
+#define MSR_MTRRfix4K_F8000 0x0000026f
+#define MSR_MTRRdefType 0x000002ff
+
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg))
+#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+
+#define MTRR_MEMTYPE_UC 0
+#define MTRR_MEMTYPE_WC 1
+#define MTRR_MEMTYPE_WT 4
+#define MTRR_MEMTYPE_WP 5
+#define MTRR_MEMTYPE_WB 6
+
+void mtrr_setup(void)
+{
+ if (!CONFIG_MTRR_INIT || CONFIG_COREBOOT || usingXen())
+ return;
+
+ u32 eax, ebx, ecx, edx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (!(cpuid_features & CPUID_MTRR))
+ return;
+ if (!(cpuid_features & CPUID_MSR))
+ return;
+
+ dprintf(3, "init mtrr\n");
+
+ u32 mtrr_cap = rdmsr(MSR_MTRRcap);
+ int vcnt = mtrr_cap & 0xff;
+ int fix = mtrr_cap & 0x100;
+ if (!vcnt || !fix)
+ return;
+
+ // Disable MTRRs
+ wrmsr_smp(MSR_MTRRdefType, 0);
+
+ // Set fixed MTRRs
+ union u64b {
+ u8 valb[8];
+ u64 val;
+ } u;
+ u.val = 0;
+ int i;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 65536 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
+ wrmsr_smp(MSR_MTRRfix64K_00000, u.val);
+ u.val = 0;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0x80000 + 16384 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WB;
+ wrmsr_smp(MSR_MTRRfix16K_80000, u.val);
+ wrmsr_smp(MSR_MTRRfix16K_A0000, 0); // 0xA0000-0xC0000 is uncached
+ int j;
+ for (j = 0; j < 8; j++) {
+ u.val = 0;
+ for (i = 0; i < 8; i++)
+ if (RamSize >= 0xC0000 + j * 0x8000 + 4096 * (i + 1))
+ u.valb[i] = MTRR_MEMTYPE_WP;
+ wrmsr_smp(MSR_MTRRfix4K_C0000 + j, u.val);
+ }
+
+ // Set variable MTRRs
+ int phys_bits = 36;
+ cpuid(0x80000000u, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0x80000008) {
+ /* Get physical bits from leaf 0x80000008 (if available) */
+ cpuid(0x80000008u, &eax, &ebx, &ecx, &edx);
+ phys_bits = eax & 0xff;
+ }
+ u64 phys_mask = ((1ull << phys_bits) - 1);
+ for (i=0; i<vcnt; i++) {
+ wrmsr_smp(MTRRphysBase_MSR(i), 0);
+ wrmsr_smp(MTRRphysMask_MSR(i), 0);
+ }
+ /* Mark 3.5-4GB as UC, anything not specified defaults to WB */
+ wrmsr_smp(MTRRphysBase_MSR(0), BUILD_MAX_HIGHMEM | MTRR_MEMTYPE_UC);
+ wrmsr_smp(MTRRphysMask_MSR(0)
+ , (-((1ull<<32)-BUILD_MAX_HIGHMEM) & phys_mask) | 0x800);
+
+ // Enable fixed and variable MTRRs; set default type.
+ wrmsr_smp(MSR_MTRRdefType, 0xc00 | MTRR_MEMTYPE_WB);
+}
--- /dev/null
+// Option rom scanning code.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // struct bregs
+#include "farptr.h" // FLATPTR_TO_SEG
+#include "config.h" // CONFIG_*
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "pci_regs.h" // PCI_ROM_ADDRESS
+#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
+#include "boot.h" // IPL
+#include "paravirt.h" // qemu_cfg_*
+
+
+/****************************************************************
+ * Definitions
+ ****************************************************************/
+
+struct rom_header {
+ u16 signature;
+ u8 size;
+ u8 initVector[4];
+ u8 reserved[17];
+ u16 pcioffset;
+ u16 pnpoffset;
+} PACKED;
+
+struct pci_data {
+ u32 signature;
+ u16 vendor;
+ u16 device;
+ u16 vitaldata;
+ u16 dlen;
+ u8 drevision;
+ u8 class_lo;
+ u16 class_hi;
+ u16 ilen;
+ u16 irevision;
+ u8 type;
+ u8 indicator;
+ u16 reserved;
+} PACKED;
+
+struct pnp_data {
+ u32 signature;
+ u8 revision;
+ u8 len;
+ u16 nextoffset;
+ u8 reserved_08;
+ u8 checksum;
+ u32 devid;
+ u16 manufacturer;
+ u16 productname;
+ u8 type_lo;
+ u16 type_hi;
+ u8 dev_flags;
+ u16 bcv;
+ u16 dv;
+ u16 bev;
+ u16 reserved_1c;
+ u16 staticresource;
+} PACKED;
+
+#define OPTION_ROM_SIGNATURE 0xaa55
+#define OPTION_ROM_ALIGN 2048
+#define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0])
+#define PCI_ROM_SIGNATURE 0x52494350 // PCIR
+#define PCIROM_CODETYPE_X86 0
+
+// The end of the last deployed rom.
+u32 RomEnd = BUILD_ROM_START;
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Execute a given option rom.
+static void
+__callrom(struct rom_header *rom, u16 offset, u16 bdf)
+{
+ u16 seg = FLATPTR_TO_SEG(rom);
+ dprintf(1, "Running option rom at %04x:%04x\n", seg, offset);
+
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.ax = bdf;
+ br.bx = 0xffff;
+ br.dx = 0xffff;
+ br.es = SEG_BIOS;
+ br.di = get_pnp_offset();
+ br.code = SEGOFF(seg, offset);
+ start_preempt();
+ call16big(&br);
+ finish_preempt();
+
+ debug_serial_setup();
+}
+
+// Execute a given option rom at the standard entry vector.
+static void
+callrom(struct rom_header *rom, u16 bdf)
+{
+ __callrom(rom, OPTION_ROM_INITVECTOR, bdf);
+}
+
+// Execute a BCV option rom registered via add_bcv().
+void
+call_bcv(u16 seg, u16 ip)
+{
+ __callrom(MAKE_FLATPTR(seg, 0), ip, 0);
+}
+
+static int EnforceChecksum;
+
+// Verify that an option rom looks valid
+static int
+is_valid_rom(struct rom_header *rom)
+{
+ dprintf(6, "Checking rom %p (sig %x size %d)\n"
+ , rom, rom->signature, rom->size);
+ if (rom->signature != OPTION_ROM_SIGNATURE)
+ return 0;
+ if (! rom->size)
+ return 0;
+ u32 len = rom->size * 512;
+ u8 sum = checksum(rom, len);
+ if (sum != 0) {
+ dprintf(1, "Found option rom with bad checksum: loc=%p len=%d sum=%x\n"
+ , rom, len, sum);
+ if (EnforceChecksum)
+ return 0;
+ }
+ return 1;
+}
+
+// Check if a valid option rom has a pnp struct; return it if so.
+static struct pnp_data *
+get_pnp_rom(struct rom_header *rom)
+{
+ struct pnp_data *pnp = (void*)((u8*)rom + rom->pnpoffset);
+ if (pnp->signature != PNP_SIGNATURE)
+ return NULL;
+ return pnp;
+}
+
+// Check for multiple pnp option rom headers.
+static struct pnp_data *
+get_pnp_next(struct rom_header *rom, struct pnp_data *pnp)
+{
+ if (! pnp->nextoffset)
+ return NULL;
+ pnp = (void*)((u8*)rom + pnp->nextoffset);
+ if (pnp->signature != PNP_SIGNATURE)
+ return NULL;
+ return pnp;
+}
+
+// Check if a valid option rom has a pci struct; return it if so.
+static struct pci_data *
+get_pci_rom(struct rom_header *rom)
+{
+ struct pci_data *pd = (void*)((u32)rom + rom->pcioffset);
+ if (pd->signature != PCI_ROM_SIGNATURE)
+ return NULL;
+ return pd;
+}
+
+// Return start of code in 0xc0000-0xf0000 space.
+static inline u32 _max_rom(void) {
+ extern u8 code32flat_start[], code32init_end[];
+ return CONFIG_RELOCATE_INIT ? (u32)code32init_end : (u32)code32flat_start;
+}
+// Return the memory position up to which roms may be located.
+static inline u32 max_rom(void) {
+ u32 end = _max_rom();
+ return end > BUILD_BIOS_ADDR ? BUILD_BIOS_ADDR : end;
+}
+
+// Copy a rom to its permanent location below 1MiB
+static struct rom_header *
+copy_rom(struct rom_header *rom)
+{
+ u32 romsize = rom->size * 512;
+ if (RomEnd + romsize > max_rom()) {
+ // Option rom doesn't fit.
+ warn_noalloc();
+ return NULL;
+ }
+ dprintf(4, "Copying option rom (size %d) from %p to %x\n"
+ , romsize, rom, RomEnd);
+ iomemcpy((void*)RomEnd, rom, romsize);
+ return (void*)RomEnd;
+}
+
+// Run rom init code and note rom size.
+static int
+init_optionrom(struct rom_header *rom, u16 bdf, int isvga)
+{
+ if (! is_valid_rom(rom))
+ return -1;
+
+ if (isvga || get_pnp_rom(rom))
+ // Only init vga and PnP roms here.
+ callrom(rom, bdf);
+
+ RomEnd = (u32)rom + ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
+
+ return 0;
+}
+
+#define RS_PCIROM (1LL<<33)
+
+static void
+setRomSource(u64 *sources, struct rom_header *rom, u64 source)
+{
+ if (sources)
+ sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN] = source;
+}
+
+static int
+getRomPriority(u64 *sources, struct rom_header *rom, int instance)
+{
+ u64 source = sources[((u32)rom - BUILD_ROM_START) / OPTION_ROM_ALIGN];
+ if (!source)
+ return -1;
+ if (source & RS_PCIROM)
+ return bootprio_find_pci_rom((void*)(u32)source, instance);
+ return bootprio_find_named_rom(romfile_name(source), instance);
+}
+
+
+/****************************************************************
+ * Roms in CBFS
+ ****************************************************************/
+
+// Check if an option rom is at a hardcoded location or in CBFS.
+static struct rom_header *
+lookup_hardcode(struct pci_device *pci)
+{
+ char fname[17];
+ snprintf(fname, sizeof(fname), "pci%04x,%04x.rom"
+ , pci->vendor, pci->device);
+ int ret = romfile_copy(romfile_find(fname), (void*)RomEnd
+ , max_rom() - RomEnd);
+ if (ret <= 0)
+ return NULL;
+ return (void*)RomEnd;
+}
+
+// Run all roms in a given CBFS directory.
+static void
+run_file_roms(const char *prefix, int isvga, u64 *sources)
+{
+ u32 file = 0;
+ for (;;) {
+ file = romfile_findprefix(prefix, file);
+ if (!file)
+ break;
+ struct rom_header *rom = (void*)RomEnd;
+ int ret = romfile_copy(file, rom, max_rom() - RomEnd);
+ if (ret > 0) {
+ setRomSource(sources, rom, file);
+ init_optionrom(rom, 0, isvga);
+ }
+ }
+}
+
+
+/****************************************************************
+ * PCI roms
+ ****************************************************************/
+
+// Verify device is a vga device with legacy address decoding enabled.
+static int
+is_pci_vga(struct pci_device *pci)
+{
+ if (pci->class != PCI_CLASS_DISPLAY_VGA)
+ return 0;
+ u16 cmd = pci_config_readw(pci->bdf, PCI_COMMAND);
+ if (!(cmd & PCI_COMMAND_IO && cmd & PCI_COMMAND_MEMORY))
+ return 0;
+ while (pci->parent) {
+ pci = pci->parent;
+ u32 ctrl = pci_config_readb(pci->bdf, PCI_BRIDGE_CONTROL);
+ if (!(ctrl & PCI_BRIDGE_CTL_VGA))
+ return 0;
+ }
+ return 1;
+}
+
+// Map the option rom of a given PCI device.
+static struct rom_header *
+map_pcirom(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ dprintf(6, "Attempting to map option rom on dev %02x:%02x.%x\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+
+ if ((pci->header_type & 0x7f) != PCI_HEADER_TYPE_NORMAL) {
+ dprintf(6, "Skipping non-normal pci device (type=%x)\n"
+ , pci->header_type);
+ return NULL;
+ }
+
+ u32 orig = pci_config_readl(bdf, PCI_ROM_ADDRESS);
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, ~PCI_ROM_ADDRESS_ENABLE);
+ u32 sz = pci_config_readl(bdf, PCI_ROM_ADDRESS);
+
+ dprintf(6, "Option rom sizing returned %x %x\n", orig, sz);
+ orig &= ~PCI_ROM_ADDRESS_ENABLE;
+ if (!sz || sz == 0xffffffff)
+ goto fail;
+
+ if (orig == sz || (u32)(orig + 4*1024*1024) < 20*1024*1024) {
+ // Don't try to map to a pci addresses at its max, in the last
+ // 4MiB of ram, or the first 16MiB of ram.
+ dprintf(6, "Preset rom address doesn't look valid\n");
+ goto fail;
+ }
+
+ // Looks like a rom - enable it.
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, orig | PCI_ROM_ADDRESS_ENABLE);
+
+ struct rom_header *rom = (void*)orig;
+ for (;;) {
+ dprintf(5, "Inspecting possible rom at %p (vd=%04x:%04x"
+ " bdf=%02x:%02x.%x)\n"
+ , rom, pci->vendor, pci->device
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+ if (rom->signature != OPTION_ROM_SIGNATURE) {
+ dprintf(6, "No option rom signature (got %x)\n", rom->signature);
+ goto fail;
+ }
+ struct pci_data *pd = get_pci_rom(rom);
+ if (! pd) {
+ dprintf(6, "No valid pci signature found\n");
+ goto fail;
+ }
+
+ if (pd->vendor == pci->vendor && pd->device == pci->device
+ && pd->type == PCIROM_CODETYPE_X86)
+ // A match
+ break;
+ dprintf(6, "Didn't match dev/ven (got %04x:%04x) or type (got %d)\n"
+ , pd->vendor, pd->device, pd->type);
+ if (pd->indicator & 0x80) {
+ dprintf(6, "No more images left\n");
+ goto fail;
+ }
+ rom = (void*)((u32)rom + pd->ilen * 512);
+ }
+
+ rom = copy_rom(rom);
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, orig);
+ return rom;
+fail:
+ // Not valid - restore original and exit.
+ pci_config_writel(bdf, PCI_ROM_ADDRESS, orig);
+ return NULL;
+}
+
+// Attempt to map and initialize the option rom on a given PCI device.
+static int
+init_pcirom(struct pci_device *pci, int isvga, u64 *sources)
+{
+ u16 bdf = pci->bdf;
+ dprintf(4, "Attempting to init PCI bdf %02x:%02x.%x (vd %04x:%04x)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf)
+ , pci->vendor, pci->device);
+ struct rom_header *rom = lookup_hardcode(pci);
+ if (! rom)
+ rom = map_pcirom(pci);
+ if (! rom)
+ // No ROM present.
+ return -1;
+ setRomSource(sources, rom, RS_PCIROM | (u32)pci);
+ return init_optionrom(rom, bdf, isvga);
+}
+
+
+/****************************************************************
+ * Non-VGA option rom init
+ ****************************************************************/
+
+void
+optionrom_setup(void)
+{
+ if (! CONFIG_OPTIONROMS)
+ return;
+
+ dprintf(1, "Scan for option roms\n");
+ u64 sources[(BUILD_BIOS_ADDR - BUILD_ROM_START) / OPTION_ROM_ALIGN];
+ memset(sources, 0, sizeof(sources));
+ u32 post_vga = RomEnd;
+
+ if (CONFIG_OPTIONROMS_DEPLOYED) {
+ // Option roms are already deployed on the system.
+ u32 pos = RomEnd;
+ while (pos < max_rom()) {
+ int ret = init_optionrom((void*)pos, 0, 0);
+ if (ret)
+ pos += OPTION_ROM_ALIGN;
+ else
+ pos = RomEnd;
+ }
+ } else {
+ // Find and deploy PCI roms.
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class == PCI_CLASS_DISPLAY_VGA || pci->have_driver)
+ continue;
+ init_pcirom(pci, 0, sources);
+ }
+
+ // Find and deploy CBFS roms not associated with a device.
+ run_file_roms("genroms/", 0, sources);
+ }
+
+ // All option roms found and deployed - now build BEV/BCV vectors.
+
+ u32 pos = post_vga;
+ while (pos < RomEnd) {
+ struct rom_header *rom = (void*)pos;
+ if (! is_valid_rom(rom)) {
+ pos += OPTION_ROM_ALIGN;
+ continue;
+ }
+ pos += ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
+ struct pnp_data *pnp = get_pnp_rom(rom);
+ if (! pnp) {
+ // Legacy rom.
+ boot_add_bcv(FLATPTR_TO_SEG(rom), OPTION_ROM_INITVECTOR, 0
+ , getRomPriority(sources, rom, 0));
+ continue;
+ }
+ // PnP rom.
+ if (pnp->bev) {
+ // Can boot system - add to IPL list.
+ boot_add_bev(FLATPTR_TO_SEG(rom), pnp->bev, pnp->productname
+ , getRomPriority(sources, rom, 0));
+ } else {
+ // Check for BCV (there may be multiple).
+ int instance = 0;
+ while (pnp && pnp->bcv) {
+ boot_add_bcv(FLATPTR_TO_SEG(rom), pnp->bcv, pnp->productname
+ , getRomPriority(sources, rom, instance++));
+ pnp = get_pnp_next(rom, pnp);
+ }
+ }
+ }
+}
+
+
+/****************************************************************
+ * VGA init
+ ****************************************************************/
+
+static int S3ResumeVgaInit;
+int ScreenAndDebug;
+
+// Call into vga code to turn on console.
+void
+vga_setup(void)
+{
+ if (! CONFIG_OPTIONROMS)
+ return;
+
+ dprintf(1, "Scan for VGA option rom\n");
+
+ // Load some config settings that impact VGA.
+ EnforceChecksum = romfile_loadint("etc/optionroms-checksum", 1);
+ S3ResumeVgaInit = romfile_loadint("etc/s3-resume-vga-init", 0);
+ ScreenAndDebug = romfile_loadint("etc/screen-and-debug", 1);
+
+ if (CONFIG_OPTIONROMS_DEPLOYED) {
+ // Option roms are already deployed on the system.
+ init_optionrom((void*)BUILD_ROM_START, 0, 1);
+ } else {
+ // Clear option rom memory
+ memset((void*)RomEnd, 0, max_rom() - RomEnd);
+
+ // Find and deploy PCI VGA rom.
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (!is_pci_vga(pci))
+ continue;
+ vgahook_setup(pci);
+ init_pcirom(pci, 1, NULL);
+ break;
+ }
+
+ // Find and deploy CBFS vga-style roms not associated with a device.
+ run_file_roms("vgaroms/", 1, NULL);
+ }
+
+ if (RomEnd == BUILD_ROM_START) {
+ // No VGA rom found
+ RomEnd += OPTION_ROM_ALIGN;
+ return;
+ }
+
+ enable_vga_console();
+}
+
+void
+s3_resume_vga_init(void)
+{
+ if (!S3ResumeVgaInit)
+ return;
+ struct rom_header *rom = (void*)BUILD_ROM_START;
+ if (! is_valid_rom(rom))
+ return;
+ callrom(rom, 0);
+}
--- /dev/null
+// Raw screen writing and debug output code.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include <stdarg.h> // va_list
+
+#include "farptr.h" // GET_VAR
+#include "util.h" // printf
+#include "bregs.h" // struct bregs
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+
+struct putcinfo {
+ void (*func)(struct putcinfo *info, char c);
+};
+
+
+/****************************************************************
+ * Debug output
+ ****************************************************************/
+
+#define DEBUG_TIMEOUT 100000
+
+void
+debug_serial_setup(void)
+{
+ if (!CONFIG_DEBUG_SERIAL)
+ return;
+ // setup for serial logging: 8N1
+ u8 oldparam, newparam = 0x03;
+ oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
+ outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
+ // Disable irqs
+ u8 oldier, newier = 0;
+ oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
+ outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
+
+ if (oldparam != newparam || oldier != newier)
+ dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
+ , oldparam, oldier, newparam, newier);
+}
+
+// Write a character to the serial port.
+static void
+debug_serial(char c)
+{
+ if (!CONFIG_DEBUG_SERIAL)
+ return;
+ int timeout = DEBUG_TIMEOUT;
+ while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+ outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
+}
+
+// Make sure all serial port writes have been completely sent.
+static void
+debug_serial_flush(void)
+{
+ if (!CONFIG_DEBUG_SERIAL)
+ return;
+ int timeout = DEBUG_TIMEOUT;
+ while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+}
+
+// Write a character to debug port(s).
+static void
+putc_debug(struct putcinfo *action, char c)
+{
+ if (! CONFIG_DEBUG_LEVEL)
+ return;
+ if (! CONFIG_COREBOOT)
+ // Send character to debug port.
+ outb(c, PORT_BIOS_DEBUG);
+ if (c == '\n')
+ debug_serial('\r');
+ debug_serial(c);
+}
+
+// In segmented mode just need a dummy variable (putc_debug is always
+// used anyway), and in 32bit flat mode need a pointer to the 32bit
+// instance of putc_debug().
+#if MODE16
+static struct putcinfo debuginfo VAR16;
+#elif MODESEGMENT
+static struct putcinfo debuginfo VAR32SEG;
+#else
+static struct putcinfo debuginfo = { putc_debug };
+#endif
+
+
+/****************************************************************
+ * Screen writing
+ ****************************************************************/
+
+// Show a character on the screen.
+static void
+screenc(char c)
+{
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.ah = 0x0e;
+ br.al = c;
+ call16_int(0x10, &br);
+}
+
+// Handle a character from a printf request.
+static void
+putc_screen(struct putcinfo *action, char c)
+{
+ if (ScreenAndDebug)
+ putc_debug(&debuginfo, c);
+ if (c == '\n')
+ screenc('\r');
+ screenc(c);
+}
+
+static struct putcinfo screeninfo = { putc_screen };
+
+
+/****************************************************************
+ * Xprintf code
+ ****************************************************************/
+
+// Output a character.
+static void
+putc(struct putcinfo *action, char c)
+{
+ if (MODESEGMENT) {
+ // Only debugging output supported in segmented mode.
+ putc_debug(action, c);
+ return;
+ }
+
+ void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
+ func(action, c);
+}
+
+// Ouptut a string.
+static void
+puts(struct putcinfo *action, const char *s)
+{
+ if (!MODESEGMENT && !s)
+ s = "(NULL)";
+ for (; *s; s++)
+ putc(action, *s);
+}
+
+// Output a string that is in the CS segment.
+static void
+puts_cs(struct putcinfo *action, const char *s)
+{
+ char *vs = (char*)s;
+ for (;; vs++) {
+ char c = GET_GLOBAL(*vs);
+ if (!c)
+ break;
+ putc(action, c);
+ }
+}
+
+// Output an unsigned integer.
+static void
+putuint(struct putcinfo *action, u32 val)
+{
+ char buf[12];
+ char *d = &buf[sizeof(buf) - 1];
+ *d-- = '\0';
+ for (;;) {
+ *d = (val % 10) + '0';
+ val /= 10;
+ if (!val)
+ break;
+ d--;
+ }
+ puts(action, d);
+}
+
+// Output a single digit hex character.
+static inline void
+putsinglehex(struct putcinfo *action, u32 val)
+{
+ if (val <= 9)
+ val = '0' + val;
+ else
+ val = 'a' + val - 10;
+ putc(action, val);
+}
+
+// Output an integer in hexadecimal.
+static void
+puthex(struct putcinfo *action, u32 val, int width, int spacepad)
+{
+ if (!width) {
+ u32 tmp = val;
+ width = 1;
+ while (tmp >>= 4)
+ width++;
+ } else if (spacepad) {
+ u32 tmp = val;
+ u32 count = 1;
+ while (tmp >>= 4)
+ count++;
+ if (width > count) {
+ count = width - count;
+ width -= count;
+ while (count--)
+ putc(action, ' ');
+ }
+ }
+
+ switch (width) {
+ default: putsinglehex(action, (val >> 28) & 0xf);
+ case 7: putsinglehex(action, (val >> 24) & 0xf);
+ case 6: putsinglehex(action, (val >> 20) & 0xf);
+ case 5: putsinglehex(action, (val >> 16) & 0xf);
+ case 4: putsinglehex(action, (val >> 12) & 0xf);
+ case 3: putsinglehex(action, (val >> 8) & 0xf);
+ case 2: putsinglehex(action, (val >> 4) & 0xf);
+ case 1: putsinglehex(action, (val >> 0) & 0xf);
+ }
+}
+
+static inline int
+isdigit(u8 c)
+{
+ return ((u8)(c - '0')) < 10;
+}
+
+static void
+bvprintf(struct putcinfo *action, const char *fmt, va_list args)
+{
+ const char *s = fmt;
+ for (;; s++) {
+ char c = GET_GLOBAL(*(u8*)s);
+ if (!c)
+ break;
+ if (c != '%') {
+ putc(action, c);
+ continue;
+ }
+ const char *n = s+1;
+ int field_width = 0;
+ int spacepad = 1;
+ for (;;) {
+ c = GET_GLOBAL(*(u8*)n);
+ if (!isdigit(c))
+ break;
+ if (!field_width && (c == '0'))
+ spacepad = 0;
+ else
+ field_width = field_width * 10 + c - '0';
+ n++;
+ }
+ if (c == 'l') {
+ // Ignore long format indicator
+ n++;
+ c = GET_GLOBAL(*(u8*)n);
+ }
+ s32 val;
+ const char *sarg;
+ switch (c) {
+ case '%':
+ putc(action, '%');
+ break;
+ case 'd':
+ val = va_arg(args, s32);
+ if (val < 0) {
+ putc(action, '-');
+ val = -val;
+ }
+ putuint(action, val);
+ break;
+ case 'u':
+ val = va_arg(args, s32);
+ putuint(action, val);
+ break;
+ case 'p':
+ /* %p always has 0x prepended */
+ putc(action, '0');
+ putc(action, 'x');
+ field_width = 8;
+ spacepad = 0;
+ case 'x':
+ val = va_arg(args, s32);
+ puthex(action, val, field_width, spacepad);
+ break;
+ case 'c':
+ val = va_arg(args, int);
+ putc(action, val);
+ break;
+ case '.':
+ // Hack to support "%.s" - meaning string on stack.
+ if (GET_GLOBAL(*(u8*)(n+1)) != 's')
+ break;
+ n++;
+ sarg = va_arg(args, const char *);
+ puts(action, sarg);
+ break;
+ case 's':
+ sarg = va_arg(args, const char *);
+ puts_cs(action, sarg);
+ break;
+ default:
+ putc(action, '%');
+ n = s;
+ }
+ s = n;
+ }
+}
+
+void
+panic(const char *fmt, ...)
+{
+ if (CONFIG_DEBUG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&debuginfo, fmt, args);
+ va_end(args);
+ debug_serial_flush();
+ }
+
+ // XXX - use PANIC PORT.
+ irq_disable();
+ for (;;)
+ hlt();
+}
+
+void
+__dprintf(const char *fmt, ...)
+{
+ if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
+ && *fmt != '\\' && *fmt != '/') {
+ struct thread_info *cur = getCurThread();
+ if (cur != &MainThread) {
+ // Show "thread id" for this debug message.
+ putc_debug(&debuginfo, '|');
+ puthex(&debuginfo, (u32)cur, 8, 0);
+ putc_debug(&debuginfo, '|');
+ putc_debug(&debuginfo, ' ');
+ }
+ }
+
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&debuginfo, fmt, args);
+ va_end(args);
+ debug_serial_flush();
+}
+
+void
+printf(const char *fmt, ...)
+{
+ ASSERT32FLAT();
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&screeninfo, fmt, args);
+ va_end(args);
+ if (ScreenAndDebug)
+ debug_serial_flush();
+}
+
+
+/****************************************************************
+ * snprintf
+ ****************************************************************/
+
+struct snprintfinfo {
+ struct putcinfo info;
+ char *str, *end;
+};
+
+static void
+putc_str(struct putcinfo *info, char c)
+{
+ struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
+ if (sinfo->str >= sinfo->end)
+ return;
+ *sinfo->str = c;
+ sinfo->str++;
+}
+
+// Build a formatted string. Note, this function returns the actual
+// number of bytes used (not including null) even in the overflow
+// case.
+int
+snprintf(char *str, size_t size, const char *fmt, ...)
+{
+ ASSERT32FLAT();
+ if (!size)
+ return 0;
+ struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&sinfo.info, fmt, args);
+ va_end(args);
+ char *end = sinfo.str;
+ if (end >= sinfo.end)
+ end = sinfo.end - 1;
+ *end = '\0';
+ return end - str;
+}
+
+// Build a formatted string - malloc'ing the memory.
+char *
+znprintf(size_t size, const char *fmt, ...)
+{
+ ASSERT32FLAT();
+ if (!size)
+ return NULL;
+ char *str = malloc_tmp(size);
+ if (!str) {
+ warn_noalloc();
+ return NULL;
+ }
+ struct snprintfinfo sinfo = { { putc_str }, str, str + size };
+ va_list args;
+ va_start(args, fmt);
+ bvprintf(&sinfo.info, fmt, args);
+ va_end(args);
+ char *end = sinfo.str;
+ if (end >= sinfo.end)
+ end = sinfo.end - 1;
+ *end = '\0';
+ return str;
+}
+
+
+/****************************************************************
+ * Misc helpers
+ ****************************************************************/
+
+void
+hexdump(const void *d, int len)
+{
+ int count=0;
+ while (len > 0) {
+ if (count % 8 == 0) {
+ putc(&debuginfo, '\n');
+ puthex(&debuginfo, count*4, 8, 0);
+ putc(&debuginfo, ':');
+ } else {
+ putc(&debuginfo, ' ');
+ }
+ puthex(&debuginfo, *(u32*)d, 8, 0);
+ count++;
+ len-=4;
+ d+=4;
+ }
+ putc(&debuginfo, '\n');
+ debug_serial_flush();
+}
+
+static void
+dump_regs(struct bregs *regs)
+{
+ if (!regs) {
+ dprintf(1, " NULL\n");
+ return;
+ }
+ dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n"
+ , regs->eax, regs->ebx, regs->ecx, regs->edx
+ , regs->ds, regs->es, GET_SEG(SS));
+ dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
+ , regs->esi, regs->edi, regs->ebp, (u32)®s[1]
+ , regs->code.seg, regs->code.offset, regs->flags);
+}
+
+// Report entry to an Interrupt Service Routine (ISR).
+void
+__debug_isr(const char *fname)
+{
+ puts_cs(&debuginfo, fname);
+ putc(&debuginfo, '\n');
+ debug_serial_flush();
+}
+
+// Function called on handler startup.
+void
+__debug_enter(struct bregs *regs, const char *fname)
+{
+ dprintf(1, "enter %s:\n", fname);
+ dump_regs(regs);
+}
+
+// Send debugging output info.
+void
+__debug_stub(struct bregs *regs, int lineno, const char *fname)
+{
+ dprintf(1, "stub %s:%d:\n", fname, lineno);
+ dump_regs(regs);
+}
+
+// Report on an invalid parameter.
+void
+__warn_invalid(struct bregs *regs, int lineno, const char *fname)
+{
+ if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
+ dprintf(1, "invalid %s:%d:\n", fname, lineno);
+ dump_regs(regs);
+ }
+}
+
+// Report on an unimplemented feature.
+void
+__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
+{
+ if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
+ dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
+ dump_regs(regs);
+ }
+}
+
+// Report a detected internal inconsistency.
+void
+__warn_internalerror(int lineno, const char *fname)
+{
+ dprintf(1, "WARNING - internal error detected at %s:%d!\n"
+ , fname, lineno);
+}
+
+// Report on an allocation failure.
+void
+__warn_noalloc(int lineno, const char *fname)
+{
+ dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
+ , fname, lineno);
+}
+
+// Report on a timeout exceeded.
+void
+__warn_timeout(int lineno, const char *fname)
+{
+ dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
+}
+
+// Report a handler reporting an invalid parameter to the caller.
+void
+__set_invalid(struct bregs *regs, int lineno, const char *fname)
+{
+ __warn_invalid(regs, lineno, fname);
+ set_invalid_silent(regs);
+}
+
+// Report a call of an unimplemented function.
+void
+__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
+{
+ __warn_unimplemented(regs, lineno, fname);
+ set_invalid_silent(regs);
+}
+
+// Report a handler reporting an invalid parameter code to the
+// caller. Note, the lineno and return code are encoded in the same
+// parameter as gcc does a better job of scheduling function calls
+// when there are 3 or less parameters.
+void
+__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ u32 lineno = linecode >> 8;
+ __warn_invalid(regs, lineno, fname);
+ set_code_invalid_silent(regs, code);
+}
+
+// Report a call of an unimplemented function.
+void
+__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
+{
+ u8 code = linecode;
+ u32 lineno = linecode >> 8;
+ __warn_unimplemented(regs, lineno, fname);
+ set_code_invalid_silent(regs, code);
+}
--- /dev/null
+// Paravirtualization support.
+//
+// Copyright (C) 2009 Red Hat Inc.
+//
+// Authors:
+// Gleb Natapov <gnatapov@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_COREBOOT
+#include "util.h" // ntoh[ls]
+#include "ioport.h" // outw
+#include "paravirt.h" // qemu_cfg_port_probe
+#include "smbios.h" // struct smbios_structure_header
+
+int qemu_cfg_present;
+
+static void
+qemu_cfg_select(u16 f)
+{
+ outw(f, PORT_QEMU_CFG_CTL);
+}
+
+static void
+qemu_cfg_read(u8 *buf, int len)
+{
+ insb(PORT_QEMU_CFG_DATA, buf, len);
+}
+
+static void
+qemu_cfg_skip(int len)
+{
+ while (len--)
+ inb(PORT_QEMU_CFG_DATA);
+}
+
+static void
+qemu_cfg_read_entry(void *buf, int e, int len)
+{
+ qemu_cfg_select(e);
+ qemu_cfg_read(buf, len);
+}
+
+void qemu_cfg_port_probe(void)
+{
+ char *sig = "QEMU";
+ int i;
+
+ if (CONFIG_COREBOOT)
+ return;
+
+ qemu_cfg_present = 1;
+
+ qemu_cfg_select(QEMU_CFG_SIGNATURE);
+
+ for (i = 0; i < 4; i++)
+ if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
+ qemu_cfg_present = 0;
+ break;
+ }
+ dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
+}
+
+void qemu_cfg_get_uuid(u8 *uuid)
+{
+ if (!qemu_cfg_present)
+ return;
+
+ qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
+}
+
+int qemu_cfg_show_boot_menu(void)
+{
+ u16 v;
+ if (!qemu_cfg_present)
+ return 1;
+
+ qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
+
+ return v;
+}
+
+int qemu_cfg_irq0_override(void)
+{
+ u8 v;
+
+ if (!qemu_cfg_present)
+ return 0;
+
+ qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
+
+ return v;
+}
+
+u16 qemu_cfg_acpi_additional_tables(void)
+{
+ u16 cnt;
+
+ if (!qemu_cfg_present)
+ return 0;
+
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
+
+ return cnt;
+}
+
+u16 qemu_cfg_next_acpi_table_len(void)
+{
+ u16 len;
+
+ qemu_cfg_read((u8*)&len, sizeof(len));
+
+ return len;
+}
+
+void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
+{
+ qemu_cfg_read(addr, len);
+ return addr;
+}
+
+u16 qemu_cfg_smbios_entries(void)
+{
+ u16 cnt;
+
+ if (!qemu_cfg_present)
+ return 0;
+
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
+
+ return cnt;
+}
+
+u32 qemu_cfg_e820_entries(void)
+{
+ u32 cnt;
+
+ if (!qemu_cfg_present)
+ return 0;
+
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
+ return cnt;
+}
+
+void* qemu_cfg_e820_load_next(void *addr)
+{
+ qemu_cfg_read(addr, sizeof(struct e820_reservation));
+ return addr;
+}
+
+struct smbios_header {
+ u16 length;
+ u8 type;
+} PACKED;
+
+struct smbios_field {
+ struct smbios_header header;
+ u8 type;
+ u16 offset;
+ u8 data[];
+} PACKED;
+
+struct smbios_table {
+ struct smbios_header header;
+ u8 data[];
+} PACKED;
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
+{
+ int i;
+
+ for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
+ struct smbios_field field;
+
+ qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
+ field.header.length -= sizeof(struct smbios_header);
+
+ if (field.header.type != SMBIOS_FIELD_ENTRY) {
+ qemu_cfg_skip(field.header.length);
+ continue;
+ }
+
+ qemu_cfg_read((u8 *)&field.type,
+ sizeof(field) - sizeof(struct smbios_header));
+ field.header.length -= sizeof(field) - sizeof(struct smbios_header);
+
+ if (field.type != type || field.offset != offset) {
+ qemu_cfg_skip(field.header.length);
+ continue;
+ }
+
+ qemu_cfg_read(addr, field.header.length);
+ return (size_t)field.header.length;
+ }
+ return 0;
+}
+
+int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
+ unsigned *max_struct_size, char *end)
+{
+ static u64 used_bitmap[4] = { 0 };
+ char *start = *p;
+ int i;
+
+ /* Check if we've already reported these tables */
+ if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
+ return 1;
+
+ /* Don't introduce spurious end markers */
+ if (type == 127)
+ return 0;
+
+ for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
+ struct smbios_table table;
+ struct smbios_structure_header *header = (void *)*p;
+ int string;
+
+ qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
+ table.header.length -= sizeof(struct smbios_header);
+
+ if (table.header.type != SMBIOS_TABLE_ENTRY) {
+ qemu_cfg_skip(table.header.length);
+ continue;
+ }
+
+ if (end - *p < sizeof(struct smbios_structure_header)) {
+ warn_noalloc();
+ break;
+ }
+
+ qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
+ table.header.length -= sizeof(struct smbios_structure_header);
+
+ if (header->type != type) {
+ qemu_cfg_skip(table.header.length);
+ continue;
+ }
+
+ *p += sizeof(struct smbios_structure_header);
+
+ /* Entries end with a double NULL char, if there's a string at
+ * the end (length is greater than formatted length), the string
+ * terminator provides the first NULL. */
+ string = header->length < table.header.length +
+ sizeof(struct smbios_structure_header);
+
+ /* Read the rest and terminate the entry */
+ if (end - *p < table.header.length) {
+ warn_noalloc();
+ *p -= sizeof(struct smbios_structure_header);
+ continue;
+ }
+ qemu_cfg_read((u8 *)*p, table.header.length);
+ *p += table.header.length;
+ *((u8*)*p) = 0;
+ (*p)++;
+ if (!string) {
+ *((u8*)*p) = 0;
+ (*p)++;
+ }
+
+ (*nr_structs)++;
+ if (*p - (char *)header > *max_struct_size)
+ *max_struct_size = *p - (char *)header;
+ }
+
+ if (start != *p) {
+ /* Mark that we've reported on this type */
+ used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
+ return 1;
+ }
+
+ return 0;
+}
+
+int qemu_cfg_get_numa_nodes(void)
+{
+ u64 cnt;
+
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
+
+ return (int)cnt;
+}
+
+void qemu_cfg_get_numa_data(u64 *data, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ qemu_cfg_read((u8*)(data + i), sizeof(u64));
+}
+
+u16 qemu_cfg_get_max_cpus(void)
+{
+ u16 cnt;
+
+ if (!qemu_cfg_present)
+ return 0;
+
+ qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
+
+ return cnt;
+}
+
+static QemuCfgFile LastFile;
+
+static u32
+__cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect)
+{
+ if (!qemu_cfg_present)
+ return 0;
+
+ u32 count;
+ qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+ count = ntohl(count);
+ u32 e;
+ for (e = 0; e < count; e++) {
+ qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
+ u32 select = ntohs(LastFile.select);
+ if (select <= prevselect)
+ continue;
+ if (memcmp(prefix, LastFile.name, prefixlen) == 0)
+ return select;
+ }
+ return 0;
+}
+
+u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect)
+{
+ return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect);
+}
+
+u32 qemu_cfg_find_file(const char *name)
+{
+ return __cfg_next_prefix_file(name, strlen(name) + 1, 0);
+}
+
+static int
+__qemu_cfg_set_file(u32 select)
+{
+ if (!qemu_cfg_present || !select)
+ return -1;
+ if (select == ntohs(LastFile.select))
+ return 0;
+
+ u32 count;
+ qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
+ count = ntohl(count);
+ u32 e;
+ for (e = 0; e < count; e++) {
+ qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
+ if (select == ntohs(LastFile.select))
+ return 0;
+ }
+ return -1;
+}
+
+int qemu_cfg_size_file(u32 select)
+{
+ if (__qemu_cfg_set_file(select))
+ return -1;
+ return ntohl(LastFile.size);
+}
+
+const char* qemu_cfg_name_file(u32 select)
+{
+ if (__qemu_cfg_set_file(select))
+ return NULL;
+ return LastFile.name;
+}
+
+int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen)
+{
+ if (__qemu_cfg_set_file(select))
+ return -1;
+ int len = qemu_cfg_size_file(select);
+ if (len < 0 || len > maxlen)
+ return -1;
+ qemu_cfg_read_entry(dst, select, len);
+ return len;
+}
+
+// Helper function to find, malloc_tmphigh, and copy a romfile. This
+// function adds a trailing zero to the malloc'd copy.
+void *
+romfile_loadfile(const char *name, int *psize)
+{
+ u32 file = romfile_find(name);
+ if (!file)
+ return NULL;
+
+ int filesize = romfile_size(file);
+ if (!filesize)
+ return NULL;
+
+ char *data = malloc_tmphigh(filesize+1);
+ if (!data) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize);
+ romfile_copy(file, data, filesize);
+ if (psize)
+ *psize = filesize;
+ data[filesize] = '\0';
+ return data;
+}
+
+// Attempt to load an integer from the given file - return 'defval'
+// if unsuccesful.
+u64
+romfile_loadint(const char *name, u64 defval)
+{
+ u32 file = romfile_find(name);
+ if (!file)
+ return defval;
+
+ int filesize = romfile_size(file);
+ if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1)))
+ // Doesn't look like a valid integer.
+ return defval;
+
+ u64 val = 0;
+ romfile_copy(file, &val, sizeof(val));
+ return val;
+}
--- /dev/null
+#ifndef __PV_H
+#define __PV_H
+
+#include "config.h" // CONFIG_COREBOOT
+#include "util.h"
+
+/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
+ * should be used to determine that a VM is running under KVM.
+ */
+#define KVM_CPUID_SIGNATURE 0x40000000
+
+static inline int kvm_para_available(void)
+{
+ unsigned int eax, ebx, ecx, edx;
+ char signature[13];
+
+ cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
+ memcpy(signature + 0, &ebx, 4);
+ memcpy(signature + 4, &ecx, 4);
+ memcpy(signature + 8, &edx, 4);
+ signature[12] = 0;
+
+ if (strcmp(signature, "KVMKVMKVM") == 0)
+ return 1;
+
+ return 0;
+}
+
+#define QEMU_CFG_SIGNATURE 0x00
+#define QEMU_CFG_ID 0x01
+#define QEMU_CFG_UUID 0x02
+#define QEMU_CFG_NUMA 0x0d
+#define QEMU_CFG_BOOT_MENU 0x0e
+#define QEMU_CFG_MAX_CPUS 0x0f
+#define QEMU_CFG_FILE_DIR 0x19
+#define QEMU_CFG_ARCH_LOCAL 0x8000
+#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
+#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
+#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
+#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
+
+extern int qemu_cfg_present;
+
+void qemu_cfg_port_probe(void);
+int qemu_cfg_show_boot_menu(void);
+void qemu_cfg_get_uuid(u8 *uuid);
+int qemu_cfg_irq0_override(void);
+u16 qemu_cfg_acpi_additional_tables(void);
+u16 qemu_cfg_next_acpi_table_len(void);
+void *qemu_cfg_next_acpi_table_load(void *addr, u16 len);
+u16 qemu_cfg_smbios_entries(void);
+size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr);
+int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
+ unsigned *max_struct_size, char *end);
+int qemu_cfg_get_numa_nodes(void);
+void qemu_cfg_get_numa_data(u64 *data, int n);
+u16 qemu_cfg_get_max_cpus(void);
+
+typedef struct QemuCfgFile {
+ u32 size; /* file size */
+ u16 select; /* write this to 0x510 to read it */
+ u16 reserved;
+ char name[56];
+} QemuCfgFile;
+
+struct e820_reservation {
+ u64 address;
+ u64 length;
+ u32 type;
+};
+
+u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect);
+u32 qemu_cfg_find_file(const char *name);
+int qemu_cfg_size_file(u32 select);
+const char* qemu_cfg_name_file(u32 select);
+int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen);
+
+// Wrappers that select cbfs or qemu_cfg file interface.
+static inline u32 romfile_findprefix(const char *prefix, u32 previd) {
+ if (CONFIG_COREBOOT)
+ return (u32)cbfs_findprefix(prefix, (void*)previd);
+ return qemu_cfg_next_prefix_file(prefix, previd);
+}
+static inline u32 romfile_find(const char *name) {
+ if (CONFIG_COREBOOT)
+ return (u32)cbfs_finddatafile(name);
+ return qemu_cfg_find_file(name);
+}
+static inline u32 romfile_size(u32 fileid) {
+ if (CONFIG_COREBOOT)
+ return cbfs_datasize((void*)fileid);
+ return qemu_cfg_size_file(fileid);
+}
+static inline int romfile_copy(u32 fileid, void *dst, u32 maxlen) {
+ if (CONFIG_COREBOOT)
+ return cbfs_copyfile((void*)fileid, dst, maxlen);
+ return qemu_cfg_read_file(fileid, dst, maxlen);
+}
+static inline const char* romfile_name(u32 fileid) {
+ if (CONFIG_COREBOOT)
+ return cbfs_filename((void*)fileid);
+ return qemu_cfg_name_file(fileid);
+}
+void *romfile_loadfile(const char *name, int *psize);
+u64 romfile_loadint(const char *name, u64 defval);
+
+u32 qemu_cfg_e820_entries(void);
+void* qemu_cfg_e820_load_next(void *addr);
+
+#endif
--- /dev/null
+// PCI config space access functions.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pci.h" // pci_config_writel
+#include "ioport.h" // outl
+#include "util.h" // dprintf
+#include "paravirt.h" // romfile_loadint
+#include "farptr.h" // MAKE_FLATPTR
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
+
+void pci_config_writel(u16 bdf, u32 addr, u32 val)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ outl(val, PORT_PCI_DATA);
+}
+
+void pci_config_writew(u16 bdf, u32 addr, u16 val)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ outw(val, PORT_PCI_DATA + (addr & 2));
+}
+
+void pci_config_writeb(u16 bdf, u32 addr, u8 val)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ outb(val, PORT_PCI_DATA + (addr & 3));
+}
+
+u32 pci_config_readl(u16 bdf, u32 addr)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ return inl(PORT_PCI_DATA);
+}
+
+u16 pci_config_readw(u16 bdf, u32 addr)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ return inw(PORT_PCI_DATA + (addr & 2));
+}
+
+u8 pci_config_readb(u16 bdf, u32 addr)
+{
+ outl(0x80000000 | (bdf << 8) | (addr & 0xfc), PORT_PCI_CMD);
+ return inb(PORT_PCI_DATA + (addr & 3));
+}
+
+void
+pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on)
+{
+ u16 val = pci_config_readw(bdf, addr);
+ val = (val & ~off) | on;
+ pci_config_writew(bdf, addr, val);
+}
+
+// Helper function for foreachbdf() macro - return next device
+int
+pci_next(int bdf, int bus)
+{
+ if (pci_bdf_to_fn(bdf) == 0
+ && (pci_config_readb(bdf, PCI_HEADER_TYPE) & 0x80) == 0)
+ // Last found device wasn't a multi-function device - skip to
+ // the next device.
+ bdf += 8;
+ else
+ bdf += 1;
+
+ for (;;) {
+ if (pci_bdf_to_bus(bdf) != bus)
+ return -1;
+
+ u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
+ if (v != 0x0000 && v != 0xffff)
+ // Device is present.
+ return bdf;
+
+ if (pci_bdf_to_fn(bdf) == 0)
+ bdf += 8;
+ else
+ bdf += 1;
+ }
+}
+
+struct pci_device *PCIDevices;
+int MaxPCIBus VAR16VISIBLE;
+
+// Check if PCI is available at all
+int
+pci_probe_host(void)
+{
+ outl(0x80000000, PORT_PCI_CMD);
+ if (inl(PORT_PCI_CMD) != 0x80000000) {
+ dprintf(1, "Detected non-PCI system\n");
+ return -1;
+ }
+ return 0;
+}
+
+// Find all PCI devices and populate PCIDevices linked list.
+void
+pci_probe_devices(void)
+{
+ dprintf(3, "PCI probe\n");
+ struct pci_device *busdevs[256];
+ memset(busdevs, 0, sizeof(busdevs));
+ struct pci_device **pprev = &PCIDevices;
+ int extraroots = romfile_loadint("etc/extra-pci-roots", 0);
+ int bus = -1, lastbus = 0, rootbuses = 0, count=0;
+ while (bus < 0xff && (bus < MaxPCIBus || rootbuses < extraroots)) {
+ bus++;
+ int bdf;
+ foreachbdf(bdf, bus) {
+ // Create new pci_device struct and add to list.
+ struct pci_device *dev = malloc_tmp(sizeof(*dev));
+ if (!dev) {
+ warn_noalloc();
+ return;
+ }
+ memset(dev, 0, sizeof(*dev));
+ *pprev = dev;
+ pprev = &dev->next;
+ count++;
+
+ // Find parent device.
+ int rootbus;
+ struct pci_device *parent = busdevs[bus];
+ if (!parent) {
+ if (bus != lastbus)
+ rootbuses++;
+ lastbus = bus;
+ rootbus = rootbuses;
+ if (bus > MaxPCIBus)
+ MaxPCIBus = bus;
+ } else {
+ rootbus = parent->rootbus;
+ }
+
+ // Populate pci_device info.
+ dev->bdf = bdf;
+ dev->parent = parent;
+ dev->rootbus = rootbus;
+ u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+ dev->vendor = vendev & 0xffff;
+ dev->device = vendev >> 16;
+ u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
+ dev->class = classrev >> 16;
+ dev->prog_if = classrev >> 8;
+ dev->revision = classrev & 0xff;
+ dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
+ u8 v = dev->header_type & 0x7f;
+ if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
+ u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+ dev->secondary_bus = secbus;
+ if (secbus > bus && !busdevs[secbus])
+ busdevs[secbus] = dev;
+ if (secbus > MaxPCIBus)
+ MaxPCIBus = secbus;
+ }
+ dprintf(4, "PCI device %02x:%02x.%x (vd=%04x:%04x c=%04x)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf)
+ , dev->vendor, dev->device, dev->class);
+ }
+ }
+ dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus);
+}
+
+// Search for a device with the specified vendor and device ids.
+struct pci_device *
+pci_find_device(u16 vendid, u16 devid)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor == vendid && pci->device == devid)
+ return pci;
+ }
+ return NULL;
+}
+
+// Search for a device with the specified class id.
+struct pci_device *
+pci_find_class(u16 classid)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class == classid)
+ return pci;
+ }
+ return NULL;
+}
+
+int pci_init_device(const struct pci_device_id *ids
+ , struct pci_device *pci, void *arg)
+{
+ while (ids->vendid || ids->class_mask) {
+ if ((ids->vendid == PCI_ANY_ID || ids->vendid == pci->vendor) &&
+ (ids->devid == PCI_ANY_ID || ids->devid == pci->device) &&
+ !((ids->class ^ pci->class) & ids->class_mask)) {
+ if (ids->func)
+ ids->func(pci, arg);
+ return 0;
+ }
+ ids++;
+ }
+ return -1;
+}
+
+struct pci_device *
+pci_find_init_device(const struct pci_device_id *ids, void *arg)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci_init_device(ids, pci, arg) == 0)
+ return pci;
+ }
+ return NULL;
+}
+
+void
+pci_reboot(void)
+{
+ u8 v = inb(PORT_PCI_REBOOT) & ~6;
+ outb(v|2, PORT_PCI_REBOOT); /* Request hard reset */
+ udelay(50);
+ outb(v|6, PORT_PCI_REBOOT); /* Actually do the reset */
+ udelay(50);
+}
+
+// helper functions to access pci mmio bars from real mode
+
+u32 VISIBLE32FLAT
+pci_readl_32(u32 addr)
+{
+ dprintf(3, "32: pci read : %x\n", addr);
+ return readl((void*)addr);
+}
+
+u32 pci_readl(u32 addr)
+{
+ if (MODESEGMENT) {
+ dprintf(3, "16: pci read : %x\n", addr);
+ extern void _cfunc32flat_pci_readl_32(u32 addr);
+ return call32(_cfunc32flat_pci_readl_32, addr, -1);
+ } else {
+ return pci_readl_32(addr);
+ }
+}
+
+struct reg32 {
+ u32 addr;
+ u32 data;
+};
+
+void VISIBLE32FLAT
+pci_writel_32(struct reg32 *reg32)
+{
+ dprintf(3, "32: pci write: %x, %x (%p)\n", reg32->addr, reg32->data, reg32);
+ writel((void*)(reg32->addr), reg32->data);
+}
+
+void pci_writel(u32 addr, u32 val)
+{
+ struct reg32 reg32 = { .addr = addr, .data = val };
+ if (MODESEGMENT) {
+ dprintf(3, "16: pci write: %x, %x (%x:%p)\n",
+ reg32.addr, reg32.data, GET_SEG(SS), ®32);
+ void *flatptr = MAKE_FLATPTR(GET_SEG(SS), ®32);
+ extern void _cfunc32flat_pci_writel_32(struct reg32 *reg32);
+ call32(_cfunc32flat_pci_writel_32, (u32)flatptr, -1);
+ } else {
+ pci_writel_32(®32);
+ }
+}
--- /dev/null
+#ifndef __PCI_H
+#define __PCI_H
+
+#include "types.h" // u32
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+static inline u8 pci_bdf_to_bus(u16 bdf) {
+ return bdf >> 8;
+}
+static inline u8 pci_bdf_to_devfn(u16 bdf) {
+ return bdf & 0xff;
+}
+static inline u16 pci_bdf_to_busdev(u16 bdf) {
+ return bdf & ~0x07;
+}
+static inline u8 pci_bdf_to_dev(u16 bdf) {
+ return (bdf >> 3) & 0x1f;
+}
+static inline u8 pci_bdf_to_fn(u16 bdf) {
+ return bdf & 0x07;
+}
+static inline u16 pci_to_bdf(int bus, int dev, int fn) {
+ return (bus<<8) | (dev<<3) | fn;
+}
+static inline u16 pci_bus_devfn_to_bdf(int bus, u16 devfn) {
+ return (bus << 8) | devfn;
+}
+
+void pci_config_writel(u16 bdf, u32 addr, u32 val);
+void pci_config_writew(u16 bdf, u32 addr, u16 val);
+void pci_config_writeb(u16 bdf, u32 addr, u8 val);
+u32 pci_config_readl(u16 bdf, u32 addr);
+u16 pci_config_readw(u16 bdf, u32 addr);
+u8 pci_config_readb(u16 bdf, u32 addr);
+void pci_config_maskw(u16 bdf, u32 addr, u16 off, u16 on);
+
+struct pci_device *pci_find_device(u16 vendid, u16 devid);
+struct pci_device *pci_find_class(u16 classid);
+
+struct pci_device {
+ u16 bdf;
+ u8 rootbus;
+ struct pci_device *next;
+ struct pci_device *parent;
+
+ // Configuration space device information
+ u16 vendor, device;
+ u16 class;
+ u8 prog_if, revision;
+ u8 header_type;
+ u8 secondary_bus;
+ struct {
+ u32 addr;
+ u32 size;
+ int is64;
+ } bars[PCI_NUM_REGIONS];
+
+ // Local information on device.
+ int have_driver;
+};
+extern struct pci_device *PCIDevices;
+extern int MaxPCIBus;
+int pci_probe_host(void);
+void pci_probe_devices(void);
+static inline u32 pci_classprog(struct pci_device *pci) {
+ return (pci->class << 8) | pci->prog_if;
+}
+
+#define foreachpci(PCI) \
+ for (PCI=PCIDevices; PCI; PCI=PCI->next)
+
+int pci_next(int bdf, int bus);
+#define foreachbdf(BDF, BUS) \
+ for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS)) \
+ ; BDF >= 0 \
+ ; BDF=pci_next(BDF, (BUS)))
+
+#define PCI_ANY_ID (~0)
+struct pci_device_id {
+ u32 vendid;
+ u32 devid;
+ u32 class;
+ u32 class_mask;
+ void (*func)(struct pci_device *pci, void *arg);
+};
+
+#define PCI_DEVICE(vendor_id, device_id, init_func) \
+ { \
+ .vendid = (vendor_id), \
+ .devid = (device_id), \
+ .class = PCI_ANY_ID, \
+ .class_mask = 0, \
+ .func = (init_func) \
+ }
+
+#define PCI_DEVICE_CLASS(vendor_id, device_id, class_code, init_func) \
+ { \
+ .vendid = (vendor_id), \
+ .devid = (device_id), \
+ .class = (class_code), \
+ .class_mask = ~0, \
+ .func = (init_func) \
+ }
+
+#define PCI_DEVICE_END \
+ { \
+ .vendid = 0, \
+ }
+
+int pci_init_device(const struct pci_device_id *ids
+ , struct pci_device *pci, void *arg);
+struct pci_device *pci_find_init_device(const struct pci_device_id *ids
+ , void *arg);
+void pci_reboot(void);
+
+// helper functions to access pci mmio bars from real mode
+u32 pci_readl(u32 addr);
+void pci_writel(u32 addr, u32 val);
+
+// pirtable.c
+void create_pirtable(void);
+
+
+/****************************************************************
+ * PIR table
+ ****************************************************************/
+
+extern u16 PirOffset;
+
+struct link_info {
+ u8 link;
+ u16 bitmap;
+} PACKED;
+
+struct pir_slot {
+ u8 bus;
+ u8 dev;
+ struct link_info links[4];
+ u8 slot_nr;
+ u8 reserved;
+} PACKED;
+
+struct pir_header {
+ u32 signature;
+ u16 version;
+ u16 size;
+ u8 router_bus;
+ u8 router_devfunc;
+ u16 exclusive_irqs;
+ u32 compatible_devid;
+ u32 miniport_data;
+ u8 reserved[11];
+ u8 checksum;
+ struct pir_slot slots[0];
+} PACKED;
+
+#define PIR_SIGNATURE 0x52495024 // $PIR
+
+
+#endif
--- /dev/null
+/*
+ * PCI Class, Vendor and Device IDs
+ *
+ * Please keep sorted.
+ */
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED 0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA 0x0001
+
+#define PCI_BASE_CLASS_STORAGE 0x01
+#define PCI_CLASS_STORAGE_SCSI 0x0100
+#define PCI_CLASS_STORAGE_IDE 0x0101
+#define PCI_CLASS_STORAGE_FLOPPY 0x0102
+#define PCI_CLASS_STORAGE_IPI 0x0103
+#define PCI_CLASS_STORAGE_RAID 0x0104
+#define PCI_CLASS_STORAGE_SATA 0x0106
+#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601
+#define PCI_CLASS_STORAGE_SAS 0x0107
+#define PCI_CLASS_STORAGE_OTHER 0x0180
+
+#define PCI_BASE_CLASS_NETWORK 0x02
+#define PCI_CLASS_NETWORK_ETHERNET 0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201
+#define PCI_CLASS_NETWORK_FDDI 0x0202
+#define PCI_CLASS_NETWORK_ATM 0x0203
+#define PCI_CLASS_NETWORK_OTHER 0x0280
+
+#define PCI_BASE_CLASS_DISPLAY 0x03
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_DISPLAY_XGA 0x0301
+#define PCI_CLASS_DISPLAY_3D 0x0302
+#define PCI_CLASS_DISPLAY_OTHER 0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA 0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
+#define PCI_CLASS_MULTIMEDIA_PHONE 0x0402
+#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
+
+#define PCI_BASE_CLASS_MEMORY 0x05
+#define PCI_CLASS_MEMORY_RAM 0x0500
+#define PCI_CLASS_MEMORY_FLASH 0x0501
+#define PCI_CLASS_MEMORY_OTHER 0x0580
+
+#define PCI_BASE_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_HOST 0x0600
+#define PCI_CLASS_BRIDGE_ISA 0x0601
+#define PCI_CLASS_BRIDGE_EISA 0x0602
+#define PCI_CLASS_BRIDGE_MC 0x0603
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+#define PCI_CLASS_BRIDGE_PCMCIA 0x0605
+#define PCI_CLASS_BRIDGE_NUBUS 0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS 0x0607
+#define PCI_CLASS_BRIDGE_RACEWAY 0x0608
+#define PCI_CLASS_BRIDGE_OTHER 0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION 0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
+#define PCI_CLASS_COMMUNICATION_MODEM 0x0703
+#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
+
+#define PCI_BASE_CLASS_SYSTEM 0x08
+#define PCI_CLASS_SYSTEM_PIC 0x0800
+#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010
+#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020
+#define PCI_CLASS_SYSTEM_DMA 0x0801
+#define PCI_CLASS_SYSTEM_TIMER 0x0802
+#define PCI_CLASS_SYSTEM_RTC 0x0803
+#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804
+#define PCI_CLASS_SYSTEM_SDHCI 0x0805
+#define PCI_CLASS_SYSTEM_OTHER 0x0880
+
+#define PCI_BASE_CLASS_INPUT 0x09
+#define PCI_CLASS_INPUT_KEYBOARD 0x0900
+#define PCI_CLASS_INPUT_PEN 0x0901
+#define PCI_CLASS_INPUT_MOUSE 0x0902
+#define PCI_CLASS_INPUT_SCANNER 0x0903
+#define PCI_CLASS_INPUT_GAMEPORT 0x0904
+#define PCI_CLASS_INPUT_OTHER 0x0980
+
+#define PCI_BASE_CLASS_DOCKING 0x0a
+#define PCI_CLASS_DOCKING_GENERIC 0x0a00
+#define PCI_CLASS_DOCKING_OTHER 0x0a80
+
+#define PCI_BASE_CLASS_PROCESSOR 0x0b
+#define PCI_CLASS_PROCESSOR_386 0x0b00
+#define PCI_CLASS_PROCESSOR_486 0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
+#define PCI_CLASS_PROCESSOR_MIPS 0x0b30
+#define PCI_CLASS_PROCESSOR_CO 0x0b40
+
+#define PCI_BASE_CLASS_SERIAL 0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
+#define PCI_CLASS_SERIAL_FIREWIRE_OHCI 0x0c0010
+#define PCI_CLASS_SERIAL_ACCESS 0x0c01
+#define PCI_CLASS_SERIAL_SSA 0x0c02
+#define PCI_CLASS_SERIAL_USB 0x0c03
+#define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310
+#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320
+#define PCI_CLASS_SERIAL_FIBER 0x0c04
+#define PCI_CLASS_SERIAL_SMBUS 0x0c05
+
+#define PCI_BASE_CLASS_WIRELESS 0x0d
+#define PCI_CLASS_WIRELESS_RF_CONTROLLER 0x0d10
+#define PCI_CLASS_WIRELESS_WHCI 0x0d1010
+
+#define PCI_BASE_CLASS_INTELLIGENT 0x0e
+#define PCI_CLASS_INTELLIGENT_I2O 0x0e00
+
+#define PCI_BASE_CLASS_SATELLITE 0x0f
+#define PCI_CLASS_SATELLITE_TV 0x0f00
+#define PCI_CLASS_SATELLITE_AUDIO 0x0f01
+#define PCI_CLASS_SATELLITE_VOICE 0x0f03
+#define PCI_CLASS_SATELLITE_DATA 0x0f04
+
+#define PCI_BASE_CLASS_CRYPT 0x10
+#define PCI_CLASS_CRYPT_NETWORK 0x1000
+#define PCI_CLASS_CRYPT_ENTERTAINMENT 0x1001
+#define PCI_CLASS_CRYPT_OTHER 0x1080
+
+#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11
+#define PCI_CLASS_SP_DPIO 0x1100
+#define PCI_CLASS_SP_OTHER 0x1180
+
+#define PCI_CLASS_OTHERS 0xff
+
+/* Vendors and devices. Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_TTTECH 0x0357
+#define PCI_DEVICE_ID_TTTECH_MC322 0x000a
+
+#define PCI_VENDOR_ID_DYNALINK 0x0675
+#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702
+
+#define PCI_VENDOR_ID_BERKOM 0x0871
+#define PCI_DEVICE_ID_BERKOM_A1T 0xffa1
+#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xffa2
+#define PCI_DEVICE_ID_BERKOM_A4T 0xffa4
+#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xffa8
+
+#define PCI_VENDOR_ID_COMPAQ 0x0e11
+#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508
+#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc
+#define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae10
+#define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32
+#define PCI_DEVICE_ID_COMPAQ_NETEL10 0xae34
+#define PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE 0xae33
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I 0xae35
+#define PCI_DEVICE_ID_COMPAQ_NETEL100D 0xae40
+#define PCI_DEVICE_ID_COMPAQ_NETEL100PI 0xae43
+#define PCI_DEVICE_ID_COMPAQ_NETEL100I 0xb011
+#define PCI_DEVICE_ID_COMPAQ_CISS 0xb060
+#define PCI_DEVICE_ID_COMPAQ_CISSB 0xb178
+#define PCI_DEVICE_ID_COMPAQ_CISSC 0x46
+#define PCI_DEVICE_ID_COMPAQ_THUNDER 0xf130
+#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B 0xf150
+
+#define PCI_VENDOR_ID_NCR 0x1000
+#define PCI_VENDOR_ID_LSI_LOGIC 0x1000
+#define PCI_DEVICE_ID_NCR_53C810 0x0001
+#define PCI_DEVICE_ID_NCR_53C820 0x0002
+#define PCI_DEVICE_ID_NCR_53C825 0x0003
+#define PCI_DEVICE_ID_NCR_53C815 0x0004
+#define PCI_DEVICE_ID_LSI_53C810AP 0x0005
+#define PCI_DEVICE_ID_NCR_53C860 0x0006
+#define PCI_DEVICE_ID_LSI_53C1510 0x000a
+#define PCI_DEVICE_ID_NCR_53C896 0x000b
+#define PCI_DEVICE_ID_NCR_53C895 0x000c
+#define PCI_DEVICE_ID_NCR_53C885 0x000d
+#define PCI_DEVICE_ID_NCR_53C875 0x000f
+#define PCI_DEVICE_ID_NCR_53C1510 0x0010
+#define PCI_DEVICE_ID_LSI_53C895A 0x0012
+#define PCI_DEVICE_ID_LSI_53C875A 0x0013
+#define PCI_DEVICE_ID_LSI_53C1010_33 0x0020
+#define PCI_DEVICE_ID_LSI_53C1010_66 0x0021
+#define PCI_DEVICE_ID_LSI_53C1030 0x0030
+#define PCI_DEVICE_ID_LSI_1030_53C1035 0x0032
+#define PCI_DEVICE_ID_LSI_53C1035 0x0040
+#define PCI_DEVICE_ID_NCR_53C875J 0x008f
+#define PCI_DEVICE_ID_LSI_FC909 0x0621
+#define PCI_DEVICE_ID_LSI_FC929 0x0622
+#define PCI_DEVICE_ID_LSI_FC929_LAN 0x0623
+#define PCI_DEVICE_ID_LSI_FC919 0x0624
+#define PCI_DEVICE_ID_LSI_FC919_LAN 0x0625
+#define PCI_DEVICE_ID_LSI_FC929X 0x0626
+#define PCI_DEVICE_ID_LSI_FC939X 0x0642
+#define PCI_DEVICE_ID_LSI_FC949X 0x0640
+#define PCI_DEVICE_ID_LSI_FC949ES 0x0646
+#define PCI_DEVICE_ID_LSI_FC919X 0x0628
+#define PCI_DEVICE_ID_NCR_YELLOWFIN 0x0701
+#define PCI_DEVICE_ID_LSI_61C102 0x0901
+#define PCI_DEVICE_ID_LSI_63C815 0x1000
+#define PCI_DEVICE_ID_LSI_SAS1064 0x0050
+#define PCI_DEVICE_ID_LSI_SAS1064R 0x0411
+#define PCI_DEVICE_ID_LSI_SAS1066 0x005E
+#define PCI_DEVICE_ID_LSI_SAS1068 0x0054
+#define PCI_DEVICE_ID_LSI_SAS1064A 0x005C
+#define PCI_DEVICE_ID_LSI_SAS1064E 0x0056
+#define PCI_DEVICE_ID_LSI_SAS1066E 0x005A
+#define PCI_DEVICE_ID_LSI_SAS1068E 0x0058
+#define PCI_DEVICE_ID_LSI_SAS1078 0x0060
+
+#define PCI_VENDOR_ID_ATI 0x1002
+/* Mach64 */
+#define PCI_DEVICE_ID_ATI_68800 0x4158
+#define PCI_DEVICE_ID_ATI_215CT222 0x4354
+#define PCI_DEVICE_ID_ATI_210888CX 0x4358
+#define PCI_DEVICE_ID_ATI_215ET222 0x4554
+/* Mach64 / Rage */
+#define PCI_DEVICE_ID_ATI_215GB 0x4742
+#define PCI_DEVICE_ID_ATI_215GD 0x4744
+#define PCI_DEVICE_ID_ATI_215GI 0x4749
+#define PCI_DEVICE_ID_ATI_215GP 0x4750
+#define PCI_DEVICE_ID_ATI_215GQ 0x4751
+#define PCI_DEVICE_ID_ATI_215XL 0x4752
+#define PCI_DEVICE_ID_ATI_215GT 0x4754
+#define PCI_DEVICE_ID_ATI_215GTB 0x4755
+#define PCI_DEVICE_ID_ATI_215_IV 0x4756
+#define PCI_DEVICE_ID_ATI_215_IW 0x4757
+#define PCI_DEVICE_ID_ATI_215_IZ 0x475A
+#define PCI_DEVICE_ID_ATI_210888GX 0x4758
+#define PCI_DEVICE_ID_ATI_215_LB 0x4c42
+#define PCI_DEVICE_ID_ATI_215_LD 0x4c44
+#define PCI_DEVICE_ID_ATI_215_LG 0x4c47
+#define PCI_DEVICE_ID_ATI_215_LI 0x4c49
+#define PCI_DEVICE_ID_ATI_215_LM 0x4c4D
+#define PCI_DEVICE_ID_ATI_215_LN 0x4c4E
+#define PCI_DEVICE_ID_ATI_215_LR 0x4c52
+#define PCI_DEVICE_ID_ATI_215_LS 0x4c53
+#define PCI_DEVICE_ID_ATI_264_LT 0x4c54
+/* Mach64 VT */
+#define PCI_DEVICE_ID_ATI_264VT 0x5654
+#define PCI_DEVICE_ID_ATI_264VU 0x5655
+#define PCI_DEVICE_ID_ATI_264VV 0x5656
+/* Rage128 GL */
+#define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245
+#define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246
+#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247
+/* Rage128 VR */
+#define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b
+#define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c
+#define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345
+#define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346
+#define PCI_DEVICE_ID_ATI_RAGE128_SG 0x5347
+#define PCI_DEVICE_ID_ATI_RAGE128_SH 0x5348
+#define PCI_DEVICE_ID_ATI_RAGE128_SK 0x534b
+#define PCI_DEVICE_ID_ATI_RAGE128_SL 0x534c
+#define PCI_DEVICE_ID_ATI_RAGE128_SM 0x534d
+#define PCI_DEVICE_ID_ATI_RAGE128_SN 0x534e
+/* Rage128 Ultra */
+#define PCI_DEVICE_ID_ATI_RAGE128_TF 0x5446
+#define PCI_DEVICE_ID_ATI_RAGE128_TL 0x544c
+#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452
+#define PCI_DEVICE_ID_ATI_RAGE128_TS 0x5453
+#define PCI_DEVICE_ID_ATI_RAGE128_TT 0x5454
+#define PCI_DEVICE_ID_ATI_RAGE128_TU 0x5455
+/* Rage128 M3 */
+#define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45
+#define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46
+/* Rage128 M4 */
+#define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46
+#define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c
+/* Rage128 Pro GL */
+#define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041
+#define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042
+#define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043
+#define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044
+#define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045
+#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046
+/* Rage128 Pro VR */
+#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047
+#define PCI_DEVICE_ID_ATI_RAGE128_PH 0x5048
+#define PCI_DEVICE_ID_ATI_RAGE128_PI 0x5049
+#define PCI_DEVICE_ID_ATI_RAGE128_PJ 0x504A
+#define PCI_DEVICE_ID_ATI_RAGE128_PK 0x504B
+#define PCI_DEVICE_ID_ATI_RAGE128_PL 0x504C
+#define PCI_DEVICE_ID_ATI_RAGE128_PM 0x504D
+#define PCI_DEVICE_ID_ATI_RAGE128_PN 0x504E
+#define PCI_DEVICE_ID_ATI_RAGE128_PO 0x504F
+#define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050
+#define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051
+#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052
+#define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053
+#define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054
+#define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055
+#define PCI_DEVICE_ID_ATI_RAGE128_PV 0x5056
+#define PCI_DEVICE_ID_ATI_RAGE128_PW 0x5057
+#define PCI_DEVICE_ID_ATI_RAGE128_PX 0x5058
+/* Rage128 M4 */
+/* Radeon R100 */
+#define PCI_DEVICE_ID_ATI_RADEON_QD 0x5144
+#define PCI_DEVICE_ID_ATI_RADEON_QE 0x5145
+#define PCI_DEVICE_ID_ATI_RADEON_QF 0x5146
+#define PCI_DEVICE_ID_ATI_RADEON_QG 0x5147
+/* Radeon RV100 (VE) */
+#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
+#define PCI_DEVICE_ID_ATI_RADEON_QZ 0x515a
+/* Radeon R200 (8500) */
+#define PCI_DEVICE_ID_ATI_RADEON_QL 0x514c
+#define PCI_DEVICE_ID_ATI_RADEON_QN 0x514e
+#define PCI_DEVICE_ID_ATI_RADEON_QO 0x514f
+#define PCI_DEVICE_ID_ATI_RADEON_Ql 0x516c
+#define PCI_DEVICE_ID_ATI_RADEON_BB 0x4242
+/* Radeon R200 (9100) */
+#define PCI_DEVICE_ID_ATI_RADEON_QM 0x514d
+/* Radeon RV200 (7500) */
+#define PCI_DEVICE_ID_ATI_RADEON_QW 0x5157
+#define PCI_DEVICE_ID_ATI_RADEON_QX 0x5158
+/* Radeon NV-100 */
+/* Radeon RV250 (9000) */
+#define PCI_DEVICE_ID_ATI_RADEON_Id 0x4964
+#define PCI_DEVICE_ID_ATI_RADEON_Ie 0x4965
+#define PCI_DEVICE_ID_ATI_RADEON_If 0x4966
+#define PCI_DEVICE_ID_ATI_RADEON_Ig 0x4967
+/* Radeon RV280 (9200) */
+#define PCI_DEVICE_ID_ATI_RADEON_Ya 0x5961
+#define PCI_DEVICE_ID_ATI_RADEON_Yd 0x5964
+/* Radeon R300 (9500) */
+/* Radeon R300 (9700) */
+#define PCI_DEVICE_ID_ATI_RADEON_ND 0x4e44
+#define PCI_DEVICE_ID_ATI_RADEON_NE 0x4e45
+#define PCI_DEVICE_ID_ATI_RADEON_NF 0x4e46
+#define PCI_DEVICE_ID_ATI_RADEON_NG 0x4e47
+/* Radeon R350 (9800) */
+/* Radeon RV350 (9600) */
+/* Radeon M6 */
+#define PCI_DEVICE_ID_ATI_RADEON_LY 0x4c59
+#define PCI_DEVICE_ID_ATI_RADEON_LZ 0x4c5a
+/* Radeon M7 */
+#define PCI_DEVICE_ID_ATI_RADEON_LW 0x4c57
+#define PCI_DEVICE_ID_ATI_RADEON_LX 0x4c58
+/* Radeon M9 */
+#define PCI_DEVICE_ID_ATI_RADEON_Ld 0x4c64
+#define PCI_DEVICE_ID_ATI_RADEON_Le 0x4c65
+#define PCI_DEVICE_ID_ATI_RADEON_Lf 0x4c66
+#define PCI_DEVICE_ID_ATI_RADEON_Lg 0x4c67
+/* Radeon */
+/* RadeonIGP */
+#define PCI_DEVICE_ID_ATI_RS100 0xcab0
+#define PCI_DEVICE_ID_ATI_RS200 0xcab2
+#define PCI_DEVICE_ID_ATI_RS200_B 0xcbb2
+#define PCI_DEVICE_ID_ATI_RS250 0xcab3
+#define PCI_DEVICE_ID_ATI_RS300_100 0x5830
+#define PCI_DEVICE_ID_ATI_RS300_133 0x5831
+#define PCI_DEVICE_ID_ATI_RS300_166 0x5832
+#define PCI_DEVICE_ID_ATI_RS300_200 0x5833
+#define PCI_DEVICE_ID_ATI_RS350_100 0x7830
+#define PCI_DEVICE_ID_ATI_RS350_133 0x7831
+#define PCI_DEVICE_ID_ATI_RS350_166 0x7832
+#define PCI_DEVICE_ID_ATI_RS350_200 0x7833
+#define PCI_DEVICE_ID_ATI_RS400_100 0x5a30
+#define PCI_DEVICE_ID_ATI_RS400_133 0x5a31
+#define PCI_DEVICE_ID_ATI_RS400_166 0x5a32
+#define PCI_DEVICE_ID_ATI_RS400_200 0x5a33
+#define PCI_DEVICE_ID_ATI_RS480 0x5950
+/* ATI IXP Chipset */
+#define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349
+#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353
+#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363
+#define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369
+#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e
+#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372
+#define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376
+#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379
+#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a
+#define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380
+#define PCI_DEVICE_ID_ATI_SBX00_SMBUS 0x4385
+#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c
+#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390
+#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c
+
+#define PCI_VENDOR_ID_VLSI 0x1004
+#define PCI_DEVICE_ID_VLSI_82C592 0x0005
+#define PCI_DEVICE_ID_VLSI_82C593 0x0006
+#define PCI_DEVICE_ID_VLSI_82C594 0x0007
+#define PCI_DEVICE_ID_VLSI_82C597 0x0009
+#define PCI_DEVICE_ID_VLSI_82C541 0x000c
+#define PCI_DEVICE_ID_VLSI_82C543 0x000d
+#define PCI_DEVICE_ID_VLSI_82C532 0x0101
+#define PCI_DEVICE_ID_VLSI_82C534 0x0102
+#define PCI_DEVICE_ID_VLSI_82C535 0x0104
+#define PCI_DEVICE_ID_VLSI_82C147 0x0105
+#define PCI_DEVICE_ID_VLSI_VAS96011 0x0702
+
+#define PCI_VENDOR_ID_ADL 0x1005
+#define PCI_DEVICE_ID_ADL_2301 0x2301
+
+#define PCI_VENDOR_ID_NS 0x100b
+#define PCI_DEVICE_ID_NS_87415 0x0002
+#define PCI_DEVICE_ID_NS_87560_LIO 0x000e
+#define PCI_DEVICE_ID_NS_87560_USB 0x0012
+#define PCI_DEVICE_ID_NS_83815 0x0020
+#define PCI_DEVICE_ID_NS_83820 0x0022
+#define PCI_DEVICE_ID_NS_CS5535_ISA 0x002b
+#define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d
+#define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e
+#define PCI_DEVICE_ID_NS_CS5535_USB 0x002f
+#define PCI_DEVICE_ID_NS_GX_VIDEO 0x0030
+#define PCI_DEVICE_ID_NS_SATURN 0x0035
+#define PCI_DEVICE_ID_NS_SCx200_BRIDGE 0x0500
+#define PCI_DEVICE_ID_NS_SCx200_SMI 0x0501
+#define PCI_DEVICE_ID_NS_SCx200_IDE 0x0502
+#define PCI_DEVICE_ID_NS_SCx200_AUDIO 0x0503
+#define PCI_DEVICE_ID_NS_SCx200_VIDEO 0x0504
+#define PCI_DEVICE_ID_NS_SCx200_XBUS 0x0505
+#define PCI_DEVICE_ID_NS_SC1100_BRIDGE 0x0510
+#define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511
+#define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515
+#define PCI_DEVICE_ID_NS_87410 0xd001
+
+#define PCI_DEVICE_ID_NS_GX_HOST_BRIDGE 0x0028
+
+#define PCI_VENDOR_ID_TSENG 0x100c
+#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202
+#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205
+#define PCI_DEVICE_ID_TSENG_W32P_c 0x3206
+#define PCI_DEVICE_ID_TSENG_W32P_d 0x3207
+#define PCI_DEVICE_ID_TSENG_ET6000 0x3208
+
+#define PCI_VENDOR_ID_WEITEK 0x100e
+#define PCI_DEVICE_ID_WEITEK_P9000 0x9001
+#define PCI_DEVICE_ID_WEITEK_P9100 0x9100
+
+#define PCI_VENDOR_ID_DEC 0x1011
+#define PCI_DEVICE_ID_DEC_BRD 0x0001
+#define PCI_DEVICE_ID_DEC_TULIP 0x0002
+#define PCI_DEVICE_ID_DEC_TGA 0x0004
+#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
+#define PCI_DEVICE_ID_DEC_TGA2 0x000D
+#define PCI_DEVICE_ID_DEC_FDDI 0x000F
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
+#define PCI_DEVICE_ID_DEC_21142 0x0019
+#define PCI_DEVICE_ID_DEC_21052 0x0021
+#define PCI_DEVICE_ID_DEC_21150 0x0022
+#define PCI_DEVICE_ID_DEC_21152 0x0024
+#define PCI_DEVICE_ID_DEC_21153 0x0025
+#define PCI_DEVICE_ID_DEC_21154 0x0026
+#define PCI_DEVICE_ID_DEC_21285 0x1065
+#define PCI_DEVICE_ID_COMPAQ_42XX 0x0046
+
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+#define PCI_DEVICE_ID_CIRRUS_7548 0x0038
+#define PCI_DEVICE_ID_CIRRUS_5430 0x00a0
+#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4
+#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8
+#define PCI_DEVICE_ID_CIRRUS_5436 0x00ac
+#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8
+#define PCI_DEVICE_ID_CIRRUS_5480 0x00bc
+#define PCI_DEVICE_ID_CIRRUS_5462 0x00d0
+#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4
+#define PCI_DEVICE_ID_CIRRUS_5465 0x00d6
+#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
+#define PCI_DEVICE_ID_CIRRUS_6832 0x1110
+#define PCI_DEVICE_ID_CIRRUS_7543 0x1202
+#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
+#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
+#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
+
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_DEVICE_ID_IBM_TR 0x0018
+#define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e
+#define PCI_DEVICE_ID_IBM_CPC710_PCI64 0x00fc
+#define PCI_DEVICE_ID_IBM_SNIPE 0x0180
+#define PCI_DEVICE_ID_IBM_CITRINE 0x028C
+#define PCI_DEVICE_ID_IBM_GEMSTONE 0xB166
+#define PCI_DEVICE_ID_IBM_OBSIDIAN 0x02BD
+#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1 0x0031
+#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2 0x0219
+#define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX 0x021A
+#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM 0x0251
+#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361
+#define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252
+
+#define PCI_VENDOR_ID_UNISYS 0x1018
+#define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C
+
+#define PCI_VENDOR_ID_COMPEX2 0x101a /* pci.ids says "AT&T GIS (NCR)" */
+#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005
+
+#define PCI_VENDOR_ID_WD 0x101c
+#define PCI_DEVICE_ID_WD_90C 0xc24a
+
+#define PCI_VENDOR_ID_AMI 0x101e
+#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960
+#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010
+#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060
+
+#define PCI_VENDOR_ID_AMD 0x1022
+#define PCI_DEVICE_ID_AMD_K8_NB 0x1100
+#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP 0x1101
+#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL 0x1102
+#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103
+#define PCI_DEVICE_ID_AMD_10H_NB_HT 0x1200
+#define PCI_DEVICE_ID_AMD_10H_NB_MAP 0x1201
+#define PCI_DEVICE_ID_AMD_10H_NB_DRAM 0x1202
+#define PCI_DEVICE_ID_AMD_10H_NB_MISC 0x1203
+#define PCI_DEVICE_ID_AMD_10H_NB_LINK 0x1204
+#define PCI_DEVICE_ID_AMD_11H_NB_HT 0x1300
+#define PCI_DEVICE_ID_AMD_11H_NB_MAP 0x1301
+#define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302
+#define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303
+#define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304
+#define PCI_DEVICE_ID_AMD_LANCE 0x2000
+#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
+#define PCI_DEVICE_ID_AMD_SCSI 0x2020
+#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0
+#define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006
+#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007
+#define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C
+#define PCI_DEVICE_ID_AMD_FE_GATE_700E 0x700E
+#define PCI_DEVICE_ID_AMD_COBRA_7401 0x7401
+#define PCI_DEVICE_ID_AMD_VIPER_7409 0x7409
+#define PCI_DEVICE_ID_AMD_VIPER_740B 0x740B
+#define PCI_DEVICE_ID_AMD_VIPER_7410 0x7410
+#define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411
+#define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413
+#define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440
+#define PCI_DEVICE_ID_AMD_OPUS_7441 0x7441
+#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443
+#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443
+#define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445
+#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468
+#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
+#define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a
+#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b
+#define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d
+#define PCI_DEVICE_ID_AMD_8151_0 0x7454
+#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
+#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
+#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
+#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
+#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
+#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
+#define PCI_DEVICE_ID_AMD_CS5536_OHC 0x2094
+#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095
+#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096
+#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
+#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
+
+#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081
+#define PCI_DEVICE_ID_AMD_LX_AES 0x2082
+
+#define PCI_VENDOR_ID_TRIDENT 0x1023
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
+#define PCI_DEVICE_ID_TRIDENT_9320 0x9320
+#define PCI_DEVICE_ID_TRIDENT_9388 0x9388
+#define PCI_DEVICE_ID_TRIDENT_9397 0x9397
+#define PCI_DEVICE_ID_TRIDENT_939A 0x939A
+#define PCI_DEVICE_ID_TRIDENT_9520 0x9520
+#define PCI_DEVICE_ID_TRIDENT_9525 0x9525
+#define PCI_DEVICE_ID_TRIDENT_9420 0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440 0x9440
+#define PCI_DEVICE_ID_TRIDENT_9660 0x9660
+#define PCI_DEVICE_ID_TRIDENT_9750 0x9750
+#define PCI_DEVICE_ID_TRIDENT_9850 0x9850
+#define PCI_DEVICE_ID_TRIDENT_9880 0x9880
+#define PCI_DEVICE_ID_TRIDENT_8400 0x8400
+#define PCI_DEVICE_ID_TRIDENT_8420 0x8420
+#define PCI_DEVICE_ID_TRIDENT_8500 0x8500
+
+#define PCI_VENDOR_ID_AI 0x1025
+#define PCI_DEVICE_ID_AI_M1435 0x1435
+
+#define PCI_VENDOR_ID_DELL 0x1028
+#define PCI_DEVICE_ID_DELL_RACIII 0x0008
+#define PCI_DEVICE_ID_DELL_RAC4 0x0012
+#define PCI_DEVICE_ID_DELL_PERC5 0x0015
+
+#define PCI_VENDOR_ID_MATROX 0x102B
+#define PCI_DEVICE_ID_MATROX_MGA_2 0x0518
+#define PCI_DEVICE_ID_MATROX_MIL 0x0519
+#define PCI_DEVICE_ID_MATROX_MYS 0x051A
+#define PCI_DEVICE_ID_MATROX_MIL_2 0x051b
+#define PCI_DEVICE_ID_MATROX_MYS_AGP 0x051e
+#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f
+#define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10
+#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000
+#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
+#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
+#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
+#define PCI_DEVICE_ID_MATROX_G400 0x0525
+#define PCI_DEVICE_ID_MATROX_G200EV_PCI 0x0530
+#define PCI_DEVICE_ID_MATROX_G550 0x2527
+#define PCI_DEVICE_ID_MATROX_VIA 0x4536
+
+#define PCI_VENDOR_ID_CT 0x102c
+#define PCI_DEVICE_ID_CT_69000 0x00c0
+#define PCI_DEVICE_ID_CT_65545 0x00d8
+#define PCI_DEVICE_ID_CT_65548 0x00dc
+#define PCI_DEVICE_ID_CT_65550 0x00e0
+#define PCI_DEVICE_ID_CT_65554 0x00e4
+#define PCI_DEVICE_ID_CT_65555 0x00e5
+
+#define PCI_VENDOR_ID_MIRO 0x1031
+#define PCI_DEVICE_ID_MIRO_36050 0x5601
+#define PCI_DEVICE_ID_MIRO_DC10PLUS 0x7efe
+#define PCI_DEVICE_ID_MIRO_DC30PLUS 0xd801
+
+#define PCI_VENDOR_ID_NEC 0x1033
+#define PCI_DEVICE_ID_NEC_CBUS_1 0x0001 /* PCI-Cbus Bridge */
+#define PCI_DEVICE_ID_NEC_LOCAL 0x0002 /* Local Bridge */
+#define PCI_DEVICE_ID_NEC_ATM 0x0003 /* ATM LAN Controller */
+#define PCI_DEVICE_ID_NEC_R4000 0x0004 /* R4000 Bridge */
+#define PCI_DEVICE_ID_NEC_486 0x0005 /* 486 Like Peripheral Bus Bridge */
+#define PCI_DEVICE_ID_NEC_ACCEL_1 0x0006 /* Graphic Accelerator */
+#define PCI_DEVICE_ID_NEC_UXBUS 0x0007 /* UX-Bus Bridge */
+#define PCI_DEVICE_ID_NEC_ACCEL_2 0x0008 /* Graphic Accelerator */
+#define PCI_DEVICE_ID_NEC_GRAPH 0x0009 /* PCI-CoreGraph Bridge */
+#define PCI_DEVICE_ID_NEC_VL 0x0016 /* PCI-VL Bridge */
+#define PCI_DEVICE_ID_NEC_STARALPHA2 0x002c /* STAR ALPHA2 */
+#define PCI_DEVICE_ID_NEC_CBUS_2 0x002d /* PCI-Cbus Bridge */
+#define PCI_DEVICE_ID_NEC_USB 0x0035 /* PCI-USB Host */
+#define PCI_DEVICE_ID_NEC_CBUS_3 0x003b
+#define PCI_DEVICE_ID_NEC_NAPCCARD 0x003e
+#define PCI_DEVICE_ID_NEC_PCX2 0x0046 /* PowerVR */
+#define PCI_DEVICE_ID_NEC_VRC5476 0x009b
+#define PCI_DEVICE_ID_NEC_VRC4173 0x00a5
+#define PCI_DEVICE_ID_NEC_VRC5477_AC97 0x00a6
+#define PCI_DEVICE_ID_NEC_PC9821CS01 0x800c /* PC-9821-CS01 */
+#define PCI_DEVICE_ID_NEC_PC9821NRB06 0x800d /* PC-9821NR-B06 */
+
+#define PCI_VENDOR_ID_FD 0x1036
+#define PCI_DEVICE_ID_FD_36C70 0x0000
+
+#define PCI_VENDOR_ID_SI 0x1039
+#define PCI_DEVICE_ID_SI_5591_AGP 0x0001
+#define PCI_DEVICE_ID_SI_6202 0x0002
+#define PCI_DEVICE_ID_SI_503 0x0008
+#define PCI_DEVICE_ID_SI_ACPI 0x0009
+#define PCI_DEVICE_ID_SI_SMBUS 0x0016
+#define PCI_DEVICE_ID_SI_LPC 0x0018
+#define PCI_DEVICE_ID_SI_5597_VGA 0x0200
+#define PCI_DEVICE_ID_SI_6205 0x0205
+#define PCI_DEVICE_ID_SI_501 0x0406
+#define PCI_DEVICE_ID_SI_496 0x0496
+#define PCI_DEVICE_ID_SI_300 0x0300
+#define PCI_DEVICE_ID_SI_315H 0x0310
+#define PCI_DEVICE_ID_SI_315 0x0315
+#define PCI_DEVICE_ID_SI_315PRO 0x0325
+#define PCI_DEVICE_ID_SI_530 0x0530
+#define PCI_DEVICE_ID_SI_540 0x0540
+#define PCI_DEVICE_ID_SI_550 0x0550
+#define PCI_DEVICE_ID_SI_540_VGA 0x5300
+#define PCI_DEVICE_ID_SI_550_VGA 0x5315
+#define PCI_DEVICE_ID_SI_620 0x0620
+#define PCI_DEVICE_ID_SI_630 0x0630
+#define PCI_DEVICE_ID_SI_633 0x0633
+#define PCI_DEVICE_ID_SI_635 0x0635
+#define PCI_DEVICE_ID_SI_640 0x0640
+#define PCI_DEVICE_ID_SI_645 0x0645
+#define PCI_DEVICE_ID_SI_646 0x0646
+#define PCI_DEVICE_ID_SI_648 0x0648
+#define PCI_DEVICE_ID_SI_650 0x0650
+#define PCI_DEVICE_ID_SI_651 0x0651
+#define PCI_DEVICE_ID_SI_655 0x0655
+#define PCI_DEVICE_ID_SI_661 0x0661
+#define PCI_DEVICE_ID_SI_730 0x0730
+#define PCI_DEVICE_ID_SI_733 0x0733
+#define PCI_DEVICE_ID_SI_630_VGA 0x6300
+#define PCI_DEVICE_ID_SI_735 0x0735
+#define PCI_DEVICE_ID_SI_740 0x0740
+#define PCI_DEVICE_ID_SI_741 0x0741
+#define PCI_DEVICE_ID_SI_745 0x0745
+#define PCI_DEVICE_ID_SI_746 0x0746
+#define PCI_DEVICE_ID_SI_755 0x0755
+#define PCI_DEVICE_ID_SI_760 0x0760
+#define PCI_DEVICE_ID_SI_900 0x0900
+#define PCI_DEVICE_ID_SI_961 0x0961
+#define PCI_DEVICE_ID_SI_962 0x0962
+#define PCI_DEVICE_ID_SI_963 0x0963
+#define PCI_DEVICE_ID_SI_965 0x0965
+#define PCI_DEVICE_ID_SI_966 0x0966
+#define PCI_DEVICE_ID_SI_968 0x0968
+#define PCI_DEVICE_ID_SI_1180 0x1180
+#define PCI_DEVICE_ID_SI_5511 0x5511
+#define PCI_DEVICE_ID_SI_5513 0x5513
+#define PCI_DEVICE_ID_SI_5517 0x5517
+#define PCI_DEVICE_ID_SI_5518 0x5518
+#define PCI_DEVICE_ID_SI_5571 0x5571
+#define PCI_DEVICE_ID_SI_5581 0x5581
+#define PCI_DEVICE_ID_SI_5582 0x5582
+#define PCI_DEVICE_ID_SI_5591 0x5591
+#define PCI_DEVICE_ID_SI_5596 0x5596
+#define PCI_DEVICE_ID_SI_5597 0x5597
+#define PCI_DEVICE_ID_SI_5598 0x5598
+#define PCI_DEVICE_ID_SI_5600 0x5600
+#define PCI_DEVICE_ID_SI_7012 0x7012
+#define PCI_DEVICE_ID_SI_7013 0x7013
+#define PCI_DEVICE_ID_SI_7016 0x7016
+#define PCI_DEVICE_ID_SI_7018 0x7018
+
+#define PCI_VENDOR_ID_HP 0x103c
+#define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008
+#define PCI_DEVICE_ID_HP_VISUALIZE_FX2 0x100a
+#define PCI_DEVICE_ID_HP_TACHYON 0x1028
+#define PCI_DEVICE_ID_HP_TACHLITE 0x1029
+#define PCI_DEVICE_ID_HP_J2585A 0x1030
+#define PCI_DEVICE_ID_HP_J2585B 0x1031
+#define PCI_DEVICE_ID_HP_J2973A 0x1040
+#define PCI_DEVICE_ID_HP_J2970A 0x1042
+#define PCI_DEVICE_ID_HP_DIVA 0x1048
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A
+#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B
+#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1
+#define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b
+#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223
+#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226
+#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227
+#define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a
+#define PCI_DEVICE_ID_HP_PCIX_LBA 0x122e
+#define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c
+#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282
+#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290
+#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301
+#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a
+#define PCI_DEVICE_ID_HP_CISSA 0x3220
+#define PCI_DEVICE_ID_HP_CISSC 0x3230
+#define PCI_DEVICE_ID_HP_CISSD 0x3238
+#define PCI_DEVICE_ID_HP_CISSE 0x323a
+#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031
+
+#define PCI_VENDOR_ID_PCTECH 0x1042
+#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000
+#define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001
+#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
+
+#define PCI_VENDOR_ID_ASUSTEK 0x1043
+#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675
+
+#define PCI_VENDOR_ID_DPT 0x1044
+#define PCI_DEVICE_ID_DPT 0xa400
+
+#define PCI_VENDOR_ID_OPTI 0x1045
+#define PCI_DEVICE_ID_OPTI_82C558 0xc558
+#define PCI_DEVICE_ID_OPTI_82C621 0xc621
+#define PCI_DEVICE_ID_OPTI_82C700 0xc700
+#define PCI_DEVICE_ID_OPTI_82C825 0xd568
+
+#define PCI_VENDOR_ID_ELSA 0x1048
+#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
+#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
+
+#define PCI_VENDOR_ID_BUSLOGIC 0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040
+#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130
+
+#define PCI_VENDOR_ID_TI 0x104c
+#define PCI_DEVICE_ID_TI_TVP4020 0x3d07
+#define PCI_DEVICE_ID_TI_4450 0x8011
+#define PCI_DEVICE_ID_TI_TSB43AB22 0x8023
+#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
+#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033
+#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034
+#define PCI_DEVICE_ID_TI_X515 0x8036
+#define PCI_DEVICE_ID_TI_XX12 0x8039
+#define PCI_DEVICE_ID_TI_XX12_FM 0x803b
+#define PCI_DEVICE_ID_TI_1130 0xac12
+#define PCI_DEVICE_ID_TI_1031 0xac13
+#define PCI_DEVICE_ID_TI_1131 0xac15
+#define PCI_DEVICE_ID_TI_1250 0xac16
+#define PCI_DEVICE_ID_TI_1220 0xac17
+#define PCI_DEVICE_ID_TI_1221 0xac19
+#define PCI_DEVICE_ID_TI_1210 0xac1a
+#define PCI_DEVICE_ID_TI_1450 0xac1b
+#define PCI_DEVICE_ID_TI_1225 0xac1c
+#define PCI_DEVICE_ID_TI_1251A 0xac1d
+#define PCI_DEVICE_ID_TI_1211 0xac1e
+#define PCI_DEVICE_ID_TI_1251B 0xac1f
+#define PCI_DEVICE_ID_TI_4410 0xac41
+#define PCI_DEVICE_ID_TI_4451 0xac42
+#define PCI_DEVICE_ID_TI_4510 0xac44
+#define PCI_DEVICE_ID_TI_4520 0xac46
+#define PCI_DEVICE_ID_TI_7510 0xac47
+#define PCI_DEVICE_ID_TI_7610 0xac48
+#define PCI_DEVICE_ID_TI_7410 0xac49
+#define PCI_DEVICE_ID_TI_1410 0xac50
+#define PCI_DEVICE_ID_TI_1420 0xac51
+#define PCI_DEVICE_ID_TI_1451A 0xac52
+#define PCI_DEVICE_ID_TI_1620 0xac54
+#define PCI_DEVICE_ID_TI_1520 0xac55
+#define PCI_DEVICE_ID_TI_1510 0xac56
+#define PCI_DEVICE_ID_TI_X620 0xac8d
+#define PCI_DEVICE_ID_TI_X420 0xac8e
+#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f
+
+#define PCI_VENDOR_ID_SONY 0x104d
+
+/* Winbond have two vendor IDs! See 0x10ad as well */
+#define PCI_VENDOR_ID_WINBOND2 0x1050
+#define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a
+#define PCI_DEVICE_ID_WINBOND2_6692 0x6692
+
+#define PCI_VENDOR_ID_ANIGMA 0x1051
+#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100
+
+#define PCI_VENDOR_ID_EFAR 0x1055
+#define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130
+#define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463
+
+#define PCI_VENDOR_ID_MOTOROLA 0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001
+#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002
+#define PCI_DEVICE_ID_MOTOROLA_MPC107 0x0004
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801
+#define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802
+#define PCI_DEVICE_ID_MOTOROLA_HAWK 0x4803
+#define PCI_DEVICE_ID_MOTOROLA_HARRIER 0x480b
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200 0x5803
+#define PCI_DEVICE_ID_MOTOROLA_MPC5200B 0x5809
+
+#define PCI_VENDOR_ID_PROMISE 0x105a
+#define PCI_DEVICE_ID_PROMISE_20265 0x0d30
+#define PCI_DEVICE_ID_PROMISE_20267 0x4d30
+#define PCI_DEVICE_ID_PROMISE_20246 0x4d33
+#define PCI_DEVICE_ID_PROMISE_20262 0x4d38
+#define PCI_DEVICE_ID_PROMISE_20263 0x0D38
+#define PCI_DEVICE_ID_PROMISE_20268 0x4d68
+#define PCI_DEVICE_ID_PROMISE_20269 0x4d69
+#define PCI_DEVICE_ID_PROMISE_20270 0x6268
+#define PCI_DEVICE_ID_PROMISE_20271 0x6269
+#define PCI_DEVICE_ID_PROMISE_20275 0x1275
+#define PCI_DEVICE_ID_PROMISE_20276 0x5275
+#define PCI_DEVICE_ID_PROMISE_20277 0x7275
+
+#define PCI_VENDOR_ID_UMC 0x1060
+#define PCI_DEVICE_ID_UMC_UM8673F 0x0101
+#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a
+#define PCI_DEVICE_ID_UMC_UM8886A 0x886a
+
+#define PCI_VENDOR_ID_PICOPOWER 0x1066
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523 0x0002
+#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP 0x8002
+
+#define PCI_VENDOR_ID_MYLEX 0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960_PD 0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960_PG 0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960_LA 0x0020
+#define PCI_DEVICE_ID_MYLEX_DAC960_LP 0x0050
+#define PCI_DEVICE_ID_MYLEX_DAC960_BA 0xBA56
+#define PCI_DEVICE_ID_MYLEX_DAC960_GEM 0xB166
+
+#define PCI_VENDOR_ID_APPLE 0x106b
+#define PCI_DEVICE_ID_APPLE_BANDIT 0x0001
+#define PCI_DEVICE_ID_APPLE_HYDRA 0x000e
+#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI15 0x002e
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032
+#define PCI_DEVICE_ID_APPLE_UNI_N_ATA 0x0033
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034
+#define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b
+#define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043
+#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
+#define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c
+#define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050
+#define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051
+#define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058
+#define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059
+#define PCI_DEVICE_ID_APPLE_IPID2_AGP 0x0066
+#define PCI_DEVICE_ID_APPLE_IPID2_ATA 0x0069
+#define PCI_DEVICE_ID_APPLE_IPID2_FW 0x006a
+#define PCI_DEVICE_ID_APPLE_IPID2_GMAC 0x006b
+#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645
+
+#define PCI_VENDOR_ID_YAMAHA 0x1073
+#define PCI_DEVICE_ID_YAMAHA_724 0x0004
+#define PCI_DEVICE_ID_YAMAHA_724F 0x000d
+#define PCI_DEVICE_ID_YAMAHA_740 0x000a
+#define PCI_DEVICE_ID_YAMAHA_740C 0x000c
+#define PCI_DEVICE_ID_YAMAHA_744 0x0010
+#define PCI_DEVICE_ID_YAMAHA_754 0x0012
+
+#define PCI_VENDOR_ID_QLOGIC 0x1077
+#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016
+#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020
+#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080
+#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216
+#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240
+#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280
+#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100
+#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200
+#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300
+#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312
+#define PCI_DEVICE_ID_QLOGIC_ISP2322 0x2322
+#define PCI_DEVICE_ID_QLOGIC_ISP6312 0x6312
+#define PCI_DEVICE_ID_QLOGIC_ISP6322 0x6322
+#define PCI_DEVICE_ID_QLOGIC_ISP2422 0x2422
+#define PCI_DEVICE_ID_QLOGIC_ISP2432 0x2432
+#define PCI_DEVICE_ID_QLOGIC_ISP2512 0x2512
+#define PCI_DEVICE_ID_QLOGIC_ISP2522 0x2522
+#define PCI_DEVICE_ID_QLOGIC_ISP5422 0x5422
+#define PCI_DEVICE_ID_QLOGIC_ISP5432 0x5432
+
+#define PCI_VENDOR_ID_CYRIX 0x1078
+#define PCI_DEVICE_ID_CYRIX_5510 0x0000
+#define PCI_DEVICE_ID_CYRIX_PCI_MASTER 0x0001
+#define PCI_DEVICE_ID_CYRIX_5520 0x0002
+#define PCI_DEVICE_ID_CYRIX_5530_LEGACY 0x0100
+#define PCI_DEVICE_ID_CYRIX_5530_IDE 0x0102
+#define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103
+#define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104
+
+#define PCI_VENDOR_ID_CONTAQ 0x1080
+#define PCI_DEVICE_ID_CONTAQ_82C693 0xc693
+
+#define PCI_VENDOR_ID_OLICOM 0x108d
+#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012
+#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013
+#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014
+
+#define PCI_VENDOR_ID_SUN 0x108e
+#define PCI_DEVICE_ID_SUN_EBUS 0x1000
+#define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001
+#define PCI_DEVICE_ID_SUN_RIO_EBUS 0x1100
+#define PCI_DEVICE_ID_SUN_RIO_GEM 0x1101
+#define PCI_DEVICE_ID_SUN_RIO_1394 0x1102
+#define PCI_DEVICE_ID_SUN_RIO_USB 0x1103
+#define PCI_DEVICE_ID_SUN_GEM 0x2bad
+#define PCI_DEVICE_ID_SUN_SIMBA 0x5000
+#define PCI_DEVICE_ID_SUN_PBM 0x8000
+#define PCI_DEVICE_ID_SUN_SCHIZO 0x8001
+#define PCI_DEVICE_ID_SUN_SABRE 0xa000
+#define PCI_DEVICE_ID_SUN_HUMMINGBIRD 0xa001
+#define PCI_DEVICE_ID_SUN_TOMATILLO 0xa801
+#define PCI_DEVICE_ID_SUN_CASSINI 0xabba
+
+#define PCI_VENDOR_ID_CMD 0x1095
+#define PCI_DEVICE_ID_CMD_643 0x0643
+#define PCI_DEVICE_ID_CMD_646 0x0646
+#define PCI_DEVICE_ID_CMD_648 0x0648
+#define PCI_DEVICE_ID_CMD_649 0x0649
+
+#define PCI_DEVICE_ID_SII_680 0x0680
+#define PCI_DEVICE_ID_SII_3112 0x3112
+#define PCI_DEVICE_ID_SII_1210SA 0x0240
+
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#define PCI_DEVICE_ID_BROOKTREE_878 0x0878
+#define PCI_DEVICE_ID_BROOKTREE_879 0x0879
+
+#define PCI_VENDOR_ID_SGI 0x10a9
+#define PCI_DEVICE_ID_SGI_IOC3 0x0003
+#define PCI_DEVICE_ID_SGI_LITHIUM 0x1002
+#define PCI_DEVICE_ID_SGI_IOC4 0x100a
+
+#define PCI_VENDOR_ID_WINBOND 0x10ad
+#define PCI_DEVICE_ID_WINBOND_82C105 0x0105
+#define PCI_DEVICE_ID_WINBOND_83C553 0x0565
+
+#define PCI_VENDOR_ID_PLX 0x10b5
+#define PCI_DEVICE_ID_PLX_R685 0x1030
+#define PCI_DEVICE_ID_PLX_ROMULUS 0x106a
+#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076
+#define PCI_DEVICE_ID_PLX_1077 0x1077
+#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103
+#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151
+#define PCI_DEVICE_ID_PLX_R753 0x1152
+#define PCI_DEVICE_ID_PLX_OLITEC 0x1187
+#define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196
+#define PCI_DEVICE_ID_PLX_9030 0x9030
+#define PCI_DEVICE_ID_PLX_9050 0x9050
+#define PCI_DEVICE_ID_PLX_9080 0x9080
+#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001
+
+#define PCI_VENDOR_ID_MADGE 0x10b6
+#define PCI_DEVICE_ID_MADGE_MK2 0x0002
+
+#define PCI_VENDOR_ID_3COM 0x10b7
+#define PCI_DEVICE_ID_3COM_3C985 0x0001
+#define PCI_DEVICE_ID_3COM_3C940 0x1700
+#define PCI_DEVICE_ID_3COM_3C339 0x3390
+#define PCI_DEVICE_ID_3COM_3C359 0x3590
+#define PCI_DEVICE_ID_3COM_3C940B 0x80eb
+#define PCI_DEVICE_ID_3COM_3CR990 0x9900
+#define PCI_DEVICE_ID_3COM_3CR990_TX_95 0x9902
+#define PCI_DEVICE_ID_3COM_3CR990_TX_97 0x9903
+#define PCI_DEVICE_ID_3COM_3CR990B 0x9904
+#define PCI_DEVICE_ID_3COM_3CR990_FX 0x9905
+#define PCI_DEVICE_ID_3COM_3CR990SVR95 0x9908
+#define PCI_DEVICE_ID_3COM_3CR990SVR97 0x9909
+#define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a
+
+#define PCI_VENDOR_ID_AL 0x10b9
+#define PCI_DEVICE_ID_AL_M1533 0x1533
+#define PCI_DEVICE_ID_AL_M1535 0x1535
+#define PCI_DEVICE_ID_AL_M1541 0x1541
+#define PCI_DEVICE_ID_AL_M1563 0x1563
+#define PCI_DEVICE_ID_AL_M1621 0x1621
+#define PCI_DEVICE_ID_AL_M1631 0x1631
+#define PCI_DEVICE_ID_AL_M1632 0x1632
+#define PCI_DEVICE_ID_AL_M1641 0x1641
+#define PCI_DEVICE_ID_AL_M1644 0x1644
+#define PCI_DEVICE_ID_AL_M1647 0x1647
+#define PCI_DEVICE_ID_AL_M1651 0x1651
+#define PCI_DEVICE_ID_AL_M1671 0x1671
+#define PCI_DEVICE_ID_AL_M1681 0x1681
+#define PCI_DEVICE_ID_AL_M1683 0x1683
+#define PCI_DEVICE_ID_AL_M1689 0x1689
+#define PCI_DEVICE_ID_AL_M5219 0x5219
+#define PCI_DEVICE_ID_AL_M5228 0x5228
+#define PCI_DEVICE_ID_AL_M5229 0x5229
+#define PCI_DEVICE_ID_AL_M5451 0x5451
+#define PCI_DEVICE_ID_AL_M7101 0x7101
+
+#define PCI_VENDOR_ID_NEOMAGIC 0x10c8
+#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
+#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
+#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016
+
+#define PCI_VENDOR_ID_TCONRAD 0x10da
+#define PCI_DEVICE_ID_TCONRAD_TOKENRING 0x0508
+
+#define PCI_VENDOR_ID_NVIDIA 0x10de
+#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020
+#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028
+#define PCI_DEVICE_ID_NVIDIA_UTNT2 0x0029
+#define PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN 0x002a
+#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C
+#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036
+#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037
+#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800 0x0041
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE 0x0042
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x0045
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000 0x004E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055
+#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056
+#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057
+#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059
+#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065
+#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066
+#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069
+#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085
+#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086
+#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089
+#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a
+#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT 0x0090
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX 0x0091
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800 0x0098
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX 0x0099
+#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0
+#define PCI_DEVICE_ID_GEFORCE_6800A 0x00c1
+#define PCI_DEVICE_ID_GEFORCE_6800A_LE 0x00c2
+#define PCI_DEVICE_ID_GEFORCE_GO_6800 0x00c8
+#define PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA 0x00c9
+#define PCI_DEVICE_ID_QUADRO_FX_GO1400 0x00cc
+#define PCI_DEVICE_ID_QUADRO_FX_1400 0x00ce
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6
+#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9
+#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da
+#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6
+#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1 0x00f1
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3
+#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x00f9
+#define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280 0x00fd
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101
+#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112
+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT 0x0140
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600 0x0141
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL 0x0145
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540 0x014E
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200 0x014F
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152
+#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE 0x0161
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200 0x0164
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250 0x0166
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1 0x0167
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1 0x0168
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460 0x0170
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440 0x0171
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420 0x0172
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE 0x0173
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO 0x0174
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO 0x0175
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO 0x0177
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL 0x0178
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_200 0x017A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16 0x017D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X 0x0181
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X 0x0182
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X 0x0183
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000 0x0185
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO 0x0186
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO 0x0187
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL 0x0188
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC 0x0189
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS 0x018A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL 0x018B
+#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4
+#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc
+#define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1
+#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B 0x0211
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE 0x0212
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT 0x0215
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600 0x0250
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400 0x0251
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200 0x0253
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F
+#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268
+#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO 0x0286
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL 0x0288
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL 0x0289
+#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL 0x028C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA 0x0301
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800 0x0302
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000 0x0308
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000 0x0309
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA 0x0311
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600 0x0312
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE 0x0314
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600 0x031A
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650 0x031B
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700 0x031C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200 0x0320
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA 0x0321
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1 0x0322
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE 0x0323
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200 0x0324
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250 0x0325
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500 0x0326
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100 0x0327
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32 0x0328
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200 0x0329
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI 0x032A
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500 0x032B
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300 0x032C
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100 0x032D
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA 0x0330
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900 0x0331
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT 0x0332
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA 0x0333
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT 0x0334
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000 0x0338
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700 0x033F
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA 0x0341
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700 0x0342
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE 0x0343
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE 0x0344
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1 0x0347
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372
+#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373
+#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5
+#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC
+#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE
+#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448
+#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450
+#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451
+#define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452
+#define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453
+#define PCI_DEVICE_ID_NVIDIA_NVENET_24 0x054C
+#define PCI_DEVICE_ID_NVIDIA_NVENET_25 0x054D
+#define PCI_DEVICE_ID_NVIDIA_NVENET_26 0x054E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_27 0x054F
+#define PCI_DEVICE_ID_NVIDIA_NVENET_28 0x07DC
+#define PCI_DEVICE_ID_NVIDIA_NVENET_29 0x07DD
+#define PCI_DEVICE_ID_NVIDIA_NVENET_30 0x07DE
+#define PCI_DEVICE_ID_NVIDIA_NVENET_31 0x07DF
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE 0x056C
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE 0x0759
+#define PCI_DEVICE_ID_NVIDIA_NVENET_32 0x0760
+#define PCI_DEVICE_ID_NVIDIA_NVENET_33 0x0761
+#define PCI_DEVICE_ID_NVIDIA_NVENET_34 0x0762
+#define PCI_DEVICE_ID_NVIDIA_NVENET_35 0x0763
+#define PCI_DEVICE_ID_NVIDIA_NVENET_36 0x0AB0
+#define PCI_DEVICE_ID_NVIDIA_NVENET_37 0x0AB1
+#define PCI_DEVICE_ID_NVIDIA_NVENET_38 0x0AB2
+#define PCI_DEVICE_ID_NVIDIA_NVENET_39 0x0AB3
+
+#define PCI_VENDOR_ID_IMS 0x10e0
+#define PCI_DEVICE_ID_IMS_TT128 0x9128
+#define PCI_DEVICE_ID_IMS_TT3D 0x9135
+
+#define PCI_VENDOR_ID_INTERG 0x10ea
+#define PCI_DEVICE_ID_INTERG_1682 0x1682
+#define PCI_DEVICE_ID_INTERG_2000 0x2000
+#define PCI_DEVICE_ID_INTERG_2010 0x2010
+#define PCI_DEVICE_ID_INTERG_5000 0x5000
+#define PCI_DEVICE_ID_INTERG_5050 0x5050
+
+#define PCI_VENDOR_ID_REALTEK 0x10ec
+#define PCI_DEVICE_ID_REALTEK_8139 0x8139
+
+#define PCI_VENDOR_ID_XILINX 0x10ee
+#define PCI_DEVICE_ID_RME_DIGI96 0x3fc0
+#define PCI_DEVICE_ID_RME_DIGI96_8 0x3fc1
+#define PCI_DEVICE_ID_RME_DIGI96_8_PRO 0x3fc2
+#define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5
+#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6
+
+#define PCI_VENDOR_ID_INIT 0x1101
+
+#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */
+#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
+
+#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */
+#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
+
+#define PCI_VENDOR_ID_TTI 0x1103
+#define PCI_DEVICE_ID_TTI_HPT343 0x0003
+#define PCI_DEVICE_ID_TTI_HPT366 0x0004
+#define PCI_DEVICE_ID_TTI_HPT372 0x0005
+#define PCI_DEVICE_ID_TTI_HPT302 0x0006
+#define PCI_DEVICE_ID_TTI_HPT371 0x0007
+#define PCI_DEVICE_ID_TTI_HPT374 0x0008
+#define PCI_DEVICE_ID_TTI_HPT372N 0x0009 /* apparently a 372N variant? */
+
+#define PCI_VENDOR_ID_VIA 0x1106
+#define PCI_DEVICE_ID_VIA_8763_0 0x0198
+#define PCI_DEVICE_ID_VIA_8380_0 0x0204
+#define PCI_DEVICE_ID_VIA_3238_0 0x0238
+#define PCI_DEVICE_ID_VIA_PT880 0x0258
+#define PCI_DEVICE_ID_VIA_PT880ULTRA 0x0308
+#define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259
+#define PCI_DEVICE_ID_VIA_3269_0 0x0269
+#define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282
+#define PCI_DEVICE_ID_VIA_3296_0 0x0296
+#define PCI_DEVICE_ID_VIA_8363_0 0x0305
+#define PCI_DEVICE_ID_VIA_P4M800CE 0x0314
+#define PCI_DEVICE_ID_VIA_P4M890 0x0327
+#define PCI_DEVICE_ID_VIA_VT3324 0x0324
+#define PCI_DEVICE_ID_VIA_VT3336 0x0336
+#define PCI_DEVICE_ID_VIA_VT3351 0x0351
+#define PCI_DEVICE_ID_VIA_VT3364 0x0364
+#define PCI_DEVICE_ID_VIA_8371_0 0x0391
+#define PCI_DEVICE_ID_VIA_8501_0 0x0501
+#define PCI_DEVICE_ID_VIA_82C561 0x0561
+#define PCI_DEVICE_ID_VIA_82C586_1 0x0571
+#define PCI_DEVICE_ID_VIA_82C576 0x0576
+#define PCI_DEVICE_ID_VIA_82C586_0 0x0586
+#define PCI_DEVICE_ID_VIA_82C596 0x0596
+#define PCI_DEVICE_ID_VIA_82C597_0 0x0597
+#define PCI_DEVICE_ID_VIA_82C598_0 0x0598
+#define PCI_DEVICE_ID_VIA_8601_0 0x0601
+#define PCI_DEVICE_ID_VIA_8605_0 0x0605
+#define PCI_DEVICE_ID_VIA_82C686 0x0686
+#define PCI_DEVICE_ID_VIA_82C691_0 0x0691
+#define PCI_DEVICE_ID_VIA_82C576_1 0x1571
+#define PCI_DEVICE_ID_VIA_82C586_2 0x3038
+#define PCI_DEVICE_ID_VIA_82C586_3 0x3040
+#define PCI_DEVICE_ID_VIA_82C596_3 0x3050
+#define PCI_DEVICE_ID_VIA_82C596B_3 0x3051
+#define PCI_DEVICE_ID_VIA_82C686_4 0x3057
+#define PCI_DEVICE_ID_VIA_82C686_5 0x3058
+#define PCI_DEVICE_ID_VIA_8233_5 0x3059
+#define PCI_DEVICE_ID_VIA_8233_0 0x3074
+#define PCI_DEVICE_ID_VIA_8633_0 0x3091
+#define PCI_DEVICE_ID_VIA_8367_0 0x3099
+#define PCI_DEVICE_ID_VIA_8653_0 0x3101
+#define PCI_DEVICE_ID_VIA_8622 0x3102
+#define PCI_DEVICE_ID_VIA_8235_USB_2 0x3104
+#define PCI_DEVICE_ID_VIA_8233C_0 0x3109
+#define PCI_DEVICE_ID_VIA_8361 0x3112
+#define PCI_DEVICE_ID_VIA_XM266 0x3116
+#define PCI_DEVICE_ID_VIA_612X 0x3119
+#define PCI_DEVICE_ID_VIA_862X_0 0x3123
+#define PCI_DEVICE_ID_VIA_8753_0 0x3128
+#define PCI_DEVICE_ID_VIA_8233A 0x3147
+#define PCI_DEVICE_ID_VIA_8703_51_0 0x3148
+#define PCI_DEVICE_ID_VIA_8237_SATA 0x3149
+#define PCI_DEVICE_ID_VIA_XN266 0x3156
+#define PCI_DEVICE_ID_VIA_6410 0x3164
+#define PCI_DEVICE_ID_VIA_8754C_0 0x3168
+#define PCI_DEVICE_ID_VIA_8235 0x3177
+#define PCI_DEVICE_ID_VIA_8385_0 0x3188
+#define PCI_DEVICE_ID_VIA_8377_0 0x3189
+#define PCI_DEVICE_ID_VIA_8378_0 0x3205
+#define PCI_DEVICE_ID_VIA_8783_0 0x3208
+#define PCI_DEVICE_ID_VIA_8237 0x3227
+#define PCI_DEVICE_ID_VIA_8251 0x3287
+#define PCI_DEVICE_ID_VIA_8237A 0x3337
+#define PCI_DEVICE_ID_VIA_8237S 0x3372
+#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x5324
+#define PCI_DEVICE_ID_VIA_8231 0x8231
+#define PCI_DEVICE_ID_VIA_8231_4 0x8235
+#define PCI_DEVICE_ID_VIA_8365_1 0x8305
+#define PCI_DEVICE_ID_VIA_CX700 0x8324
+#define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581
+#define PCI_DEVICE_ID_VIA_VX800 0x8353
+#define PCI_DEVICE_ID_VIA_8371_1 0x8391
+#define PCI_DEVICE_ID_VIA_82C598_1 0x8598
+#define PCI_DEVICE_ID_VIA_838X_1 0xB188
+#define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198
+
+#define PCI_VENDOR_ID_SIEMENS 0x110A
+#define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102
+
+#define PCI_VENDOR_ID_VORTEX 0x1119
+#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000
+#define PCI_DEVICE_ID_VORTEX_GDT6000B 0x0001
+#define PCI_DEVICE_ID_VORTEX_GDT6x10 0x0002
+#define PCI_DEVICE_ID_VORTEX_GDT6x20 0x0003
+#define PCI_DEVICE_ID_VORTEX_GDT6530 0x0004
+#define PCI_DEVICE_ID_VORTEX_GDT6550 0x0005
+#define PCI_DEVICE_ID_VORTEX_GDT6x17 0x0006
+#define PCI_DEVICE_ID_VORTEX_GDT6x27 0x0007
+#define PCI_DEVICE_ID_VORTEX_GDT6537 0x0008
+#define PCI_DEVICE_ID_VORTEX_GDT6557 0x0009
+#define PCI_DEVICE_ID_VORTEX_GDT6x15 0x000a
+#define PCI_DEVICE_ID_VORTEX_GDT6x25 0x000b
+#define PCI_DEVICE_ID_VORTEX_GDT6535 0x000c
+#define PCI_DEVICE_ID_VORTEX_GDT6555 0x000d
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x0100
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x0101
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x0102
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x0103
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x0104
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x0105
+
+#define PCI_VENDOR_ID_EF 0x111a
+#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000
+#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002
+#define PCI_DEVICE_ID_EF_ATM_LANAI2 0x0003
+#define PCI_DEVICE_ID_EF_ATM_LANAIHB 0x0005
+
+#define PCI_VENDOR_ID_IDT 0x111d
+#define PCI_DEVICE_ID_IDT_IDT77201 0x0001
+
+#define PCI_VENDOR_ID_FORE 0x1127
+#define PCI_DEVICE_ID_FORE_PCA200E 0x0300
+
+#define PCI_VENDOR_ID_PHILIPS 0x1131
+#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146
+#define PCI_DEVICE_ID_PHILIPS_SAA9730 0x9730
+
+#define PCI_VENDOR_ID_EICON 0x1133
+#define PCI_DEVICE_ID_EICON_DIVA20 0xe002
+#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004
+#define PCI_DEVICE_ID_EICON_DIVA201 0xe005
+#define PCI_DEVICE_ID_EICON_DIVA202 0xe00b
+#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010
+#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012
+#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013
+#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014
+
+#define PCI_VENDOR_ID_CISCO 0x1137
+
+#define PCI_VENDOR_ID_ZIATECH 0x1138
+#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550
+
+
+#define PCI_VENDOR_ID_SYSKONNECT 0x1148
+#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200
+#define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300
+#define PCI_DEVICE_ID_SYSKONNECT_YU 0x4320
+#define PCI_DEVICE_ID_SYSKONNECT_9DXX 0x4400
+#define PCI_DEVICE_ID_SYSKONNECT_9MXX 0x4500
+
+#define PCI_VENDOR_ID_DIGI 0x114f
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070
+#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072
+#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073
+#define PCI_DEVICE_ID_NEO_2DB9 0x00C8
+#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9
+#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA
+#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB
+#define PCIE_DEVICE_ID_NEO_4_IBM 0x00F4
+
+#define PCI_VENDOR_ID_XIRCOM 0x115d
+#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101
+#define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103
+
+#define PCI_VENDOR_ID_SERVERWORKS 0x1166
+#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008
+#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009
+#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB 0x0036
+#define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103
+#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132
+#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200
+#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205
+#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
+#define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213
+#define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
+
+#define PCI_VENDOR_ID_SBE 0x1176
+#define PCI_DEVICE_ID_SBE_WANXL100 0x0301
+#define PCI_DEVICE_ID_SBE_WANXL200 0x0302
+#define PCI_DEVICE_ID_SBE_WANXL400 0x0104
+
+#define PCI_VENDOR_ID_TOSHIBA 0x1179
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO 0x0102
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0103
+#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0105
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617
+
+#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
+#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
+#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
+
+#define PCI_VENDOR_ID_ATTO 0x117c
+
+#define PCI_VENDOR_ID_RICOH 0x1180
+#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465
+#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466
+#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475
+#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476
+#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478
+#define PCI_DEVICE_ID_RICOH_R5C822 0x0822
+#define PCI_DEVICE_ID_RICOH_R5C832 0x0832
+#define PCI_DEVICE_ID_RICOH_R5C843 0x0843
+
+#define PCI_VENDOR_ID_DLINK 0x1186
+#define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00
+
+#define PCI_VENDOR_ID_ARTOP 0x1191
+#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005
+#define PCI_DEVICE_ID_ARTOP_ATP860 0x0006
+#define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007
+#define PCI_DEVICE_ID_ARTOP_ATP865 0x0008
+#define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009
+#define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002
+#define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010
+#define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020
+#define PCI_DEVICE_ID_ARTOP_AEC7612S 0x8030
+#define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040
+#define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050
+#define PCI_DEVICE_ID_ARTOP_8060 0x8060
+
+#define PCI_VENDOR_ID_ZEITNET 0x1193
+#define PCI_DEVICE_ID_ZEITNET_1221 0x0001
+#define PCI_DEVICE_ID_ZEITNET_1225 0x0002
+
+#define PCI_VENDOR_ID_FUJITSU_ME 0x119e
+#define PCI_DEVICE_ID_FUJITSU_FS155 0x0001
+#define PCI_DEVICE_ID_FUJITSU_FS50 0x0003
+
+#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9
+#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334
+
+#define PCI_VENDOR_ID_MARVELL 0x11ab
+#define PCI_DEVICE_ID_MARVELL_GT64111 0x4146
+#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
+#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
+#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480
+#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND 0x4100
+#define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101
+#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102
+
+#define PCI_VENDOR_ID_V3 0x11b0
+#define PCI_DEVICE_ID_V3_V960 0x0001
+#define PCI_DEVICE_ID_V3_V351 0x0002
+
+#define PCI_VENDOR_ID_ATT 0x11c1
+#define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480
+
+#define PCI_VENDOR_ID_SPECIALIX 0x11cb
+#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000
+#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000
+#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004
+
+#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4
+#define PCI_DEVICE_ID_AD1889JS 0x1889
+
+#define PCI_DEVICE_ID_SEGA_BBA 0x1234
+
+#define PCI_VENDOR_ID_ZORAN 0x11de
+#define PCI_DEVICE_ID_ZORAN_36057 0x6057
+#define PCI_DEVICE_ID_ZORAN_36120 0x6120
+
+#define PCI_VENDOR_ID_COMPEX 0x11f6
+#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
+
+#define PCI_VENDOR_ID_RP 0x11fe
+#define PCI_DEVICE_ID_RP32INTF 0x0001
+#define PCI_DEVICE_ID_RP8INTF 0x0002
+#define PCI_DEVICE_ID_RP16INTF 0x0003
+#define PCI_DEVICE_ID_RP4QUAD 0x0004
+#define PCI_DEVICE_ID_RP8OCTA 0x0005
+#define PCI_DEVICE_ID_RP8J 0x0006
+#define PCI_DEVICE_ID_RP4J 0x0007
+#define PCI_DEVICE_ID_RP8SNI 0x0008
+#define PCI_DEVICE_ID_RP16SNI 0x0009
+#define PCI_DEVICE_ID_RPP4 0x000A
+#define PCI_DEVICE_ID_RPP8 0x000B
+#define PCI_DEVICE_ID_RP4M 0x000D
+#define PCI_DEVICE_ID_RP2_232 0x000E
+#define PCI_DEVICE_ID_RP2_422 0x000F
+#define PCI_DEVICE_ID_URP32INTF 0x0801
+#define PCI_DEVICE_ID_URP8INTF 0x0802
+#define PCI_DEVICE_ID_URP16INTF 0x0803
+#define PCI_DEVICE_ID_URP8OCTA 0x0805
+#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C
+#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D
+#define PCI_DEVICE_ID_CRP16INTF 0x0903
+
+#define PCI_VENDOR_ID_CYCLADES 0x120e
+#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100
+#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101
+#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102
+#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103
+#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104
+#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105
+#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200
+#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201
+#define PCI_DEVICE_ID_PC300_RX_2 0x0300
+#define PCI_DEVICE_ID_PC300_RX_1 0x0301
+#define PCI_DEVICE_ID_PC300_TE_2 0x0310
+#define PCI_DEVICE_ID_PC300_TE_1 0x0311
+#define PCI_DEVICE_ID_PC300_TE_M_2 0x0320
+#define PCI_DEVICE_ID_PC300_TE_M_1 0x0321
+
+#define PCI_VENDOR_ID_ESSENTIAL 0x120f
+#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001
+
+#define PCI_VENDOR_ID_O2 0x1217
+#define PCI_DEVICE_ID_O2_6729 0x6729
+#define PCI_DEVICE_ID_O2_6730 0x673a
+#define PCI_DEVICE_ID_O2_6832 0x6832
+#define PCI_DEVICE_ID_O2_6836 0x6836
+
+#define PCI_VENDOR_ID_3DFX 0x121a
+#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001
+#define PCI_DEVICE_ID_3DFX_VOODOO2 0x0002
+#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
+#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
+#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009
+
+#define PCI_VENDOR_ID_AVM 0x1244
+#define PCI_DEVICE_ID_AVM_B1 0x0700
+#define PCI_DEVICE_ID_AVM_C4 0x0800
+#define PCI_DEVICE_ID_AVM_A1 0x0a00
+#define PCI_DEVICE_ID_AVM_A1_V2 0x0e00
+#define PCI_DEVICE_ID_AVM_C2 0x1100
+#define PCI_DEVICE_ID_AVM_T1 0x1200
+
+#define PCI_VENDOR_ID_STALLION 0x124d
+
+/* Allied Telesyn */
+#define PCI_VENDOR_ID_AT 0x1259
+#define PCI_SUBDEVICE_ID_AT_2700FX 0x2701
+#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703
+
+#define PCI_VENDOR_ID_ESS 0x125d
+#define PCI_DEVICE_ID_ESS_ESS1968 0x1968
+#define PCI_DEVICE_ID_ESS_ESS1978 0x1978
+#define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988
+#define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989
+#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990
+#define PCI_DEVICE_ID_ESS_CANYON3D_2 0x1992
+#define PCI_DEVICE_ID_ESS_MAESTRO3 0x1998
+#define PCI_DEVICE_ID_ESS_MAESTRO3_1 0x1999
+#define PCI_DEVICE_ID_ESS_MAESTRO3_HW 0x199a
+#define PCI_DEVICE_ID_ESS_MAESTRO3_2 0x199b
+
+#define PCI_VENDOR_ID_SATSAGEM 0x1267
+#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016
+
+#define PCI_VENDOR_ID_ENSONIQ 0x1274
+#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880
+#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
+#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371
+
+#define PCI_VENDOR_ID_TRANSMETA 0x1279
+#define PCI_DEVICE_ID_EFFICEON 0x0060
+
+#define PCI_VENDOR_ID_ROCKWELL 0x127A
+
+#define PCI_VENDOR_ID_ITE 0x1283
+#define PCI_DEVICE_ID_ITE_8211 0x8211
+#define PCI_DEVICE_ID_ITE_8212 0x8212
+#define PCI_DEVICE_ID_ITE_8213 0x8213
+#define PCI_DEVICE_ID_ITE_8152 0x8152
+#define PCI_DEVICE_ID_ITE_8872 0x8872
+#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886
+
+/* formerly Platform Tech */
+#define PCI_DEVICE_ID_ESS_ESS0100 0x0100
+
+#define PCI_VENDOR_ID_ALTEON 0x12ae
+
+#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232 0x0002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232 0x0003
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485 0x0004
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4 0x0005
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485 0x0006
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2 0x0007
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485 0x0008
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6 0x0009
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ 0x000C
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_PTM 0x000D
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_NT960PCI 0x0100
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2 0x0201
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4 0x0202
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232 0x0300
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232 0x0301
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232 0x0302
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1 0x0310
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2 0x0311
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4 0x0312
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2 0x0320
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4 0x0321
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8 0x0322
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485 0x0330
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485 0x0331
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485 0x0332
+
+#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2
+#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
+
+#define PCI_SUBVENDOR_ID_CHASE_PCIFAST 0x12E0
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4 0x0031
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8 0x0021
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16 0x0011
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC 0x0041
+#define PCI_SUBVENDOR_ID_CHASE_PCIRAS 0x124D
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4 0xF001
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8 0xF010
+
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+#define PCI_DEVICE_ID_AUREAL_VORTEX_1 0x0001
+#define PCI_DEVICE_ID_AUREAL_VORTEX_2 0x0002
+#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003
+
+#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8
+#define PCI_DEVICE_ID_LML_33R10 0x8a02
+
+#define PCI_VENDOR_ID_ESDGMBH 0x12fe
+#define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111
+
+#define PCI_VENDOR_ID_SIIG 0x131f
+#define PCI_SUBVENDOR_ID_SIIG 0x131f
+#define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000
+#define PCI_DEVICE_ID_SIIG_1S_10x_650 0x1001
+#define PCI_DEVICE_ID_SIIG_1S_10x_850 0x1002
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012
+#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020
+#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021
+#define PCI_DEVICE_ID_SIIG_2S_10x_550 0x1030
+#define PCI_DEVICE_ID_SIIG_2S_10x_650 0x1031
+#define PCI_DEVICE_ID_SIIG_2S_10x_850 0x1032
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036
+#define PCI_DEVICE_ID_SIIG_4S_10x_550 0x1050
+#define PCI_DEVICE_ID_SIIG_4S_10x_650 0x1051
+#define PCI_DEVICE_ID_SIIG_4S_10x_850 0x1052
+#define PCI_DEVICE_ID_SIIG_1S_20x_550 0x2000
+#define PCI_DEVICE_ID_SIIG_1S_20x_650 0x2001
+#define PCI_DEVICE_ID_SIIG_1S_20x_850 0x2002
+#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020
+#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021
+#define PCI_DEVICE_ID_SIIG_2S_20x_550 0x2030
+#define PCI_DEVICE_ID_SIIG_2S_20x_650 0x2031
+#define PCI_DEVICE_ID_SIIG_2S_20x_850 0x2032
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012
+#define PCI_DEVICE_ID_SIIG_4S_20x_550 0x2050
+#define PCI_DEVICE_ID_SIIG_4S_20x_650 0x2051
+#define PCI_DEVICE_ID_SIIG_4S_20x_850 0x2052
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
+#define PCI_DEVICE_ID_SIIG_8S_20x_550 0x2080
+#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081
+#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082
+#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050
+
+#define PCI_VENDOR_ID_RADISYS 0x1331
+
+#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332
+#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415
+#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425
+#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155
+
+#define PCI_VENDOR_ID_DOMEX 0x134a
+#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001
+
+#define PCI_VENDOR_ID_INTASHIELD 0x135a
+#define PCI_DEVICE_ID_INTASHIELD_IS200 0x0d80
+#define PCI_DEVICE_ID_INTASHIELD_IS400 0x0dc0
+
+#define PCI_VENDOR_ID_QUATECH 0x135C
+#define PCI_DEVICE_ID_QUATECH_QSC100 0x0010
+#define PCI_DEVICE_ID_QUATECH_DSC100 0x0020
+#define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050
+#define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060
+#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278
+
+#define PCI_VENDOR_ID_SEALEVEL 0x135e
+#define PCI_DEVICE_ID_SEALEVEL_U530 0x7101
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM2 0x7201
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM422 0x7402
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202
+#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401
+#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804
+
+#define PCI_VENDOR_ID_HYPERCOPE 0x1365
+#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050
+#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104
+#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106
+#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107
+#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108
+
+#define PCI_VENDOR_ID_KAWASAKI 0x136b
+#define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01
+
+#define PCI_VENDOR_ID_CNET 0x1371
+#define PCI_DEVICE_ID_CNET_GIGACARD 0x434e
+
+#define PCI_VENDOR_ID_LMC 0x1376
+#define PCI_DEVICE_ID_LMC_HSSI 0x0003
+#define PCI_DEVICE_ID_LMC_DS3 0x0004
+#define PCI_DEVICE_ID_LMC_SSI 0x0005
+#define PCI_DEVICE_ID_LMC_T1 0x0006
+
+#define PCI_VENDOR_ID_NETGEAR 0x1385
+#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
+
+#define PCI_VENDOR_ID_APPLICOM 0x1389
+#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001
+#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002
+#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003
+
+#define PCI_VENDOR_ID_MOXA 0x1393
+#define PCI_DEVICE_ID_MOXA_RC7000 0x0001
+#define PCI_DEVICE_ID_MOXA_CP102 0x1020
+#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021
+#define PCI_DEVICE_ID_MOXA_CP102U 0x1022
+#define PCI_DEVICE_ID_MOXA_C104 0x1040
+#define PCI_DEVICE_ID_MOXA_CP104U 0x1041
+#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042
+#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043
+#define PCI_DEVICE_ID_MOXA_CT114 0x1140
+#define PCI_DEVICE_ID_MOXA_CP114 0x1141
+#define PCI_DEVICE_ID_MOXA_CP118U 0x1180
+#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181
+#define PCI_DEVICE_ID_MOXA_CP132 0x1320
+#define PCI_DEVICE_ID_MOXA_CP132U 0x1321
+#define PCI_DEVICE_ID_MOXA_CP134U 0x1340
+#define PCI_DEVICE_ID_MOXA_C168 0x1680
+#define PCI_DEVICE_ID_MOXA_CP168U 0x1681
+#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682
+#define PCI_DEVICE_ID_MOXA_CP204J 0x2040
+#define PCI_DEVICE_ID_MOXA_C218 0x2180
+#define PCI_DEVICE_ID_MOXA_C320 0x3200
+
+#define PCI_VENDOR_ID_CCD 0x1397
+#define PCI_DEVICE_ID_CCD_HFC4S 0x08B4
+#define PCI_SUBDEVICE_ID_CCD_PMX2S 0x1234
+#define PCI_DEVICE_ID_CCD_HFC8S 0x16B8
+#define PCI_DEVICE_ID_CCD_2BD0 0x2bd0
+#define PCI_DEVICE_ID_CCD_HFCE1 0x30B1
+#define PCI_SUBDEVICE_ID_CCD_SPD4S 0x3136
+#define PCI_SUBDEVICE_ID_CCD_SPDE1 0x3137
+#define PCI_DEVICE_ID_CCD_B000 0xb000
+#define PCI_DEVICE_ID_CCD_B006 0xb006
+#define PCI_DEVICE_ID_CCD_B007 0xb007
+#define PCI_DEVICE_ID_CCD_B008 0xb008
+#define PCI_DEVICE_ID_CCD_B009 0xb009
+#define PCI_DEVICE_ID_CCD_B00A 0xb00a
+#define PCI_DEVICE_ID_CCD_B00B 0xb00b
+#define PCI_DEVICE_ID_CCD_B00C 0xb00c
+#define PCI_DEVICE_ID_CCD_B100 0xb100
+#define PCI_SUBDEVICE_ID_CCD_IOB4ST 0xB520
+#define PCI_SUBDEVICE_ID_CCD_IOB8STR 0xB521
+#define PCI_SUBDEVICE_ID_CCD_IOB8ST 0xB522
+#define PCI_SUBDEVICE_ID_CCD_IOB1E1 0xB523
+#define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540
+#define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550
+#define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552
+#define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560
+#define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562
+#define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563
+#define PCI_SUBDEVICE_ID_CCD_BNE1D 0xB564
+#define PCI_SUBDEVICE_ID_CCD_BNE1DP 0xB565
+#define PCI_SUBDEVICE_ID_CCD_BN2S 0xB566
+#define PCI_SUBDEVICE_ID_CCD_BN1SM 0xB567
+#define PCI_SUBDEVICE_ID_CCD_BN4SM 0xB568
+#define PCI_SUBDEVICE_ID_CCD_BN2SM 0xB569
+#define PCI_SUBDEVICE_ID_CCD_BNE1M 0xB56A
+#define PCI_SUBDEVICE_ID_CCD_BN8SP 0xB56B
+#define PCI_SUBDEVICE_ID_CCD_HFC4S 0xB620
+#define PCI_SUBDEVICE_ID_CCD_HFC8S 0xB622
+#define PCI_DEVICE_ID_CCD_B700 0xb700
+#define PCI_DEVICE_ID_CCD_B701 0xb701
+#define PCI_SUBDEVICE_ID_CCD_HFCE1 0xC523
+#define PCI_SUBDEVICE_ID_CCD_OV2S 0xE884
+#define PCI_SUBDEVICE_ID_CCD_OV4S 0xE888
+#define PCI_SUBDEVICE_ID_CCD_OV8S 0xE998
+
+#define PCI_VENDOR_ID_EXAR 0x13a8
+#define PCI_DEVICE_ID_EXAR_XR17C152 0x0152
+#define PCI_DEVICE_ID_EXAR_XR17C154 0x0154
+#define PCI_DEVICE_ID_EXAR_XR17C158 0x0158
+
+#define PCI_VENDOR_ID_MICROGATE 0x13c0
+#define PCI_DEVICE_ID_MICROGATE_USC 0x0010
+#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030
+
+#define PCI_VENDOR_ID_3WARE 0x13C1
+#define PCI_DEVICE_ID_3WARE_1000 0x1000
+#define PCI_DEVICE_ID_3WARE_7000 0x1001
+#define PCI_DEVICE_ID_3WARE_9000 0x1002
+
+#define PCI_VENDOR_ID_IOMEGA 0x13ca
+#define PCI_DEVICE_ID_IOMEGA_BUZ 0x4231
+
+#define PCI_VENDOR_ID_ABOCOM 0x13D1
+#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1
+
+#define PCI_VENDOR_ID_SUNDANCE 0x13f0
+
+#define PCI_VENDOR_ID_CMEDIA 0x13f6
+#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100
+#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101
+#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111
+#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
+
+#define PCI_VENDOR_ID_LAVA 0x1407
+#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */
+#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUATRO_B 0x0102 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_A 0x0180 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_B 0x0181 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_PORT_PLUS 0x0200 /* 2x 16650 */
+#define PCI_DEVICE_ID_LAVA_QUAD_A 0x0201 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUAD_B 0x0202 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_SSERIAL 0x0500 /* 1x 16550 */
+#define PCI_DEVICE_ID_LAVA_PORT_650 0x0600 /* 1x 16650 */
+#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */
+#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */
+#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR 0x8800
+
+#define PCI_VENDOR_ID_TIMEDIA 0x1409
+#define PCI_DEVICE_ID_TIMEDIA_1889 0x7168
+
+#define PCI_VENDOR_ID_ICE 0x1412
+#define PCI_DEVICE_ID_ICE_1712 0x1712
+#define PCI_DEVICE_ID_VT1724 0x1724
+
+#define PCI_VENDOR_ID_OXSEMI 0x1415
+#define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403
+#define PCI_DEVICE_ID_OXSEMI_PCIe840 0xC000
+#define PCI_DEVICE_ID_OXSEMI_PCIe840_G 0xC004
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_0 0xC100
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_0_G 0xC104
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1 0xC110
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_G 0xC114
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U 0xC118
+#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU 0xC11C
+#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501
+#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
+#define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513
+#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521
+#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523
+
+#define PCI_VENDOR_ID_CHELSIO 0x1425
+
+#define PCI_VENDOR_ID_SAMSUNG 0x144d
+
+#define PCI_VENDOR_ID_MYRICOM 0x14c1
+
+#define PCI_VENDOR_ID_TITAN 0x14D2
+#define PCI_DEVICE_ID_TITAN_010L 0x8001
+#define PCI_DEVICE_ID_TITAN_100L 0x8010
+#define PCI_DEVICE_ID_TITAN_110L 0x8011
+#define PCI_DEVICE_ID_TITAN_200L 0x8020
+#define PCI_DEVICE_ID_TITAN_210L 0x8021
+#define PCI_DEVICE_ID_TITAN_400L 0x8040
+#define PCI_DEVICE_ID_TITAN_800L 0x8080
+#define PCI_DEVICE_ID_TITAN_100 0xA001
+#define PCI_DEVICE_ID_TITAN_200 0xA005
+#define PCI_DEVICE_ID_TITAN_400 0xA003
+#define PCI_DEVICE_ID_TITAN_800B 0xA004
+
+#define PCI_VENDOR_ID_PANACOM 0x14d4
+#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
+#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
+
+#define PCI_VENDOR_ID_SIPACKETS 0x14d9
+#define PCI_DEVICE_ID_SP1011 0x0010
+
+#define PCI_VENDOR_ID_AFAVLAB 0x14db
+#define PCI_DEVICE_ID_AFAVLAB_P028 0x2180
+#define PCI_DEVICE_ID_AFAVLAB_P030 0x2182
+#define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150
+
+#define PCI_VENDOR_ID_BROADCOM 0x14e4
+#define PCI_DEVICE_ID_TIGON3_5752 0x1600
+#define PCI_DEVICE_ID_TIGON3_5752M 0x1601
+#define PCI_DEVICE_ID_NX2_5709 0x1639
+#define PCI_DEVICE_ID_NX2_5709S 0x163a
+#define PCI_DEVICE_ID_TIGON3_5700 0x1644
+#define PCI_DEVICE_ID_TIGON3_5701 0x1645
+#define PCI_DEVICE_ID_TIGON3_5702 0x1646
+#define PCI_DEVICE_ID_TIGON3_5703 0x1647
+#define PCI_DEVICE_ID_TIGON3_5704 0x1648
+#define PCI_DEVICE_ID_TIGON3_5704S_2 0x1649
+#define PCI_DEVICE_ID_NX2_5706 0x164a
+#define PCI_DEVICE_ID_NX2_5708 0x164c
+#define PCI_DEVICE_ID_TIGON3_5702FE 0x164d
+#define PCI_DEVICE_ID_NX2_57710 0x164e
+#define PCI_DEVICE_ID_NX2_57711 0x164f
+#define PCI_DEVICE_ID_NX2_57711E 0x1650
+#define PCI_DEVICE_ID_TIGON3_5705 0x1653
+#define PCI_DEVICE_ID_TIGON3_5705_2 0x1654
+#define PCI_DEVICE_ID_TIGON3_5720 0x1658
+#define PCI_DEVICE_ID_TIGON3_5721 0x1659
+#define PCI_DEVICE_ID_TIGON3_5722 0x165a
+#define PCI_DEVICE_ID_TIGON3_5723 0x165b
+#define PCI_DEVICE_ID_TIGON3_5705M 0x165d
+#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e
+#define PCI_DEVICE_ID_TIGON3_5714 0x1668
+#define PCI_DEVICE_ID_TIGON3_5714S 0x1669
+#define PCI_DEVICE_ID_TIGON3_5780 0x166a
+#define PCI_DEVICE_ID_TIGON3_5780S 0x166b
+#define PCI_DEVICE_ID_TIGON3_5705F 0x166e
+#define PCI_DEVICE_ID_TIGON3_5754M 0x1672
+#define PCI_DEVICE_ID_TIGON3_5755M 0x1673
+#define PCI_DEVICE_ID_TIGON3_5756 0x1674
+#define PCI_DEVICE_ID_TIGON3_5750 0x1676
+#define PCI_DEVICE_ID_TIGON3_5751 0x1677
+#define PCI_DEVICE_ID_TIGON3_5715 0x1678
+#define PCI_DEVICE_ID_TIGON3_5715S 0x1679
+#define PCI_DEVICE_ID_TIGON3_5754 0x167a
+#define PCI_DEVICE_ID_TIGON3_5755 0x167b
+#define PCI_DEVICE_ID_TIGON3_5750M 0x167c
+#define PCI_DEVICE_ID_TIGON3_5751M 0x167d
+#define PCI_DEVICE_ID_TIGON3_5751F 0x167e
+#define PCI_DEVICE_ID_TIGON3_5787F 0x167f
+#define PCI_DEVICE_ID_TIGON3_5761E 0x1680
+#define PCI_DEVICE_ID_TIGON3_5761 0x1681
+#define PCI_DEVICE_ID_TIGON3_5764 0x1684
+#define PCI_DEVICE_ID_TIGON3_5787M 0x1693
+#define PCI_DEVICE_ID_TIGON3_5782 0x1696
+#define PCI_DEVICE_ID_TIGON3_5784 0x1698
+#define PCI_DEVICE_ID_TIGON3_5785 0x1699
+#define PCI_DEVICE_ID_TIGON3_5786 0x169a
+#define PCI_DEVICE_ID_TIGON3_5787 0x169b
+#define PCI_DEVICE_ID_TIGON3_5788 0x169c
+#define PCI_DEVICE_ID_TIGON3_5789 0x169d
+#define PCI_DEVICE_ID_TIGON3_5702X 0x16a6
+#define PCI_DEVICE_ID_TIGON3_5703X 0x16a7
+#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8
+#define PCI_DEVICE_ID_NX2_5706S 0x16aa
+#define PCI_DEVICE_ID_NX2_5708S 0x16ac
+#define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6
+#define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7
+#define PCI_DEVICE_ID_TIGON3_5781 0x16dd
+#define PCI_DEVICE_ID_TIGON3_5753 0x16f7
+#define PCI_DEVICE_ID_TIGON3_5753M 0x16fd
+#define PCI_DEVICE_ID_TIGON3_5753F 0x16fe
+#define PCI_DEVICE_ID_TIGON3_5901 0x170d
+#define PCI_DEVICE_ID_BCM4401B1 0x170c
+#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
+#define PCI_DEVICE_ID_TIGON3_5906 0x1712
+#define PCI_DEVICE_ID_TIGON3_5906M 0x1713
+#define PCI_DEVICE_ID_BCM4401 0x4401
+#define PCI_DEVICE_ID_BCM4401B0 0x4402
+
+#define PCI_VENDOR_ID_TOPIC 0x151f
+#define PCI_DEVICE_ID_TOPIC_TP560 0x0000
+
+#define PCI_VENDOR_ID_MAINPINE 0x1522
+#define PCI_DEVICE_ID_MAINPINE_PBRIDGE 0x0100
+#define PCI_VENDOR_ID_ENE 0x1524
+#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550
+#define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551
+#define PCI_DEVICE_ID_ENE_CB714_SD 0x0750
+#define PCI_DEVICE_ID_ENE_CB714_SD_2 0x0751
+#define PCI_DEVICE_ID_ENE_1211 0x1211
+#define PCI_DEVICE_ID_ENE_1225 0x1225
+#define PCI_DEVICE_ID_ENE_1410 0x1410
+#define PCI_DEVICE_ID_ENE_710 0x1411
+#define PCI_DEVICE_ID_ENE_712 0x1412
+#define PCI_DEVICE_ID_ENE_1420 0x1420
+#define PCI_DEVICE_ID_ENE_720 0x1421
+#define PCI_DEVICE_ID_ENE_722 0x1422
+
+#define PCI_SUBVENDOR_ID_PERLE 0x155f
+#define PCI_SUBDEVICE_ID_PCI_RAS4 0xf001
+#define PCI_SUBDEVICE_ID_PCI_RAS8 0xf010
+
+#define PCI_VENDOR_ID_SYBA 0x1592
+#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782
+#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783
+
+#define PCI_VENDOR_ID_MORETON 0x15aa
+#define PCI_DEVICE_ID_RASTEL_2PORT 0x2000
+
+#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
+#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0
+
+#define PCI_VENDOR_ID_MELLANOX 0x15b3
+#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
+#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46
+#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
+#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282
+#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
+#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
+
+#define PCI_VENDOR_ID_QUICKNET 0x15e2
+#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
+
+/*
+ * ADDI-DATA GmbH communication cards <info@addi-data.com>
+ */
+#define PCI_VENDOR_ID_ADDIDATA_OLD 0x10E8
+#define PCI_VENDOR_ID_ADDIDATA 0x15B8
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500 0x7000
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420 0x7001
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300 0x7002
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800 0x818E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2 0x7009
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2 0x700A
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2 0x700B
+#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3 0x700C
+#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3 0x700D
+#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3 0x700E
+#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3 0x700F
+
+#define PCI_VENDOR_ID_PDC 0x15e9
+
+#define PCI_VENDOR_ID_FARSITE 0x1619
+#define PCI_DEVICE_ID_FARSITE_T2P 0x0400
+#define PCI_DEVICE_ID_FARSITE_T4P 0x0440
+#define PCI_DEVICE_ID_FARSITE_T1U 0x0610
+#define PCI_DEVICE_ID_FARSITE_T2U 0x0620
+#define PCI_DEVICE_ID_FARSITE_T4U 0x0640
+#define PCI_DEVICE_ID_FARSITE_TE1 0x1610
+#define PCI_DEVICE_ID_FARSITE_TE1C 0x1612
+
+#define PCI_VENDOR_ID_ARIMA 0x161f
+
+#define PCI_VENDOR_ID_BROCADE 0x1657
+
+#define PCI_VENDOR_ID_SIBYTE 0x166d
+#define PCI_DEVICE_ID_BCM1250_PCI 0x0001
+#define PCI_DEVICE_ID_BCM1250_HT 0x0002
+
+#define PCI_VENDOR_ID_ATHEROS 0x168c
+
+#define PCI_VENDOR_ID_NETCELL 0x169c
+#define PCI_DEVICE_ID_REVOLUTION 0x0044
+
+#define PCI_VENDOR_ID_CENATEK 0x16CA
+#define PCI_DEVICE_ID_CENATEK_IDE 0x0001
+
+#define PCI_VENDOR_ID_VITESSE 0x1725
+#define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174
+
+#define PCI_VENDOR_ID_LINKSYS 0x1737
+#define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064
+
+#define PCI_VENDOR_ID_ALTIMA 0x173b
+#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8
+#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9
+#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
+#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb
+
+#define PCI_VENDOR_ID_BELKIN 0x1799
+#define PCI_DEVICE_ID_BELKIN_F5D7010V7 0x701f
+
+#define PCI_VENDOR_ID_RDC 0x17f3
+#define PCI_DEVICE_ID_RDC_R6020 0x6020
+#define PCI_DEVICE_ID_RDC_R6030 0x6030
+#define PCI_DEVICE_ID_RDC_R6040 0x6040
+#define PCI_DEVICE_ID_RDC_R6060 0x6060
+#define PCI_DEVICE_ID_RDC_R6061 0x6061
+
+#define PCI_VENDOR_ID_LENOVO 0x17aa
+
+#define PCI_VENDOR_ID_ARECA 0x17d3
+#define PCI_DEVICE_ID_ARECA_1110 0x1110
+#define PCI_DEVICE_ID_ARECA_1120 0x1120
+#define PCI_DEVICE_ID_ARECA_1130 0x1130
+#define PCI_DEVICE_ID_ARECA_1160 0x1160
+#define PCI_DEVICE_ID_ARECA_1170 0x1170
+#define PCI_DEVICE_ID_ARECA_1200 0x1200
+#define PCI_DEVICE_ID_ARECA_1201 0x1201
+#define PCI_DEVICE_ID_ARECA_1202 0x1202
+#define PCI_DEVICE_ID_ARECA_1210 0x1210
+#define PCI_DEVICE_ID_ARECA_1220 0x1220
+#define PCI_DEVICE_ID_ARECA_1230 0x1230
+#define PCI_DEVICE_ID_ARECA_1260 0x1260
+#define PCI_DEVICE_ID_ARECA_1270 0x1270
+#define PCI_DEVICE_ID_ARECA_1280 0x1280
+#define PCI_DEVICE_ID_ARECA_1380 0x1380
+#define PCI_DEVICE_ID_ARECA_1381 0x1381
+#define PCI_DEVICE_ID_ARECA_1680 0x1680
+#define PCI_DEVICE_ID_ARECA_1681 0x1681
+
+#define PCI_VENDOR_ID_S2IO 0x17d5
+#define PCI_DEVICE_ID_S2IO_WIN 0x5731
+#define PCI_DEVICE_ID_S2IO_UNI 0x5831
+#define PCI_DEVICE_ID_HERC_WIN 0x5732
+#define PCI_DEVICE_ID_HERC_UNI 0x5832
+
+#define PCI_VENDOR_ID_SITECOM 0x182d
+#define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069
+
+#define PCI_VENDOR_ID_TOPSPIN 0x1867
+
+#define PCI_VENDOR_ID_TDI 0x192E
+#define PCI_DEVICE_ID_TDI_EHCI 0x0101
+
+#define PCI_VENDOR_ID_FREESCALE 0x1957
+#define PCI_DEVICE_ID_MPC8548E 0x0012
+#define PCI_DEVICE_ID_MPC8548 0x0013
+#define PCI_DEVICE_ID_MPC8543E 0x0014
+#define PCI_DEVICE_ID_MPC8543 0x0015
+#define PCI_DEVICE_ID_MPC8547E 0x0018
+#define PCI_DEVICE_ID_MPC8545E 0x0019
+#define PCI_DEVICE_ID_MPC8545 0x001a
+#define PCI_DEVICE_ID_MPC8568E 0x0020
+#define PCI_DEVICE_ID_MPC8568 0x0021
+#define PCI_DEVICE_ID_MPC8567E 0x0022
+#define PCI_DEVICE_ID_MPC8567 0x0023
+#define PCI_DEVICE_ID_MPC8533E 0x0030
+#define PCI_DEVICE_ID_MPC8533 0x0031
+#define PCI_DEVICE_ID_MPC8544E 0x0032
+#define PCI_DEVICE_ID_MPC8544 0x0033
+#define PCI_DEVICE_ID_MPC8572E 0x0040
+#define PCI_DEVICE_ID_MPC8572 0x0041
+#define PCI_DEVICE_ID_MPC8536E 0x0050
+#define PCI_DEVICE_ID_MPC8536 0x0051
+#define PCI_DEVICE_ID_MPC8641 0x7010
+#define PCI_DEVICE_ID_MPC8641D 0x7011
+#define PCI_DEVICE_ID_MPC8610 0x7018
+
+#define PCI_VENDOR_ID_PASEMI 0x1959
+
+#define PCI_VENDOR_ID_ATTANSIC 0x1969
+#define PCI_DEVICE_ID_ATTANSIC_L1 0x1048
+#define PCI_DEVICE_ID_ATTANSIC_L2 0x2048
+
+#define PCI_VENDOR_ID_JMICRON 0x197B
+#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
+#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
+#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
+#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
+#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
+#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
+#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381
+#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382
+#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383
+
+#define PCI_VENDOR_ID_KORENIX 0x1982
+#define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600
+#define PCI_DEVICE_ID_KORENIX_JETCARDF1 0x16ff
+
+#define PCI_VENDOR_ID_TEKRAM 0x1de1
+#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
+
+#define PCI_VENDOR_ID_TEHUTI 0x1fc9
+#define PCI_DEVICE_ID_TEHUTI_3009 0x3009
+#define PCI_DEVICE_ID_TEHUTI_3010 0x3010
+#define PCI_DEVICE_ID_TEHUTI_3014 0x3014
+
+#define PCI_VENDOR_ID_HINT 0x3388
+#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013
+
+#define PCI_VENDOR_ID_3DLABS 0x3d3d
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009
+
+#define PCI_VENDOR_ID_NETXEN 0x4040
+#define PCI_DEVICE_ID_NX2031_10GXSR 0x0001
+#define PCI_DEVICE_ID_NX2031_10GCX4 0x0002
+#define PCI_DEVICE_ID_NX2031_4GCU 0x0003
+#define PCI_DEVICE_ID_NX2031_IMEZ 0x0004
+#define PCI_DEVICE_ID_NX2031_HMEZ 0x0005
+#define PCI_DEVICE_ID_NX2031_XG_MGMT 0x0024
+#define PCI_DEVICE_ID_NX2031_XG_MGMT2 0x0025
+#define PCI_DEVICE_ID_NX3031 0x0100
+
+#define PCI_VENDOR_ID_AKS 0x416c
+#define PCI_DEVICE_ID_AKS_ALADDINCARD 0x0100
+
+#define PCI_VENDOR_ID_S3 0x5333
+#define PCI_DEVICE_ID_S3_TRIO 0x8811
+#define PCI_DEVICE_ID_S3_868 0x8880
+#define PCI_DEVICE_ID_S3_968 0x88f0
+#define PCI_DEVICE_ID_S3_SAVAGE4 0x8a25
+#define PCI_DEVICE_ID_S3_PROSAVAGE8 0x8d04
+#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
+
+#define PCI_VENDOR_ID_DUNORD 0x5544
+#define PCI_DEVICE_ID_DUNORD_I3000 0x0001
+
+#define PCI_VENDOR_ID_DCI 0x6666
+#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
+#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002
+#define PCI_DEVICE_ID_DCI_PCCOM2 0x0004
+
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_EESSC 0x0008
+#define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320
+#define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321
+#define PCI_DEVICE_ID_INTEL_PXH_0 0x0329
+#define PCI_DEVICE_ID_INTEL_PXH_1 0x032A
+#define PCI_DEVICE_ID_INTEL_PXHV 0x032C
+#define PCI_DEVICE_ID_INTEL_82375 0x0482
+#define PCI_DEVICE_ID_INTEL_82424 0x0483
+#define PCI_DEVICE_ID_INTEL_82378 0x0484
+#define PCI_DEVICE_ID_INTEL_I960 0x0960
+#define PCI_DEVICE_ID_INTEL_I960RM 0x0962
+#define PCI_DEVICE_ID_INTEL_82815_MC 0x1130
+#define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132
+#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221
+#define PCI_DEVICE_ID_INTEL_7505_0 0x2550
+#define PCI_DEVICE_ID_INTEL_7205_0 0x255d
+#define PCI_DEVICE_ID_INTEL_82437 0x122d
+#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e
+#define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230
+#define PCI_DEVICE_ID_INTEL_82371MX 0x1234
+#define PCI_DEVICE_ID_INTEL_82441 0x1237
+#define PCI_DEVICE_ID_INTEL_82380FB 0x124b
+#define PCI_DEVICE_ID_INTEL_82439 0x1250
+#define PCI_DEVICE_ID_INTEL_80960_RP 0x1960
+#define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21
+#define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30
+#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38
+#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410
+#define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411
+#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413
+#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
+#define PCI_DEVICE_ID_INTEL_82801AA_6 0x2416
+#define PCI_DEVICE_ID_INTEL_82801AA_8 0x2418
+#define PCI_DEVICE_ID_INTEL_82801AB_0 0x2420
+#define PCI_DEVICE_ID_INTEL_82801AB_1 0x2421
+#define PCI_DEVICE_ID_INTEL_82801AB_3 0x2423
+#define PCI_DEVICE_ID_INTEL_82801AB_5 0x2425
+#define PCI_DEVICE_ID_INTEL_82801AB_6 0x2426
+#define PCI_DEVICE_ID_INTEL_82801AB_8 0x2428
+#define PCI_DEVICE_ID_INTEL_82801BA_0 0x2440
+#define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443
+#define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445
+#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448
+#define PCI_DEVICE_ID_INTEL_82801BA_8 0x244a
+#define PCI_DEVICE_ID_INTEL_82801BA_9 0x244b
+#define PCI_DEVICE_ID_INTEL_82801BA_10 0x244c
+#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e
+#define PCI_DEVICE_ID_INTEL_82801E_0 0x2450
+#define PCI_DEVICE_ID_INTEL_82801E_11 0x245b
+#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480
+#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483
+#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485
+#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486
+#define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a
+#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b
+#define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c
+#define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0
+#define PCI_DEVICE_ID_INTEL_82801DB_1 0x24c1
+#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3
+#define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5
+#define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6
+#define PCI_DEVICE_ID_INTEL_82801DB_9 0x24c9
+#define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca
+#define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb
+#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc
+#define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0
+#define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1
+#define PCI_DEVICE_ID_INTEL_82801EB_3 0x24d3
+#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5
+#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6
+#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db
+#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc
+#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd
+#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1
+#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2
+#define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4
+#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6
+#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab
+#define PCI_DEVICE_ID_INTEL_82820_HB 0x2500
+#define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501
+#define PCI_DEVICE_ID_INTEL_82850_HB 0x2530
+#define PCI_DEVICE_ID_INTEL_82860_HB 0x2531
+#define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c
+#define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560
+#define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562
+#define PCI_DEVICE_ID_INTEL_82865_HB 0x2570
+#define PCI_DEVICE_ID_INTEL_82865_IG 0x2572
+#define PCI_DEVICE_ID_INTEL_82875_HB 0x2578
+#define PCI_DEVICE_ID_INTEL_82915G_HB 0x2580
+#define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582
+#define PCI_DEVICE_ID_INTEL_82915GM_HB 0x2590
+#define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592
+#define PCI_DEVICE_ID_INTEL_5000_ERR 0x25F0
+#define PCI_DEVICE_ID_INTEL_5000_FBD0 0x25F5
+#define PCI_DEVICE_ID_INTEL_5000_FBD1 0x25F6
+#define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770
+#define PCI_DEVICE_ID_INTEL_82945G_IG 0x2772
+#define PCI_DEVICE_ID_INTEL_3000_HB 0x2778
+#define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0
+#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2
+#define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640
+#define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641
+#define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642
+#define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a
+#define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d
+#define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e
+#define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f
+#define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670
+#define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698
+#define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b
+#define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e
+#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8
+#define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9
+#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0
+#define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd
+#define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da
+#define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd
+#define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de
+#define PCI_DEVICE_ID_INTEL_ICH7_21 0x27df
+#define PCI_DEVICE_ID_INTEL_ICH8_0 0x2810
+#define PCI_DEVICE_ID_INTEL_ICH8_1 0x2811
+#define PCI_DEVICE_ID_INTEL_ICH8_2 0x2812
+#define PCI_DEVICE_ID_INTEL_ICH8_3 0x2814
+#define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815
+#define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e
+#define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850
+#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910
+#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917
+#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912
+#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913
+#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914
+#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919
+#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930
+#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916
+#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918
+#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432
+#define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433
+#define PCI_DEVICE_ID_INTEL_82830_HB 0x3575
+#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
+#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580
+#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582
+#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590
+#define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592
+#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595
+#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596
+#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597
+#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598
+#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599
+#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a
+#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e
+#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b
+#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c
+#define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14
+#define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16
+#define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18
+#define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a
+#define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30
+#define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60
+#define PCI_DEVICE_ID_INTEL_PCH_LPC_MIN 0x3b00
+#define PCI_DEVICE_ID_INTEL_PCH_LPC_MAX 0x3b1f
+#define PCI_DEVICE_ID_INTEL_PCH_SMBUS 0x3b30
+#define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f
+#define PCI_DEVICE_ID_INTEL_5100_16 0x65f0
+#define PCI_DEVICE_ID_INTEL_5100_21 0x65f5
+#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6
+#define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030
+#define PCI_DEVICE_ID_INTEL_5400_FBD0 0x4035
+#define PCI_DEVICE_ID_INTEL_5400_FBD1 0x4036
+#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff
+#define PCI_DEVICE_ID_INTEL_TOLAPAI_0 0x5031
+#define PCI_DEVICE_ID_INTEL_TOLAPAI_1 0x5032
+#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
+#define PCI_DEVICE_ID_INTEL_82437VX 0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX 0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+#define PCI_DEVICE_ID_INTEL_82810_MC1 0x7120
+#define PCI_DEVICE_ID_INTEL_82810_IG1 0x7121
+#define PCI_DEVICE_ID_INTEL_82810_MC3 0x7122
+#define PCI_DEVICE_ID_INTEL_82810_IG3 0x7123
+#define PCI_DEVICE_ID_INTEL_82810E_MC 0x7124
+#define PCI_DEVICE_ID_INTEL_82810E_IG 0x7125
+#define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180
+#define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181
+#define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192
+#define PCI_DEVICE_ID_INTEL_440MX 0x7195
+#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196
+#define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198
+#define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199
+#define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b
+#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0
+#define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2
+#define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601
+#define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119
+#define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a
+#define PCI_DEVICE_ID_INTEL_82454GX 0x84c4
+#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5
+#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb
+#define PCI_DEVICE_ID_INTEL_84460GX 0x84ea
+#define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500
+#define PCI_DEVICE_ID_INTEL_IXP2800 0x9004
+#define PCI_DEVICE_ID_INTEL_S21152BB 0xb152
+
+#define PCI_VENDOR_ID_SCALEMP 0x8686
+#define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010
+
+#define PCI_VENDOR_ID_COMPUTONE 0x8e0e
+#define PCI_DEVICE_ID_COMPUTONE_IP2EX 0x0291
+#define PCI_DEVICE_ID_COMPUTONE_PG 0x0302
+#define PCI_SUBVENDOR_ID_COMPUTONE 0x8e0e
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG8 0x0002
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG6 0x0003
+
+#define PCI_VENDOR_ID_KTI 0x8e2e
+
+#define PCI_VENDOR_ID_ADAPTEC 0x9004
+#define PCI_DEVICE_ID_ADAPTEC_7810 0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821 0x2178
+#define PCI_DEVICE_ID_ADAPTEC_38602 0x3860
+#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078
+#define PCI_DEVICE_ID_ADAPTEC_7855 0x5578
+#define PCI_DEVICE_ID_ADAPTEC_3860 0x6038
+#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
+#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078
+#define PCI_DEVICE_ID_ADAPTEC_7861 0x6178
+#define PCI_DEVICE_ID_ADAPTEC_7870 0x7078
+#define PCI_DEVICE_ID_ADAPTEC_7871 0x7178
+#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278
+#define PCI_DEVICE_ID_ADAPTEC_7873 0x7378
+#define PCI_DEVICE_ID_ADAPTEC_7874 0x7478
+#define PCI_DEVICE_ID_ADAPTEC_7895 0x7895
+#define PCI_DEVICE_ID_ADAPTEC_7880 0x8078
+#define PCI_DEVICE_ID_ADAPTEC_7881 0x8178
+#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278
+#define PCI_DEVICE_ID_ADAPTEC_7883 0x8378
+#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885 0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886 0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887 0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888 0x8878
+
+#define PCI_VENDOR_ID_ADAPTEC2 0x9005
+#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B 0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f
+#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050
+#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051
+#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A 0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B 0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D 0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P 0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A 0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B 0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D 0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf
+#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN 0x0500
+#define PCI_DEVICE_ID_ADAPTEC2_SCAMP 0x0503
+
+#define PCI_VENDOR_ID_HOLTEK 0x9412
+#define PCI_DEVICE_ID_HOLTEK_6565 0x6565
+
+#define PCI_VENDOR_ID_NETMOS 0x9710
+#define PCI_DEVICE_ID_NETMOS_9705 0x9705
+#define PCI_DEVICE_ID_NETMOS_9715 0x9715
+#define PCI_DEVICE_ID_NETMOS_9735 0x9735
+#define PCI_DEVICE_ID_NETMOS_9745 0x9745
+#define PCI_DEVICE_ID_NETMOS_9755 0x9755
+#define PCI_DEVICE_ID_NETMOS_9805 0x9805
+#define PCI_DEVICE_ID_NETMOS_9815 0x9815
+#define PCI_DEVICE_ID_NETMOS_9835 0x9835
+#define PCI_DEVICE_ID_NETMOS_9845 0x9845
+#define PCI_DEVICE_ID_NETMOS_9855 0x9855
+
+#define PCI_VENDOR_ID_3COM_2 0xa727
+
+#define PCI_VENDOR_ID_DIGIUM 0xd161
+#define PCI_DEVICE_ID_DIGIUM_HFC4S 0xb410
+
+#define PCI_SUBVENDOR_ID_EXSYS 0xd84d
+#define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014
+#define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055
+
+#define PCI_VENDOR_ID_TIGERJET 0xe159
+#define PCI_DEVICE_ID_TIGERJET_300 0x0001
+#define PCI_DEVICE_ID_TIGERJET_100 0x0002
+
+#define PCI_VENDOR_ID_XILINX_RME 0xea60
+#define PCI_DEVICE_ID_RME_DIGI32 0x9896
+#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897
+#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001
--- /dev/null
+/*
+ * pci_regs.h
+ *
+ * PCI standard defines
+ * Copyright 1994, Drew Eckhardt
+ * Copyright 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ * For more information, please consult the following manuals (look at
+ * http://www.pcisig.com/ for how to get them):
+ *
+ * PCI BIOS Specification
+ * PCI Local Bus Specification
+ * PCI to PCI Bridge Specification
+ * PCI System Design Guide
+ *
+ * For hypertransport information, please consult the following manuals
+ * from http://www.hypertransport.org
+ *
+ * The Hypertransport I/O Link Specification
+ */
+
+#ifndef LINUX_PCI_REGS_H
+#define LINUX_PCI_REGS_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
+#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
+#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
+#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
+#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */
+#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */
+#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */
+#define PCI_COMMAND_SERR 0x100 /* Enable SERR */
+#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */
+#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+#define PCI_STATUS 0x06 /* 16 bits */
+#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
+#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
+#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
+#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
+#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
+#define PCI_STATUS_DEVSEL_FAST 0x000
+#define PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define PCI_STATUS_DEVSEL_SLOW 0x400
+#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */
+#define PCI_REVISION_ID 0x08 /* Revision ID */
+#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE 0x0a /* Device class */
+
+#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
+#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
+#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+#define PCI_HEADER_TYPE_NORMAL 0
+#define PCI_HEADER_TYPE_BRIDGE 1
+#define PCI_HEADER_TYPE_CARDBUS 2
+
+#define PCI_BIST 0x0f /* 8 bits */
+#define PCI_BIST_CODE_MASK 0x0f /* Return result */
+#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back. Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
+#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
+#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
+#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
+#define PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
+#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
+#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
+#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS 0x28
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+#define PCI_SUBSYSTEM_ID 0x2e
+#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
+#define PCI_ROM_ADDRESS_ENABLE 0x01
+#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
+#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
+#define PCI_MIN_GNT 0x3e /* 8 bits */
+#define PCI_MAX_LAT 0x3f /* 8 bits */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */
+#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */
+#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */
+#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */
+#define PCI_IO_LIMIT 0x1d
+#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */
+#define PCI_IO_RANGE_TYPE_16 0x00
+#define PCI_IO_RANGE_TYPE_32 0x01
+#define PCI_IO_RANGE_MASK (~0x0fUL)
+#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE 0x20 /* Memory range behind */
+#define PCI_MEMORY_LIMIT 0x22
+#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
+#define PCI_MEMORY_RANGE_MASK (~0x0fUL)
+#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT 0x26
+#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define PCI_PREF_RANGE_TYPE_32 0x00
+#define PCI_PREF_RANGE_TYPE_64 0x01
+#define PCI_PREF_RANGE_MASK (~0x0fUL)
+#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32 0x2c
+#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16 0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL 0x3e
+#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */
+#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */
+#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */
+#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */
+#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */
+#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */
+#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+#define PCI_CB_CAPABILITY_LIST 0x14
+/* 0x15 reserved */
+#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */
+#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */
+#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0 0x1c
+#define PCI_CB_MEMORY_LIMIT_0 0x20
+#define PCI_CB_MEMORY_BASE_1 0x24
+#define PCI_CB_MEMORY_LIMIT_1 0x28
+#define PCI_CB_IO_BASE_0 0x2c
+#define PCI_CB_IO_BASE_0_HI 0x2e
+#define PCI_CB_IO_LIMIT_0 0x30
+#define PCI_CB_IO_LIMIT_0_HI 0x32
+#define PCI_CB_IO_BASE_1 0x34
+#define PCI_CB_IO_BASE_1_HI 0x36
+#define PCI_CB_IO_LIMIT_1 0x38
+#define PCI_CB_IO_LIMIT_1_HI 0x3a
+#define PCI_CB_IO_RANGE_MASK (~0x03UL)
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL 0x3e
+#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */
+#define PCI_CB_BRIDGE_CTL_SERR 0x02
+#define PCI_CB_BRIDGE_CTL_ISA 0x04
+#define PCI_CB_BRIDGE_CTL_VGA 0x08
+#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20
+#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */
+#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
+#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
+#define PCI_CB_SUBSYSTEM_ID 0x42
+#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID 0 /* Capability ID */
+#define PCI_CAP_ID_PM 0x01 /* Power Management */
+#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
+#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */
+#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */
+#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
+#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
+#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
+#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
+#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific */
+#define PCI_CAP_ID_DBG 0x0A /* Debug port */
+#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */
+#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
+#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */
+#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */
+#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
+#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
+#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
+#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF 4
+
+/* Power Management Registers */
+
+#define PCI_PM_PMC 2 /* PM Capabilities Register */
+#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */
+#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */
+#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */
+#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */
+#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxilliary power support mask */
+#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */
+#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */
+#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */
+#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */
+#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */
+#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */
+#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */
+#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */
+#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */
+#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */
+#define PCI_PM_CTRL 4 /* PM control and status register */
+#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */
+#define PCI_PM_CTRL_NO_SOFT_RESET 0x0004 /* No reset for D3hot->D0 */
+#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */
+#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */
+#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */
+#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */
+#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */
+#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */
+#define PCI_PM_DATA_REGISTER 7 /* (??) */
+#define PCI_PM_SIZEOF 8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION 2 /* BCD version number */
+#define PCI_AGP_RFU 3 /* Rest of capability flags */
+#define PCI_AGP_STATUS 4 /* Status register */
+#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */
+#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */
+#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */
+#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */
+#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */
+#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */
+#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */
+#define PCI_AGP_COMMAND 8 /* Control register */
+#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */
+#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */
+#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */
+#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */
+#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */
+#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */
+#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */
+#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */
+#define PCI_AGP_SIZEOF 12
+
+/* Vital Product Data */
+
+#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */
+#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */
+#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */
+#define PCI_VPD_DATA 4 /* 32-bits of data returned here */
+
+/* Slot Identification */
+
+#define PCI_SID_ESR 2 /* Expansion Slot Register */
+#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */
+#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */
+
+/* Message Signalled Interrupts registers */
+
+#define PCI_MSI_FLAGS 2 /* Various flags */
+#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */
+#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */
+#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */
+#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */
+#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */
+#define PCI_MSI_RFU 3 /* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
+#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
+#define PCI_MSI_MASK_BIT 16 /* Mask bits register */
+
+/* MSI-X registers (these are at offset PCI_MSIX_FLAGS) */
+#define PCI_MSIX_FLAGS 2
+#define PCI_MSIX_FLAGS_QSIZE 0x7FF
+#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
+#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
+#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
+
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR 2 /* Control and Status Register */
+#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */
+#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */
+#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */
+#define PCI_CHSWP_LOO 0x08 /* LED On / Off */
+#define PCI_CHSWP_PI 0x30 /* Programming Interface */
+#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */
+#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */
+
+/* PCI-X registers */
+
+#define PCI_X_CMD 2 /* Modes & Features */
+#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */
+#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */
+#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */
+#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */
+#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */
+#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */
+#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */
+ /* Max # of outstanding split transactions */
+#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */
+#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */
+#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */
+#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */
+#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */
+#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */
+#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */
+#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */
+#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */
+#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */
+#define PCI_X_STATUS 4 /* PCI-X capabilities */
+#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */
+#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */
+#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */
+#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */
+#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */
+#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */
+#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */
+#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */
+#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */
+#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */
+#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */
+#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */
+#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */
+
+/* PCI Express capability registers */
+
+#define PCI_EXP_FLAGS 2 /* Capabilities register */
+#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */
+#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */
+#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */
+#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */
+#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */
+#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */
+#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */
+#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */
+#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */
+#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */
+#define PCI_EXP_DEVCAP 4 /* Device capabilities */
+#define PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */
+#define PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */
+#define PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */
+#define PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */
+#define PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */
+#define PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */
+#define PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */
+#define PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */
+#define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */
+#define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */
+#define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */
+#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */
+#define PCI_EXP_DEVCTL 8 /* Device Control */
+#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */
+#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */
+#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */
+#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */
+#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */
+#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */
+#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */
+#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */
+#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */
+#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
+#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */
+#define PCI_EXP_DEVSTA 10 /* Device Status */
+#define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */
+#define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */
+#define PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */
+#define PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */
+#define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */
+#define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */
+#define PCI_EXP_LNKCAP 12 /* Link Capabilities */
+#define PCI_EXP_LNKCAP_ASPMS 0xc00 /* ASPM Support */
+#define PCI_EXP_LNKCAP_L0SEL 0x7000 /* L0s Exit Latency */
+#define PCI_EXP_LNKCAP_L1EL 0x38000 /* L1 Exit Latency */
+#define PCI_EXP_LNKCAP_CLKPM 0x40000 /* L1 Clock Power Management */
+#define PCI_EXP_LNKCTL 16 /* Link Control */
+#define PCI_EXP_LNKCTL_RL 0x20 /* Retrain Link */
+#define PCI_EXP_LNKCTL_CCC 0x40 /* Common Clock COnfiguration */
+#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
+#define PCI_EXP_LNKSTA 18 /* Link Status */
+#define PCI_EXP_LNKSTA_LT 0x800 /* Link Training */
+#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */
+#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */
+#define PCI_EXP_SLTCTL 24 /* Slot Control */
+#define PCI_EXP_SLTSTA 26 /* Slot Status */
+#define PCI_EXP_RTCTL 28 /* Root Control */
+#define PCI_EXP_RTCTL_SECEE 0x01 /* System Error on Correctable Error */
+#define PCI_EXP_RTCTL_SENFEE 0x02 /* System Error on Non-Fatal Error */
+#define PCI_EXP_RTCTL_SEFEE 0x04 /* System Error on Fatal Error */
+#define PCI_EXP_RTCTL_PMEIE 0x08 /* PME Interrupt Enable */
+#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */
+#define PCI_EXP_RTCAP 30 /* Root Capabilities */
+#define PCI_EXP_RTSTA 32 /* Root Status */
+#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
+#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */
+#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
+#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */
+
+/* Extended Capabilities (PCI-X 2.0 and Express) */
+#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff)
+#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf)
+#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc)
+
+#define PCI_EXT_CAP_ID_ERR 1
+#define PCI_EXT_CAP_ID_VC 2
+#define PCI_EXT_CAP_ID_DSN 3
+#define PCI_EXT_CAP_ID_PWR 4
+#define PCI_EXT_CAP_ID_ARI 14
+
+/* Advanced Error Reporting */
+#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */
+#define PCI_ERR_UNC_TRAIN 0x00000001 /* Training */
+#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */
+#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */
+#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */
+#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */
+#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */
+#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */
+#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */
+#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */
+#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */
+#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */
+#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */
+ /* Same bits as above */
+#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */
+ /* Same bits as above */
+#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */
+#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */
+#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */
+#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */
+#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */
+#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */
+#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */
+ /* Same bits as above */
+#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */
+#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */
+#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
+#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
+#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
+#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
+#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */
+#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */
+/* Correctable Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001
+/* Non-fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002
+/* Fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004
+#define PCI_ERR_ROOT_STATUS 48
+#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */
+/* Multi ERR_COR Received */
+#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002
+/* ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004
+/* Multi ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008
+#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */
+#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */
+#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */
+#define PCI_ERR_ROOT_COR_SRC 52
+#define PCI_ERR_ROOT_SRC 54
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1 4
+#define PCI_VC_PORT_REG2 8
+#define PCI_VC_PORT_CTRL 12
+#define PCI_VC_PORT_STATUS 14
+#define PCI_VC_RES_CAP 16
+#define PCI_VC_RES_CTRL 20
+#define PCI_VC_RES_STATUS 26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR 4 /* Data Select Register */
+#define PCI_PWR_DATA 8 /* Data Register */
+#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */
+#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */
+#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */
+#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */
+#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */
+#define PCI_PWR_CAP 12 /* Capability */
+#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
+
+/*
+ * Hypertransport sub capability types
+ *
+ * Unfortunately there are both 3 bit and 5 bit capability types defined
+ * in the HT spec, catering for that is a little messy. You probably don't
+ * want to use these directly, just use pci_find_ht_capability() and it
+ * will do the right thing for you.
+ */
+#define HT_3BIT_CAP_MASK 0xE0
+#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */
+
+#define HT_5BIT_CAP_MASK 0xF8
+#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */
+#define HT_MSI_FLAGS 0x02 /* Offset to flags */
+#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */
+#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */
+#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */
+#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */
+#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */
+#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */
+#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */
+#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */
+#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */
+
+/* Alternative Routing-ID Interpretation */
+#define PCI_ARI_CAP 0x04 /* ARI Capability Register */
+#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */
+#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */
+#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */
+#define PCI_ARI_CTRL 0x06 /* ARI Control Register */
+#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */
+#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */
+#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */
+
+#endif /* LINUX_PCI_REGS_H */
--- /dev/null
+// PCI BIOS (int 1a/b1) calls
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "types.h" // u32
+#include "util.h" // handle_1ab1
+#include "pci.h" // pci_config_readl
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_EBDA
+#include "pci_regs.h" // PCI_VENDOR_ID
+
+// romlayout.S
+extern void entry_bios32(void);
+extern void entry_pcibios32(void);
+
+#define RET_FUNC_NOT_SUPPORTED 0x81
+#define RET_BAD_VENDOR_ID 0x83
+#define RET_DEVICE_NOT_FOUND 0x86
+#define RET_BUFFER_TOO_SMALL 0x89
+
+// installation check
+static void
+handle_1ab101(struct bregs *regs)
+{
+ regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
+ regs->bx = 0x0210; // PCI version 2.10
+ regs->cl = GET_GLOBAL(MaxPCIBus);
+ regs->edx = 0x20494350; // "PCI "
+ regs->edi = (u32)entry_pcibios32 + BUILD_BIOS_ADDR;
+ set_code_success(regs);
+}
+
+// find pci device
+static void
+handle_1ab102(struct bregs *regs)
+{
+ u32 id = (regs->cx << 16) | regs->dx;
+ int count = regs->si;
+ int bus = -1;
+ while (bus < GET_GLOBAL(MaxPCIBus)) {
+ bus++;
+ int bdf;
+ foreachbdf(bdf, bus) {
+ u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
+ if (v != id)
+ continue;
+ if (count--)
+ continue;
+ regs->bx = bdf;
+ set_code_success(regs);
+ return;
+ }
+ }
+ set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
+}
+
+// find class code
+static void
+handle_1ab103(struct bregs *regs)
+{
+ int count = regs->si;
+ u32 classprog = regs->ecx;
+ int bus = -1;
+ while (bus < GET_GLOBAL(MaxPCIBus)) {
+ bus++;
+ int bdf;
+ foreachbdf(bdf, bus) {
+ u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
+ if ((v>>8) != classprog)
+ continue;
+ if (count--)
+ continue;
+ regs->bx = bdf;
+ set_code_success(regs);
+ return;
+ }
+ }
+ set_code_invalid(regs, RET_DEVICE_NOT_FOUND);
+}
+
+// read configuration byte
+static void
+handle_1ab108(struct bregs *regs)
+{
+ regs->cl = pci_config_readb(regs->bx, regs->di);
+ set_code_success(regs);
+}
+
+// read configuration word
+static void
+handle_1ab109(struct bregs *regs)
+{
+ regs->cx = pci_config_readw(regs->bx, regs->di);
+ set_code_success(regs);
+}
+
+// read configuration dword
+static void
+handle_1ab10a(struct bregs *regs)
+{
+ regs->ecx = pci_config_readl(regs->bx, regs->di);
+ set_code_success(regs);
+}
+
+// write configuration byte
+static void
+handle_1ab10b(struct bregs *regs)
+{
+ pci_config_writeb(regs->bx, regs->di, regs->cl);
+ set_code_success(regs);
+}
+
+// write configuration word
+static void
+handle_1ab10c(struct bregs *regs)
+{
+ pci_config_writew(regs->bx, regs->di, regs->cx);
+ set_code_success(regs);
+}
+
+// write configuration dword
+static void
+handle_1ab10d(struct bregs *regs)
+{
+ pci_config_writel(regs->bx, regs->di, regs->ecx);
+ set_code_success(regs);
+}
+
+// get irq routing options
+static void
+handle_1ab10e(struct bregs *regs)
+{
+ struct pir_header *pirtable_g = (void*)(GET_GLOBAL(PirOffset) + 0);
+ if (! pirtable_g) {
+ set_code_invalid(regs, RET_FUNC_NOT_SUPPORTED);
+ return;
+ }
+
+ struct param_s {
+ u16 size;
+ u16 buf_off;
+ u16 buf_seg;
+ } *param_far = (void*)(regs->di+0);
+
+ // Validate and update size.
+ u16 bufsize = GET_FARVAR(regs->es, param_far->size);
+ u16 pirsize = GET_GLOBAL(pirtable_g->size) - sizeof(struct pir_header);
+ SET_FARVAR(regs->es, param_far->size, pirsize);
+ if (bufsize < pirsize) {
+ set_code_invalid(regs, RET_BUFFER_TOO_SMALL);
+ return;
+ }
+
+ // Get dest buffer.
+ void *buf_far = (void*)(GET_FARVAR(regs->es, param_far->buf_off)+0);
+ u16 buf_seg = GET_FARVAR(regs->es, param_far->buf_seg);
+
+ // Memcpy pir table slots to dest buffer.
+ memcpy_far(buf_seg, buf_far
+ , get_global_seg()
+ , (void*)(pirtable_g->slots) + get_global_offset()
+ , pirsize);
+
+ // XXX - bochs bios sets bx to (1 << 9) | (1 << 11)
+ regs->bx = GET_GLOBAL(pirtable_g->exclusive_irqs);
+ set_code_success(regs);
+}
+
+static void
+handle_1ab1XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_FUNC_NOT_SUPPORTED);
+}
+
+void
+handle_1ab1(struct bregs *regs)
+{
+ //debug_stub(regs);
+
+ if (! CONFIG_PCIBIOS) {
+ set_invalid(regs);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x01: handle_1ab101(regs); break;
+ case 0x02: handle_1ab102(regs); break;
+ case 0x03: handle_1ab103(regs); break;
+ case 0x08: handle_1ab108(regs); break;
+ case 0x09: handle_1ab109(regs); break;
+ case 0x0a: handle_1ab10a(regs); break;
+ case 0x0b: handle_1ab10b(regs); break;
+ case 0x0c: handle_1ab10c(regs); break;
+ case 0x0d: handle_1ab10d(regs); break;
+ case 0x0e: handle_1ab10e(regs); break;
+ default: handle_1ab1XX(regs); break;
+ }
+}
+
+
+/****************************************************************
+ * 32bit interface
+ ****************************************************************/
+
+// Entry point for 32bit pci bios functions.
+void VISIBLE32SEG
+handle_pcibios32(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_pcibios32);
+ handle_1ab1(regs);
+}
+
+struct bios32_s {
+ u32 signature;
+ u32 entry;
+ u8 version;
+ u8 length;
+ u8 checksum;
+ u8 reserved[5];
+} PACKED;
+
+struct bios32_s BIOS32HEADER __aligned(16) VAR16EXPORT = {
+ .signature = 0x5f32335f, // _32_
+ .length = sizeof(BIOS32HEADER) / 16,
+};
+
+void
+bios32_setup(void)
+{
+ dprintf(3, "init bios32\n");
+
+ BIOS32HEADER.entry = (u32)entry_bios32;
+ BIOS32HEADER.checksum -= checksum(&BIOS32HEADER, sizeof(BIOS32HEADER));
+}
--- /dev/null
+// Initialize PCI devices (on emulators)
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_config_readl
+#include "biosvar.h" // GET_EBDA
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_COMMAND
+#include "xen.h" // usingXen
+
+#define PCI_IO_INDEX_SHIFT 2
+#define PCI_MEM_INDEX_SHIFT 12
+
+#define PCI_BRIDGE_IO_MIN 0x1000
+#define PCI_BRIDGE_MEM_MIN 0x100000
+
+enum pci_region_type {
+ PCI_REGION_TYPE_IO,
+ PCI_REGION_TYPE_MEM,
+ PCI_REGION_TYPE_PREFMEM,
+ PCI_REGION_TYPE_COUNT,
+};
+
+static const char *region_type_name[] = {
+ [ PCI_REGION_TYPE_IO ] = "io",
+ [ PCI_REGION_TYPE_MEM ] = "mem",
+ [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
+};
+
+static struct pci_bus {
+ struct {
+ /* pci region stats */
+ u32 count[32 - PCI_MEM_INDEX_SHIFT];
+ u32 sum, max;
+ /* seconday bus region sizes */
+ u32 size;
+ /* pci region assignments */
+ u32 bases[32 - PCI_MEM_INDEX_SHIFT];
+ u32 base;
+ } r[PCI_REGION_TYPE_COUNT];
+} *busses;
+static int busses_count;
+
+static void pci_bios_init_device_in_bus(int bus);
+static void pci_bios_check_device_in_bus(int bus);
+static void pci_bios_init_bus_bases(struct pci_bus *bus);
+static void pci_bios_map_device_in_bus(int bus);
+
+static int pci_size_to_index(u32 size, enum pci_region_type type)
+{
+ int index = __fls(size);
+ int shift = (type == PCI_REGION_TYPE_IO) ?
+ PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT;
+
+ if (index < shift)
+ index = shift;
+ index -= shift;
+ return index;
+}
+
+static u32 pci_index_to_size(int index, enum pci_region_type type)
+{
+ int shift = (type == PCI_REGION_TYPE_IO) ?
+ PCI_IO_INDEX_SHIFT : PCI_MEM_INDEX_SHIFT;
+
+ return 0x1 << (index + shift);
+}
+
+static enum pci_region_type pci_addr_to_type(u32 addr)
+{
+ if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+ return PCI_REGION_TYPE_IO;
+ if (addr & PCI_BASE_ADDRESS_MEM_PREFETCH)
+ return PCI_REGION_TYPE_PREFMEM;
+ return PCI_REGION_TYPE_MEM;
+}
+
+static u32 pci_size_roundup(u32 size)
+{
+ int index = __fls(size-1)+1;
+ return 0x1 << index;
+}
+
+/* host irqs corresponding to PCI irqs A-D */
+const u8 pci_irqs[4] = {
+ 10, 10, 11, 11
+};
+
+static u32 pci_bar(u16 bdf, int region_num)
+{
+ if (region_num != PCI_ROM_SLOT) {
+ return PCI_BASE_ADDRESS_0 + region_num * 4;
+ }
+
+#define PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+ u8 type = pci_config_readb(bdf, PCI_HEADER_TYPE);
+ type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+ return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
+}
+
+static void pci_set_io_region_addr(u16 bdf, int region_num, u32 addr)
+{
+ u32 ofs;
+
+ ofs = pci_bar(bdf, region_num);
+
+ pci_config_writel(bdf, ofs, addr);
+}
+
+/* return the global irq number corresponding to a given device irq
+ pin. We could also use the bus number to have a more precise
+ mapping. */
+static int pci_slot_get_pirq(u16 bdf, int irq_num)
+{
+ int slot_addend = pci_bdf_to_dev(bdf) - 1;
+ return (irq_num + slot_addend) & 3;
+}
+
+/* PIIX3/PIIX4 PCI to ISA bridge */
+static void piix_isa_bridge_init(struct pci_device *pci, void *arg)
+{
+ int i, irq;
+ u8 elcr[2];
+
+ elcr[0] = 0x00;
+ elcr[1] = 0x00;
+ for (i = 0; i < 4; i++) {
+ irq = pci_irqs[i];
+ /* set to trigger level */
+ elcr[irq >> 3] |= (1 << (irq & 7));
+ /* activate irq remapping in PIIX */
+ pci_config_writeb(pci->bdf, 0x60 + i, irq);
+ }
+ outb(elcr[0], 0x4d0);
+ outb(elcr[1], 0x4d1);
+ dprintf(1, "PIIX3/PIIX4 init: elcr=%02x %02x\n", elcr[0], elcr[1]);
+}
+
+static const struct pci_device_id pci_isa_bridge_tbl[] = {
+ /* PIIX3/PIIX4 PCI to ISA bridge */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0,
+ piix_isa_bridge_init),
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
+ piix_isa_bridge_init),
+
+ PCI_DEVICE_END
+};
+
+#define PCI_IO_ALIGN 4096
+#define PCI_IO_SHIFT 8
+#define PCI_MEMORY_ALIGN (1UL << 20)
+#define PCI_MEMORY_SHIFT 16
+#define PCI_PREF_MEMORY_ALIGN (1UL << 20)
+#define PCI_PREF_MEMORY_SHIFT 16
+
+static void storage_ide_init(struct pci_device *pci, void *arg)
+{
+ u16 bdf = pci->bdf;
+ /* IDE: we map it as in ISA mode */
+ pci_set_io_region_addr(bdf, 0, PORT_ATA1_CMD_BASE);
+ pci_set_io_region_addr(bdf, 1, PORT_ATA1_CTRL_BASE);
+ pci_set_io_region_addr(bdf, 2, PORT_ATA2_CMD_BASE);
+ pci_set_io_region_addr(bdf, 3, PORT_ATA2_CTRL_BASE);
+}
+
+/* PIIX3/PIIX4 IDE */
+static void piix_ide_init(struct pci_device *pci, void *arg)
+{
+ u16 bdf = pci->bdf;
+ pci_config_writew(bdf, 0x40, 0x8000); // enable IDE0
+ pci_config_writew(bdf, 0x42, 0x8000); // enable IDE1
+}
+
+static void pic_ibm_init(struct pci_device *pci, void *arg)
+{
+ /* PIC, IBM, MPIC & MPIC2 */
+ pci_set_io_region_addr(pci->bdf, 0, 0x80800000 + 0x00040000);
+}
+
+static void apple_macio_init(struct pci_device *pci, void *arg)
+{
+ /* macio bridge */
+ pci_set_io_region_addr(pci->bdf, 0, 0x80800000);
+}
+
+static const struct pci_device_id pci_class_tbl[] = {
+ /* STORAGE IDE */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1,
+ PCI_CLASS_STORAGE_IDE, piix_ide_init),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
+ PCI_CLASS_STORAGE_IDE, piix_ide_init),
+ PCI_DEVICE_CLASS(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE,
+ storage_ide_init),
+
+ /* PIC, IBM, MIPC & MPIC2 */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0x0046, PCI_CLASS_SYSTEM_PIC,
+ pic_ibm_init),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_IBM, 0xFFFF, PCI_CLASS_SYSTEM_PIC,
+ pic_ibm_init),
+
+ /* 0xff00 */
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0017, 0xff00, apple_macio_init),
+ PCI_DEVICE_CLASS(PCI_VENDOR_ID_APPLE, 0x0022, 0xff00, apple_macio_init),
+
+ PCI_DEVICE_END,
+};
+
+/* PIIX4 Power Management device (for ACPI) */
+static void piix4_pm_init(struct pci_device *pci, void *arg)
+{
+ u16 bdf = pci->bdf;
+ // acpi sci is hardwired to 9
+ pci_config_writeb(bdf, PCI_INTERRUPT_LINE, 9);
+
+ pci_config_writel(bdf, 0x40, PORT_ACPI_PM_BASE | 1);
+ pci_config_writeb(bdf, 0x80, 0x01); /* enable PM io space */
+ pci_config_writel(bdf, 0x90, PORT_SMB_BASE | 1);
+ pci_config_writeb(bdf, 0xd2, 0x09); /* enable SMBus io space */
+}
+
+static const struct pci_device_id pci_device_tbl[] = {
+ /* PIIX4 Power Management device (for ACPI) */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ piix4_pm_init),
+
+ PCI_DEVICE_END,
+};
+
+static void pci_bios_init_device(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ int pin, pic_irq;
+
+ dprintf(1, "PCI: bus=%d devfn=0x%02x: vendor_id=0x%04x device_id=0x%04x\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_devfn(bdf)
+ , pci->vendor, pci->device);
+ pci_init_device(pci_class_tbl, pci, NULL);
+
+ /* enable memory mappings */
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+ /* map the interrupt */
+ pin = pci_config_readb(bdf, PCI_INTERRUPT_PIN);
+ if (pin != 0) {
+ pin = pci_slot_get_pirq(bdf, pin - 1);
+ pic_irq = pci_irqs[pin];
+ pci_config_writeb(bdf, PCI_INTERRUPT_LINE, pic_irq);
+ }
+
+ pci_init_device(pci_device_tbl, pci, NULL);
+}
+
+static void pci_bios_init_device_in_bus(int bus)
+{
+ struct pci_device *pci;
+ foreachpci(pci) {
+ u8 pci_bus = pci_bdf_to_bus(pci->bdf);
+ if (pci_bus < bus)
+ continue;
+ if (pci_bus > bus)
+ break;
+ pci_bios_init_device(pci);
+ }
+}
+
+static void
+pci_bios_init_bus_rec(int bus, u8 *pci_bus)
+{
+ int bdf;
+ u16 class;
+
+ dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus);
+
+ /* prevent accidental access to unintended devices */
+ foreachbdf(bdf, bus) {
+ class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+ if (class == PCI_CLASS_BRIDGE_PCI) {
+ pci_config_writeb(bdf, PCI_SECONDARY_BUS, 255);
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 0);
+ }
+ }
+
+ foreachbdf(bdf, bus) {
+ class = pci_config_readw(bdf, PCI_CLASS_DEVICE);
+ if (class != PCI_CLASS_BRIDGE_PCI) {
+ continue;
+ }
+ dprintf(1, "PCI: %s bdf = 0x%x\n", __func__, bdf);
+
+ u8 pribus = pci_config_readb(bdf, PCI_PRIMARY_BUS);
+ if (pribus != bus) {
+ dprintf(1, "PCI: primary bus = 0x%x -> 0x%x\n", pribus, bus);
+ pci_config_writeb(bdf, PCI_PRIMARY_BUS, bus);
+ } else {
+ dprintf(1, "PCI: primary bus = 0x%x\n", pribus);
+ }
+
+ u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+ (*pci_bus)++;
+ if (*pci_bus != secbus) {
+ dprintf(1, "PCI: secondary bus = 0x%x -> 0x%x\n",
+ secbus, *pci_bus);
+ secbus = *pci_bus;
+ pci_config_writeb(bdf, PCI_SECONDARY_BUS, secbus);
+ } else {
+ dprintf(1, "PCI: secondary bus = 0x%x\n", secbus);
+ }
+
+ /* set to max for access to all subordinate buses.
+ later set it to accurate value */
+ u8 subbus = pci_config_readb(bdf, PCI_SUBORDINATE_BUS);
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, 255);
+
+ pci_bios_init_bus_rec(secbus, pci_bus);
+
+ if (subbus != *pci_bus) {
+ dprintf(1, "PCI: subordinate bus = 0x%x -> 0x%x\n",
+ subbus, *pci_bus);
+ subbus = *pci_bus;
+ } else {
+ dprintf(1, "PCI: subordinate bus = 0x%x\n", subbus);
+ }
+ pci_config_writeb(bdf, PCI_SUBORDINATE_BUS, subbus);
+ }
+}
+
+static void
+pci_bios_init_bus(void)
+{
+ u8 pci_bus = 0;
+ pci_bios_init_bus_rec(0 /* host bus */, &pci_bus);
+ busses_count = pci_bus + 1;
+}
+
+static void pci_bios_bus_get_bar(struct pci_bus *bus, int bdf, int bar,
+ u32 *val, u32 *size)
+{
+ u32 ofs = pci_bar(bdf, bar);
+ u32 old = pci_config_readl(bdf, ofs);
+ u32 mask;
+
+ if (bar == PCI_ROM_SLOT) {
+ mask = PCI_ROM_ADDRESS_MASK;
+ pci_config_writel(bdf, ofs, mask);
+ } else {
+ if (old & PCI_BASE_ADDRESS_SPACE_IO)
+ mask = PCI_BASE_ADDRESS_IO_MASK;
+ else
+ mask = PCI_BASE_ADDRESS_MEM_MASK;
+ pci_config_writel(bdf, ofs, ~0);
+ }
+ *val = pci_config_readl(bdf, ofs);
+ pci_config_writel(bdf, ofs, old);
+ *size = (~(*val & mask)) + 1;
+}
+
+static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size)
+{
+ u32 index;
+
+ index = pci_size_to_index(size, type);
+ size = pci_index_to_size(index, type);
+ bus->r[type].count[index]++;
+ bus->r[type].sum += size;
+ if (bus->r[type].max < size)
+ bus->r[type].max = size;
+}
+
+static u32 pci_bios_bus_get_addr(struct pci_bus *bus, int type, u32 size)
+{
+ u32 index, addr;
+
+ index = pci_size_to_index(size, type);
+ addr = bus->r[type].bases[index];
+ bus->r[type].bases[index] += pci_index_to_size(index, type);
+ return addr;
+}
+
+static void pci_bios_check_device(struct pci_bus *bus, struct pci_device *dev)
+{
+ u16 bdf = dev->bdf;
+ u32 limit;
+ int i,type;
+
+ if (dev->class == PCI_CLASS_BRIDGE_PCI) {
+ if (dev->secondary_bus >= busses_count) {
+ /* should never trigger */
+ dprintf(1, "PCI: bus count too small (%d), skipping bus #%d\n",
+ busses_count, dev->secondary_bus);
+ return;
+ }
+ struct pci_bus *s = busses + dev->secondary_bus;
+ pci_bios_check_device_in_bus(dev->secondary_bus);
+ for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+ limit = (type == PCI_REGION_TYPE_IO) ?
+ PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
+ s->r[type].size = s->r[type].sum;
+ if (s->r[type].size < limit)
+ s->r[type].size = limit;
+ s->r[type].size = pci_size_roundup(s->r[type].size);
+ pci_bios_bus_reserve(bus, type, s->r[type].size);
+ }
+ dprintf(1, "PCI: secondary bus %d sizes: io %x, mem %x, prefmem %x\n",
+ dev->secondary_bus,
+ s->r[PCI_REGION_TYPE_IO].size,
+ s->r[PCI_REGION_TYPE_MEM].size,
+ s->r[PCI_REGION_TYPE_PREFMEM].size);
+ return;
+ }
+
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ u32 val, size;
+ pci_bios_bus_get_bar(bus, bdf, i, &val, &size);
+ if (val == 0) {
+ continue;
+ }
+ pci_bios_bus_reserve(bus, pci_addr_to_type(val), size);
+ dev->bars[i].addr = val;
+ dev->bars[i].size = size;
+ dev->bars[i].is64 = (!(val & PCI_BASE_ADDRESS_SPACE_IO) &&
+ (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64);
+
+ if (dev->bars[i].is64) {
+ i++;
+ }
+ }
+}
+
+static void pci_bios_map_device(struct pci_bus *bus, struct pci_device *dev)
+{
+ u16 bdf = dev->bdf;
+ int type, i;
+
+ if (dev->class == PCI_CLASS_BRIDGE_PCI) {
+ if (dev->secondary_bus >= busses_count) {
+ return;
+ }
+ struct pci_bus *s = busses + dev->secondary_bus;
+ u32 base, limit;
+
+ for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+ s->r[type].base = pci_bios_bus_get_addr(bus, type, s->r[type].size);
+ }
+ dprintf(1, "PCI: init bases bus %d (secondary)\n", dev->secondary_bus);
+ pci_bios_init_bus_bases(s);
+
+ base = s->r[PCI_REGION_TYPE_IO].base;
+ limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
+ pci_config_writeb(bdf, PCI_IO_BASE, base >> PCI_IO_SHIFT);
+ pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
+ pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT);
+ pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0);
+
+ base = s->r[PCI_REGION_TYPE_MEM].base;
+ limit = base + s->r[PCI_REGION_TYPE_MEM].size - 1;
+ pci_config_writew(bdf, PCI_MEMORY_BASE, base >> PCI_MEMORY_SHIFT);
+ pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT);
+
+ base = s->r[PCI_REGION_TYPE_PREFMEM].base;
+ limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1;
+ pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, base >> PCI_PREF_MEMORY_SHIFT);
+ pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit >> PCI_PREF_MEMORY_SHIFT);
+ pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0);
+ pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0);
+
+ pci_bios_map_device_in_bus(dev->secondary_bus);
+ return;
+ }
+
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ u32 addr;
+ if (dev->bars[i].addr == 0) {
+ continue;
+ }
+
+ addr = pci_bios_bus_get_addr(bus, pci_addr_to_type(dev->bars[i].addr),
+ dev->bars[i].size);
+ dprintf(1, " bar %d, addr %x, size %x [%s]\n",
+ i, addr, dev->bars[i].size,
+ dev->bars[i].addr & PCI_BASE_ADDRESS_SPACE_IO ? "io" : "mem");
+ pci_set_io_region_addr(bdf, i, addr);
+
+ if (dev->bars[i].is64) {
+ i++;
+ }
+ }
+}
+
+static void pci_bios_check_device_in_bus(int bus)
+{
+ struct pci_device *pci;
+
+ dprintf(1, "PCI: check devices bus %d\n", bus);
+ foreachpci(pci) {
+ if (pci_bdf_to_bus(pci->bdf) != bus)
+ continue;
+ pci_bios_check_device(&busses[bus], pci);
+ }
+}
+
+static void pci_bios_map_device_in_bus(int bus)
+{
+ struct pci_device *pci;
+
+ foreachpci(pci) {
+ if (pci_bdf_to_bus(pci->bdf) != bus)
+ continue;
+ dprintf(1, "PCI: map device bus %d, bfd 0x%x\n", bus, pci->bdf);
+ pci_bios_map_device(&busses[bus], pci);
+ }
+}
+
+static void pci_bios_init_bus_bases(struct pci_bus *bus)
+{
+ u32 base, newbase, size;
+ int type, i;
+
+ for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+ dprintf(1, " type %s max %x sum %x base %x\n", region_type_name[type],
+ bus->r[type].max, bus->r[type].sum, bus->r[type].base);
+ base = bus->r[type].base;
+ for (i = ARRAY_SIZE(bus->r[type].count)-1; i >= 0; i--) {
+ size = pci_index_to_size(i, type);
+ if (!bus->r[type].count[i])
+ continue;
+ newbase = base + size * bus->r[type].count[i];
+ dprintf(1, " size %8x: %d bar(s), %8x -> %8x\n",
+ size, bus->r[type].count[i], base, newbase - 1);
+ bus->r[type].bases[i] = base;
+ base = newbase;
+ }
+ }
+}
+
+#define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1)
+
+static int pci_bios_init_root_regions(u32 start, u32 end)
+{
+ struct pci_bus *bus = &busses[0];
+
+ bus->r[PCI_REGION_TYPE_IO].base = 0xc000;
+
+ if (bus->r[PCI_REGION_TYPE_MEM].sum < bus->r[PCI_REGION_TYPE_PREFMEM].sum) {
+ bus->r[PCI_REGION_TYPE_MEM].base =
+ ROOT_BASE(end,
+ bus->r[PCI_REGION_TYPE_MEM].sum,
+ bus->r[PCI_REGION_TYPE_MEM].max);
+ bus->r[PCI_REGION_TYPE_PREFMEM].base =
+ ROOT_BASE(bus->r[PCI_REGION_TYPE_MEM].base,
+ bus->r[PCI_REGION_TYPE_PREFMEM].sum,
+ bus->r[PCI_REGION_TYPE_PREFMEM].max);
+ if (bus->r[PCI_REGION_TYPE_PREFMEM].base >= start) {
+ return 0;
+ }
+ } else {
+ bus->r[PCI_REGION_TYPE_PREFMEM].base =
+ ROOT_BASE(end,
+ bus->r[PCI_REGION_TYPE_PREFMEM].sum,
+ bus->r[PCI_REGION_TYPE_PREFMEM].max);
+ bus->r[PCI_REGION_TYPE_MEM].base =
+ ROOT_BASE(bus->r[PCI_REGION_TYPE_PREFMEM].base,
+ bus->r[PCI_REGION_TYPE_MEM].sum,
+ bus->r[PCI_REGION_TYPE_MEM].max);
+ if (bus->r[PCI_REGION_TYPE_MEM].base >= start) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void
+pci_setup(void)
+{
+ if (CONFIG_COREBOOT || usingXen()) {
+ // PCI setup already done by coreboot or Xen - just do probe.
+ pci_probe_devices();
+ return;
+ }
+
+ dprintf(3, "pci setup\n");
+
+ u32 start = BUILD_PCIMEM_START;
+ u32 end = BUILD_PCIMEM_END;
+
+ dprintf(1, "=== PCI bus & bridge init ===\n");
+ if (pci_probe_host() != 0) {
+ return;
+ }
+ pci_bios_init_bus();
+
+ dprintf(1, "=== PCI device probing ===\n");
+ pci_probe_devices();
+
+ dprintf(1, "=== PCI new allocation pass #1 ===\n");
+ busses = malloc_tmp(sizeof(*busses) * busses_count);
+ memset(busses, 0, sizeof(*busses) * busses_count);
+ pci_bios_check_device_in_bus(0 /* host bus */);
+ if (pci_bios_init_root_regions(start, end) != 0) {
+ panic("PCI: out of address space\n");
+ }
+
+ dprintf(1, "=== PCI new allocation pass #2 ===\n");
+ dprintf(1, "PCI: init bases bus 0 (primary)\n");
+ pci_bios_init_bus_bases(&busses[0]);
+ pci_bios_map_device_in_bus(0 /* host bus */);
+
+ pci_bios_init_device_in_bus(0 /* host bus */);
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ pci_init_device(pci_isa_bridge_tbl, pci, NULL);
+ }
+
+ free(busses);
+ busses_count = 0;
+}
--- /dev/null
+// Helpers for working with i8259 interrupt controller.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pic.h" // get_pic1_isr
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+
+void
+set_pics(u8 irq0, u8 irq8)
+{
+ // Send ICW1 (select OCW1 + will send ICW4)
+ outb(0x11, PORT_PIC1_CMD);
+ outb(0x11, PORT_PIC2_CMD);
+ // Send ICW2 (base irqs: 0x08-0x0f for irq0-7, 0x70-0x77 for irq8-15)
+ outb(irq0, PORT_PIC1_DATA);
+ outb(irq8, PORT_PIC2_DATA);
+ // Send ICW3 (cascaded pic ids)
+ outb(0x04, PORT_PIC1_DATA);
+ outb(0x02, PORT_PIC2_DATA);
+ // Send ICW4 (enable 8086 mode)
+ outb(0x01, PORT_PIC1_DATA);
+ outb(0x01, PORT_PIC2_DATA);
+ // Mask all irqs (except cascaded PIC2 irq)
+ outb(~PIC1_IRQ2, PORT_PIC1_DATA);
+ outb(~0, PORT_PIC2_DATA);
+}
+
+void
+pic_setup(void)
+{
+ dprintf(3, "init pic\n");
+ set_pics(0x08, 0x70);
+}
+
+// Handler for otherwise unused hardware irqs.
+void VISIBLE16
+handle_hwpic1(struct bregs *regs)
+{
+ dprintf(DEBUG_ISR_hwpic1, "handle_hwpic1 irq=%x\n", get_pic1_isr());
+ eoi_pic1();
+}
+
+void VISIBLE16
+handle_hwpic2(struct bregs *regs)
+{
+ dprintf(DEBUG_ISR_hwpic2, "handle_hwpic2 irq=%x\n", get_pic2_isr());
+ eoi_pic2();
+}
--- /dev/null
+// Helpers for working with i8259 interrupt controller.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __PIC_H
+#define __PIC_H
+
+#include "ioport.h" // PORT_PIC*
+#include "biosvar.h" // SET_IVT
+
+// PORT_PIC1 bitdefs
+#define PIC1_IRQ0 (1<<0)
+#define PIC1_IRQ1 (1<<1)
+#define PIC1_IRQ2 (1<<2)
+#define PIC1_IRQ5 (1<<5)
+#define PIC1_IRQ6 (1<<6)
+// PORT_PIC2 bitdefs
+#define PIC2_IRQ8 (1<<0)
+#define PIC2_IRQ12 (1<<4)
+#define PIC2_IRQ13 (1<<5)
+#define PIC2_IRQ14 (1<<6)
+
+static inline void
+eoi_pic1(void)
+{
+ // Send eoi (select OCW2 + eoi)
+ outb(0x20, PORT_PIC1_CMD);
+}
+
+static inline void
+eoi_pic2(void)
+{
+ // Send eoi (select OCW2 + eoi)
+ outb(0x20, PORT_PIC2_CMD);
+ eoi_pic1();
+}
+
+static inline void
+unmask_pic1(u8 irq)
+{
+ outb(inb(PORT_PIC1_DATA) & ~irq, PORT_PIC1_DATA);
+}
+
+static inline void
+unmask_pic2(u8 irq)
+{
+ outb(inb(PORT_PIC2_DATA) & ~irq, PORT_PIC2_DATA);
+}
+
+static inline void
+mask_pic1(u8 irq)
+{
+ outb(inb(PORT_PIC1_DATA) | irq, PORT_PIC1_DATA);
+}
+
+static inline void
+mask_pic2(u8 irq)
+{
+ outb(inb(PORT_PIC2_DATA) | irq, PORT_PIC2_DATA);
+}
+
+static inline u8
+get_pic1_isr(void)
+{
+ // 0x0b == select OCW1 + read ISR
+ outb(0x0b, PORT_PIC1_CMD);
+ return inb(PORT_PIC1_CMD);
+}
+
+static inline u8
+get_pic2_isr(void)
+{
+ // 0x0b == select OCW1 + read ISR
+ outb(0x0b, PORT_PIC2_CMD);
+ return inb(PORT_PIC2_CMD);
+}
+
+static inline void
+enable_hwirq(int hwirq, struct segoff_s func)
+{
+ int vector;
+ if (hwirq < 8) {
+ unmask_pic1(1 << hwirq);
+ vector = 0x08 + hwirq;
+ } else {
+ unmask_pic2(1 << (hwirq - 8));
+ vector = 0x70 + hwirq - 8;
+ }
+ SET_IVT(vector, func);
+}
+
+void set_pics(u8 irq0, u8 irq8);
+void pic_setup(void);
+
+#endif // pic.h
--- /dev/null
+// PIR table generation (for emulators)
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pci.h" // struct pir_header
+#include "util.h" // checksum
+#include "biosvar.h" // SET_EBDA
+
+u16 PirOffset VAR16VISIBLE;
+
+struct pir_table {
+ struct pir_header pir;
+ struct pir_slot slots[6];
+} PACKED;
+
+extern struct pir_table PIR_TABLE;
+#if CONFIG_PIRTABLE && !CONFIG_COREBOOT
+struct pir_table PIR_TABLE __aligned(16) VAR16EXPORT = {
+ .pir = {
+ .version = 0x0100,
+ .size = sizeof(struct pir_table),
+ .router_devfunc = 0x08,
+ .compatible_devid = 0x122e8086,
+ },
+ .slots = {
+ {
+ // first slot entry PCI-to-ISA (embedded)
+ .dev = 1<<3,
+ .links = {
+ {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 0, // embedded
+ }, {
+ // second slot entry: 1st PCI slot
+ .dev = 2<<3,
+ .links = {
+ {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 1,
+ }, {
+ // third slot entry: 2nd PCI slot
+ .dev = 3<<3,
+ .links = {
+ {.link = 0x62, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 2,
+ }, {
+ // 4th slot entry: 3rd PCI slot
+ .dev = 4<<3,
+ .links = {
+ {.link = 0x63, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 3,
+ }, {
+ // 5th slot entry: 4rd PCI slot
+ .dev = 5<<3,
+ .links = {
+ {.link = 0x60, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x61, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 4,
+ }, {
+ // 6th slot entry: 5rd PCI slot
+ .dev = 6<<3,
+ .links = {
+ {.link = 0x61, .bitmap = 0xdef8}, // INTA#
+ {.link = 0x62, .bitmap = 0xdef8}, // INTB#
+ {.link = 0x63, .bitmap = 0xdef8}, // INTC#
+ {.link = 0x60, .bitmap = 0xdef8}, // INTD#
+ },
+ .slot_nr = 5,
+ },
+ }
+};
+#endif // CONFIG_PIRTABLE && !CONFIG_COREBOOT
+
+void
+create_pirtable(void)
+{
+ if (! CONFIG_PIRTABLE)
+ return;
+
+ dprintf(3, "init PIR table\n");
+
+ PIR_TABLE.pir.signature = PIR_SIGNATURE;
+ PIR_TABLE.pir.checksum -= checksum(&PIR_TABLE, sizeof(PIR_TABLE));
+ PirOffset = (u32)&PIR_TABLE.pir - BUILD_BIOS_ADDR;
+}
--- /dev/null
+// Post memory manager (PMM) calls
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // checksum
+#include "config.h" // BUILD_BIOS_ADDR
+#include "memmap.h" // struct e820entry
+#include "farptr.h" // GET_FARVAR
+#include "biosvar.h" // GET_BDA
+
+// Information on a reserved area.
+struct allocinfo_s {
+ struct allocinfo_s *next, **pprev;
+ void *data, *dataend, *allocend;
+};
+
+// Information on a tracked memory allocation.
+struct allocdetail_s {
+ struct allocinfo_s detailinfo;
+ struct allocinfo_s datainfo;
+ u32 handle;
+};
+
+// The various memory zones.
+struct zone_s {
+ struct allocinfo_s *info;
+};
+
+struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh;
+
+static struct zone_s *Zones[] = {
+ &ZoneTmpLow, &ZoneLow, &ZoneFSeg, &ZoneTmpHigh, &ZoneHigh
+};
+
+
+/****************************************************************
+ * low-level memory reservations
+ ****************************************************************/
+
+// Find and reserve space from a given zone
+static void *
+allocSpace(struct zone_s *zone, u32 size, u32 align, struct allocinfo_s *fill)
+{
+ struct allocinfo_s *info;
+ for (info = zone->info; info; info = info->next) {
+ void *dataend = info->dataend;
+ void *allocend = info->allocend;
+ void *newallocend = (void*)ALIGN_DOWN((u32)allocend - size, align);
+ if (newallocend >= dataend && newallocend <= allocend) {
+ // Found space - now reserve it.
+ struct allocinfo_s **pprev = info->pprev;
+ if (!fill)
+ fill = newallocend;
+ fill->next = info;
+ fill->pprev = pprev;
+ fill->data = newallocend;
+ fill->dataend = newallocend + size;
+ fill->allocend = allocend;
+
+ info->allocend = newallocend;
+ info->pprev = &fill->next;
+ *pprev = fill;
+ return newallocend;
+ }
+ }
+ return NULL;
+}
+
+// Release space allocated with allocSpace()
+static void
+freeSpace(struct allocinfo_s *info)
+{
+ struct allocinfo_s *next = info->next;
+ struct allocinfo_s **pprev = info->pprev;
+ *pprev = next;
+ if (next) {
+ if (next->allocend == info->data)
+ next->allocend = info->allocend;
+ next->pprev = pprev;
+ }
+}
+
+// Add new memory to a zone
+static void
+addSpace(struct zone_s *zone, void *start, void *end)
+{
+ // Find position to add space
+ struct allocinfo_s **pprev = &zone->info, *info;
+ for (;;) {
+ info = *pprev;
+ if (!info || info->data < start)
+ break;
+ pprev = &info->next;
+ }
+
+ // Add space using temporary allocation info.
+ struct allocdetail_s tempdetail;
+ tempdetail.datainfo.next = info;
+ tempdetail.datainfo.pprev = pprev;
+ tempdetail.datainfo.data = tempdetail.datainfo.dataend = start;
+ tempdetail.datainfo.allocend = end;
+ *pprev = &tempdetail.datainfo;
+ if (info)
+ info->pprev = &tempdetail.datainfo.next;
+
+ // Allocate final allocation info.
+ struct allocdetail_s *detail = allocSpace(
+ &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
+ if (!detail) {
+ detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
+ , MALLOC_MIN_ALIGN, NULL);
+ if (!detail) {
+ *tempdetail.datainfo.pprev = tempdetail.datainfo.next;
+ if (tempdetail.datainfo.next)
+ tempdetail.datainfo.next->pprev = tempdetail.datainfo.pprev;
+ warn_noalloc();
+ return;
+ }
+ }
+
+ // Replace temp alloc space with final alloc space
+ memcpy(&detail->datainfo, &tempdetail.datainfo, sizeof(detail->datainfo));
+ detail->handle = PMM_DEFAULT_HANDLE;
+
+ *tempdetail.datainfo.pprev = &detail->datainfo;
+ if (tempdetail.datainfo.next)
+ tempdetail.datainfo.next->pprev = &detail->datainfo.next;
+}
+
+// Search all zones for an allocation obtained from allocSpace()
+static struct allocinfo_s *
+findAlloc(void *data)
+{
+ int i;
+ for (i=0; i<ARRAY_SIZE(Zones); i++) {
+ struct zone_s *zone = Zones[i];
+ struct allocinfo_s *info;
+ for (info = zone->info; info; info = info->next)
+ if (info->data == data)
+ return info;
+ }
+ return NULL;
+}
+
+// Return the last sentinal node of a zone
+static struct allocinfo_s *
+findLast(struct zone_s *zone)
+{
+ struct allocinfo_s *info = zone->info;
+ if (!info)
+ return NULL;
+ for (;;) {
+ struct allocinfo_s *next = info->next;
+ if (!next)
+ return info;
+ info = next;
+ }
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+void
+malloc_setup(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc setup\n");
+
+ // Populate temp high ram
+ u32 highram = 0;
+ int i;
+ for (i=e820_count-1; i>=0; i--) {
+ struct e820entry *en = &e820_list[i];
+ u64 end = en->start + en->size;
+ if (end < 1024*1024)
+ break;
+ if (en->type != E820_RAM || end > 0xffffffff)
+ continue;
+ u32 s = en->start, e = end;
+ if (!highram) {
+ u32 newe = ALIGN_DOWN(e - CONFIG_MAX_HIGHTABLE, MALLOC_MIN_ALIGN);
+ if (newe <= e && newe >= s) {
+ highram = newe;
+ e = newe;
+ }
+ }
+ addSpace(&ZoneTmpHigh, (void*)s, (void*)e);
+ }
+
+ // Populate other regions
+ addSpace(&ZoneTmpLow, (void*)BUILD_STACK_ADDR, (void*)BUILD_EBDA_MINIMUM);
+ addSpace(&ZoneFSeg, BiosTableSpace, &BiosTableSpace[CONFIG_MAX_BIOSTABLE]);
+ addSpace(&ZoneLow, (void*)BUILD_LOWRAM_END, (void*)BUILD_LOWRAM_END);
+ if (highram) {
+ addSpace(&ZoneHigh, (void*)highram
+ , (void*)highram + CONFIG_MAX_HIGHTABLE);
+ add_e820(highram, CONFIG_MAX_HIGHTABLE, E820_RESERVED);
+ }
+}
+
+// Update pointers after code relocation.
+void
+malloc_fixupreloc(void)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_RELOCATE_INIT)
+ return;
+ dprintf(3, "malloc fixup reloc\n");
+
+ int i;
+ for (i=0; i<ARRAY_SIZE(Zones); i++) {
+ struct zone_s *zone = Zones[i];
+ zone->info->pprev = &zone->info;
+ }
+
+ // Add space free'd during relocation in f-segment to ZoneFSeg
+ extern u8 code32init_end[];
+ if ((u32)code32init_end > BUILD_BIOS_ADDR) {
+ memset((void*)BUILD_BIOS_ADDR, 0, (u32)code32init_end - BUILD_BIOS_ADDR);
+ addSpace(&ZoneFSeg, (void*)BUILD_BIOS_ADDR, code32init_end);
+ }
+}
+
+void
+malloc_finalize(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc finalize\n");
+
+ // Reserve more low-mem if needed.
+ u32 endlow = GET_BDA(mem_size_kb)*1024;
+ add_e820(endlow, BUILD_LOWRAM_END-endlow, E820_RESERVED);
+
+ // Give back unused high ram.
+ struct allocinfo_s *info = findLast(&ZoneHigh);
+ if (info) {
+ u32 giveback = ALIGN_DOWN(info->allocend - info->dataend, PAGE_SIZE);
+ add_e820((u32)info->dataend, giveback, E820_RAM);
+ dprintf(1, "Returned %d bytes of ZoneHigh\n", giveback);
+ }
+}
+
+
+/****************************************************************
+ * ebda movement
+ ****************************************************************/
+
+// Move ebda
+static int
+relocate_ebda(u32 newebda, u32 oldebda, u8 ebda_size)
+{
+ u32 lowram = GET_BDA(mem_size_kb) * 1024;
+ if (oldebda != lowram)
+ // EBDA isn't at end of ram - give up.
+ return -1;
+
+ // Do copy
+ memmove((void*)newebda, (void*)oldebda, ebda_size * 1024);
+
+ // Update indexes
+ dprintf(1, "ebda moved from %x to %x\n", oldebda, newebda);
+ SET_BDA(mem_size_kb, newebda / 1024);
+ SET_BDA(ebda_seg, FLATPTR_TO_SEG(newebda));
+ return 0;
+}
+
+// Support expanding the ZoneLow dynamically.
+static void
+zonelow_expand(u32 size, u32 align)
+{
+ struct allocinfo_s *info = findLast(&ZoneLow);
+ if (!info)
+ return;
+ u32 oldpos = (u32)info->allocend;
+ u32 newpos = ALIGN_DOWN(oldpos - size, align);
+ u32 bottom = (u32)info->dataend;
+ if (newpos >= bottom && newpos <= oldpos)
+ // Space already present.
+ return;
+ u16 ebda_seg = get_ebda_seg();
+ u32 ebda_pos = (u32)MAKE_FLATPTR(ebda_seg, 0);
+ u8 ebda_size = GET_EBDA2(ebda_seg, size);
+ u32 ebda_end = ebda_pos + ebda_size * 1024;
+ if (ebda_end != bottom)
+ // Something else is after ebda - can't use any existing space.
+ newpos = ALIGN_DOWN(ebda_end - size, align);
+ u32 newbottom = ALIGN_DOWN(newpos, 1024);
+ u32 newebda = ALIGN_DOWN(newbottom - ebda_size * 1024, 1024);
+ if (newebda < BUILD_EBDA_MINIMUM)
+ // Not enough space.
+ return;
+
+ // Move ebda
+ int ret = relocate_ebda(newebda, ebda_pos, ebda_size);
+ if (ret)
+ return;
+
+ // Update zone
+ if (ebda_end == bottom) {
+ info->data = (void*)newbottom;
+ info->dataend = (void*)newbottom;
+ } else
+ addSpace(&ZoneLow, (void*)newbottom, (void*)ebda_end);
+}
+
+// Check if can expand the given zone to fulfill an allocation
+static void *
+allocExpandSpace(struct zone_s *zone, u32 size, u32 align
+ , struct allocinfo_s *fill)
+{
+ void *data = allocSpace(zone, size, align, fill);
+ if (data || zone != &ZoneLow)
+ return data;
+
+ // Make sure to not move ebda while an optionrom is running.
+ if (unlikely(wait_preempt())) {
+ data = allocSpace(zone, size, align, fill);
+ if (data)
+ return data;
+ }
+
+ zonelow_expand(size, align);
+ return allocSpace(zone, size, align, fill);
+}
+
+
+/****************************************************************
+ * tracked memory allocations
+ ****************************************************************/
+
+// Allocate memory from the given zone and track it as a PMM allocation
+void * __malloc
+pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align)
+{
+ ASSERT32FLAT();
+ if (!size)
+ return NULL;
+
+ // Find and reserve space for bookkeeping.
+ struct allocdetail_s *detail = allocSpace(
+ &ZoneTmpHigh, sizeof(*detail), MALLOC_MIN_ALIGN, NULL);
+ if (!detail) {
+ detail = allocSpace(&ZoneTmpLow, sizeof(*detail)
+ , MALLOC_MIN_ALIGN, NULL);
+ if (!detail)
+ return NULL;
+ }
+
+ // Find and reserve space for main allocation
+ void *data = allocExpandSpace(zone, size, align, &detail->datainfo);
+ if (!data) {
+ freeSpace(&detail->detailinfo);
+ return NULL;
+ }
+
+ dprintf(8, "pmm_malloc zone=%p handle=%x size=%d align=%x"
+ " ret=%p (detail=%p)\n"
+ , zone, handle, size, align
+ , data, detail);
+ detail->handle = handle;
+
+ return data;
+}
+
+// Free a data block allocated with pmm_malloc
+int
+pmm_free(void *data)
+{
+ ASSERT32FLAT();
+ struct allocinfo_s *info = findAlloc(data);
+ if (!info || data == (void*)info || data == info->dataend)
+ return -1;
+ struct allocdetail_s *detail = container_of(
+ info, struct allocdetail_s, datainfo);
+ dprintf(8, "pmm_free %p (detail=%p)\n", data, detail);
+ freeSpace(info);
+ freeSpace(&detail->detailinfo);
+ return 0;
+}
+
+// Find the amount of free space in a given zone.
+static u32
+pmm_getspace(struct zone_s *zone)
+{
+ // XXX - doesn't account for ZoneLow being able to grow.
+ // XXX - results not reliable when CONFIG_THREAD_OPTIONROMS
+ u32 maxspace = 0;
+ struct allocinfo_s *info;
+ for (info = zone->info; info; info = info->next) {
+ u32 space = info->allocend - info->dataend;
+ if (space > maxspace)
+ maxspace = space;
+ }
+
+ if (zone != &ZoneTmpHigh && zone != &ZoneTmpLow)
+ return maxspace;
+ // Account for space needed for PMM tracking.
+ u32 reserve = ALIGN(sizeof(struct allocdetail_s), MALLOC_MIN_ALIGN);
+ if (maxspace <= reserve)
+ return 0;
+ return maxspace - reserve;
+}
+
+// Find the data block allocated with pmm_malloc with a given handle.
+static void *
+pmm_find(u32 handle)
+{
+ int i;
+ for (i=0; i<ARRAY_SIZE(Zones); i++) {
+ struct zone_s *zone = Zones[i];
+ struct allocinfo_s *info;
+ for (info = zone->info; info; info = info->next) {
+ if (info->data != (void*)info)
+ continue;
+ struct allocdetail_s *detail = container_of(
+ info, struct allocdetail_s, detailinfo);
+ if (detail->handle == handle)
+ return detail->datainfo.data;
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************
+ * pmm interface
+ ****************************************************************/
+
+struct pmmheader {
+ u32 signature;
+ u8 version;
+ u8 length;
+ u8 checksum;
+ u16 entry_offset;
+ u16 entry_seg;
+ u8 reserved[5];
+} PACKED;
+
+extern struct pmmheader PMMHEADER;
+
+#define PMM_SIGNATURE 0x4d4d5024 // $PMM
+
+#if CONFIG_PMM
+struct pmmheader PMMHEADER __aligned(16) VAR16EXPORT = {
+ .version = 0x01,
+ .length = sizeof(PMMHEADER),
+ .entry_seg = SEG_BIOS,
+};
+#endif
+
+#define PMM_FUNCTION_NOT_SUPPORTED 0xffffffff
+
+// PMM - allocate
+static u32
+handle_pmm00(u16 *args)
+{
+ u32 length = *(u32*)&args[1], handle = *(u32*)&args[3];
+ u16 flags = args[5];
+ dprintf(3, "pmm00: length=%x handle=%x flags=%x\n"
+ , length, handle, flags);
+ struct zone_s *lowzone = &ZoneTmpLow, *highzone = &ZoneTmpHigh;
+ if (flags & 8) {
+ // Permanent memory request.
+ lowzone = &ZoneLow;
+ highzone = &ZoneHigh;
+ }
+ if (!length) {
+ // Memory size request
+ switch (flags & 3) {
+ default:
+ case 0:
+ return 0;
+ case 1:
+ return pmm_getspace(lowzone);
+ case 2:
+ return pmm_getspace(highzone);
+ case 3: {
+ u32 spacelow = pmm_getspace(lowzone);
+ u32 spacehigh = pmm_getspace(highzone);
+ if (spacelow > spacehigh)
+ return spacelow;
+ return spacehigh;
+ }
+ }
+ }
+ u32 size = length * 16;
+ if ((s32)size <= 0)
+ return 0;
+ u32 align = MALLOC_MIN_ALIGN;
+ if (flags & 4) {
+ align = 1<<__ffs(size);
+ if (align < MALLOC_MIN_ALIGN)
+ align = MALLOC_MIN_ALIGN;
+ }
+ switch (flags & 3) {
+ default:
+ case 0:
+ return 0;
+ case 1:
+ return (u32)pmm_malloc(lowzone, handle, size, align);
+ case 2:
+ return (u32)pmm_malloc(highzone, handle, size, align);
+ case 3: {
+ void *data = pmm_malloc(lowzone, handle, size, align);
+ if (data)
+ return (u32)data;
+ return (u32)pmm_malloc(highzone, handle, size, align);
+ }
+ }
+}
+
+// PMM - find
+static u32
+handle_pmm01(u16 *args)
+{
+ u32 handle = *(u32*)&args[1];
+ dprintf(3, "pmm01: handle=%x\n", handle);
+ if (handle == PMM_DEFAULT_HANDLE)
+ return 0;
+ return (u32)pmm_find(handle);
+}
+
+// PMM - deallocate
+static u32
+handle_pmm02(u16 *args)
+{
+ u32 buffer = *(u32*)&args[1];
+ dprintf(3, "pmm02: buffer=%x\n", buffer);
+ int ret = pmm_free((void*)buffer);
+ if (ret)
+ // Error
+ return 1;
+ return 0;
+}
+
+static u32
+handle_pmmXX(u16 *args)
+{
+ return PMM_FUNCTION_NOT_SUPPORTED;
+}
+
+u32 VISIBLE32INIT
+handle_pmm(u16 *args)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_PMM)
+ return PMM_FUNCTION_NOT_SUPPORTED;
+
+ u16 arg1 = args[0];
+ dprintf(DEBUG_HDL_pmm, "pmm call arg1=%x\n", arg1);
+
+ int oldpreempt;
+ if (CONFIG_THREAD_OPTIONROMS) {
+ // Not a preemption event - don't wait in wait_preempt()
+ oldpreempt = CanPreempt;
+ CanPreempt = 0;
+ }
+
+ u32 ret;
+ switch (arg1) {
+ case 0x00: ret = handle_pmm00(args); break;
+ case 0x01: ret = handle_pmm01(args); break;
+ case 0x02: ret = handle_pmm02(args); break;
+ default: ret = handle_pmmXX(args); break;
+ }
+
+ if (CONFIG_THREAD_OPTIONROMS)
+ CanPreempt = oldpreempt;
+
+ return ret;
+}
+
+// romlayout.S
+extern void entry_pmm(void);
+
+void
+pmm_setup(void)
+{
+ if (! CONFIG_PMM)
+ return;
+
+ dprintf(3, "init PMM\n");
+
+ PMMHEADER.signature = PMM_SIGNATURE;
+ PMMHEADER.entry_offset = (u32)entry_pmm - BUILD_BIOS_ADDR;
+ PMMHEADER.checksum -= checksum(&PMMHEADER, sizeof(PMMHEADER));
+}
+
+void
+pmm_finalize(void)
+{
+ if (! CONFIG_PMM)
+ return;
+
+ dprintf(3, "finalize PMM\n");
+
+ PMMHEADER.signature = 0;
+ PMMHEADER.entry_offset = 0;
+}
--- /dev/null
+// PNP BIOS calls
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // checksum
+#include "config.h" // BUILD_BIOS_ADDR
+#include "farptr.h" // SET_FARVAR
+
+struct pnpheader {
+ u32 signature;
+ u8 version;
+ u8 length;
+ u16 control;
+ u8 checksum;
+ u32 eventloc;
+ u16 real_ip;
+ u16 real_cs;
+ u16 prot_ip;
+ u32 prot_base;
+ u32 oemid;
+ u16 real_ds;
+ u32 prot_database;
+} PACKED;
+
+extern struct pnpheader PNPHEADER;
+extern char pnp_string[];
+
+#if CONFIG_PNPBIOS
+struct pnpheader PNPHEADER __aligned(16) VAR16EXPORT = {
+ .signature = PNP_SIGNATURE,
+ .version = 0x10,
+ .length = sizeof(PNPHEADER),
+ .real_cs = SEG_BIOS,
+ .prot_base = BUILD_BIOS_ADDR,
+ .real_ds = SEG_BIOS,
+ .prot_database = BUILD_BIOS_ADDR,
+};
+#else
+// We need a copy of this string in the 0xf000 segment, but we are not
+// actually a PnP BIOS, so make sure it is *not* aligned, so OSes will
+// not see it if they scan.
+char pnp_string[] __aligned(2) VAR16VISIBLE = " $PnP";
+#endif
+
+#define FUNCTION_NOT_SUPPORTED 0x82
+
+// BBS - Get Version and Installation Check
+static u16
+handle_pnp60(u16 *args)
+{
+ u16 version_ptr = args[1];
+ u16 version_seg = args[2];
+ SET_FARVAR(version_seg, *(u16*)(version_ptr+0), 0x0101);
+ return 0;
+}
+
+static u16
+handle_pnpXX(u16 *args)
+{
+ return FUNCTION_NOT_SUPPORTED;
+}
+
+u16 VISIBLE16
+handle_pnp(u16 *args)
+{
+ if (! CONFIG_PNPBIOS)
+ return FUNCTION_NOT_SUPPORTED;
+
+ u16 arg1 = args[0];
+ dprintf(DEBUG_HDL_pnp, "pnp call arg1=%x\n", arg1);
+
+ switch (arg1) {
+ case 0x60: return handle_pnp60(args);
+ default: return handle_pnpXX(args);
+ }
+}
+
+u16
+get_pnp_offset(void)
+{
+ if (! CONFIG_PNPBIOS)
+ return (u32)pnp_string + 1 - BUILD_BIOS_ADDR;
+ return (u32)&PNPHEADER - BUILD_BIOS_ADDR;
+}
+
+// romlayout.S
+extern void entry_pnp_real(void);
+extern void entry_pnp_prot(void);
+
+void
+pnp_setup(void)
+{
+ if (! CONFIG_PNPBIOS)
+ return;
+
+ dprintf(3, "init PNPBIOS table\n");
+
+ PNPHEADER.real_ip = (u32)entry_pnp_real - BUILD_BIOS_ADDR;
+ PNPHEADER.prot_ip = (u32)entry_pnp_prot - BUILD_BIOS_ADDR;
+ PNPHEADER.checksum -= checksum(&PNPHEADER, sizeof(PNPHEADER));
+}
--- /dev/null
+// 32bit code to Power On Self Test (POST) a machine.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ioport.h" // PORT_*
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_*
+#include "util.h" // memset
+#include "biosvar.h" // struct bios_data_area_s
+#include "disk.h" // floppy_drive_setup
+#include "ata.h" // ata_setup
+#include "ahci.h" // ahci_setup
+#include "memmap.h" // add_e820
+#include "pic.h" // pic_setup
+#include "pci.h" // create_pirtable
+#include "acpi.h" // acpi_bios_init
+#include "bregs.h" // struct bregs
+#include "mptable.h" // mptable_init
+#include "boot.h" // IPL
+#include "usb.h" // usb_setup
+#include "smbios.h" // smbios_init
+#include "paravirt.h" // qemu_cfg_port_probe
+#include "xen.h" // xen_probe_hvm_info
+#include "ps2port.h" // ps2port_setup
+#include "virtio-blk.h" // virtio_blk_setup
+
+
+/****************************************************************
+ * BIOS init
+ ****************************************************************/
+
+static void
+init_ivt(void)
+{
+ dprintf(3, "init ivt\n");
+
+ // Initialize all vectors to the default handler.
+ int i;
+ for (i=0; i<256; i++)
+ SET_IVT(i, FUNC16(entry_iret_official));
+
+ // Initialize all hw vectors to a default hw handler.
+ for (i=0x08; i<=0x0f; i++)
+ SET_IVT(i, FUNC16(entry_hwpic1));
+ for (i=0x70; i<=0x77; i++)
+ SET_IVT(i, FUNC16(entry_hwpic2));
+
+ // Initialize software handlers.
+ SET_IVT(0x02, FUNC16(entry_02));
+ SET_IVT(0x10, FUNC16(entry_10));
+ SET_IVT(0x11, FUNC16(entry_11));
+ SET_IVT(0x12, FUNC16(entry_12));
+ SET_IVT(0x13, FUNC16(entry_13_official));
+ SET_IVT(0x14, FUNC16(entry_14));
+ SET_IVT(0x15, FUNC16(entry_15));
+ SET_IVT(0x16, FUNC16(entry_16));
+ SET_IVT(0x17, FUNC16(entry_17));
+ SET_IVT(0x18, FUNC16(entry_18));
+ SET_IVT(0x19, FUNC16(entry_19_official));
+ SET_IVT(0x1a, FUNC16(entry_1a));
+ SET_IVT(0x40, FUNC16(entry_40));
+
+ // INT 60h-66h reserved for user interrupt
+ for (i=0x60; i<=0x66; i++)
+ SET_IVT(i, SEGOFF(0, 0));
+
+ // set vector 0x79 to zero
+ // this is used by 'gardian angel' protection system
+ SET_IVT(0x79, SEGOFF(0, 0));
+
+ SET_IVT(0x1E, SEGOFF(SEG_BIOS, (u32)&diskette_param_table2 - BUILD_BIOS_ADDR));
+}
+
+static void
+init_bda(void)
+{
+ dprintf(3, "init bda\n");
+
+ struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
+ memset(bda, 0, sizeof(*bda));
+
+ int esize = EBDA_SIZE_START;
+ SET_BDA(mem_size_kb, BUILD_LOWRAM_END/1024 - esize);
+ u16 ebda_seg = EBDA_SEGMENT_START;
+ SET_BDA(ebda_seg, ebda_seg);
+
+ // Init ebda
+ struct extended_bios_data_area_s *ebda = get_ebda_ptr();
+ memset(ebda, 0, sizeof(*ebda));
+ ebda->size = esize;
+
+ add_e820((u32)MAKE_FLATPTR(ebda_seg, 0), GET_EBDA2(ebda_seg, size) * 1024
+ , E820_RESERVED);
+}
+
+static void
+ram_probe(void)
+{
+ dprintf(3, "Find memory size\n");
+ if (CONFIG_COREBOOT) {
+ coreboot_setup();
+ } else if (usingXen()) {
+ xen_setup();
+ } else {
+ // On emulators, get memory size from nvram.
+ u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
+ | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
+ if (rs)
+ rs += 16 * 1024 * 1024;
+ else
+ rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
+ | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
+ + 1 * 1024 * 1024);
+ RamSize = rs;
+ add_e820(0, rs, E820_RAM);
+
+ // Check for memory over 4Gig
+ u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
+ | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
+ | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
+ RamSizeOver4G = high;
+ add_e820(0x100000000ull, high, E820_RAM);
+
+ /* reserve 256KB BIOS area at the end of 4 GB */
+ add_e820(0xfffc0000, 256*1024, E820_RESERVED);
+ }
+
+ // Don't declare any memory between 0xa0000 and 0x100000
+ add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE);
+
+ // Mark known areas as reserved.
+ add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
+
+ u32 count = qemu_cfg_e820_entries();
+ if (count) {
+ struct e820_reservation entry;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ qemu_cfg_e820_load_next(&entry);
+ add_e820(entry.address, entry.length, entry.type);
+ }
+ } else if (kvm_para_available()) {
+ // Backwards compatibility - provide hard coded range.
+ // 4 pages before the bios, 3 pages for vmx tss pages, the
+ // other page for EPT real mode pagetable
+ add_e820(0xfffbc000, 4*4096, E820_RESERVED);
+ }
+
+ dprintf(1, "Ram Size=0x%08x (0x%08x%08x high)\n"
+ , RamSize, (u32)(RamSizeOver4G >> 32), (u32)RamSizeOver4G);
+}
+
+static void
+init_bios_tables(void)
+{
+ if (CONFIG_COREBOOT) {
+ coreboot_copy_biostable();
+ return;
+ }
+ if (usingXen()) {
+ xen_copy_biostables();
+ return;
+ }
+
+ create_pirtable();
+
+ mptable_init();
+
+ smbios_init();
+
+ acpi_bios_init();
+}
+
+// Initialize hardware devices
+static void
+init_hw(void)
+{
+ usb_setup();
+ ps2port_setup();
+ lpt_setup();
+ serial_setup();
+
+ floppy_setup();
+ ata_setup();
+ ahci_setup();
+ cbfs_payload_setup();
+ ramdisk_setup();
+ virtio_blk_setup();
+}
+
+// Begin the boot process by invoking an int0x19 in 16bit mode.
+void VISIBLE32FLAT
+startBoot(void)
+{
+ // Clear low-memory allocations (required by PMM spec).
+ memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR);
+
+ dprintf(3, "Jump to int19\n");
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x19, &br);
+}
+
+// Main setup code.
+static void
+maininit(void)
+{
+ // Running at new code address - do code relocation fixups
+ malloc_fixupreloc();
+
+ // Setup ivt/bda/ebda
+ init_ivt();
+ init_bda();
+
+ // Init base pc hardware.
+ pic_setup();
+ timer_setup();
+ mathcp_setup();
+
+ // Initialize mtrr
+ mtrr_setup();
+
+ // Initialize pci
+ pci_setup();
+ smm_init();
+
+ // Setup Xen hypercalls
+ xen_init_hypercalls();
+
+ // Initialize internal tables
+ boot_setup();
+
+ // Start hardware initialization (if optionrom threading)
+ if (CONFIG_THREADS && CONFIG_THREAD_OPTIONROMS)
+ init_hw();
+
+ // Find and initialize other cpus
+ smp_probe();
+
+ // Setup interfaces that option roms may need
+ bios32_setup();
+ pmm_setup();
+ pnp_setup();
+ kbd_setup();
+ mouse_setup();
+ init_bios_tables();
+
+ // Run vga option rom
+ vga_setup();
+
+ // Do hardware initialization (if running synchronously)
+ if (!CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS) {
+ init_hw();
+ wait_threads();
+ }
+
+ // Run option roms
+ optionrom_setup();
+
+ // Run BCVs and show optional boot menu
+ boot_prep();
+
+ // Finalize data structures before boot
+ cdemu_setup();
+ pmm_finalize();
+ malloc_finalize();
+ memmap_finalize();
+
+ // Setup bios checksum.
+ BiosChecksum -= checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE);
+
+ // Write protect bios memory.
+ make_bios_readonly();
+
+ // Invoke int 19 to start boot process.
+ startBoot();
+}
+
+
+/****************************************************************
+ * POST entry and code relocation
+ ****************************************************************/
+
+// Update given relocs for the code at 'dest' with a given 'delta'
+static void
+updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta)
+{
+ u32 *reloc;
+ for (reloc = rstart; reloc < rend; reloc++)
+ *((u32*)(dest + *reloc)) += delta;
+}
+
+// Relocate init code and then call maininit() at new address.
+static void
+reloc_init(void)
+{
+ if (!CONFIG_RELOCATE_INIT) {
+ maininit();
+ return;
+ }
+ // Symbols populated by the build.
+ extern u8 code32flat_start[];
+ extern u8 _reloc_min_align[];
+ extern u32 _reloc_abs_start[], _reloc_abs_end[];
+ extern u32 _reloc_rel_start[], _reloc_rel_end[];
+ extern u32 _reloc_init_start[], _reloc_init_end[];
+ extern u8 code32init_start[], code32init_end[];
+
+ // Allocate space for init code.
+ u32 initsize = code32init_end - code32init_start;
+ u32 align = (u32)&_reloc_min_align;
+ void *dest = memalign_tmp(align, initsize);
+ if (!dest)
+ panic("No space for init relocation.\n");
+
+ // Copy code and update relocs (init absolute, init relative, and runtime)
+ dprintf(1, "Relocating init from %p to %p (size %d)\n"
+ , code32init_start, dest, initsize);
+ s32 delta = dest - (void*)code32init_start;
+ memcpy(dest, code32init_start, initsize);
+ updateRelocs(dest, _reloc_abs_start, _reloc_abs_end, delta);
+ updateRelocs(dest, _reloc_rel_start, _reloc_rel_end, -delta);
+ updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta);
+
+ // Call maininit() in relocated code.
+ void (*func)(void) = (void*)maininit + delta;
+ barrier();
+ func();
+}
+
+// Setup for code relocation and then call reloc_init
+void VISIBLE32INIT
+dopost(void)
+{
+ HaveRunPost = 1;
+
+ // Detect ram and setup internal malloc.
+ qemu_cfg_port_probe();
+ ram_probe();
+ malloc_setup();
+
+ // Relocate initialization code and call maininit().
+ reloc_init();
+}
+
+// Entry point for Power On Self Test (POST) - the BIOS initilization
+// phase. This function makes the memory at 0xc0000-0xfffff
+// read/writable and then calls dopost().
+void VISIBLE32FLAT
+handle_post(void)
+{
+ debug_serial_setup();
+ dprintf(1, "Start bios (version %s)\n", VERSION);
+
+ // Enable CPU caching
+ setcr0(getcr0() & ~(CR0_CD|CR0_NW));
+
+ // Clear CMOS reboot flag.
+ outb_cmos(0, CMOS_RESET_CODE);
+
+ // Make sure legacy DMA isn't running.
+ init_dma();
+
+ // Check if we are running under Xen.
+ xen_probe();
+
+ // Allow writes to modify bios area (0xf0000)
+ make_bios_writable();
+
+ // Now that memory is read/writable - start post process.
+ dopost();
+}
--- /dev/null
+// Support for handling the PS/2 mouse/keyboard ports.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Several ideas taken from code Copyright (c) 1999-2004 Vojtech Pavlik
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ioport.h" // inb
+#include "util.h" // dprintf
+#include "paravirt.h" // romfile_loadint
+#include "biosvar.h" // GET_EBDA
+#include "ps2port.h" // ps2_kbd_command
+#include "pic.h" // eoi_pic1
+
+
+/****************************************************************
+ * Low level i8042 commands.
+ ****************************************************************/
+
+// Timeout value.
+#define I8042_CTL_TIMEOUT 10000
+
+#define I8042_BUFFER_SIZE 16
+
+static int
+i8042_wait_read(void)
+{
+ dprintf(7, "i8042_wait_read\n");
+ int i;
+ for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (status & I8042_STR_OBF)
+ return 0;
+ udelay(50);
+ }
+ warn_timeout();
+ return -1;
+}
+
+static int
+i8042_wait_write(void)
+{
+ dprintf(7, "i8042_wait_write\n");
+ int i;
+ for (i=0; i<I8042_CTL_TIMEOUT; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (! (status & I8042_STR_IBF))
+ return 0;
+ udelay(50);
+ }
+ warn_timeout();
+ return -1;
+}
+
+static int
+i8042_flush(void)
+{
+ dprintf(7, "i8042_flush\n");
+ int i;
+ for (i=0; i<I8042_BUFFER_SIZE; i++) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (! (status & I8042_STR_OBF))
+ return 0;
+ udelay(50);
+ u8 data = inb(PORT_PS2_DATA);
+ dprintf(7, "i8042 flushed %x (status=%x)\n", data, status);
+ }
+
+ warn_timeout();
+ return -1;
+}
+
+static int
+__i8042_command(int command, u8 *param)
+{
+ int receive = (command >> 8) & 0xf;
+ int send = (command >> 12) & 0xf;
+
+ // Send the command.
+ int ret = i8042_wait_write();
+ if (ret)
+ return ret;
+ outb(command, PORT_PS2_STATUS);
+
+ // Send parameters (if any).
+ int i;
+ for (i = 0; i < send; i++) {
+ ret = i8042_wait_write();
+ if (ret)
+ return ret;
+ outb(param[i], PORT_PS2_DATA);
+ }
+
+ // Receive parameters (if any).
+ for (i = 0; i < receive; i++) {
+ ret = i8042_wait_read();
+ if (ret)
+ return ret;
+ param[i] = inb(PORT_PS2_DATA);
+ dprintf(7, "i8042 param=%x\n", param[i]);
+ }
+
+ return 0;
+}
+
+static int
+i8042_command(int command, u8 *param)
+{
+ dprintf(7, "i8042_command cmd=%x\n", command);
+ int ret = __i8042_command(command, param);
+ if (ret)
+ dprintf(2, "i8042 command %x failed\n", command);
+ return ret;
+}
+
+static int
+i8042_kbd_write(u8 c)
+{
+ dprintf(7, "i8042_kbd_write c=%d\n", c);
+ int ret = i8042_wait_write();
+ if (! ret)
+ outb(c, PORT_PS2_DATA);
+ return ret;
+}
+
+static int
+i8042_aux_write(u8 c)
+{
+ return i8042_command(I8042_CMD_AUX_SEND, &c);
+}
+
+void
+i8042_reboot(void)
+{
+ int i;
+ for (i=0; i<10; i++) {
+ i8042_wait_write();
+ udelay(50);
+ outb(0xfe, PORT_PS2_STATUS); /* pulse reset low */
+ udelay(50);
+ }
+}
+
+
+/****************************************************************
+ * Device commands.
+ ****************************************************************/
+
+#define PS2_RET_ACK 0xfa
+#define PS2_RET_NAK 0xfe
+
+static int
+ps2_recvbyte(int aux, int needack, int timeout)
+{
+ u64 end = calc_future_tsc(timeout);
+ for (;;) {
+ u8 status = inb(PORT_PS2_STATUS);
+ if (status & I8042_STR_OBF) {
+ u8 data = inb(PORT_PS2_DATA);
+ dprintf(7, "ps2 read %x\n", data);
+
+ if (!!(status & I8042_STR_AUXDATA) == aux) {
+ if (!needack)
+ return data;
+ if (data == PS2_RET_ACK)
+ return data;
+ if (data == PS2_RET_NAK) {
+ dprintf(1, "Got ps2 nak (status=%x)\n", status);
+ return data;
+ }
+ }
+
+ // This data not part of command - just discard it.
+ dprintf(1, "Discarding ps2 data %02x (status=%02x)\n", data, status);
+ }
+
+ if (check_tsc(end)) {
+ // Don't warn on second byte of a reset
+ if (timeout > 100)
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+static int
+ps2_sendbyte(int aux, u8 command, int timeout)
+{
+ dprintf(7, "ps2_sendbyte aux=%d cmd=%x\n", aux, command);
+ int ret;
+ if (aux)
+ ret = i8042_aux_write(command);
+ else
+ ret = i8042_kbd_write(command);
+ if (ret)
+ return ret;
+
+ // Read ack.
+ ret = ps2_recvbyte(aux, 1, timeout);
+ if (ret < 0)
+ return ret;
+ if (ret != PS2_RET_ACK)
+ return -1;
+
+ return 0;
+}
+
+static int
+__ps2_command(int aux, int command, u8 *param)
+{
+ int ret2;
+ int receive = (command >> 8) & 0xf;
+ int send = (command >> 12) & 0xf;
+
+ // Disable interrupts and keyboard/mouse.
+ u8 ps2ctr = GET_EBDA(ps2ctr);
+ u8 newctr = ((ps2ctr | I8042_CTR_AUXDIS | I8042_CTR_KBDDIS)
+ & ~(I8042_CTR_KBDINT|I8042_CTR_AUXINT));
+ dprintf(6, "i8042 ctr old=%x new=%x\n", ps2ctr, newctr);
+ int ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+ if (ret)
+ return ret;
+
+ // Flush any interrupts already pending.
+ yield();
+
+ // Enable port command is being sent to.
+ if (aux)
+ newctr &= ~I8042_CTR_AUXDIS;
+ else
+ newctr &= ~I8042_CTR_KBDDIS;
+ ret = i8042_command(I8042_CMD_CTL_WCTR, &newctr);
+ if (ret)
+ goto fail;
+
+ if (command == ATKBD_CMD_RESET_BAT) {
+ // Reset is special wrt timeouts and bytes received.
+
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 1000);
+ if (ret)
+ goto fail;
+
+ // Receive parameters.
+ ret = ps2_recvbyte(aux, 0, 4000);
+ if (ret < 0)
+ goto fail;
+ param[0] = ret;
+ ret = ps2_recvbyte(aux, 0, 100);
+ if (ret < 0)
+ // Some devices only respond with one byte on reset.
+ ret = 0;
+ param[1] = ret;
+ } else if (command == ATKBD_CMD_GETID) {
+ // Getid is special wrt bytes received.
+
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 200);
+ if (ret)
+ goto fail;
+
+ // Receive parameters.
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[0] = ret;
+ if (ret == 0xab || ret == 0xac || ret == 0x2b || ret == 0x5d
+ || ret == 0x60 || ret == 0x47) {
+ // These ids (keyboards) return two bytes.
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[1] = ret;
+ } else {
+ param[1] = 0;
+ }
+ } else {
+ // Send command.
+ ret = ps2_sendbyte(aux, command, 200);
+ if (ret)
+ goto fail;
+
+ // Send parameters (if any).
+ int i;
+ for (i = 0; i < send; i++) {
+ ret = ps2_sendbyte(aux, param[i], 200);
+ if (ret)
+ goto fail;
+ }
+
+ // Receive parameters (if any).
+ for (i = 0; i < receive; i++) {
+ ret = ps2_recvbyte(aux, 0, 500);
+ if (ret < 0)
+ goto fail;
+ param[i] = ret;
+ }
+ }
+
+ ret = 0;
+
+fail:
+ // Restore interrupts and keyboard/mouse.
+ ret2 = i8042_command(I8042_CMD_CTL_WCTR, &ps2ctr);
+ if (ret2)
+ return ret2;
+
+ return ret;
+}
+
+static int
+ps2_command(int aux, int command, u8 *param)
+{
+ dprintf(7, "ps2_command aux=%d cmd=%x\n", aux, command);
+ int ret = __ps2_command(aux, command, param);
+ if (ret)
+ dprintf(2, "ps2 command %x failed (aux=%d)\n", command, aux);
+ return ret;
+}
+
+int
+ps2_kbd_command(int command, u8 *param)
+{
+ return ps2_command(0, command, param);
+}
+
+int
+ps2_mouse_command(int command, u8 *param)
+{
+ // Update ps2ctr for mouse enable/disable.
+ if (command == PSMOUSE_CMD_ENABLE || command == PSMOUSE_CMD_DISABLE) {
+ u16 ebda_seg = get_ebda_seg();
+ u8 ps2ctr = GET_EBDA2(ebda_seg, ps2ctr);
+ if (command == PSMOUSE_CMD_ENABLE)
+ ps2ctr = (ps2ctr | I8042_CTR_AUXINT) & ~I8042_CTR_AUXDIS;
+ else
+ ps2ctr = (ps2ctr | I8042_CTR_AUXDIS) & ~I8042_CTR_AUXINT;
+ SET_EBDA2(ebda_seg, ps2ctr, ps2ctr);
+ }
+
+ return ps2_command(1, command, param);
+}
+
+
+/****************************************************************
+ * IRQ handlers
+ ****************************************************************/
+
+// INT74h : PS/2 mouse hardware interrupt
+void VISIBLE16
+handle_74(void)
+{
+ if (! CONFIG_PS2PORT)
+ return;
+
+ debug_isr(DEBUG_ISR_74);
+
+ u8 v = inb(PORT_PS2_STATUS);
+ if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA))
+ != (I8042_STR_OBF|I8042_STR_AUXDATA)) {
+ dprintf(1, "ps2 mouse irq but no mouse data.\n");
+ goto done;
+ }
+ v = inb(PORT_PS2_DATA);
+
+ if (!(GET_EBDA(ps2ctr) & I8042_CTR_AUXINT))
+ // Interrupts not enabled.
+ goto done;
+
+ process_mouse(v);
+
+done:
+ eoi_pic2();
+}
+
+// INT09h : Keyboard Hardware Service Entry Point
+void VISIBLE16
+handle_09(void)
+{
+ if (! CONFIG_PS2PORT)
+ return;
+
+ debug_isr(DEBUG_ISR_09);
+
+ // read key from keyboard controller
+ u8 v = inb(PORT_PS2_STATUS);
+ if (v & I8042_STR_AUXDATA) {
+ dprintf(1, "ps2 keyboard irq but found mouse data?!\n");
+ goto done;
+ }
+ v = inb(PORT_PS2_DATA);
+
+ if (!(GET_EBDA(ps2ctr) & I8042_CTR_KBDINT))
+ // Interrupts not enabled.
+ goto done;
+
+ process_key(v);
+
+done:
+ eoi_pic1();
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+keyboard_init(void *data)
+{
+ /* flush incoming keys */
+ int ret = i8042_flush();
+ if (ret)
+ return;
+
+ // Controller self-test.
+ u8 param[2];
+ ret = i8042_command(I8042_CMD_CTL_TEST, param);
+ if (ret)
+ return;
+ if (param[0] != 0x55) {
+ dprintf(1, "i8042 self test failed (got %x not 0x55)\n", param[0]);
+ return;
+ }
+
+ // Controller keyboard test.
+ ret = i8042_command(I8042_CMD_KBD_TEST, param);
+ if (ret)
+ return;
+ if (param[0] != 0x00) {
+ dprintf(1, "i8042 keyboard test failed (got %x not 0x00)\n", param[0]);
+ return;
+ }
+
+ // Disable keyboard and mouse events.
+ SET_EBDA(ps2ctr, I8042_CTR_KBDDIS | I8042_CTR_AUXDIS);
+
+
+ /* ------------------- keyboard side ------------------------*/
+ /* reset keyboard and self test (keyboard side) */
+ int spinupdelay = romfile_loadint("etc/ps2-keyboard-spinup", 0);
+ u64 end = calc_future_tsc(spinupdelay);
+ for (;;) {
+ ret = ps2_kbd_command(ATKBD_CMD_RESET_BAT, param);
+ if (!ret)
+ break;
+ if (check_tsc(end)) {
+ if (spinupdelay)
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+ if (param[0] != 0xaa) {
+ dprintf(1, "keyboard self test failed (got %x not 0xaa)\n", param[0]);
+ return;
+ }
+
+ /* Disable keyboard */
+ ret = ps2_kbd_command(ATKBD_CMD_RESET_DIS, NULL);
+ if (ret)
+ return;
+
+ // Set scancode command (mode 2)
+ param[0] = 0x02;
+ ret = ps2_kbd_command(ATKBD_CMD_SSCANSET, param);
+ if (ret)
+ return;
+
+ // Keyboard Mode: disable mouse, scan code convert, enable kbd IRQ
+ SET_EBDA(ps2ctr, I8042_CTR_AUXDIS | I8042_CTR_XLATE | I8042_CTR_KBDINT);
+
+ /* Enable keyboard */
+ ret = ps2_kbd_command(ATKBD_CMD_ENABLE, NULL);
+ if (ret)
+ return;
+
+ dprintf(1, "PS2 keyboard initialized\n");
+}
+
+void
+ps2port_setup(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_PS2PORT)
+ return;
+ dprintf(3, "init ps2port\n");
+
+ enable_hwirq(1, FUNC16(entry_09));
+ enable_hwirq(12, FUNC16(entry_74));
+
+ run_thread(keyboard_init, NULL);
+}
--- /dev/null
+// Basic ps2 port (keyboard/mouse) command handling.
+#ifndef __PS2PORT_H
+#define __PS2PORT_H
+
+#include "types.h" // u8
+
+// Standard commands.
+#define I8042_CMD_CTL_RCTR 0x0120
+#define I8042_CMD_CTL_WCTR 0x1060
+#define I8042_CMD_CTL_TEST 0x01aa
+
+#define I8042_CMD_KBD_TEST 0x01ab
+#define I8042_CMD_KBD_DISABLE 0x00ad
+#define I8042_CMD_KBD_ENABLE 0x00ae
+
+#define I8042_CMD_AUX_DISABLE 0x00a7
+#define I8042_CMD_AUX_ENABLE 0x00a8
+#define I8042_CMD_AUX_SEND 0x10d4
+
+// Keyboard commands
+#define ATKBD_CMD_SETLEDS 0x10ed
+#define ATKBD_CMD_SSCANSET 0x10f0
+#define ATKBD_CMD_GETID 0x02f2
+#define ATKBD_CMD_ENABLE 0x00f4
+#define ATKBD_CMD_RESET_DIS 0x00f5
+#define ATKBD_CMD_RESET_BAT 0x02ff
+
+// Mouse commands
+#define PSMOUSE_CMD_SETSCALE11 0x00e6
+#define PSMOUSE_CMD_SETSCALE21 0x00e7
+#define PSMOUSE_CMD_SETRES 0x10e8
+#define PSMOUSE_CMD_GETINFO 0x03e9
+#define PSMOUSE_CMD_GETID 0x02f2
+#define PSMOUSE_CMD_SETRATE 0x10f3
+#define PSMOUSE_CMD_ENABLE 0x00f4
+#define PSMOUSE_CMD_DISABLE 0x00f5
+#define PSMOUSE_CMD_RESET_BAT 0x02ff
+
+// Status register bits.
+#define I8042_STR_PARITY 0x80
+#define I8042_STR_TIMEOUT 0x40
+#define I8042_STR_AUXDATA 0x20
+#define I8042_STR_KEYLOCK 0x10
+#define I8042_STR_CMDDAT 0x08
+#define I8042_STR_MUXERR 0x04
+#define I8042_STR_IBF 0x02
+#define I8042_STR_OBF 0x01
+
+// Control register bits.
+#define I8042_CTR_KBDINT 0x01
+#define I8042_CTR_AUXINT 0x02
+#define I8042_CTR_IGNKEYLOCK 0x08
+#define I8042_CTR_KBDDIS 0x10
+#define I8042_CTR_AUXDIS 0x20
+#define I8042_CTR_XLATE 0x40
+
+// functions
+void i8042_reboot(void);
+int ps2_kbd_command(int command, u8 *param);
+int ps2_mouse_command(int command, u8 *param);
+void ps2port_setup(void);
+
+#endif // ps2port.h
--- /dev/null
+// Code for emulating a drive via high-memory accesses.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "disk.h" // process_ramdisk_op
+#include "util.h" // dprintf
+#include "memmap.h" // add_e820
+#include "biosvar.h" // GET_GLOBAL
+#include "bregs.h" // struct bregs
+#include "boot.h" // boot_add_floppy
+
+void
+ramdisk_setup(void)
+{
+ if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY)
+ return;
+
+ // Find image.
+ struct cbfs_file *file = cbfs_findprefix("floppyimg/", NULL);
+ if (!file)
+ return;
+ const char *filename = cbfs_filename(file);
+ u32 size = cbfs_datasize(file);
+ dprintf(3, "Found floppy file %s of size %d\n", filename, size);
+ int ftype = find_floppy_type(size);
+ if (ftype < 0) {
+ dprintf(3, "No floppy type found for ramdisk size\n");
+ return;
+ }
+
+ // Allocate ram for image.
+ void *pos = memalign_tmphigh(PAGE_SIZE, size);
+ if (!pos) {
+ warn_noalloc();
+ return;
+ }
+ add_e820((u32)pos, size, E820_RESERVED);
+
+ // Copy image into ram.
+ cbfs_copyfile(file, pos, size);
+
+ // Setup driver.
+ struct drive_s *drive_g = init_floppy((u32)pos, ftype);
+ if (!drive_g)
+ return;
+ drive_g->type = DTYPE_RAMDISK;
+ dprintf(1, "Mapping CBFS floppy %s to addr %p\n", filename, pos);
+ char *desc = znprintf(MAXDESCSIZE, "Ramdisk [%s]", &filename[10]);
+ boot_add_floppy(drive_g, desc, bootprio_find_named_rom(filename, 0));
+}
+
+static int
+ramdisk_copy(struct disk_op_s *op, int iswrite)
+{
+ u32 offset = GET_GLOBAL(op->drive_g->cntl_id);
+ offset += (u32)op->lba * DISK_SECTOR_SIZE;
+ u64 opd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE((u32)op->buf_fl);
+ u64 ramd = GDT_DATA | GDT_LIMIT(0xfffff) | GDT_BASE(offset);
+
+ u64 gdt[6];
+ if (iswrite) {
+ gdt[2] = opd;
+ gdt[3] = ramd;
+ } else {
+ gdt[2] = ramd;
+ gdt[3] = opd;
+ }
+
+ // Call int 1587 to copy data.
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_CF|F_IF;
+ br.ah = 0x87;
+ br.es = GET_SEG(SS);
+ br.si = (u32)gdt;
+ br.cx = op->count * DISK_SECTOR_SIZE / 2;
+ call16_int(0x15, &br);
+
+ if (br.flags & F_CF)
+ return DISK_RET_EBADTRACK;
+ return DISK_RET_SUCCESS;
+}
+
+int
+process_ramdisk_op(struct disk_op_s *op)
+{
+ if (!CONFIG_COREBOOT || !CONFIG_COREBOOT_FLASH || !CONFIG_FLASH_FLOPPY)
+ return 0;
+
+ switch (op->command) {
+ case CMD_READ:
+ return ramdisk_copy(op, 0);
+ case CMD_WRITE:
+ return ramdisk_copy(op, 1);
+ case CMD_VERIFY:
+ case CMD_FORMAT:
+ case CMD_RESET:
+ return DISK_RET_SUCCESS;
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
--- /dev/null
+// Code for handling calls to "post" that are resume related.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "ioport.h" // outb
+#include "pic.h" // eoi_pic2
+#include "biosvar.h" // struct bios_data_area_s
+#include "bregs.h" // struct bregs
+#include "acpi.h" // find_resume_vector
+#include "ps2port.h" // i8042_reboot
+#include "pci.h" // pci_reboot
+#include "cmos.h" // inb_cmos
+
+// Indicator if POST phase has been run.
+int HaveRunPost VAR16VISIBLE;
+
+// Reset DMA controller
+void
+init_dma(void)
+{
+ // first reset the DMA controllers
+ outb(0, PORT_DMA1_MASTER_CLEAR);
+ outb(0, PORT_DMA2_MASTER_CLEAR);
+
+ // then initialize the DMA controllers
+ outb(0xc0, PORT_DMA2_MODE_REG);
+ outb(0x00, PORT_DMA2_MASK_REG);
+}
+
+// Handler for post calls that look like a resume.
+void VISIBLE16
+handle_resume(void)
+{
+ debug_serial_setup();
+ int status = inb_cmos(CMOS_RESET_CODE);
+ outb_cmos(0, CMOS_RESET_CODE);
+ dprintf(1, "In resume (status=%d)\n", status);
+
+ init_dma();
+
+ switch (status) {
+ case 0x01 ... 0x04:
+ case 0x06 ... 0x09:
+ panic("Unimplemented shutdown status: %02x\n", status);
+
+ case 0x05:
+ // flush keyboard (issue EOI) and jump via 40h:0067h
+ eoi_pic2();
+ // NO BREAK
+ case 0x0a:
+#define BDA_JUMP (((struct bios_data_area_s *)0)->jump)
+ // resume execution by jump via 40h:0067h
+ asm volatile(
+ "movw %w1, %%ds\n"
+ "ljmpw *%0\n"
+ : : "m"(BDA_JUMP), "r"(SEG_BDA)
+ );
+ break;
+
+ case 0x0b:
+ // resume execution via IRET via 40h:0067h
+ asm volatile(
+ "movw %w1, %%ds\n"
+ "lssw %0, %%sp\n"
+ "iretw\n"
+ : : "m"(BDA_JUMP), "r"(SEG_BDA)
+ );
+ break;
+
+ case 0x0c:
+ // resume execution via RETF via 40h:0067h
+ asm volatile(
+ "movw %w1, %%ds\n"
+ "lssw %0, %%sp\n"
+ "lretw\n"
+ : : "m"(BDA_JUMP), "r"(SEG_BDA)
+ );
+ break;
+
+ default:
+ break;
+ }
+
+ // Not a 16bit resume - do remaining checks in 32bit mode
+ asm volatile(
+ "movw %w1, %%ss\n"
+ "movl %0, %%esp\n"
+ "movl $_cfunc32flat_handle_resume32, %%edx\n"
+ "jmp transition32\n"
+ : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0), "a"(status)
+ );
+}
+
+// Handle an S3 resume event
+static void
+s3_resume(void)
+{
+ if (!CONFIG_S3_RESUME)
+ return;
+
+ u32 s3_resume_vector = find_resume_vector();
+ if (!s3_resume_vector) {
+ dprintf(1, "No resume vector set!\n");
+ return;
+ }
+
+ smm_init();
+
+ s3_resume_vga_init();
+
+ make_bios_readonly();
+
+ // Invoke the resume vector.
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
+ br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
+ call16big(&br);
+}
+
+// Attempt to invoke a hard-reboot.
+static void
+tryReboot(void)
+{
+ dprintf(1, "Attempting a hard reboot\n");
+
+ // Setup for reset on qemu.
+ if (! CONFIG_COREBOOT) {
+ qemu_prep_reset();
+ if (HaveRunPost)
+ apm_shutdown();
+ }
+
+ // Try keyboard controller reboot.
+ i8042_reboot();
+
+ // Try PCI 0xcf9 reboot
+ pci_reboot();
+
+ // Try triple fault
+ asm volatile("int3");
+
+ panic("Could not reboot");
+}
+
+void VISIBLE32FLAT
+handle_resume32(int status)
+{
+ ASSERT32FLAT();
+ dprintf(1, "In 32bit resume\n");
+
+ if (status == 0xfe)
+ s3_resume();
+
+ // Must be a soft reboot - invoke a hard reboot.
+ tryReboot();
+}
--- /dev/null
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Include of 16bit C code
+ ****************************************************************/
+
+ .code16gcc
+#include "ccode.16.s"
+
+#include "config.h" // CONFIG_*
+#include "ioport.h" // PORT_A20
+#include "bregs.h" // CR0_*
+#include "cmos.h" // CMOS_RESET_CODE
+#include "asm-offsets.h" // BREGS_*
+#include "entryfuncs.S" // ENTRY_*
+
+
+/****************************************************************
+ * Call trampolines
+ ****************************************************************/
+
+// Place CPU into 32bit mode from 16bit mode.
+// %edx = return location (in 32bit mode)
+// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
+ DECLFUNC transition32
+transition32:
+ movl %eax, %ecx
+
+ // Disable irqs (and clear direction flag)
+ cli
+ cld
+
+ // Disable nmi
+ movl $CMOS_RESET_CODE|NMI_DISABLE_BIT, %eax
+ outb %al, $PORT_CMOS_INDEX
+ inb $PORT_CMOS_DATA, %al
+
+ // enable a20
+ inb $PORT_A20, %al
+ orb $A20_ENABLE_BIT, %al
+ outb %al, $PORT_A20
+
+ // Set segment descriptors
+ lidtw %cs:pmode_IDT_info
+ lgdtw %cs:rombios32_gdt_48
+
+ // Enable protected mode
+ movl %cr0, %eax
+ orl $CR0_PE, %eax
+ movl %eax, %cr0
+
+ // start 32bit protected mode code
+ ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
+
+ .code32
+1:
+ // init data segments
+ movl $SEG32_MODE32_DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ movl %ecx, %eax
+ jmpl *%edx
+
+// Place CPU into 16bit mode from 32bit mode.
+// %edx = return location (in 16bit mode)
+// Clobbers: ecx, flags, segment registers, cr0, idt/gdt
+ DECLFUNC transition16
+ .global transition16big
+transition16:
+ movl %eax, %ecx
+
+ // restore data segment limits to 0xffff
+ movl $SEG32_MODE16_DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+#if CONFIG_DISABLE_A20
+ // disable a20
+ inb $PORT_A20, %al
+ andb $~A20_ENABLE_BIT, %al
+ outb %al, $PORT_A20
+#endif
+
+ // Jump to 16bit mode
+ ljmpw $SEG32_MODE16_CS, $1f
+
+transition16big:
+ movl %eax, %ecx
+
+ movl $SEG32_MODE16BIG_DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ ljmpw $SEG32_MODE16BIG_CS, $1f
+
+ .code16gcc
+1:
+ // Disable protected mode
+ movl %cr0, %eax
+ andl $~CR0_PE, %eax
+ movl %eax, %cr0
+
+ // far jump to flush CPU queue after transition to real mode
+ ljmpw $SEG_BIOS, $2f
+
+2:
+ // restore IDT to normal real-mode defaults
+ lidtw %cs:rmode_IDT_info
+
+ // Clear segment registers
+ xorw %ax, %ax
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %es
+ movw %ax, %ds
+ movw %ax, %ss // Assume stack is in segment 0
+
+ movl %ecx, %eax
+ jmpl *%edx
+
+// Call a 16bit function from 16bit mode with a specified cpu register state
+// %eax = address of struct bregs
+// Clobbers: %e[bcd]x, %e[ds]i, flags
+ DECLFUNC __call16
+__call16:
+ // Save %eax, %ebp
+ pushl %ebp
+ pushl %eax
+
+ // Setup for iretw call
+ pushw %cs
+ pushw $1f // return point
+ pushw BREGS_flags(%eax) // flags
+ pushl BREGS_code(%eax) // CS:IP
+
+ // Load calling registers.
+ movl BREGS_edi(%eax), %edi
+ movl BREGS_esi(%eax), %esi
+ movl BREGS_ebp(%eax), %ebp
+ movl BREGS_ebx(%eax), %ebx
+ movl BREGS_edx(%eax), %edx
+ movl BREGS_ecx(%eax), %ecx
+ movw BREGS_es(%eax), %es
+ movw BREGS_ds(%eax), %ds
+ movl %ss:BREGS_eax(%eax), %eax
+
+ // Invoke call
+ iretw // XXX - just do a lcalll
+1:
+ // Store flags, eax, ecx
+ pushfw
+ pushl %eax
+ movl 0x06(%esp), %eax
+ movl %ecx, %ss:BREGS_ecx(%eax)
+ movw %ds, %ss:BREGS_ds(%eax)
+ movw %ss, %cx
+ movw %cx, %ds // Restore %ds == %ss
+ popl %ecx
+ movl %ecx, BREGS_eax(%eax)
+ popw %cx
+ movw %cx, BREGS_flags(%eax)
+
+ // Store remaining registers
+ movw %es, BREGS_es(%eax)
+ movl %edi, BREGS_edi(%eax)
+ movl %esi, BREGS_esi(%eax)
+ movl %ebp, BREGS_ebp(%eax)
+ movl %ebx, BREGS_ebx(%eax)
+ movl %edx, BREGS_edx(%eax)
+
+ // Remove %eax, restore %ebp
+ popl %eax
+ popl %ebp
+
+ retl
+
+// Call a 16bit function from 32bit mode.
+// %eax = address of struct bregs
+// Clobbers: %e[bcd]x, %e[ds]i, flags, segment registers, idt/gdt
+ DECLFUNC __call16_from32
+ .global __call16big_from32
+ .code32
+__call16_from32:
+ movl $1f, %edx
+ jmp transition16
+__call16big_from32:
+ movl $1f, %edx
+ jmp transition16big
+
+ // Make call.
+ .code16gcc
+1: calll __call16
+ // Return via transition32
+ movl $(2f + BUILD_BIOS_ADDR), %edx
+ jmp transition32
+ .code32
+2: retl
+
+ .code16gcc
+// IRQ trampolines
+ .macro IRQ_TRAMPOLINE num
+ DECLFUNC irq_trampoline_0x\num
+ irq_trampoline_0x\num :
+ int $0x\num
+ lretw
+ .endm
+
+ IRQ_TRAMPOLINE 10
+ IRQ_TRAMPOLINE 13
+ IRQ_TRAMPOLINE 15
+ IRQ_TRAMPOLINE 16
+ IRQ_TRAMPOLINE 18
+ IRQ_TRAMPOLINE 19
+
+
+/****************************************************************
+ * Misc. entry points.
+ ****************************************************************/
+
+// Resume (and reboot) entry point - called from entry_post
+ DECLFUNC entry_resume
+entry_resume:
+ // Disable interrupts
+ cli
+ cld
+ // Use a stack in EBDA
+ movw $SEG_BDA, %ax
+ movw %ax, %ds
+ movw BDA_ebda_seg, %ax
+ movw %ax, %ds
+ movw %ax, %ss
+ movl $EBDA_OFFSET_TOP_STACK, %esp
+ // Call handler.
+ jmp handle_resume
+
+// PMM entry point
+ DECLFUNC entry_pmm
+entry_pmm:
+ pushl %esp // Backup %esp, then clear high bits
+ movzwl %sp, %esp
+ pushfl // Save registers clobbered by C code
+ cli
+ cld
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ pushw %es
+ pushw %ds
+ movw %ss, %cx // Move %ss to %ds
+ movw %cx, %ds
+ movl $_cfunc32flat_handle_pmm, %eax // Setup: call32(handle_pmm, args, -1)
+ leal 28(%esp), %edx // %edx points to start of args
+ movl $-1, %ecx
+ calll call32
+ movw %ax, 12(%esp) // Modify %ax:%dx to return %eax
+ shrl $16, %eax
+ movw %ax, 4(%esp)
+ popw %ds // Restore saved registers
+ popw %es
+ popl %edx
+ popl %ecx
+ popl %eax
+ popfl
+ popl %esp
+ lretw
+
+// PnP entry points
+ DECLFUNC entry_pnp_real
+ .global entry_pnp_prot
+entry_pnp_prot:
+ pushl %esp
+ jmp 1f
+entry_pnp_real:
+ pushl %esp // Backup %esp, then clear high bits
+ movzwl %sp, %esp
+1:
+ pushfl // Save registers clobbered by C code
+ cli
+ cld
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ pushw %es
+ pushw %ds
+ movw %ss, %cx // Move %ss to %ds
+ movw %cx, %ds
+ leal 28(%esp), %eax // %eax points to start of u16 args
+ calll handle_pnp
+ movw %ax, 12(%esp) // Modify %eax to return %ax
+ popw %ds
+ popw %es
+ popl %edx
+ popl %ecx
+ popl %eax
+ popfl
+ popl %esp
+ lretw
+
+// APM entry points
+ DECLFUNC entry_apm16
+entry_apm16:
+ pushfw // save flags
+ pushl %eax // dummy
+ ENTRY_ARG handle_apm16
+ addw $4, %sp // pop dummy
+ popfw // restore flags
+ lretw
+
+ .code32
+ DECLFUNC entry_apm32
+entry_apm32:
+ pushfl
+ pushl %gs
+ pushl %cs // Move second descriptor after %cs to %gs
+ addl $16, (%esp)
+ popl %gs
+ ENTRY_ARG_ESP _cfunc32seg_handle_apm32
+ popl %gs
+ popfl
+ lretl
+
+// PCI-BIOS 32bit entry point
+ DECLFUNC entry_pcibios32
+entry_pcibios32:
+ pushfl
+ pushl %gs // Backup %gs and set %gs=%ds
+ pushl %ds
+ popl %gs
+ ENTRY_ARG_ESP _cfunc32seg_handle_pcibios32
+ popl %gs
+ popfl
+ lretl
+
+// BIOS32 support
+ EXPORTFUNC entry_bios32
+entry_bios32:
+ pushfl
+#if CONFIG_PCIBIOS
+ // Check for PCI-BIOS request
+ cmpl $0x49435024, %eax // $PCI
+ jne 1f
+ movl $BUILD_BIOS_ADDR, %ebx
+ movl $BUILD_BIOS_SIZE, %ecx
+ movl $entry_pcibios32, %edx
+ xorb %al, %al
+ jmp 2f
+#endif
+ // Unknown request
+1: movb $0x80, %al
+ // Return to caller
+2: popfl
+ lretl
+
+// 32bit elf entry point
+ EXPORTFUNC entry_elf
+entry_elf:
+ cli
+ cld
+ lidtl (BUILD_BIOS_ADDR + pmode_IDT_info)
+ lgdtl (BUILD_BIOS_ADDR + rombios32_gdt_48)
+ movl $SEG32_MODE32_DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+ movl $BUILD_STACK_ADDR, %esp
+ ljmpl $SEG32_MODE32_CS, $_cfunc32flat_handle_post
+
+ .code16gcc
+
+
+/****************************************************************
+ * Interrupt entry points
+ ****************************************************************/
+
+ // Main entry point for interrupts without args
+ DECLFUNC irqentry
+irqentry:
+ ENTRY_ST
+ iretw
+
+ // Main entry point for interrupts with args
+ DECLFUNC irqentryarg
+irqentryarg:
+ ENTRY_ARG_ST
+ iretw
+
+ // Define an entry point for an interrupt (no args passed).
+ .macro IRQ_ENTRY num
+ .global entry_\num
+ entry_\num :
+ pushl $ handle_\num
+ jmp irqentry
+ .endm
+
+ .macro DECL_IRQ_ENTRY num
+ DECLFUNC entry_\num
+ IRQ_ENTRY \num
+ .endm
+
+ // Define an entry point for an interrupt (can read/modify args).
+ .macro IRQ_ENTRY_ARG num
+ .global entry_\num
+ entry_\num :
+ pushl $ handle_\num
+ jmp irqentryarg
+ .endm
+
+ .macro DECL_IRQ_ENTRY_ARG num
+ DECLFUNC entry_\num
+ IRQ_ENTRY_ARG \num
+ .endm
+
+ // Various entry points (that don't require a fixed location).
+ DECL_IRQ_ENTRY_ARG 13
+ DECL_IRQ_ENTRY 76
+ DECL_IRQ_ENTRY 70
+ DECL_IRQ_ENTRY 74
+ DECL_IRQ_ENTRY 75
+ DECL_IRQ_ENTRY hwpic1
+ DECL_IRQ_ENTRY hwpic2
+
+ // int 18/19 are special - they reset stack and call into 32bit mode.
+ DECLFUNC entry_19
+entry_19:
+ ENTRY_INTO32 _cfunc32flat_handle_19
+
+ DECLFUNC entry_18
+entry_18:
+ ENTRY_INTO32 _cfunc32flat_handle_18
+
+
+/****************************************************************
+ * Fixed position entry points
+ ****************************************************************/
+
+ // Specify a location in the fixed part of bios area.
+ .macro ORG addr
+ .section .fixedaddr.\addr
+ .endm
+
+ ORG 0xe05b
+entry_post:
+ cmpl $0, %cs:HaveRunPost // Check for resume/reboot
+ jnz entry_resume
+ ENTRY_INTO32 _cfunc32flat_handle_post // Normal entry point
+
+ ORG 0xe2c3
+ IRQ_ENTRY 02
+
+ ORG 0xe3fe
+ .global entry_13_official
+entry_13_official:
+ jmp entry_13
+
+ // 0xe401 - OldFDPT in disk.c
+
+ ORG 0xe6f2
+ .global entry_19_official
+entry_19_official:
+ jmp entry_19
+
+ // 0xe6f5 - BIOS_CONFIG_TABLE in misc.c
+
+ // 0xe729 - BaudTable in serial.c
+
+ ORG 0xe739
+ IRQ_ENTRY_ARG 14
+
+ ORG 0xe82e
+ IRQ_ENTRY_ARG 16
+
+ ORG 0xe987
+ IRQ_ENTRY 09
+
+ ORG 0xec59
+ IRQ_ENTRY_ARG 40
+
+ ORG 0xef57
+ IRQ_ENTRY 0e
+
+ // 0xefc7 - diskette_param_table in floppy.c
+
+ ORG 0xefd2
+ IRQ_ENTRY_ARG 17
+
+ ORG 0xf045
+entry_10_0x0f:
+ // XXX - INT 10 Functions 0-Fh Entry Point
+ iretw
+
+ ORG 0xf065
+ IRQ_ENTRY_ARG 10
+
+ // 0xf0a4 - VideoParams in misc.c
+
+ ORG 0xf841
+ IRQ_ENTRY_ARG 12
+
+ ORG 0xf84d
+ IRQ_ENTRY_ARG 11
+
+ ORG 0xf859
+ IRQ_ENTRY_ARG 15
+
+ // 0xfa6e - vgafont8 in font.c
+
+ ORG 0xfe6e
+ IRQ_ENTRY_ARG 1a
+
+ ORG 0xfea5
+ IRQ_ENTRY 08
+
+ // 0xfef3 - InitVectors in misc.c
+
+ // 0xff00 - BiosCopyright in misc.c
+
+ ORG 0xff53
+ .global entry_iret_official
+entry_iret_official:
+ iretw
+
+ ORG 0xff54
+ IRQ_ENTRY_ARG 05
+
+ ORG 0xfff0 // Power-up Entry Point
+ .global reset_vector
+reset_vector:
+ ljmpw $SEG_BIOS, $entry_post
+
+ // 0xfff5 - BiosDate in misc.c
+
+ // 0xfffe - BiosModelId in misc.c
+
+ // 0xffff - BiosChecksum in misc.c
+
+ .end
--- /dev/null
+// 16bit code to handle serial and printer services.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // SET_BDA
+#include "util.h" // debug_enter
+#include "bregs.h" // struct bregs
+
+
+/****************************************************************
+ * COM ports
+ ****************************************************************/
+
+static u16
+detect_serial(u16 port, u8 timeout, u8 count)
+{
+ outb(0x02, port+SEROFF_IER);
+ u8 ier = inb(port+SEROFF_IER);
+ if (ier != 0x02)
+ return 0;
+ u8 iir = inb(port+SEROFF_IIR);
+ if ((iir & 0x3f) != 0x02)
+ return 0;
+
+ outb(0x00, port+SEROFF_IER);
+ SET_BDA(port_com[count], port);
+ SET_BDA(com_timeout[count], timeout);
+ return 1;
+}
+
+void
+serial_setup(void)
+{
+ if (! CONFIG_SERIAL)
+ return;
+ dprintf(3, "init serial\n");
+
+ u16 count = 0;
+ count += detect_serial(PORT_SERIAL1, 0x0a, count);
+ count += detect_serial(PORT_SERIAL2, 0x0a, count);
+ count += detect_serial(PORT_SERIAL3, 0x0a, count);
+ count += detect_serial(PORT_SERIAL4, 0x0a, count);
+ dprintf(1, "Found %d serial ports\n", count);
+
+ // Equipment word bits 9..11 determing # serial ports
+ u16 eqb = GET_BDA(equipment_list_flags);
+ SET_BDA(equipment_list_flags, (eqb & 0xf1ff) | (count << 9));
+}
+
+static u16
+getComAddr(struct bregs *regs)
+{
+ if (regs->dx >= 4) {
+ set_invalid(regs);
+ return 0;
+ }
+ u16 addr = GET_BDA(port_com[regs->dx]);
+ if (! addr)
+ set_invalid(regs);
+ return addr;
+}
+
+// SERIAL - INITIALIZE PORT
+static void
+handle_1400(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ outb(inb(addr+SEROFF_LCR) | 0x80, addr+SEROFF_LCR);
+ if ((regs->al & 0xE0) == 0) {
+ outb(0x17, addr+SEROFF_DLL);
+ outb(0x04, addr+SEROFF_DLH);
+ } else {
+ u16 val16 = 0x600 >> ((regs->al & 0xE0) >> 5);
+ outb(val16 & 0xFF, addr+SEROFF_DLL);
+ outb(val16 >> 8, addr+SEROFF_DLH);
+ }
+ outb(regs->al & 0x1F, addr+SEROFF_LCR);
+ regs->ah = inb(addr+SEROFF_LSR);
+ regs->al = inb(addr+SEROFF_MSR);
+ set_success(regs);
+}
+
+// SERIAL - WRITE CHARACTER TO PORT
+static void
+handle_1401(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx]));
+ for (;;) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if ((lsr & 0x60) == 0x60) {
+ // Success - can write data
+ outb(regs->al, addr+SEROFF_DATA);
+ // XXX - reread lsr?
+ regs->ah = lsr;
+ break;
+ }
+ if (check_timer(end)) {
+ // Timed out - can't write data.
+ regs->ah = lsr | 0x80;
+ break;
+ }
+ yield();
+ }
+ set_success(regs);
+}
+
+// SERIAL - READ CHARACTER FROM PORT
+static void
+handle_1402(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ u32 end = calc_future_timer_ticks(GET_BDA(com_timeout[regs->dx]));
+ for (;;) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if (lsr & 0x01) {
+ // Success - can read data
+ regs->al = inb(addr+SEROFF_DATA);
+ regs->ah = lsr;
+ break;
+ }
+ if (check_timer(end)) {
+ // Timed out - can't read data.
+ regs->ah = lsr | 0x80;
+ break;
+ }
+ yield();
+ }
+ set_success(regs);
+}
+
+// SERIAL - GET PORT STATUS
+static void
+handle_1403(struct bregs *regs)
+{
+ u16 addr = getComAddr(regs);
+ if (!addr)
+ return;
+ regs->ah = inb(addr+SEROFF_LSR);
+ regs->al = inb(addr+SEROFF_MSR);
+ set_success(regs);
+}
+
+static void
+handle_14XX(struct bregs *regs)
+{
+ set_unimplemented(regs);
+}
+
+// INT 14h Serial Communications Service Entry Point
+void VISIBLE16
+handle_14(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_14);
+ if (! CONFIG_SERIAL) {
+ handle_14XX(regs);
+ return;
+ }
+
+ switch (regs->ah) {
+ case 0x00: handle_1400(regs); break;
+ case 0x01: handle_1401(regs); break;
+ case 0x02: handle_1402(regs); break;
+ case 0x03: handle_1403(regs); break;
+ default: handle_14XX(regs); break;
+ }
+}
+
+// XXX - Baud Rate Generator Table
+u8 BaudTable[16] VAR16FIXED(0xe729);
+
+
+/****************************************************************
+ * LPT ports
+ ****************************************************************/
+
+static u16
+detect_parport(u16 port, u8 timeout, u8 count)
+{
+ // clear input mode
+ outb(inb(port+2) & 0xdf, port+2);
+
+ outb(0xaa, port);
+ if (inb(port) != 0xaa)
+ // Not present
+ return 0;
+ SET_BDA(port_lpt[count], port);
+ SET_BDA(lpt_timeout[count], timeout);
+ return 1;
+}
+
+void
+lpt_setup(void)
+{
+ if (! CONFIG_LPT)
+ return;
+ dprintf(3, "init lpt\n");
+
+ u16 count = 0;
+ count += detect_parport(PORT_LPT1, 0x14, count);
+ count += detect_parport(PORT_LPT2, 0x14, count);
+ dprintf(1, "Found %d lpt ports\n", count);
+
+ // Equipment word bits 14..15 determing # parallel ports
+ u16 eqb = GET_BDA(equipment_list_flags);
+ SET_BDA(equipment_list_flags, (eqb & 0x3fff) | (count << 14));
+}
+
+static u16
+getLptAddr(struct bregs *regs)
+{
+ if (regs->dx >= 3) {
+ set_invalid(regs);
+ return 0;
+ }
+ u16 addr = GET_BDA(port_lpt[regs->dx]);
+ if (! addr)
+ set_invalid(regs);
+ return addr;
+}
+
+// INT 17 - PRINTER - WRITE CHARACTER
+static void
+handle_1700(struct bregs *regs)
+{
+ u16 addr = getLptAddr(regs);
+ if (!addr)
+ return;
+
+ u32 end = calc_future_timer_ticks(GET_BDA(lpt_timeout[regs->dx]));
+
+ outb(regs->al, addr);
+ u8 val8 = inb(addr+2);
+ outb(val8 | 0x01, addr+2); // send strobe
+ udelay(5);
+ outb(val8 & ~0x01, addr+2);
+
+ for (;;) {
+ u8 v = inb(addr+1);
+ if (!(v & 0x40)) {
+ // Success
+ regs->ah = v ^ 0x48;
+ break;
+ }
+ if (check_timer(end)) {
+ // Timeout
+ regs->ah = (v ^ 0x48) | 0x01;
+ break;
+ }
+ yield();
+ }
+
+ set_success(regs);
+}
+
+// INT 17 - PRINTER - INITIALIZE PORT
+static void
+handle_1701(struct bregs *regs)
+{
+ u16 addr = getLptAddr(regs);
+ if (!addr)
+ return;
+
+ u8 val8 = inb(addr+2);
+ outb(val8 & ~0x04, addr+2); // send init
+ udelay(5);
+ outb(val8 | 0x04, addr+2);
+
+ regs->ah = inb(addr+1) ^ 0x48;
+ set_success(regs);
+}
+
+// INT 17 - PRINTER - GET STATUS
+static void
+handle_1702(struct bregs *regs)
+{
+ u16 addr = getLptAddr(regs);
+ if (!addr)
+ return;
+ regs->ah = inb(addr+1) ^ 0x48;
+ set_success(regs);
+}
+
+static void
+handle_17XX(struct bregs *regs)
+{
+ set_unimplemented(regs);
+}
+
+// INT17h : Printer Service Entry Point
+void VISIBLE16
+handle_17(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_17);
+ if (! CONFIG_LPT) {
+ handle_17XX(regs);
+ return;
+ }
+
+ switch (regs->ah) {
+ case 0x00: handle_1700(regs); break;
+ case 0x01: handle_1701(regs); break;
+ case 0x02: handle_1702(regs); break;
+ default: handle_17XX(regs); break;
+ }
+}
--- /dev/null
+// Support for enabling/disabling BIOS ram shadowing.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // memcpy
+#include "pci.h" // pci_config_writeb
+#include "config.h" // CONFIG_*
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "xen.h" // usingXen
+
+// On the emulators, the bios at 0xf0000 is also at 0xffff0000
+#define BIOS_SRC_OFFSET 0xfff00000
+
+#define I440FX_PAM0 0x59
+
+// Enable shadowing and copy bios.
+static void
+__make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+ // Make ram from 0xc0000-0xf0000 writable
+ int clear = 0;
+ int i;
+ for (i=0; i<6; i++) {
+ u32 pam = pam0 + 1 + i;
+ int reg = pci_config_readb(bdf, pam);
+ if (CONFIG_OPTIONROMS_DEPLOYED && (reg & 0x11) != 0x11) {
+ // Need to copy optionroms to work around qemu implementation
+ void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
+ memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
+ pci_config_writeb(bdf, pam, 0x33);
+ memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
+ clear = 1;
+ } else {
+ pci_config_writeb(bdf, pam, 0x33);
+ }
+ }
+ if (clear)
+ memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
+
+ // Make ram from 0xf0000-0x100000 writable
+ int reg = pci_config_readb(bdf, pam0);
+ pci_config_writeb(bdf, pam0, 0x30);
+ if (reg & 0x10)
+ // Ram already present.
+ return;
+
+ // Copy bios.
+ extern u8 code32flat_start[], code32flat_end[];
+ memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+ , code32flat_end - code32flat_start);
+}
+
+static void
+make_bios_writable_intel(u16 bdf, u32 pam0)
+{
+ int reg = pci_config_readb(bdf, pam0);
+ if (!(reg & 0x10)) {
+ // QEMU doesn't fully implement the piix shadow capabilities -
+ // if ram isn't backing the bios segment when shadowing is
+ // disabled, the code itself wont be in memory. So, run the
+ // code from the high-memory flash location.
+ u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET;
+ void (*func)(u16 bdf, u32 pam0) = (void*)pos;
+ func(bdf, pam0);
+ return;
+ }
+ // Ram already present - just enable writes
+ __make_bios_writable_intel(bdf, pam0);
+}
+
+static void
+make_bios_readonly_intel(u16 bdf, u32 pam0)
+{
+ // Flush any pending writes before locking memory.
+ wbinvd();
+
+ // Write protect roms from 0xc0000-0xf0000
+ int i;
+ for (i=0; i<6; i++) {
+ u32 mem = BUILD_ROM_START + i * 32*1024;
+ u32 pam = pam0 + 1 + i;
+ if (RomEnd <= mem + 16*1024) {
+ if (RomEnd > mem)
+ pci_config_writeb(bdf, pam, 0x31);
+ break;
+ }
+ pci_config_writeb(bdf, pam, 0x11);
+ }
+
+ // Write protect 0xf0000-0x100000
+ pci_config_writeb(bdf, pam0, 0x10);
+}
+
+static void i440fx_bios_make_readonly(struct pci_device *pci, void *arg)
+{
+ make_bios_readonly_intel(pci->bdf, I440FX_PAM0);
+}
+
+static const struct pci_device_id dram_controller_make_readonly_tbl[] = {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,
+ i440fx_bios_make_readonly),
+ PCI_DEVICE_END
+};
+
+// Make the 0xc0000-0x100000 area read/writable.
+void
+make_bios_writable(void)
+{
+ if (CONFIG_COREBOOT || usingXen())
+ return;
+
+ dprintf(3, "enabling shadow ram\n");
+
+ // At this point, statically allocated variables can't be written,
+ // so do this search manually.
+ int bdf;
+ foreachbdf(bdf, 0) {
+ u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+ u16 vendor = vendev & 0xffff, device = vendev >> 16;
+ if (vendor == PCI_VENDOR_ID_INTEL
+ && device == PCI_DEVICE_ID_INTEL_82441) {
+ make_bios_writable_intel(bdf, I440FX_PAM0);
+ return;
+ }
+ }
+ dprintf(1, "Unable to unlock ram - bridge not found\n");
+}
+
+// Make the BIOS code segment area (0xf0000) read-only.
+void
+make_bios_readonly(void)
+{
+ if (CONFIG_COREBOOT || usingXen())
+ return;
+
+ dprintf(3, "locking shadow ram\n");
+ struct pci_device *pci = pci_find_init_device(
+ dram_controller_make_readonly_tbl, NULL);
+ if (!pci)
+ dprintf(1, "Unable to lock ram - bridge not found\n");
+}
+
+void
+qemu_prep_reset(void)
+{
+ if (CONFIG_COREBOOT)
+ return;
+ // QEMU doesn't map 0xc0000-0xfffff back to the original rom on a
+ // reset, so do that manually before invoking a hard reset.
+ make_bios_writable();
+ extern u8 code32flat_start[], code32flat_end[];
+ memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET
+ , code32flat_end - code32flat_start);
+}
--- /dev/null
+// smbios table generation (on emulators)
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "biosvar.h" // GET_EBDA
+#include "paravirt.h" // qemu_cfg_smbios_load_field
+#include "smbios.h" // struct smbios_entry_point
+
+struct smbios_entry_point *SMBiosAddr;
+
+static void
+smbios_entry_point_init(u16 max_structure_size,
+ u16 structure_table_length,
+ void *structure_table_address,
+ u16 number_of_structures)
+{
+ struct smbios_entry_point *ep = malloc_fseg(sizeof(*ep));
+ void *finaltable;
+ if (structure_table_length <= BUILD_MAX_SMBIOS_FSEG)
+ // Table is small enough for f-seg - allocate there. This
+ // works around a bug in JunOS (at least for small SMBIOS tables).
+ finaltable = malloc_fseg(structure_table_length);
+ else
+ finaltable = malloc_high(structure_table_length);
+ if (!ep || !finaltable) {
+ warn_noalloc();
+ free(ep);
+ free(finaltable);
+ return;
+ }
+ memcpy(finaltable, structure_table_address, structure_table_length);
+
+ memcpy(ep->anchor_string, "_SM_", 4);
+ ep->length = 0x1f;
+ ep->smbios_major_version = 2;
+ ep->smbios_minor_version = 4;
+ ep->max_structure_size = max_structure_size;
+ ep->entry_point_revision = 0;
+ memset(ep->formatted_area, 0, 5);
+ memcpy(ep->intermediate_anchor_string, "_DMI_", 5);
+
+ ep->structure_table_length = structure_table_length;
+ ep->structure_table_address = (u32)finaltable;
+ ep->number_of_structures = number_of_structures;
+ ep->smbios_bcd_revision = 0x24;
+
+ ep->checksum -= checksum(ep, 0x10);
+
+ ep->intermediate_checksum -= checksum((void*)ep + 0x10, ep->length - 0x10);
+
+ SMBiosAddr = ep;
+ dprintf(1, "SMBIOS ptr=%p table=%p size=%d\n"
+ , ep, finaltable, structure_table_length);
+}
+
+#define load_str_field_with_default(type, field, def) \
+ do { \
+ size = qemu_cfg_smbios_load_field(type, \
+ offsetof(struct smbios_type_##type, \
+ field), end); \
+ if (size > 0) { \
+ end += size; \
+ } else { \
+ memcpy(end, def, sizeof(def)); \
+ end += sizeof(def); \
+ } \
+ p->field = ++str_index; \
+ } while (0)
+
+#define load_str_field_or_skip(type, field) \
+ do { \
+ size = qemu_cfg_smbios_load_field(type, \
+ offsetof(struct smbios_type_##type, \
+ field), end); \
+ if (size > 0) { \
+ end += size; \
+ p->field = ++str_index; \
+ } else { \
+ p->field = 0; \
+ } \
+ } while (0)
+
+#define set_field_with_default(type, field, def) \
+ do { \
+ if (!qemu_cfg_smbios_load_field(type, \
+ offsetof(struct smbios_type_##type, \
+ field), &p->field)) { \
+ p->field = def; \
+ } \
+ } while (0)
+
+/* Type 0 -- BIOS Information */
+#define RELEASE_DATE_STR "01/01/2007"
+static void *
+smbios_init_type_0(void *start)
+{
+ struct smbios_type_0 *p = (struct smbios_type_0 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_0);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 0;
+ p->header.length = sizeof(struct smbios_type_0);
+ p->header.handle = 0;
+
+ load_str_field_with_default(0, vendor_str, CONFIG_APPNAME);
+ load_str_field_with_default(0, bios_version_str, CONFIG_APPNAME);
+
+ p->bios_starting_address_segment = 0xe800;
+
+ load_str_field_with_default(0, bios_release_date_str, RELEASE_DATE_STR);
+
+ p->bios_rom_size = 0; /* FIXME */
+
+ if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
+ bios_characteristics),
+ &p->bios_characteristics)) {
+ memset(p->bios_characteristics, 0, 8);
+ /* BIOS characteristics not supported */
+ p->bios_characteristics[0] = 0x08;
+ }
+
+ if (!qemu_cfg_smbios_load_field(0, offsetof(struct smbios_type_0,
+ bios_characteristics_extension_bytes),
+ &p->bios_characteristics_extension_bytes)) {
+ p->bios_characteristics_extension_bytes[0] = 0;
+ /* Enable targeted content distribution. Needed for SVVP */
+ p->bios_characteristics_extension_bytes[1] = 4;
+ }
+
+ set_field_with_default(0, system_bios_major_release, 1);
+ set_field_with_default(0, system_bios_minor_release, 0);
+ set_field_with_default(0, embedded_controller_major_release, 0xff);
+ set_field_with_default(0, embedded_controller_minor_release, 0xff);
+
+ *end = 0;
+ end++;
+
+ return end;
+}
+
+/* Type 1 -- System Information */
+static void *
+smbios_init_type_1(void *start)
+{
+ struct smbios_type_1 *p = (struct smbios_type_1 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_1);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 1;
+ p->header.length = sizeof(struct smbios_type_1);
+ p->header.handle = 0x100;
+
+ load_str_field_with_default(1, manufacturer_str, CONFIG_APPNAME);
+ load_str_field_with_default(1, product_name_str, CONFIG_APPNAME);
+ load_str_field_or_skip(1, version_str);
+ load_str_field_or_skip(1, serial_number_str);
+
+ if (!qemu_cfg_smbios_load_field(1, offsetof(struct smbios_type_1,
+ uuid), &p->uuid)) {
+ memset(p->uuid, 0, 16);
+ }
+
+ set_field_with_default(1, wake_up_type, 0x06); /* power switch */
+
+ load_str_field_or_skip(1, sku_number_str);
+ load_str_field_or_skip(1, family_str);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 3 -- System Enclosure */
+static void *
+smbios_init_type_3(void *start)
+{
+ struct smbios_type_3 *p = (struct smbios_type_3 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_3);
+ size_t size;
+ int str_index = 0;
+
+ p->header.type = 3;
+ p->header.length = sizeof(struct smbios_type_3);
+ p->header.handle = 0x300;
+
+ load_str_field_with_default(3, manufacturer_str, CONFIG_APPNAME);
+ set_field_with_default(3, type, 0x01); /* other */
+
+ load_str_field_or_skip(3, version_str);
+ load_str_field_or_skip(3, serial_number_str);
+ load_str_field_or_skip(3, asset_tag_number_str);
+
+ set_field_with_default(3, boot_up_state, 0x03); /* safe */
+ set_field_with_default(3, power_supply_state, 0x03); /* safe */
+ set_field_with_default(3, thermal_state, 0x03); /* safe */
+ set_field_with_default(3, security_status, 0x02); /* unknown */
+
+ set_field_with_default(3, oem_defined, 0);
+ set_field_with_default(3, height, 0);
+ set_field_with_default(3, number_of_power_cords, 0);
+ set_field_with_default(3, contained_element_count, 0);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 4 -- Processor Information */
+static void *
+smbios_init_type_4(void *start, unsigned int cpu_number)
+{
+ struct smbios_type_4 *p = (struct smbios_type_4 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_4);
+ size_t size;
+ int str_index = 0;
+ char name[1024];
+
+ p->header.type = 4;
+ p->header.length = sizeof(struct smbios_type_4);
+ p->header.handle = 0x400 + cpu_number;
+
+ size = qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
+ socket_designation_str),
+ name);
+ if (size)
+ snprintf(name + size - 1, sizeof(name) - size, "%2x", cpu_number);
+ else
+ snprintf(name, sizeof(name), "CPU%2x", cpu_number);
+
+ memcpy(end, name, strlen(name) + 1);
+ end += strlen(name) + 1;
+ p->socket_designation_str = ++str_index;
+
+ set_field_with_default(4, processor_type, 0x03); /* CPU */
+ set_field_with_default(4, processor_family, 0x01); /* other */
+
+ load_str_field_with_default(4, processor_manufacturer_str, CONFIG_APPNAME);
+
+ if (!qemu_cfg_smbios_load_field(4, offsetof(struct smbios_type_4,
+ processor_id), p->processor_id)) {
+ u32 cpuid_signature, ebx, ecx, cpuid_features;
+ cpuid(1, &cpuid_signature, &ebx, &ecx, &cpuid_features);
+ p->processor_id[0] = cpuid_signature;
+ p->processor_id[1] = cpuid_features;
+ }
+
+ load_str_field_or_skip(4, processor_version_str);
+ set_field_with_default(4, voltage, 0);
+ set_field_with_default(4, external_clock, 0);
+
+ set_field_with_default(4, max_speed, 2000);
+ set_field_with_default(4, current_speed, 2000);
+
+ set_field_with_default(4, status, 0x41); /* socket populated, CPU enabled */
+ set_field_with_default(4, processor_upgrade, 0x01); /* other */
+
+ /* cache information structure not provided */
+ p->l1_cache_handle = 0xffff;
+ p->l2_cache_handle = 0xffff;
+ p->l3_cache_handle = 0xffff;
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 16 -- Physical Memory Array */
+static void *
+smbios_init_type_16(void *start, u32 memory_size_mb, int nr_mem_devs)
+{
+ struct smbios_type_16 *p = (struct smbios_type_16*)start;
+
+ p->header.type = 16;
+ p->header.length = sizeof(struct smbios_type_16);
+ p->header.handle = 0x1000;
+
+ set_field_with_default(16, location, 0x01); /* other */
+ set_field_with_default(16, use, 0x03); /* system memory */
+ /* Multi-bit ECC to make Microsoft happy */
+ set_field_with_default(16, error_correction, 0x06);
+ /* 0x80000000 = unknown, accept sizes < 2TB - TODO multiple arrays */
+ p->maximum_capacity = memory_size_mb < 2 << 20 ?
+ memory_size_mb << 10 : 0x80000000;
+ p->memory_error_information_handle = 0xfffe; /* none provided */
+ p->number_of_memory_devices = nr_mem_devs;
+
+ start += sizeof(struct smbios_type_16);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+/* Type 17 -- Memory Device */
+static void *
+smbios_init_type_17(void *start, u32 size_mb, int instance)
+{
+ struct smbios_type_17 *p = (struct smbios_type_17 *)start;
+ char *end = (char *)start + sizeof(struct smbios_type_17);
+ size_t size;
+ int str_index = 0;
+ char name[1024];
+
+ p->header.type = 17;
+ p->header.length = sizeof(struct smbios_type_17);
+ p->header.handle = 0x1100 + instance;
+
+ p->physical_memory_array_handle = 0x1000;
+ set_field_with_default(17, total_width, 64);
+ set_field_with_default(17, data_width, 64);
+/* TODO: should assert in case something is wrong ASSERT((memory_size_mb & ~0x7fff) == 0); */
+ p->size = size_mb;
+ set_field_with_default(17, form_factor, 0x09); /* DIMM */
+ p->device_set = 0;
+
+ size = qemu_cfg_smbios_load_field(17, offsetof(struct smbios_type_17,
+ device_locator_str),
+ name);
+ if (size)
+ snprintf(name + size - 1, sizeof(name) - size, "%d", instance);
+ else
+ snprintf(name, sizeof(name), "DIMM %d", instance);
+
+ memcpy(end, name, strlen(name) + 1);
+ end += strlen(name) + 1;
+ p->device_locator_str = ++str_index;
+
+ load_str_field_or_skip(17, bank_locator_str);
+ set_field_with_default(17, memory_type, 0x07); /* RAM */
+ set_field_with_default(17, type_detail, 0);
+
+ *end = 0;
+ end++;
+ if (!str_index) {
+ *end = 0;
+ end++;
+ }
+
+ return end;
+}
+
+/* Type 19 -- Memory Array Mapped Address */
+static void *
+smbios_init_type_19(void *start, u32 start_mb, u32 size_mb, int instance)
+{
+ struct smbios_type_19 *p = (struct smbios_type_19 *)start;
+
+ p->header.type = 19;
+ p->header.length = sizeof(struct smbios_type_19);
+ p->header.handle = 0x1300 + instance;
+
+ p->starting_address = start_mb << 10;
+ p->ending_address = p->starting_address + (size_mb << 10) - 1;
+ p->memory_array_handle = 0x1000;
+ p->partition_width = 1;
+
+ start += sizeof(struct smbios_type_19);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+/* Type 20 -- Memory Device Mapped Address */
+static void *
+smbios_init_type_20(void *start, u32 start_mb, u32 size_mb, int instance,
+ int dev_handle, int array_handle)
+{
+ struct smbios_type_20 *p = (struct smbios_type_20 *)start;
+
+ p->header.type = 20;
+ p->header.length = sizeof(struct smbios_type_20);
+ p->header.handle = 0x1400 + instance;
+
+ p->starting_address = start_mb << 10;
+ p->ending_address = p->starting_address + (size_mb << 10) - 1;
+ p->memory_device_handle = 0x1100 + dev_handle;
+ p->memory_array_mapped_address_handle = 0x1300 + array_handle;
+ p->partition_row_position = 1;
+ p->interleave_position = 0;
+ p->interleaved_data_depth = 0;
+
+ start += sizeof(struct smbios_type_20);
+
+ *((u16 *)start) = 0;
+ return start+2;
+}
+
+/* Type 32 -- System Boot Information */
+static void *
+smbios_init_type_32(void *start)
+{
+ struct smbios_type_32 *p = (struct smbios_type_32 *)start;
+
+ p->header.type = 32;
+ p->header.length = sizeof(struct smbios_type_32);
+ p->header.handle = 0x2000;
+ memset(p->reserved, 0, 6);
+ set_field_with_default(32, boot_status, 0); /* no errors detected */
+
+ start += sizeof(struct smbios_type_32);
+ *((u16 *)start) = 0;
+
+ return start+2;
+}
+
+/* Type 127 -- End of Table */
+static void *
+smbios_init_type_127(void *start)
+{
+ struct smbios_type_127 *p = (struct smbios_type_127 *)start;
+
+ p->header.type = 127;
+ p->header.length = sizeof(struct smbios_type_127);
+ p->header.handle = 0x7f00;
+
+ start += sizeof(struct smbios_type_127);
+ *((u16 *)start) = 0;
+
+ return start + 2;
+}
+
+#define TEMPSMBIOSSIZE (32 * 1024)
+
+void
+smbios_init(void)
+{
+ if (! CONFIG_SMBIOS)
+ return;
+
+ dprintf(3, "init SMBIOS tables\n");
+
+ char *start = malloc_tmphigh(TEMPSMBIOSSIZE);
+ if (! start) {
+ warn_noalloc();
+ return;
+ }
+
+ u32 nr_structs = 0, max_struct_size = 0;
+ char *q, *p = start;
+ char *end = start + TEMPSMBIOSSIZE - sizeof(struct smbios_type_127);
+
+#define add_struct(type, args...) \
+ do { \
+ if (!qemu_cfg_smbios_load_external(type, &p, &nr_structs, \
+ &max_struct_size, end)) { \
+ q = smbios_init_type_##type(args); \
+ nr_structs++; \
+ if ((q - p) > max_struct_size) \
+ max_struct_size = q - p; \
+ p = q; \
+ } \
+ } while (0)
+
+ add_struct(0, p);
+ add_struct(1, p);
+ add_struct(3, p);
+
+ int cpu_num;
+ for (cpu_num = 1; cpu_num <= MaxCountCPUs; cpu_num++)
+ add_struct(4, p, cpu_num);
+
+ int ram_mb = (RamSize + RamSizeOver4G) >> 20;
+ int nr_mem_devs = (ram_mb + 0x3fff) >> 14;
+ add_struct(16, p, ram_mb, nr_mem_devs);
+
+ int i, j;
+ for (i = 0; i < nr_mem_devs; i++) {
+ u32 dev_mb = ((i == (nr_mem_devs - 1))
+ ? (((ram_mb - 1) & 0x3fff) + 1)
+ : 16384);
+ add_struct(17, p, dev_mb, i);
+ }
+
+ add_struct(19, p, 0, RamSize >> 20, 0);
+ if (RamSizeOver4G)
+ add_struct(19, p, 4096, RamSizeOver4G >> 20, 1);
+
+ add_struct(20, p, 0, RamSize >> 20, 0, 0, 0);
+ if (RamSizeOver4G) {
+ u32 start_mb = 4096;
+ for (j = 1, i = 0; i < nr_mem_devs; i++, j++) {
+ u32 dev_mb = ((i == (nr_mem_devs - 1))
+ ? (((ram_mb - 1) & 0x3fff) + 1)
+ : 16384);
+ if (i == 0)
+ dev_mb -= RamSize >> 20;
+
+ add_struct(20, p, start_mb, dev_mb, j, i, 1);
+ start_mb += dev_mb;
+ }
+ }
+
+ add_struct(32, p);
+ /* Add any remaining provided entries before the end marker */
+ for (i = 0; i < 256; i++)
+ qemu_cfg_smbios_load_external(i, &p, &nr_structs, &max_struct_size,
+ end);
+ add_struct(127, p);
+
+#undef add_struct
+
+ smbios_entry_point_init(max_struct_size, p - start, start, nr_structs);
+ free(start);
+}
--- /dev/null
+#ifndef __SMBIOS_H
+#define __SMBIOS_H
+
+// smbios.c
+void smbios_init(void);
+
+/* SMBIOS entry point -- must be written to a 16-bit aligned address
+ between 0xf0000 and 0xfffff.
+ */
+struct smbios_entry_point {
+ char anchor_string[4];
+ u8 checksum;
+ u8 length;
+ u8 smbios_major_version;
+ u8 smbios_minor_version;
+ u16 max_structure_size;
+ u8 entry_point_revision;
+ u8 formatted_area[5];
+ char intermediate_anchor_string[5];
+ u8 intermediate_checksum;
+ u16 structure_table_length;
+ u32 structure_table_address;
+ u16 number_of_structures;
+ u8 smbios_bcd_revision;
+} PACKED;
+
+extern struct smbios_entry_point *SMBiosAddr;
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+ u8 type;
+ u8 length;
+ u16 handle;
+} PACKED;
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+ struct smbios_structure_header header;
+ u8 vendor_str;
+ u8 bios_version_str;
+ u16 bios_starting_address_segment;
+ u8 bios_release_date_str;
+ u8 bios_rom_size;
+ u8 bios_characteristics[8];
+ u8 bios_characteristics_extension_bytes[2];
+ u8 system_bios_major_release;
+ u8 system_bios_minor_release;
+ u8 embedded_controller_major_release;
+ u8 embedded_controller_minor_release;
+} PACKED;
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+ struct smbios_structure_header header;
+ u8 manufacturer_str;
+ u8 product_name_str;
+ u8 version_str;
+ u8 serial_number_str;
+ u8 uuid[16];
+ u8 wake_up_type;
+ u8 sku_number_str;
+ u8 family_str;
+} PACKED;
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+ struct smbios_structure_header header;
+ u8 manufacturer_str;
+ u8 type;
+ u8 version_str;
+ u8 serial_number_str;
+ u8 asset_tag_number_str;
+ u8 boot_up_state;
+ u8 power_supply_state;
+ u8 thermal_state;
+ u8 security_status;
+ u32 oem_defined;
+ u8 height;
+ u8 number_of_power_cords;
+ u8 contained_element_count;
+ // contained elements follow
+} PACKED;
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+ struct smbios_structure_header header;
+ u8 socket_designation_str;
+ u8 processor_type;
+ u8 processor_family;
+ u8 processor_manufacturer_str;
+ u32 processor_id[2];
+ u8 processor_version_str;
+ u8 voltage;
+ u16 external_clock;
+ u16 max_speed;
+ u16 current_speed;
+ u8 status;
+ u8 processor_upgrade;
+ u16 l1_cache_handle;
+ u16 l2_cache_handle;
+ u16 l3_cache_handle;
+} PACKED;
+
+/* SMBIOS type 16 - Physical Memory Array
+ * Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+ struct smbios_structure_header header;
+ u8 location;
+ u8 use;
+ u8 error_correction;
+ u32 maximum_capacity;
+ u16 memory_error_information_handle;
+ u16 number_of_memory_devices;
+} PACKED;
+
+/* SMBIOS type 17 - Memory Device
+ * Associated with one type 19
+ */
+struct smbios_type_17 {
+ struct smbios_structure_header header;
+ u16 physical_memory_array_handle;
+ u16 memory_error_information_handle;
+ u16 total_width;
+ u16 data_width;
+ u16 size;
+ u8 form_factor;
+ u8 device_set;
+ u8 device_locator_str;
+ u8 bank_locator_str;
+ u8 memory_type;
+ u16 type_detail;
+} PACKED;
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+ struct smbios_structure_header header;
+ u32 starting_address;
+ u32 ending_address;
+ u16 memory_array_handle;
+ u8 partition_width;
+} PACKED;
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+ struct smbios_structure_header header;
+ u32 starting_address;
+ u32 ending_address;
+ u16 memory_device_handle;
+ u16 memory_array_mapped_address_handle;
+ u8 partition_row_position;
+ u8 interleave_position;
+ u8 interleaved_data_depth;
+} PACKED;
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+ struct smbios_structure_header header;
+ u8 reserved[6];
+ u8 boot_status;
+} PACKED;
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+ struct smbios_structure_header header;
+} PACKED;
+
+#endif // smbios.h
--- /dev/null
+// System Management Mode support (on emulators)
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "pci.h" // pci_config_writel
+#include "util.h" // wbinvd
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outb
+#include "pci_ids.h" // PCI_VENDOR_ID_INTEL
+
+ASM32FLAT(
+ ".global smm_relocation_start\n"
+ ".global smm_relocation_end\n"
+ ".global smm_code_start\n"
+ ".global smm_code_end\n"
+ " .code16\n"
+
+ /* code to relocate SMBASE to 0xa0000 */
+ "smm_relocation_start:\n"
+ " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7efc, %ebx\n"
+ " addr32 mov (%ebx), %al\n" /* revision ID to see if x86_64 or x86 */
+ " cmp $0x64, %al\n"
+ " je 1f\n"
+ " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7ef8, %ebx\n"
+ " jmp 2f\n"
+ "1:\n"
+ " mov $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7f00, %ebx\n"
+ "2:\n"
+ " movl $" __stringify(BUILD_SMM_ADDR) " - 0x8000, %eax\n"
+ " addr32 movl %eax, (%ebx)\n"
+ /* indicate to the BIOS that the SMM code was executed */
+ " mov $0x00, %al\n"
+ " movw $" __stringify(PORT_SMI_STATUS) ", %dx\n"
+ " outb %al, %dx\n"
+ " rsm\n"
+ "smm_relocation_end:\n"
+
+ /* minimal SMM code to enable or disable ACPI */
+ "smm_code_start:\n"
+ " movw $" __stringify(PORT_SMI_CMD) ", %dx\n"
+ " inb %dx, %al\n"
+ " cmp $0xf0, %al\n"
+ " jne 1f\n"
+
+ /* ACPI disable */
+ " mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
+ " inw %dx, %ax\n"
+ " andw $~1, %ax\n"
+ " outw %ax, %dx\n"
+
+ " jmp 2f\n"
+
+ "1:\n"
+ " cmp $0xf1, %al\n"
+ " jne 2f\n"
+
+ /* ACPI enable */
+ " mov $" __stringify(PORT_ACPI_PM_BASE) " + 0x04, %dx\n" /* PMCNTRL */
+ " inw %dx, %ax\n"
+ " orw $1, %ax\n"
+ " outw %ax, %dx\n"
+
+ "2:\n"
+ " rsm\n"
+ "smm_code_end:\n"
+ " .code32\n"
+ );
+
+extern u8 smm_relocation_start, smm_relocation_end;
+extern u8 smm_code_start, smm_code_end;
+
+static void
+smm_save_and_copy(void)
+{
+ /* save original memory content */
+ memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE);
+
+ /* copy the SMM relocation code */
+ memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start,
+ &smm_relocation_end - &smm_relocation_start);
+}
+
+static void
+smm_relocate_and_restore(void)
+{
+ /* init APM status port */
+ outb(0x01, PORT_SMI_STATUS);
+
+ /* raise an SMI interrupt */
+ outb(0x00, PORT_SMI_CMD);
+
+ /* wait until SMM code executed */
+ while (inb(PORT_SMI_STATUS) != 0x00)
+ ;
+
+ /* restore original memory content */
+ memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE);
+
+ /* copy the SMM code */
+ memcpy((void *)BUILD_SMM_ADDR, &smm_code_start
+ , &smm_code_end - &smm_code_start);
+ wbinvd();
+}
+
+#define I440FX_SMRAM 0x72
+#define PIIX_DEVACTB 0x58
+#define PIIX_APMC_EN (1 << 25)
+
+// This code is hardcoded for PIIX4 Power Management device.
+static void piix4_apmc_smm_init(struct pci_device *pci, void *arg)
+{
+ struct pci_device *i440_pci = pci_find_device(PCI_VENDOR_ID_INTEL
+ , PCI_DEVICE_ID_INTEL_82441);
+ if (!i440_pci)
+ return;
+
+ /* check if SMM init is already done */
+ u32 value = pci_config_readl(pci->bdf, PIIX_DEVACTB);
+ if (value & PIIX_APMC_EN)
+ return;
+
+ /* enable the SMM memory window */
+ pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x48);
+
+ smm_save_and_copy();
+
+ /* enable SMI generation when writing to the APMC register */
+ pci_config_writel(pci->bdf, PIIX_DEVACTB, value | PIIX_APMC_EN);
+
+ smm_relocate_and_restore();
+
+ /* close the SMM memory window and enable normal SMM */
+ pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08);
+}
+
+static const struct pci_device_id smm_init_tbl[] = {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ piix4_apmc_smm_init),
+
+ PCI_DEVICE_END,
+};
+
+void
+smm_init(void)
+{
+ if (CONFIG_COREBOOT)
+ // SMM only supported on emulators.
+ return;
+ if (!CONFIG_USE_SMM)
+ return;
+
+ dprintf(3, "init smm\n");
+ pci_find_init_device(smm_init_tbl, NULL);
+}
--- /dev/null
+// CPU count detection
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2006 Fabrice Bellard
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_*
+#include "cmos.h" // CMOS_BIOS_SMP_COUNT
+#include "paravirt.h"
+
+#define APIC_ICR_LOW ((u8*)BUILD_APIC_ADDR + 0x300)
+#define APIC_SVR ((u8*)BUILD_APIC_ADDR + 0x0F0)
+#define APIC_LINT0 ((u8*)BUILD_APIC_ADDR + 0x350)
+#define APIC_LINT1 ((u8*)BUILD_APIC_ADDR + 0x360)
+
+#define APIC_ENABLED 0x0100
+
+struct { u32 ecx, eax, edx; } smp_mtrr[32] VAR16VISIBLE;
+u32 smp_mtrr_count VAR16VISIBLE;
+
+void
+wrmsr_smp(u32 index, u64 val)
+{
+ wrmsr(index, val);
+ if (smp_mtrr_count >= ARRAY_SIZE(smp_mtrr)) {
+ warn_noalloc();
+ return;
+ }
+ smp_mtrr[smp_mtrr_count].ecx = index;
+ smp_mtrr[smp_mtrr_count].eax = val;
+ smp_mtrr[smp_mtrr_count].edx = val >> 32;
+ smp_mtrr_count++;
+}
+
+u32 CountCPUs VAR16VISIBLE;
+u32 MaxCountCPUs VAR16VISIBLE;
+extern void smp_ap_boot_code(void);
+ASM16(
+ " .global smp_ap_boot_code\n"
+ "smp_ap_boot_code:\n"
+
+ // Setup data segment
+ " movw $" __stringify(SEG_BIOS) ", %ax\n"
+ " movw %ax, %ds\n"
+
+ // MTRR setup
+ " movl $smp_mtrr, %esi\n"
+ " movl smp_mtrr_count, %ebx\n"
+ "1:testl %ebx, %ebx\n"
+ " jz 2f\n"
+ " movl 0(%esi), %ecx\n"
+ " movl 4(%esi), %eax\n"
+ " movl 8(%esi), %edx\n"
+ " wrmsr\n"
+ " addl $12, %esi\n"
+ " decl %ebx\n"
+ " jmp 1b\n"
+ "2:\n"
+
+ // Increment the cpu counter
+ " lock incl CountCPUs\n"
+
+ // Halt the processor.
+ "1:hlt\n"
+ " jmp 1b\n"
+ );
+
+// find and initialize the CPUs by launching a SIPI to them
+void
+smp_probe(void)
+{
+ ASSERT32FLAT();
+ u32 eax, ebx, ecx, cpuid_features;
+ cpuid(1, &eax, &ebx, &ecx, &cpuid_features);
+ if (eax < 1 || !(cpuid_features & CPUID_APIC)) {
+ // No apic - only the main cpu is present.
+ dprintf(1, "No apic - only the main cpu is present.\n");
+ CountCPUs= 1;
+ MaxCountCPUs = 1;
+ return;
+ }
+
+ // Init the counter.
+ writel(&CountCPUs, 1);
+
+ // Setup jump trampoline to counter code.
+ u64 old = *(u64*)BUILD_AP_BOOT_ADDR;
+ // ljmpw $SEG_BIOS, $(smp_ap_boot_code - BUILD_BIOS_ADDR)
+ u64 new = (0xea | ((u64)SEG_BIOS<<24)
+ | (((u32)smp_ap_boot_code - BUILD_BIOS_ADDR) << 8));
+ *(u64*)BUILD_AP_BOOT_ADDR = new;
+
+ // enable local APIC
+ u32 val = readl(APIC_SVR);
+ writel(APIC_SVR, val | APIC_ENABLED);
+
+ if (! CONFIG_COREBOOT) {
+ /* Set LINT0 as Ext_INT, level triggered */
+ writel(APIC_LINT0, 0x8700);
+
+ /* Set LINT1 as NMI, level triggered */
+ writel(APIC_LINT1, 0x8400);
+ }
+
+ // broadcast SIPI
+ barrier();
+ writel(APIC_ICR_LOW, 0x000C4500);
+ u32 sipi_vector = BUILD_AP_BOOT_ADDR >> 12;
+ writel(APIC_ICR_LOW, 0x000C4600 | sipi_vector);
+
+ // Wait for other CPUs to process the SIPI.
+ if (CONFIG_COREBOOT) {
+ msleep(10);
+ } else {
+ u8 cmos_smp_count = inb_cmos(CMOS_BIOS_SMP_COUNT);
+ while (cmos_smp_count + 1 != readl(&CountCPUs))
+ yield();
+ }
+
+ // Restore memory.
+ *(u64*)BUILD_AP_BOOT_ADDR = old;
+
+ MaxCountCPUs = qemu_cfg_get_max_cpus();
+ if (!MaxCountCPUs || MaxCountCPUs < CountCPUs)
+ MaxCountCPUs = CountCPUs;
+
+ dprintf(1, "Found %d cpu(s) max supported %d cpu(s)\n", readl(&CountCPUs),
+ MaxCountCPUs);
+}
--- /dev/null
+/* This file is the basis for the ssdt_proc[] variable in src/acpi.c.
+ * It defines the contents of the per-cpu Processor() object. At
+ * runtime, a dynamically generated SSDT will contain one copy of this
+ * AML snippet for every possible cpu in the system. The objects will
+ * be placed in the \_SB_ namespace.
+ *
+ * To generate a new ssdt_proc[], run the commands:
+ * cpp -P src/ssdt-proc.dsl > out/ssdt-proc.dsl.i
+ * iasl -ta -p out/ssdt-proc out/ssdt-proc.dsl.i
+ * tail -c +37 < out/ssdt-proc.aml | hexdump -e '" " 8/1 "0x%02x," "\n"'
+ * and then cut-and-paste the output into the src/acpi.c ssdt_proc[]
+ * array.
+ *
+ * In addition to the aml code generated from this file, the
+ * src/acpi.c file creates a NTFY method with an entry for each cpu:
+ * Method(NTFY, 2) {
+ * If (LEqual(Arg0, 0x00)) { Notify(CP00, Arg1) }
+ * If (LEqual(Arg0, 0x01)) { Notify(CP01, Arg1) }
+ * ...
+ * }
+ * and a CPON array with the list of active and inactive cpus:
+ * Name(CPON, Package() { One, One, ..., Zero, Zero, ... })
+ */
+DefinitionBlock ("ssdt-proc.aml", "SSDT", 0x01, "BXPC", "BXSSDT", 0x1)
+/* v------------------ DO NOT EDIT ------------------v */
+{
+ Processor (CPAA, 0xAA, 0x0000b010, 0x06) {
+ Name (ID, 0xAA)
+/* ^------------------ DO NOT EDIT ------------------^
+ *
+ * The src/acpi.c code requires the above layout so that it can update
+ * CPAA and 0xAA with the appropriate CPU id (see
+ * SD_OFFSET_CPUHEX/CPUID1/CPUID2). Don't change the above without
+ * also updating the C code.
+ */
+ Name (_HID, "ACPI0007")
+ External(CPMA, MethodObj)
+ External(CPST, MethodObj)
+ External(CPEJ, MethodObj)
+ Method(_MAT, 0) {
+ Return(CPMA(ID))
+ }
+ Method (_STA, 0) {
+ Return(CPST(ID))
+ }
+ Method (_EJ0, 1, NotSerialized) {
+ CPEJ(ID, Arg0)
+ }
+ }
+}
--- /dev/null
+// Code for manipulating stack locations.
+//
+// Copyright (C) 2009-2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // get_ebda_seg
+#include "util.h" // dprintf
+#include "bregs.h" // CR0_PE
+
+// Thread info - stored at bottom of each thread stack - don't change
+// without also updating the inline assembler below.
+struct thread_info {
+ struct thread_info *next;
+ void *stackpos;
+ struct thread_info **pprev;
+};
+struct thread_info VAR32FLATVISIBLE MainThread = {
+ &MainThread, NULL, &MainThread.next
+};
+
+
+/****************************************************************
+ * Low level helpers
+ ****************************************************************/
+
+static inline void sgdt(struct descloc_s *desc) {
+ asm("sgdtl %0" : "=m"(*desc));
+}
+static inline void lgdt(struct descloc_s *desc) {
+ asm("lgdtl %0" : : "m"(*desc) : "memory");
+}
+
+// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function.
+u32 VISIBLE16
+call32(void *func, u32 eax, u32 errret)
+{
+ ASSERT16();
+ u32 cr0 = getcr0();
+ if (cr0 & CR0_PE)
+ // Called in 16bit protected mode?!
+ return errret;
+
+ // Backup cmos index register and disable nmi
+ u8 cmosindex = inb(PORT_CMOS_INDEX);
+ outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX);
+ inb(PORT_CMOS_DATA);
+
+ // Backup fs/gs and gdt
+ u16 fs = GET_SEG(FS), gs = GET_SEG(GS);
+ struct descloc_s gdt;
+ sgdt(&gdt);
+
+ u32 bkup_ss, bkup_esp;
+ asm volatile(
+ // Backup ss/esp / set esp to flat stack location
+ " movl %%ss, %0\n"
+ " movl %%esp, %1\n"
+ " shll $4, %0\n"
+ " addl %0, %%esp\n"
+ " shrl $4, %0\n"
+
+ // Transition to 32bit mode, call func, return to 16bit
+ " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n"
+ " jmp transition32\n"
+ " .code32\n"
+ "1:calll *%3\n"
+ " movl $2f, %%edx\n"
+ " jmp transition16big\n"
+
+ // Restore ds/ss/esp
+ " .code16gcc\n"
+ "2:movl %0, %%ds\n"
+ " movl %0, %%ss\n"
+ " movl %1, %%esp\n"
+ : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax)
+ : "r" (func)
+ : "ecx", "edx", "cc", "memory");
+
+ // Restore gdt and fs/gs
+ lgdt(&gdt);
+ SET_SEG(FS, fs);
+ SET_SEG(GS, gs);
+
+ // Restore cmos index register
+ outb(cmosindex, PORT_CMOS_INDEX);
+ inb(PORT_CMOS_DATA);
+ return eax;
+}
+
+// 16bit trampoline for enabling irqs from 32bit mode.
+ASM16(
+ " .global trampoline_checkirqs\n"
+ "trampoline_checkirqs:\n"
+ " rep ; nop\n"
+ " lretw"
+ );
+
+static void
+check_irqs(void)
+{
+ if (MODESEGMENT) {
+ asm volatile(
+ "sti\n"
+ "nop\n"
+ "rep ; nop\n"
+ "cli\n"
+ "cld\n"
+ : : :"memory");
+ return;
+ }
+ extern void trampoline_checkirqs();
+ struct bregs br;
+ br.flags = F_IF;
+ br.code.seg = SEG_BIOS;
+ br.code.offset = (u32)&trampoline_checkirqs;
+ call16big(&br);
+}
+
+// 16bit trampoline for waiting for an irq from 32bit mode.
+ASM16(
+ " .global trampoline_waitirq\n"
+ "trampoline_waitirq:\n"
+ " sti\n"
+ " hlt\n"
+ " lretw"
+ );
+
+// Wait for next irq to occur.
+void
+wait_irq(void)
+{
+ if (MODESEGMENT) {
+ asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+ return;
+ }
+ if (CONFIG_THREADS && MainThread.next != &MainThread) {
+ // Threads still active - do a yield instead.
+ yield();
+ return;
+ }
+ extern void trampoline_waitirq();
+ struct bregs br;
+ br.flags = 0;
+ br.code.seg = SEG_BIOS;
+ br.code.offset = (u32)&trampoline_waitirq;
+ call16big(&br);
+}
+
+
+/****************************************************************
+ * Stack in EBDA
+ ****************************************************************/
+
+// Switch to the extra stack in ebda and call a function.
+inline u32
+stack_hop(u32 eax, u32 edx, void *func)
+{
+ ASSERT16();
+ u16 ebda_seg = get_ebda_seg(), bkup_ss;
+ u32 bkup_esp;
+ asm volatile(
+ // Backup current %ss/%esp values.
+ "movw %%ss, %w3\n"
+ "movl %%esp, %4\n"
+ // Copy ebda seg to %ds/%ss and set %esp
+ "movw %w6, %%ds\n"
+ "movw %w6, %%ss\n"
+ "movl %5, %%esp\n"
+ // Call func
+ "calll *%2\n"
+ // Restore segments and stack
+ "movw %w3, %%ds\n"
+ "movw %w3, %%ss\n"
+ "movl %4, %%esp"
+ : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp)
+ : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg)
+ : "cc", "memory");
+ return eax;
+}
+
+
+/****************************************************************
+ * Threads
+ ****************************************************************/
+
+#define THREADSTACKSIZE 4096
+int VAR16VISIBLE CanPreempt;
+
+// Return the 'struct thread_info' for the currently running thread.
+struct thread_info *
+getCurThread(void)
+{
+ u32 esp = getesp();
+ if (esp <= BUILD_STACK_ADDR)
+ return &MainThread;
+ return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE);
+}
+
+// Switch to next thread stack.
+static void
+switch_next(struct thread_info *cur)
+{
+ struct thread_info *next = cur->next;
+ if (cur == next)
+ // Nothing to do.
+ return;
+ asm volatile(
+ " pushl $1f\n" // store return pc
+ " pushl %%ebp\n" // backup %ebp
+ " movl %%esp, 4(%%eax)\n" // cur->stackpos = %esp
+ " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos
+ " popl %%ebp\n" // restore %ebp
+ " retl\n" // restore pc
+ "1:\n"
+ : "+a"(cur), "+c"(next)
+ :
+ : "ebx", "edx", "esi", "edi", "cc", "memory");
+}
+
+// Briefly permit irqs to occur.
+void
+yield(void)
+{
+ if (MODESEGMENT || !CONFIG_THREADS) {
+ // Just directly check irqs.
+ check_irqs();
+ return;
+ }
+ struct thread_info *cur = getCurThread();
+ if (cur == &MainThread)
+ // Permit irqs to fire
+ check_irqs();
+
+ // Switch to the next thread
+ switch_next(cur);
+}
+
+// Last thing called from a thread (called on "next" stack).
+static void
+__end_thread(struct thread_info *old)
+{
+ old->next->pprev = old->pprev;
+ *old->pprev = old->next;
+ free(old);
+ dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old);
+ if (MainThread.next == &MainThread)
+ dprintf(1, "All threads complete.\n");
+}
+
+// Create a new thread and start executing 'func' in it.
+void
+run_thread(void (*func)(void*), void *data)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_THREADS)
+ goto fail;
+ struct thread_info *thread;
+ thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE);
+ if (!thread)
+ goto fail;
+
+ thread->stackpos = (void*)thread + THREADSTACKSIZE;
+ struct thread_info *cur = getCurThread();
+ thread->next = cur;
+ thread->pprev = cur->pprev;
+ cur->pprev = &thread->next;
+ *thread->pprev = thread;
+
+ dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread);
+ asm volatile(
+ // Start thread
+ " pushl $1f\n" // store return pc
+ " pushl %%ebp\n" // backup %ebp
+ " movl %%esp, 4(%%edx)\n" // cur->stackpos = %esp
+ " movl 4(%%ebx), %%esp\n" // %esp = thread->stackpos
+ " calll *%%ecx\n" // Call func
+
+ // End thread
+ " movl (%%ebx), %%ecx\n" // %ecx = thread->next
+ " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos
+ " movl %%ebx, %%eax\n"
+ " calll %4\n" // call __end_thread(thread)
+ " popl %%ebp\n" // restore %ebp
+ " retl\n" // restore pc
+ "1:\n"
+ : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur)
+ : "m"(*(u8*)__end_thread)
+ : "esi", "edi", "cc", "memory");
+ return;
+
+fail:
+ func(data);
+}
+
+// Wait for all threads (other than the main thread) to complete.
+void
+wait_threads(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_THREADS)
+ return;
+ while (MainThread.next != &MainThread)
+ yield();
+}
+
+void
+mutex_lock(struct mutex_s *mutex)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_THREADS)
+ return;
+ while (mutex->isLocked)
+ yield();
+ mutex->isLocked = 1;
+}
+
+void
+mutex_unlock(struct mutex_s *mutex)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_THREADS)
+ return;
+ mutex->isLocked = 0;
+}
+
+
+/****************************************************************
+ * Thread preemption
+ ****************************************************************/
+
+static u32 PreemptCount;
+
+// Turn on RTC irqs and arrange for them to check the 32bit threads.
+void
+start_preempt(void)
+{
+ if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS)
+ return;
+ CanPreempt = 1;
+ PreemptCount = 0;
+ useRTC();
+}
+
+// Turn off RTC irqs / stop checking for thread execution.
+void
+finish_preempt(void)
+{
+ if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS) {
+ yield();
+ return;
+ }
+ CanPreempt = 0;
+ releaseRTC();
+ dprintf(9, "Done preempt - %d checks\n", PreemptCount);
+ yield();
+}
+
+// Check if preemption is on, and wait for it to complete if so.
+int
+wait_preempt(void)
+{
+ if (MODESEGMENT || !CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS
+ || !CanPreempt)
+ return 0;
+ while (CanPreempt)
+ yield();
+ return 1;
+}
+
+// Try to execute 32bit threads.
+void VISIBLE32INIT
+yield_preempt(void)
+{
+ PreemptCount++;
+ switch_next(&MainThread);
+}
+
+// 16bit code that checks if threads are pending and executes them if so.
+void
+check_preempt(void)
+{
+ if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS
+ || !GET_GLOBAL(CanPreempt)
+ || GET_FLATPTR(MainThread.next) == &MainThread)
+ return;
+
+ extern void _cfunc32flat_yield_preempt(void);
+ call32(_cfunc32flat_yield_preempt, 0, 0);
+}
--- /dev/null
+// Handler for int 0x15 "system" calls
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2002 MandrakeSoft S.A.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // memcpy_far
+#include "biosvar.h" // BIOS_CONFIG_TABLE
+#include "ioport.h" // inb
+#include "memmap.h" // E820_RAM
+#include "pic.h" // eoi_pic2
+#include "bregs.h" // struct bregs
+
+// Use PS2 System Control port A to set A20 enable
+static inline u8
+set_a20(u8 cond)
+{
+ // get current setting first
+ u8 newval, oldval = inb(PORT_A20);
+ if (cond)
+ newval = oldval | A20_ENABLE_BIT;
+ else
+ newval = oldval & ~A20_ENABLE_BIT;
+ outb(newval, PORT_A20);
+
+ return (oldval & A20_ENABLE_BIT) != 0;
+}
+
+static void
+handle_152400(struct bregs *regs)
+{
+ set_a20(0);
+ set_code_success(regs);
+}
+
+static void
+handle_152401(struct bregs *regs)
+{
+ set_a20(1);
+ set_code_success(regs);
+}
+
+static void
+handle_152402(struct bregs *regs)
+{
+ regs->al = (inb(PORT_A20) & A20_ENABLE_BIT) != 0;
+ set_code_success(regs);
+}
+
+static void
+handle_152403(struct bregs *regs)
+{
+ regs->bx = 3;
+ set_code_success(regs);
+}
+
+static void
+handle_1524XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_1524(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_152400(regs); break;
+ case 0x01: handle_152401(regs); break;
+ case 0x02: handle_152402(regs); break;
+ case 0x03: handle_152403(regs); break;
+ default: handle_1524XX(regs); break;
+ }
+}
+
+// removable media eject
+static void
+handle_1552(struct bregs *regs)
+{
+ set_code_success(regs);
+}
+
+static void
+handle_1587(struct bregs *regs)
+{
+ // +++ should probably have descriptor checks
+ // +++ should have exception handlers
+
+ u8 prev_a20_enable = set_a20(1); // enable A20 line
+
+ // 128K max of transfer on 386+ ???
+ // source == destination ???
+
+ // ES:SI points to descriptor table
+ // offset use initially comments
+ // ==============================================
+ // 00..07 Unused zeros Null descriptor
+ // 08..0f GDT zeros filled in by BIOS
+ // 10..17 source ssssssss source of data
+ // 18..1f dest dddddddd destination of data
+ // 20..27 CS zeros filled in by BIOS
+ // 28..2f SS zeros filled in by BIOS
+
+// check for access rights of source & dest here
+
+ // Initialize GDT descriptor
+ u32 si = regs->si;
+ u64 *gdt_far = (void*)si;
+ u16 gdt_seg = regs->es;
+ u32 loc = (u32)MAKE_FLATPTR(gdt_seg, gdt_far);
+ SET_FARVAR(gdt_seg, gdt_far[1], GDT_DATA | GDT_LIMIT((6*sizeof(u64))-1)
+ | GDT_BASE(loc));
+ // Initialize CS descriptor
+ SET_FARVAR(gdt_seg, gdt_far[4], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
+ | GDT_BASE(BUILD_BIOS_ADDR));
+ // Initialize SS descriptor
+ loc = (u32)MAKE_FLATPTR(GET_SEG(SS), 0);
+ SET_FARVAR(gdt_seg, gdt_far[5], GDT_DATA | GDT_LIMIT(0x0ffff)
+ | GDT_BASE(loc));
+
+ u16 count = regs->cx;
+ asm volatile(
+ // Load new descriptor tables
+ " lgdtw %%es:(1<<3)(%%si)\n"
+ " lidtw %%cs:pmode_IDT_info\n"
+
+ // Enable protected mode
+ " movl %%cr0, %%eax\n"
+ " orl $" __stringify(CR0_PE) ", %%eax\n"
+ " movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to protected mode
+ " ljmpw $(4<<3), $1f\n"
+
+ // GDT points to valid descriptor table, now load DS, ES
+ "1:movw $(2<<3), %%ax\n" // 2nd descriptor in table, TI=GDT, RPL=00
+ " movw %%ax, %%ds\n"
+ " movw $(3<<3), %%ax\n" // 3rd descriptor in table, TI=GDT, RPL=00
+ " movw %%ax, %%es\n"
+
+ // move CX words from DS:SI to ES:DI
+ " xorw %%si, %%si\n"
+ " xorw %%di, %%di\n"
+ " rep movsw\n"
+
+ // Restore DS and ES segment limits to 0xffff
+ " movw $(5<<3), %%ax\n" // 5th descriptor in table (SS)
+ " movw %%ax, %%ds\n"
+ " movw %%ax, %%es\n"
+
+ // Disable protected mode
+ " movl %%cr0, %%eax\n"
+ " andl $~" __stringify(CR0_PE) ", %%eax\n"
+ " movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to real mode
+ " ljmpw $" __stringify(SEG_BIOS) ", $2f\n"
+
+ // restore IDT to normal real-mode defaults
+ "2:lidtw %%cs:rmode_IDT_info\n"
+
+ // Restore %ds (from %ss)
+ " movw %%ss, %%ax\n"
+ " movw %%ax, %%ds\n"
+ : "+c"(count), "+S"(si)
+ : : "eax", "di", "cc"); // XXX - also clobbers %es
+
+ set_a20(prev_a20_enable);
+
+ set_code_success(regs);
+}
+
+// Get the amount of extended memory (above 1M)
+static void
+handle_1588(struct bregs *regs)
+{
+ u32 rs = GET_GLOBAL(RamSize);
+
+ // According to Ralf Brown's interrupt the limit should be 15M,
+ // but real machines mostly return max. 63M.
+ if (rs > 64*1024*1024)
+ regs->ax = 63 * 1024;
+ else
+ regs->ax = (rs - 1*1024*1024) / 1024;
+ set_success(regs);
+}
+
+// Switch to protected mode
+static void
+handle_1589(struct bregs *regs)
+{
+ set_a20(1);
+
+ set_pics(regs->bl, regs->bh);
+
+ u64 *gdt_far = (void*)(regs->si + 0);
+ u16 gdt_seg = regs->es;
+ SET_FARVAR(gdt_seg, gdt_far[7], GDT_CODE | GDT_LIMIT(BUILD_BIOS_SIZE-1)
+ | GDT_BASE(BUILD_BIOS_ADDR));
+
+ regs->ds = 3<<3; // 3rd gdt descriptor is %ds
+ regs->es = 4<<3; // 4th gdt descriptor is %es
+ regs->code.seg = 6<<3; // 6th gdt descriptor is %cs
+
+ set_code_success(regs);
+
+ asm volatile(
+ // Load new descriptor tables
+ " lgdtw %%es:(1<<3)(%%si)\n"
+ " lidtw %%es:(2<<3)(%%si)\n"
+
+ // Enable protected mode
+ " movl %%cr0, %%eax\n"
+ " orl $" __stringify(CR0_PE) ", %%eax\n"
+ " movl %%eax, %%cr0\n"
+
+ // far jump to flush CPU queue after transition to protected mode
+ " ljmpw $(7<<3), $1f\n"
+
+ // GDT points to valid descriptor table, now load SS
+ "1:movw $(5<<3), %%ax\n"
+ " movw %%ax, %%ds\n"
+ " movw %%ax, %%ss\n"
+ :
+ : "S"(gdt_far)
+ : "eax", "cc");
+}
+
+// Device busy interrupt. Called by Int 16h when no key available
+static void
+handle_1590(struct bregs *regs)
+{
+}
+
+// Interrupt complete. Called by Int 16h when key becomes available
+static void
+handle_1591(struct bregs *regs)
+{
+}
+
+// keyboard intercept
+static void
+handle_154f(struct bregs *regs)
+{
+ set_invalid_silent(regs);
+}
+
+static void
+handle_15c0(struct bregs *regs)
+{
+ regs->es = SEG_BIOS;
+ regs->bx = (u32)&BIOS_CONFIG_TABLE;
+ set_code_success(regs);
+}
+
+static void
+handle_15c1(struct bregs *regs)
+{
+ regs->es = get_ebda_seg();
+ set_success(regs);
+}
+
+static void
+handle_15e801(struct bregs *regs)
+{
+ // my real system sets ax and bx to 0
+ // this is confirmed by Ralph Brown list
+ // but syslinux v1.48 is known to behave
+ // strangely if ax is set to 0
+ // regs.u.r16.ax = 0;
+ // regs.u.r16.bx = 0;
+
+ u32 rs = GET_GLOBAL(RamSize);
+
+ // Get the amount of extended memory (above 1M)
+ if (rs > 16*1024*1024) {
+ // limit to 15M
+ regs->cx = 15*1024;
+ // Get the amount of extended memory above 16M in 64k blocks
+ regs->dx = (rs - 16*1024*1024) / (64*1024);
+ } else {
+ regs->cx = (rs - 1*1024*1024) / 1024;
+ regs->dx = 0;
+ }
+
+ // Set configured memory equal to extended memory
+ regs->ax = regs->cx;
+ regs->bx = regs->dx;
+
+ set_success(regs);
+}
+
+// Info on e820 map location and size.
+struct e820entry e820_list[CONFIG_MAX_E820] VAR16VISIBLE;
+int e820_count VAR16VISIBLE;
+
+static void
+handle_15e820(struct bregs *regs)
+{
+ int count = GET_GLOBAL(e820_count);
+ if (regs->edx != 0x534D4150 || regs->bx >= count
+ || regs->ecx < sizeof(e820_list[0])) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+
+ memcpy_far(regs->es, (void*)(regs->di+0)
+ , get_global_seg(), &e820_list[regs->bx]
+ , sizeof(e820_list[0]));
+ if (regs->bx == count-1)
+ regs->ebx = 0;
+ else
+ regs->ebx++;
+ regs->eax = 0x534D4150;
+ regs->ecx = sizeof(e820_list[0]);
+ set_success(regs);
+}
+
+static void
+handle_15e8XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+static void
+handle_15e8(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x01: handle_15e801(regs); break;
+ case 0x20: handle_15e820(regs); break;
+ default: handle_15e8XX(regs); break;
+ }
+}
+
+static void
+handle_15XX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+// INT 15h System Services Entry Point
+void VISIBLE16
+handle_15(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_HDL_15);
+ switch (regs->ah) {
+ case 0x24: handle_1524(regs); break;
+ case 0x4f: handle_154f(regs); break;
+ case 0x52: handle_1552(regs); break;
+ case 0x53: handle_1553(regs); break;
+ case 0x5f: handle_155f(regs); break;
+ case 0x83: handle_1583(regs); break;
+ case 0x86: handle_1586(regs); break;
+ case 0x87: handle_1587(regs); break;
+ case 0x88: handle_1588(regs); break;
+ case 0x89: handle_1589(regs); break;
+ case 0x90: handle_1590(regs); break;
+ case 0x91: handle_1591(regs); break;
+ case 0xc0: handle_15c0(regs); break;
+ case 0xc1: handle_15c1(regs); break;
+ case 0xc2: handle_15c2(regs); break;
+ case 0xe8: handle_15e8(regs); break;
+ default: handle_15XX(regs); break;
+ }
+}
--- /dev/null
+// Basic type definitions for X86 cpus.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __TYPES_H
+#define __TYPES_H
+
+typedef unsigned char u8;
+typedef signed char s8;
+typedef unsigned short u16;
+typedef signed short s16;
+typedef unsigned int u32;
+typedef signed int s32;
+typedef unsigned long long u64;
+typedef signed long long s64;
+typedef u32 size_t;
+
+union u64_u32_u {
+ struct { u32 hi, lo; };
+ u64 val;
+};
+
+#ifdef MANUAL_NO_JUMP_TABLE
+# define default case 775324556: asm(""); default
+#endif
+
+#ifdef WHOLE_PROGRAM
+# define __VISIBLE __attribute__((externally_visible))
+#else
+# define __VISIBLE
+#endif
+
+#define UNIQSEC __FILE__ "." __stringify(__LINE__)
+
+#define __noreturn __attribute__((noreturn))
+extern void __force_link_error__only_in_32bit_flat(void) __noreturn;
+extern void __force_link_error__only_in_32bit_segmented(void) __noreturn;
+extern void __force_link_error__only_in_16bit(void) __noreturn;
+
+#define __ASM(code) asm(".section .text.asm." UNIQSEC "\n\t" code)
+
+#if MODE16 == 1
+// Notes a function as externally visible in the 16bit code chunk.
+# define VISIBLE16 __VISIBLE
+// Notes a function as externally visible in the 32bit flat code chunk.
+# define VISIBLE32FLAT __section(".discard.func32flat." UNIQSEC) noinline
+// Notes a 32bit flat function that will only be called during init.
+# define VISIBLE32INIT VISIBLE32FLAT
+// Notes a function as externally visible in the 32bit segmented code chunk.
+# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline
+// Designate a variable as (only) visible to 16bit code.
+# define VAR16 __section(".data16." UNIQSEC)
+// Designate a variable as visible to 16bit, 32bit, and assembler code.
+# define VAR16VISIBLE VAR16 __VISIBLE
+// Designate a variable as externally visible (in addition to all internal code).
+# define VAR16EXPORT __section(".data16.export." UNIQSEC) __VISIBLE
+// Designate a variable at a specific 16bit address
+# define VAR16FIXED(addr) __aligned(1) __VISIBLE __section(".fixedaddr." __stringify(addr))
+// Designate a variable as (only) visible to 32bit segmented code.
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+// Designate a 32bit variable also available in 16bit "big real" mode.
+# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+// Designate top-level assembler as 16bit only.
+# define ASM16(code) __ASM(code)
+// Designate top-level assembler as 32bit flat only.
+# define ASM32FLAT(code)
+// Compile time check for a given mode.
+# define ASSERT16() do { } while (0)
+# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented()
+# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
+#elif MODESEGMENT == 1
+# define VISIBLE16 __section(".discard.func16." UNIQSEC) noinline
+# define VISIBLE32FLAT __section(".discard.func32flat." UNIQSEC) noinline
+# define VISIBLE32INIT VISIBLE32FLAT
+# define VISIBLE32SEG __VISIBLE
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR16VISIBLE VAR16 __VISIBLE __weak
+# define VAR16EXPORT VAR16VISIBLE
+# define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".data32seg." UNIQSEC)
+# define VAR32FLATVISIBLE __section(".discard.var32flat." UNIQSEC) __VISIBLE __weak
+# define ASM16(code)
+# define ASM32FLAT(code)
+# define ASSERT16() __force_link_error__only_in_16bit()
+# define ASSERT32SEG() do { } while (0)
+# define ASSERT32FLAT() __force_link_error__only_in_32bit_flat()
+#else
+# define VISIBLE16 __section(".discard.func16." UNIQSEC) noinline
+# define VISIBLE32FLAT __section(".text.runtime." UNIQSEC) __VISIBLE
+# define VISIBLE32INIT __section(".text.init." UNIQSEC) __VISIBLE
+# define VISIBLE32SEG __section(".discard.func32seg." UNIQSEC) noinline
+# define VAR16 __section(".discard.var16." UNIQSEC)
+# define VAR16VISIBLE VAR16 __VISIBLE __weak
+# define VAR16EXPORT VAR16VISIBLE
+# define VAR16FIXED(addr) VAR16VISIBLE
+# define VAR32SEG __section(".discard.var32seg." UNIQSEC)
+# define VAR32FLATVISIBLE __section(".data.runtime." UNIQSEC) __VISIBLE
+# define ASM16(code)
+# define ASM32FLAT(code) __ASM(code)
+# define ASSERT16() __force_link_error__only_in_16bit()
+# define ASSERT32SEG() __force_link_error__only_in_32bit_segmented()
+# define ASSERT32FLAT() do { } while (0)
+#endif
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define DIV_ROUND_CLOSEST(x, divisor)({ \
+ typeof(divisor) __divisor = divisor; \
+ (((x) + ((__divisor) / 2)) / (__divisor)); \
+ })
+#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
+#define ALIGN_DOWN(x,a) ((x) & ~((typeof(x))(a)-1))
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define NULL ((void*)0)
+
+#define __weak __attribute__((weak))
+#define __section(S) __attribute__((section(S)))
+
+#define PACKED __attribute__((packed))
+#define __aligned(x) __attribute__((aligned(x)))
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#define noinline __attribute__((noinline))
+#define __always_inline inline __attribute__((always_inline))
+#define __malloc __attribute__((__malloc__))
+#define __attribute_const __attribute__((__const__))
+
+#define __stringify_1(x) #x
+#define __stringify(x) __stringify_1(x)
+
+#endif // types.h
--- /dev/null
+// Code for handling EHCI USB controllers.
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outw
+#include "usb-ehci.h" // struct ehci_qh
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+#include "usb-uhci.h" // init_uhci
+#include "usb-ohci.h" // init_ohci
+
+struct usb_ehci_s {
+ struct usb_s usb;
+ struct ehci_caps *caps;
+ struct ehci_regs *regs;
+ struct ehci_qh *async_qh;
+ struct pci_device *companion[8];
+ int checkports;
+ int legacycount;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+#define EHCI_TIME_POSTPOWER 20
+#define EHCI_TIME_POSTRESET 2
+
+// Check if need companion controllers for full/low speed devices
+static void
+ehci_note_port(struct usb_ehci_s *cntl)
+{
+ if (--cntl->checkports)
+ // Ports still being detected.
+ return;
+ if (! cntl->legacycount)
+ // No full/low speed devices found.
+ return;
+ // Start companion controllers.
+ int i;
+ for (i=0; i<ARRAY_SIZE(cntl->companion); i++) {
+ struct pci_device *pci = cntl->companion[i];
+ if (!pci)
+ break;
+
+ // ohci/uhci_init call pci_config_XXX - don't run from irq handler.
+ wait_preempt();
+
+ if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
+ uhci_init(pci, cntl->usb.busid + i);
+ else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
+ ohci_init(pci, cntl->usb.busid + i);
+ }
+}
+
+// Check if device attached to port
+static int
+ehci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+ u32 *portreg = &cntl->regs->portsc[port];
+ u32 portsc = readl(portreg);
+
+ // Power up port.
+ if (!(portsc & PORT_POWER)) {
+ portsc |= PORT_POWER;
+ writel(portreg, portsc);
+ msleep(EHCI_TIME_POSTPOWER);
+ } else {
+ msleep(1); // XXX - time for connect to be detected.
+ }
+ portsc = readl(portreg);
+
+ if (!(portsc & PORT_CONNECT))
+ // No device present
+ goto doneearly;
+
+ if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) {
+ // low speed device
+ cntl->legacycount++;
+ writel(portreg, portsc | PORT_OWNER);
+ goto doneearly;
+ }
+
+ // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
+
+ // Begin reset on port
+ portsc = (portsc & ~PORT_PE) | PORT_RESET;
+ writel(portreg, portsc);
+ msleep(USB_TIME_DRSTR);
+ return 0;
+
+doneearly:
+ ehci_note_port(cntl);
+ return -1;
+}
+
+// Reset device on port
+static int
+ehci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+ u32 *portreg = &cntl->regs->portsc[port];
+ u32 portsc = readl(portreg);
+
+ // Finish reset on port
+ portsc &= ~PORT_RESET;
+ writel(portreg, portsc);
+ msleep(EHCI_TIME_POSTRESET);
+
+ int rv = -1;
+ portsc = readl(portreg);
+ if (!(portsc & PORT_CONNECT))
+ // No longer connected
+ goto resetfail;
+ if (!(portsc & PORT_PE)) {
+ // full speed device
+ cntl->legacycount++;
+ writel(portreg, portsc | PORT_OWNER);
+ goto resetfail;
+ }
+
+ rv = USB_HIGHSPEED;
+resetfail:
+ ehci_note_port(cntl);
+ return rv;
+}
+
+// Disable port
+static void
+ehci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ehci_s *cntl = container_of(hub->cntl, struct usb_ehci_s, usb);
+ u32 *portreg = &cntl->regs->portsc[port];
+ u32 portsc = readl(portreg);
+ writel(portreg, portsc & ~PORT_PE);
+}
+
+static struct usbhub_op_s ehci_HubOp = {
+ .detect = ehci_hub_detect,
+ .reset = ehci_hub_reset,
+ .disconnect = ehci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_ehci_ports(struct usb_ehci_s *cntl)
+{
+ ASSERT32FLAT();
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &cntl->usb;
+ hub.portcount = cntl->checkports;
+ hub.op = &ehci_HubOp;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+configure_ehci(void *data)
+{
+ struct usb_ehci_s *cntl = data;
+
+ // Allocate ram for schedule storage
+ struct ehci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
+ struct ehci_qh *intr_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*intr_qh));
+ struct ehci_qh *async_qh = memalign_high(EHCI_QH_ALIGN, sizeof(*async_qh));
+ if (!fl || !intr_qh || !async_qh) {
+ warn_noalloc();
+ goto fail;
+ }
+
+ // XXX - check for halted?
+
+ // Reset the HC
+ u32 cmd = readl(&cntl->regs->usbcmd);
+ writel(&cntl->regs->usbcmd, (cmd & ~(CMD_ASE | CMD_PSE)) | CMD_HCRESET);
+ u64 end = calc_future_tsc(250);
+ for (;;) {
+ cmd = readl(&cntl->regs->usbcmd);
+ if (!(cmd & CMD_HCRESET))
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ goto fail;
+ }
+ yield();
+ }
+
+ // Disable interrupts (just to be safe).
+ writel(&cntl->regs->usbintr, 0);
+
+ // Set schedule to point to primary intr queue head
+ memset(intr_qh, 0, sizeof(*intr_qh));
+ intr_qh->next = EHCI_PTR_TERM;
+ intr_qh->info2 = (0x01 << QH_SMASK_SHIFT);
+ intr_qh->token = QTD_STS_HALT;
+ intr_qh->qtd_next = intr_qh->alt_next = EHCI_PTR_TERM;
+ int i;
+ for (i=0; i<ARRAY_SIZE(fl->links); i++)
+ fl->links[i] = (u32)intr_qh | EHCI_PTR_QH;
+ writel(&cntl->regs->periodiclistbase, (u32)fl);
+
+ // Set async list to point to primary async queue head
+ memset(async_qh, 0, sizeof(*async_qh));
+ async_qh->next = (u32)async_qh | EHCI_PTR_QH;
+ async_qh->info1 = QH_HEAD;
+ async_qh->token = QTD_STS_HALT;
+ async_qh->qtd_next = async_qh->alt_next = EHCI_PTR_TERM;
+ cntl->async_qh = async_qh;
+ writel(&cntl->regs->asynclistbase, (u32)async_qh);
+
+ // Enable queues
+ writel(&cntl->regs->usbcmd, cmd | CMD_ASE | CMD_PSE | CMD_RUN);
+
+ // Set default of high speed for root hub.
+ writel(&cntl->regs->configflag, 1);
+ cntl->checkports = readl(&cntl->caps->hcsparams) & HCS_N_PORTS_MASK;
+
+ // Find devices
+ int count = check_ehci_ports(cntl);
+ free_pipe(cntl->usb.defaultpipe);
+ if (count)
+ // Success
+ return;
+
+ // No devices found - shutdown and free controller.
+ writel(&cntl->regs->usbcmd, cmd & ~CMD_RUN);
+ msleep(4); // 2ms to stop reading memory - XXX
+fail:
+ free(fl);
+ free(intr_qh);
+ free(async_qh);
+ free(cntl);
+}
+
+int
+ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci)
+{
+ if (! CONFIG_USB_EHCI)
+ return -1;
+
+ u16 bdf = pci->bdf;
+ u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+ struct ehci_caps *caps = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+ u32 hcc_params = readl(&caps->hccparams);
+ if (hcc_params & HCC_64BIT_ADDR) {
+ dprintf(1, "No support for 64bit EHCI\n");
+ return -1;
+ }
+
+ struct usb_ehci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+ if (!cntl) {
+ warn_noalloc();
+ return -1;
+ }
+ memset(cntl, 0, sizeof(*cntl));
+ cntl->usb.busid = busid;
+ cntl->usb.pci = pci;
+ cntl->usb.type = USB_TYPE_EHCI;
+ cntl->caps = caps;
+ cntl->regs = (void*)caps + readb(&caps->caplength);
+
+ dprintf(1, "EHCI init on dev %02x:%02x.%x (regs=%p)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf), cntl->regs);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ // XXX - check for and disable SMM control?
+
+ // Find companion controllers.
+ int count = 0;
+ for (;;) {
+ if (!comppci || comppci == pci)
+ break;
+ if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_UHCI)
+ cntl->companion[count++] = comppci;
+ else if (pci_classprog(comppci) == PCI_CLASS_SERIAL_USB_OHCI)
+ cntl->companion[count++] = comppci;
+ comppci = comppci->next;
+ }
+
+ run_thread(configure_ehci, cntl);
+ return 0;
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+ehci_wait_qh(struct usb_ehci_s *cntl, struct ehci_qh *qh)
+{
+ // XXX - 500ms just a guess
+ u64 end = calc_future_tsc(500);
+ for (;;) {
+ if (qh->qtd_next & EHCI_PTR_TERM)
+ // XXX - confirm
+ return 0;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+// Wait for next USB async frame to start - for ensuring safe memory release.
+static void
+ehci_waittick(struct usb_ehci_s *cntl)
+{
+ if (MODE16) {
+ msleep(10);
+ return;
+ }
+ // Wait for access to "doorbell"
+ barrier();
+ u32 cmd, sts;
+ u64 end = calc_future_tsc(100);
+ for (;;) {
+ sts = readl(&cntl->regs->usbsts);
+ if (!(sts & STS_IAA)) {
+ cmd = readl(&cntl->regs->usbcmd);
+ if (!(cmd & CMD_IAAD))
+ break;
+ }
+ if (check_tsc(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+ // Ring "doorbell"
+ writel(&cntl->regs->usbcmd, cmd | CMD_IAAD);
+ // Wait for completion
+ for (;;) {
+ sts = readl(&cntl->regs->usbsts);
+ if (sts & STS_IAA)
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+ // Ack completion
+ writel(&cntl->regs->usbsts, STS_IAA);
+}
+
+struct ehci_pipe {
+ struct ehci_qh qh;
+ struct ehci_qtd *next_td, *tds;
+ void *data;
+ struct usb_pipe pipe;
+};
+
+void
+ehci_free_pipe(struct usb_pipe *p)
+{
+ if (! CONFIG_USB_EHCI)
+ return;
+ dprintf(7, "ehci_free_pipe %p\n", p);
+ struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+ struct usb_ehci_s *cntl = container_of(
+ pipe->pipe.cntl, struct usb_ehci_s, usb);
+
+ struct ehci_qh *start = cntl->async_qh;
+ struct ehci_qh *pos = start;
+ for (;;) {
+ struct ehci_qh *next = (void*)(pos->next & ~EHCI_PTR_BITS);
+ if (next == start) {
+ // Not found?! Exit without freeing.
+ warn_internalerror();
+ return;
+ }
+ if (next == &pipe->qh) {
+ pos->next = next->next;
+ ehci_waittick(cntl);
+ free(pipe);
+ return;
+ }
+ pos = next;
+ }
+}
+
+struct usb_pipe *
+ehci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+ if (! CONFIG_USB_EHCI)
+ return NULL;
+ struct usb_ehci_s *cntl = container_of(
+ dummy->cntl, struct usb_ehci_s, usb);
+ dprintf(7, "ehci_alloc_control_pipe %p\n", &cntl->usb);
+
+ // Allocate a queue head.
+ struct ehci_pipe *pipe = memalign_tmphigh(EHCI_QH_ALIGN, sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+ pipe->qh.token = QTD_STS_HALT;
+
+ // Add queue head to controller list.
+ struct ehci_qh *async_qh = cntl->async_qh;
+ pipe->qh.next = async_qh->next;
+ barrier();
+ async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+ return &pipe->pipe;
+}
+
+static int
+fillTDbuffer(struct ehci_qtd *td, u16 maxpacket, const void *buf, int bytes)
+{
+ u32 dest = (u32)buf;
+ u32 *pos = td->buf;
+ while (bytes) {
+ if (pos >= &td->buf[ARRAY_SIZE(td->buf)])
+ // More data than can transfer in a single qtd - only use
+ // full packets to prevent a babble error.
+ return ALIGN_DOWN(dest - (u32)buf, maxpacket);
+ u32 count = bytes;
+ u32 max = 0x1000 - (dest & 0xfff);
+ if (count > max)
+ count = max;
+ *pos = dest;
+ bytes -= count;
+ dest += count;
+ pos++;
+ }
+ return dest - (u32)buf;
+}
+
+int
+ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+ , void *data, int datasize)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_USB_EHCI)
+ return -1;
+ dprintf(5, "ehci_control %p\n", p);
+ if (datasize > 4*4096 || cmdsize > 4*4096) {
+ // XXX - should support larger sizes.
+ warn_noalloc();
+ return -1;
+ }
+ struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+ struct usb_ehci_s *cntl = container_of(
+ pipe->pipe.cntl, struct usb_ehci_s, usb);
+
+ u16 maxpacket = pipe->pipe.maxpacket;
+ int speed = pipe->pipe.speed;
+
+ // Setup fields in qh
+ pipe->qh.info1 = (
+ (1 << QH_MULT_SHIFT) | (speed != USB_HIGHSPEED ? QH_CONTROL : 0)
+ | (maxpacket << QH_MAXPACKET_SHIFT)
+ | QH_TOGGLECONTROL
+ | (speed << QH_SPEED_SHIFT)
+ | (pipe->pipe.ep << QH_EP_SHIFT)
+ | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT));
+ pipe->qh.info2 = ((1 << QH_MULT_SHIFT)
+ | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT)
+ | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT));
+
+ // Setup transfer descriptors
+ struct ehci_qtd *tds = memalign_tmphigh(EHCI_QTD_ALIGN, sizeof(*tds) * 3);
+ if (!tds) {
+ warn_noalloc();
+ return -1;
+ }
+ memset(tds, 0, sizeof(*tds) * 3);
+ struct ehci_qtd *td = tds;
+
+ td->qtd_next = (u32)&td[1];
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (ehci_explen(cmdsize) | QTD_STS_ACTIVE
+ | QTD_PID_SETUP | ehci_maxerr(3));
+ fillTDbuffer(td, maxpacket, cmd, cmdsize);
+ td++;
+
+ if (datasize) {
+ td->qtd_next = (u32)&td[1];
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (QTD_TOGGLE | ehci_explen(datasize) | QTD_STS_ACTIVE
+ | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
+ fillTDbuffer(td, maxpacket, data, datasize);
+ td++;
+ }
+
+ td->qtd_next = EHCI_PTR_TERM;
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (QTD_TOGGLE | QTD_STS_ACTIVE
+ | (dir ? QTD_PID_OUT : QTD_PID_IN) | ehci_maxerr(3));
+
+ // Transfer data
+ barrier();
+ pipe->qh.qtd_next = (u32)tds;
+ barrier();
+ pipe->qh.token = 0;
+ int ret = ehci_wait_qh(cntl, &pipe->qh);
+ pipe->qh.token = QTD_STS_HALT;
+ if (ret) {
+ pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+ // XXX - halt qh?
+ ehci_waittick(cntl);
+ }
+ free(tds);
+ return ret;
+}
+
+struct usb_pipe *
+ehci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+ // XXX - this func is same as alloc_control except for malloc_low
+ if (! CONFIG_USB_EHCI)
+ return NULL;
+ struct usb_ehci_s *cntl = container_of(
+ dummy->cntl, struct usb_ehci_s, usb);
+ dprintf(7, "ehci_alloc_bulk_pipe %p\n", &cntl->usb);
+
+ // Allocate a queue head.
+ struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM;
+ pipe->qh.token = QTD_STS_HALT;
+
+ // Add queue head to controller list.
+ struct ehci_qh *async_qh = cntl->async_qh;
+ pipe->qh.next = async_qh->next;
+ barrier();
+ async_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+ return &pipe->pipe;
+}
+
+static int
+ehci_wait_td(struct ehci_qtd *td)
+{
+ u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+ u32 status;
+ for (;;) {
+ status = td->token;
+ if (!(status & QTD_STS_ACTIVE))
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ if (status & QTD_STS_HALT) {
+ dprintf(1, "ehci_wait_td error - status=%x\n", status);
+ return -2;
+ }
+ return 0;
+}
+
+#define STACKQTDS 4
+
+int
+ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
+{
+ if (! CONFIG_USB_EHCI)
+ return -1;
+ struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+ dprintf(7, "ehci_send_bulk qh=%p dir=%d data=%p size=%d\n"
+ , &pipe->qh, dir, data, datasize);
+
+ // Allocate 4 tds on stack (16byte aligned)
+ u8 tdsbuf[sizeof(struct ehci_qtd) * STACKQTDS + EHCI_QTD_ALIGN - 1];
+ struct ehci_qtd *tds = (void*)ALIGN((u32)tdsbuf, EHCI_QTD_ALIGN);
+ memset(tds, 0, sizeof(*tds) * STACKQTDS);
+
+ // Setup fields in qh
+ u16 maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+ SET_FLATPTR(pipe->qh.info1
+ , ((1 << QH_MULT_SHIFT)
+ | (maxpacket << QH_MAXPACKET_SHIFT)
+ | (GET_FLATPTR(pipe->pipe.speed) << QH_SPEED_SHIFT)
+ | (GET_FLATPTR(pipe->pipe.ep) << QH_EP_SHIFT)
+ | (GET_FLATPTR(pipe->pipe.devaddr) << QH_DEVADDR_SHIFT)));
+ SET_FLATPTR(pipe->qh.info2
+ , ((1 << QH_MULT_SHIFT)
+ | (GET_FLATPTR(pipe->pipe.tt_port) << QH_HUBPORT_SHIFT)
+ | (GET_FLATPTR(pipe->pipe.tt_devaddr) << QH_HUBADDR_SHIFT)));
+ barrier();
+ SET_FLATPTR(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+ barrier();
+ SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE);
+
+ int tdpos = 0;
+ while (datasize) {
+ struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+ int ret = ehci_wait_td(td);
+ if (ret)
+ goto fail;
+
+ struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
+ , &tds[tdpos % STACKQTDS]);
+
+ int transfer = fillTDbuffer(td, maxpacket, data, datasize);
+ td->qtd_next = (transfer==datasize ? EHCI_PTR_TERM : (u32)nexttd_fl);
+ td->alt_next = EHCI_PTR_TERM;
+ barrier();
+ td->token = (ehci_explen(transfer) | QTD_STS_ACTIVE
+ | (dir ? QTD_PID_IN : QTD_PID_OUT) | ehci_maxerr(3));
+
+ data += transfer;
+ datasize -= transfer;
+ }
+ int i;
+ for (i=0; i<STACKQTDS; i++) {
+ struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS];
+ int ret = ehci_wait_td(td);
+ if (ret)
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dprintf(1, "ehci_send_bulk failed\n");
+ SET_FLATPTR(pipe->qh.qtd_next, EHCI_PTR_TERM);
+ SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM);
+ // XXX - halt qh?
+ struct usb_ehci_s *cntl = container_of(
+ GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb);
+ ehci_waittick(cntl);
+ return -1;
+}
+
+struct usb_pipe *
+ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+ if (! CONFIG_USB_EHCI)
+ return NULL;
+ struct usb_ehci_s *cntl = container_of(
+ dummy->cntl, struct usb_ehci_s, usb);
+ dprintf(7, "ehci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+ if (frameexp > 10)
+ frameexp = 10;
+ int maxpacket = dummy->maxpacket;
+ // Determine number of entries needed for 2 timer ticks.
+ int ms = 1<<frameexp;
+ int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
+ struct ehci_pipe *pipe = memalign_low(EHCI_QH_ALIGN, sizeof(*pipe));
+ struct ehci_qtd *tds = memalign_low(EHCI_QTD_ALIGN, sizeof(*tds) * count);
+ void *data = malloc_low(maxpacket * count);
+ if (!pipe || !tds || !data) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->next_td = pipe->tds = tds;
+ pipe->data = data;
+
+ pipe->qh.info1 = (
+ (1 << QH_MULT_SHIFT)
+ | (maxpacket << QH_MAXPACKET_SHIFT)
+ | (pipe->pipe.speed << QH_SPEED_SHIFT)
+ | (pipe->pipe.ep << QH_EP_SHIFT)
+ | (pipe->pipe.devaddr << QH_DEVADDR_SHIFT));
+ pipe->qh.info2 = ((1 << QH_MULT_SHIFT)
+ | (pipe->pipe.tt_port << QH_HUBPORT_SHIFT)
+ | (pipe->pipe.tt_devaddr << QH_HUBADDR_SHIFT)
+ | (0x01 << QH_SMASK_SHIFT)
+ | (0x1c << QH_CMASK_SHIFT));
+ pipe->qh.qtd_next = (u32)tds;
+
+ int i;
+ for (i=0; i<count; i++) {
+ struct ehci_qtd *td = &tds[i];
+ td->qtd_next = (i==count-1 ? (u32)tds : (u32)&td[1]);
+ td->alt_next = EHCI_PTR_TERM;
+ td->token = (ehci_explen(maxpacket) | QTD_STS_ACTIVE
+ | QTD_PID_IN | ehci_maxerr(3));
+ td->buf[0] = (u32)data + maxpacket * i;
+ }
+
+ // Add to interrupt schedule.
+ struct ehci_framelist *fl = (void*)readl(&cntl->regs->periodiclistbase);
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct ehci_qh *intr_qh = (void*)(fl->links[0] & ~EHCI_PTR_BITS);
+ pipe->qh.next = intr_qh->next;
+ barrier();
+ intr_qh->next = (u32)&pipe->qh | EHCI_PTR_QH;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ pipe->qh.next = fl->links[startpos];
+ barrier();
+ for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+ fl->links[i] = (u32)&pipe->qh | EHCI_PTR_QH;
+ }
+
+ return &pipe->pipe;
+fail:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
+}
+
+int
+ehci_poll_intr(struct usb_pipe *p, void *data)
+{
+ ASSERT16();
+ if (! CONFIG_USB_EHCI)
+ return -1;
+ struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe);
+ struct ehci_qtd *td = GET_FLATPTR(pipe->next_td);
+ u32 token = GET_FLATPTR(td->token);
+ if (token & QTD_STS_ACTIVE)
+ // No intrs found.
+ return -1;
+ // XXX - check for errors.
+
+ // Copy data.
+ int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+ int pos = td - GET_FLATPTR(pipe->tds);
+ void *tddata = GET_FLATPTR(pipe->data) + maxpacket * pos;
+ memcpy_far(GET_SEG(SS), data
+ , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata)
+ , maxpacket);
+
+ // Reenable this td.
+ struct ehci_qtd *next = (void*)(GET_FLATPTR(td->qtd_next) & ~EHCI_PTR_BITS);
+ SET_FLATPTR(pipe->next_td, next);
+ SET_FLATPTR(td->buf[0], (u32)tddata);
+ barrier();
+ SET_FLATPTR(td->token, (ehci_explen(maxpacket) | QTD_STS_ACTIVE
+ | QTD_PID_IN | ehci_maxerr(3)));
+
+ return 0;
+}
--- /dev/null
+#ifndef __USB_EHCI_H
+#define __USB_EHCI_H
+
+// usb-ehci.c
+int ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci);
+struct usb_pipe;
+void ehci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ehci_alloc_control_pipe(struct usb_pipe *dummy);
+int ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+ , void *data, int datasize);
+struct usb_pipe *ehci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *ehci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+int ehci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * ehci structs and flags
+ ****************************************************************/
+
+struct ehci_caps {
+ u8 caplength;
+ u8 reserved_01;
+ u16 hciversion;
+ u32 hcsparams;
+ u32 hccparams;
+ u64 portroute;
+} PACKED;
+
+#define HCC_64BIT_ADDR 1
+
+#define HCS_N_PORTS_MASK 0xf
+
+struct ehci_regs {
+ u32 usbcmd;
+ u32 usbsts;
+ u32 usbintr;
+ u32 frindex;
+ u32 ctrldssegment;
+ u32 periodiclistbase;
+ u32 asynclistbase;
+ u32 reserved[9];
+ u32 configflag;
+ u32 portsc[0];
+} PACKED;
+
+#define CMD_PARK (1<<11)
+#define CMD_PARK_CNT(c) (((c)>>8)&3)
+#define CMD_LRESET (1<<7)
+#define CMD_IAAD (1<<6)
+#define CMD_ASE (1<<5)
+#define CMD_PSE (1<<4)
+#define CMD_HCRESET (1<<1)
+#define CMD_RUN (1<<0)
+
+#define STS_ASS (1<<15)
+#define STS_PSS (1<<14)
+#define STS_RECL (1<<13)
+#define STS_HALT (1<<12)
+#define STS_IAA (1<<5)
+#define STS_FATAL (1<<4)
+#define STS_FLR (1<<3)
+#define STS_PCD (1<<2)
+#define STS_ERR (1<<1)
+#define STS_INT (1<<0)
+
+#define FLAG_CF (1<<0)
+
+#define PORT_WKOC_E (1<<22)
+#define PORT_WKDISC_E (1<<21)
+#define PORT_WKCONN_E (1<<20)
+#define PORT_TEST_PKT (0x4<<16)
+#define PORT_LED_OFF (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK (3<<14)
+#define PORT_OWNER (1<<13)
+#define PORT_POWER (1<<12)
+#define PORT_LINESTATUS_MASK (3<<10)
+#define PORT_LINESTATUS_KSTATE (1<<10)
+#define PORT_RESET (1<<8)
+#define PORT_SUSPEND (1<<7)
+#define PORT_RESUME (1<<6)
+#define PORT_OCC (1<<5)
+#define PORT_OC (1<<4)
+#define PORT_PEC (1<<3)
+#define PORT_PE (1<<2)
+#define PORT_CSC (1<<1)
+#define PORT_CONNECT (1<<0)
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
+
+
+#define EHCI_QH_ALIGN 64 // Can't span a 4K boundary, so increase to 64
+
+struct ehci_qh {
+ u32 next;
+ u32 info1;
+ u32 info2;
+ u32 current;
+
+ u32 qtd_next;
+ u32 alt_next;
+ u32 token;
+ u32 buf[5];
+ // u32 buf_hi[5];
+} PACKED;
+
+#define QH_CONTROL (1 << 27)
+#define QH_MAXPACKET_SHIFT 16
+#define QH_MAXPACKET_MASK (0x7ff << QH_MAXPACKET_SHIFT)
+#define QH_HEAD (1 << 15)
+#define QH_TOGGLECONTROL (1 << 14)
+#define QH_SPEED_SHIFT 12
+#define QH_SPEED_MASK (0x3 << QH_SPEED_SHIFT)
+#define QH_EP_SHIFT 8
+#define QH_EP_MASK (0xf << QH_EP_SHIFT)
+#define QH_DEVADDR_SHIFT 0
+#define QH_DEVADDR_MASK (0x7f << QH_DEVADDR_SHIFT)
+
+#define QH_SMASK_SHIFT 0
+#define QH_SMASK_MASK (0xff << QH_SMASK_SHIFT)
+#define QH_CMASK_SHIFT 8
+#define QH_CMASK_MASK (0xff << QH_CMASK_SHIFT)
+#define QH_HUBADDR_SHIFT 16
+#define QH_HUBADDR_MASK (0x7f << QH_HUBADDR_SHIFT)
+#define QH_HUBPORT_SHIFT 23
+#define QH_HUBPORT_MASK (0x7f << QH_HUBPORT_SHIFT)
+#define QH_MULT_SHIFT 30
+#define QH_MULT_MASK (0x3 << QH_MULT_SHIFT)
+
+#define EHCI_PTR_BITS 0x001F
+#define EHCI_PTR_TERM 0x0001
+#define EHCI_PTR_QH 0x0002
+
+
+#define EHCI_QTD_ALIGN 32
+
+struct ehci_qtd {
+ u32 qtd_next;
+ u32 alt_next;
+ u32 token;
+ u32 buf[5];
+ //u32 buf_hi[5];
+} PACKED;
+
+#define QTD_TOGGLE (1 << 31)
+#define QTD_LENGTH_SHIFT 16
+#define QTD_LENGTH_MASK (0x7fff << QTD_LENGTH_SHIFT)
+#define QTD_CERR_SHIFT 10
+#define QTD_CERR_MASK (0x3 << QTD_CERR_SHIFT)
+#define QTD_IOC (1 << 15)
+#define QTD_PID_OUT (0x0 << 8)
+#define QTD_PID_IN (0x1 << 8)
+#define QTD_PID_SETUP (0x2 << 8)
+#define QTD_STS_ACTIVE (1 << 7)
+#define QTD_STS_HALT (1 << 6)
+#define QTD_STS_DBE (1 << 5)
+#define QTD_STS_BABBLE (1 << 4)
+#define QTD_STS_XACT (1 << 3)
+#define QTD_STS_MMF (1 << 2)
+#define QTD_STS_STS (1 << 1)
+#define QTD_STS_PING (1 << 0)
+
+#define ehci_explen(len) (((len) << QTD_LENGTH_SHIFT) & QTD_LENGTH_MASK)
+
+#define ehci_maxerr(err) (((err) << QTD_CERR_SHIFT) & QTD_CERR_MASK)
+
+
+struct ehci_framelist {
+ u32 links[1024];
+} PACKED;
+
+#endif // usb-ehci.h
--- /dev/null
+// Code for handling USB Human Interface Devices (HID).
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "usb-hid.h" // usb_keyboard_setup
+#include "config.h" // CONFIG_*
+#include "usb.h" // usb_ctrlrequest
+#include "biosvar.h" // GET_GLOBAL
+#include "ps2port.h" // ATKBD_CMD_GETID
+
+struct usb_pipe *keyboard_pipe VAR16VISIBLE;
+struct usb_pipe *mouse_pipe VAR16VISIBLE;
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+// Send USB HID protocol message.
+static int
+set_protocol(struct usb_pipe *pipe, u16 val)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ req.bRequest = HID_REQ_SET_PROTOCOL;
+ req.wValue = val;
+ req.wIndex = 0;
+ req.wLength = 0;
+ return send_default_control(pipe, &req, NULL);
+}
+
+// Send USB HID SetIdle request.
+static int
+set_idle(struct usb_pipe *pipe, int ms)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ req.bRequest = HID_REQ_SET_IDLE;
+ req.wValue = (ms/4)<<8;
+ req.wIndex = 0;
+ req.wLength = 0;
+ return send_default_control(pipe, &req, NULL);
+}
+
+#define KEYREPEATWAITMS 500
+#define KEYREPEATMS 33
+
+static int
+usb_kbd_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return -1;
+ if (keyboard_pipe)
+ // XXX - this enables the first found keyboard (could be random)
+ return -1;
+
+ if (epdesc->wMaxPacketSize != 8)
+ return -1;
+
+ // Enable "boot" protocol.
+ int ret = set_protocol(pipe, 0);
+ if (ret)
+ return -1;
+ // Periodically send reports to enable key repeat.
+ ret = set_idle(pipe, KEYREPEATMS);
+ if (ret)
+ return -1;
+
+ keyboard_pipe = alloc_intr_pipe(pipe, epdesc);
+ if (!keyboard_pipe)
+ return -1;
+
+ dprintf(1, "USB keyboard initialized\n");
+ return 0;
+}
+
+static int
+usb_mouse_init(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+ if (! CONFIG_USB_MOUSE)
+ return -1;
+ if (mouse_pipe)
+ // XXX - this enables the first found mouse (could be random)
+ return -1;
+
+ if (epdesc->wMaxPacketSize < 3 || epdesc->wMaxPacketSize > 8)
+ return -1;
+
+ // Enable "boot" protocol.
+ int ret = set_protocol(pipe, 0);
+ if (ret)
+ return -1;
+
+ mouse_pipe = alloc_intr_pipe(pipe, epdesc);
+ if (!mouse_pipe)
+ return -1;
+
+ dprintf(1, "USB mouse initialized\n");
+ return 0;
+}
+
+// Initialize a found USB HID device (if applicable).
+int
+usb_hid_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax)
+{
+ if (! CONFIG_USB_KEYBOARD || ! CONFIG_USB_MOUSE)
+ return -1;
+ dprintf(2, "usb_hid_init %p\n", pipe);
+
+ if (iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT)
+ // Doesn't support boot protocol.
+ return -1;
+
+ // Find intr in endpoint.
+ struct usb_endpoint_descriptor *epdesc = findEndPointDesc(
+ iface, imax, USB_ENDPOINT_XFER_INT, USB_DIR_IN);
+ if (!epdesc) {
+ dprintf(1, "No usb hid intr in?\n");
+ return -1;
+ }
+
+ if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD)
+ return usb_kbd_init(pipe, epdesc);
+ if (iface->bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+ return usb_mouse_init(pipe, epdesc);
+ return -1;
+}
+
+
+/****************************************************************
+ * Keyboard events
+ ****************************************************************/
+
+// Mapping from USB key id to ps2 key sequence.
+static u16 KeyToScanCode[] VAR16 = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020,
+ 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026,
+ 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014,
+ 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003,
+ 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b,
+ 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a,
+ 0x001b, 0x002b, 0x0000, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034,
+ 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xe037, 0x0046,
+ 0xe11d, 0xe052, 0xe047, 0xe049, 0xe053, 0xe04f, 0xe051, 0xe04d,
+ 0xe04b, 0xe050, 0xe048, 0x0045, 0xe035, 0x0037, 0x004a, 0x004e,
+ 0xe01c, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047,
+ 0x0048, 0x0049, 0x0052, 0x0053
+};
+
+// Mapping from USB modifier id to ps2 key sequence.
+static u16 ModifierToScanCode[] VAR16 = {
+ //lcntl, lshift, lalt, lgui, rcntl, rshift, ralt, rgui
+ 0x001d, 0x002a, 0x0038, 0xe05b, 0xe01d, 0x0036, 0xe038, 0xe05c
+};
+
+#define RELEASEBIT 0x80
+
+// Format of USB keyboard event data
+struct keyevent {
+ u8 modifiers;
+ u8 reserved;
+ u8 keys[6];
+};
+
+// Translate data from KeyToScanCode[] to calls to process_key().
+static void
+prockeys(u16 keys)
+{
+ if (keys > 0xff) {
+ u8 key = keys>>8;
+ if (key == 0xe1) {
+ // Pause key
+ process_key(0xe1);
+ process_key(0x1d | (keys & RELEASEBIT));
+ process_key(0x45 | (keys & RELEASEBIT));
+ return;
+ }
+ process_key(key);
+ }
+ process_key(keys);
+}
+
+// Handle a USB key press/release event.
+static void
+procscankey(u8 key, u8 flags)
+{
+ if (key >= ARRAY_SIZE(KeyToScanCode))
+ return;
+ u16 keys = GET_GLOBAL(KeyToScanCode[key]);
+ if (keys)
+ prockeys(keys | flags);
+}
+
+// Handle a USB modifier press/release event.
+static void
+procmodkey(u8 mods, u8 flags)
+{
+ int i;
+ for (i=0; mods; i++)
+ if (mods & (1<<i)) {
+ // Modifier key change.
+ prockeys(GET_GLOBAL(ModifierToScanCode[i]) | flags);
+ mods &= ~(1<<i);
+ }
+}
+
+// Process USB keyboard data.
+static void noinline
+handle_key(struct keyevent *data)
+{
+ dprintf(9, "Got key %x %x\n", data->modifiers, data->keys[0]);
+
+ // Load old keys.
+ u16 ebda_seg = get_ebda_seg();
+ struct usbkeyinfo old;
+ old.data = GET_EBDA2(ebda_seg, usbkey_last.data);
+
+ // Check for keys no longer pressed.
+ int addpos = 0;
+ int i;
+ for (i=0; i<ARRAY_SIZE(old.keys); i++) {
+ u8 key = old.keys[i];
+ if (!key)
+ break;
+ int j;
+ for (j=0;; j++) {
+ if (j>=ARRAY_SIZE(data->keys)) {
+ // Key released.
+ procscankey(key, RELEASEBIT);
+ if (i+1 >= ARRAY_SIZE(old.keys) || !old.keys[i+1])
+ // Last pressed key released - disable repeat.
+ old.repeatcount = 0xff;
+ break;
+ }
+ if (data->keys[j] == key) {
+ // Key still pressed.
+ data->keys[j] = 0;
+ old.keys[addpos++] = key;
+ break;
+ }
+ }
+ }
+ procmodkey(old.modifiers & ~data->modifiers, RELEASEBIT);
+
+ // Process new keys
+ procmodkey(data->modifiers & ~old.modifiers, 0);
+ old.modifiers = data->modifiers;
+ for (i=0; i<ARRAY_SIZE(data->keys); i++) {
+ u8 key = data->keys[i];
+ if (!key)
+ continue;
+ // New key pressed.
+ procscankey(key, 0);
+ old.keys[addpos++] = key;
+ old.repeatcount = KEYREPEATWAITMS / KEYREPEATMS + 1;
+ }
+ if (addpos < ARRAY_SIZE(old.keys))
+ old.keys[addpos] = 0;
+
+ // Check for key repeat event.
+ if (addpos) {
+ if (!old.repeatcount)
+ procscankey(old.keys[addpos-1], 0);
+ else if (old.repeatcount != 0xff)
+ old.repeatcount--;
+ }
+
+ // Update old keys
+ SET_EBDA2(ebda_seg, usbkey_last.data, old.data);
+}
+
+// Check if a USB keyboard event is pending and process it if so.
+static void
+usb_check_key(void)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return;
+ struct usb_pipe *pipe = GET_GLOBAL(keyboard_pipe);
+ if (!pipe)
+ return;
+
+ for (;;) {
+ struct keyevent data;
+ int ret = usb_poll_intr(pipe, &data);
+ if (ret)
+ break;
+ handle_key(&data);
+ }
+}
+
+// Test if USB keyboard is active.
+inline int
+usb_kbd_active(void)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return 0;
+ return GET_GLOBAL(keyboard_pipe) != NULL;
+}
+
+// Handle a ps2 style keyboard command.
+inline int
+usb_kbd_command(int command, u8 *param)
+{
+ if (! CONFIG_USB_KEYBOARD)
+ return -1;
+ dprintf(9, "usb keyboard cmd=%x\n", command);
+ switch (command) {
+ case ATKBD_CMD_GETID:
+ // Return the id of a standard AT keyboard.
+ param[0] = 0xab;
+ param[1] = 0x83;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+
+/****************************************************************
+ * Mouse events
+ ****************************************************************/
+
+// Format of USB mouse event data
+struct mouseevent {
+ u8 buttons;
+ u8 x, y;
+ u8 reserved[5];
+};
+
+// Process USB mouse data.
+static void
+handle_mouse(struct mouseevent *data)
+{
+ dprintf(9, "Got mouse b=%x x=%x y=%x\n", data->buttons, data->x, data->y);
+
+ s8 x = data->x, y = -data->y;
+ u8 flag = ((data->buttons & 0x7) | (1<<3)
+ | (x & 0x80 ? (1<<4) : 0) | (y & 0x80 ? (1<<5) : 0));
+ process_mouse(flag);
+ process_mouse(x);
+ process_mouse(y);
+}
+
+// Check if a USB mouse event is pending and process it if so.
+static void
+usb_check_mouse(void)
+{
+ if (! CONFIG_USB_MOUSE)
+ return;
+ struct usb_pipe *pipe = GET_GLOBAL(mouse_pipe);
+ if (!pipe)
+ return;
+
+ for (;;) {
+ struct mouseevent data;
+ int ret = usb_poll_intr(pipe, &data);
+ if (ret)
+ break;
+ handle_mouse(&data);
+ }
+}
+
+// Test if USB mouse is active.
+inline int
+usb_mouse_active(void)
+{
+ if (! CONFIG_USB_MOUSE)
+ return 0;
+ return GET_GLOBAL(mouse_pipe) != NULL;
+}
+
+// Handle a ps2 style mouse command.
+inline int
+usb_mouse_command(int command, u8 *param)
+{
+ if (! CONFIG_USB_MOUSE)
+ return -1;
+ dprintf(9, "usb mouse cmd=%x\n", command);
+ switch (command) {
+ case PSMOUSE_CMD_ENABLE:
+ case PSMOUSE_CMD_DISABLE:
+ case PSMOUSE_CMD_SETSCALE11:
+ return 0;
+ case PSMOUSE_CMD_SETSCALE21:
+ case PSMOUSE_CMD_SETRATE:
+ case PSMOUSE_CMD_SETRES:
+ // XXX
+ return 0;
+ case PSMOUSE_CMD_RESET_BAT:
+ case PSMOUSE_CMD_GETID:
+ // Return the id of a standard AT mouse.
+ param[0] = 0xaa;
+ param[1] = 0x00;
+ return 0;
+
+ case PSMOUSE_CMD_GETINFO:
+ param[0] = 0x00;
+ param[1] = 4;
+ param[2] = 100;
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+// Check for USB events pending - called periodically from timer interrupt.
+void
+usb_check_event(void)
+{
+ usb_check_key();
+ usb_check_mouse();
+}
--- /dev/null
+#ifndef __USB_HID_H
+#define __USB_HID_H
+
+// usb-hid.c
+struct usb_interface_descriptor;
+struct usb_pipe;
+int usb_hid_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax);
+inline int usb_kbd_active(void);
+inline int usb_kbd_command(int command, u8 *param);
+inline int usb_mouse_active(void);
+inline int usb_mouse_command(int command, u8 *param);
+void usb_check_event(void);
+
+
+/****************************************************************
+ * hid flags
+ ****************************************************************/
+
+#define USB_INTERFACE_SUBCLASS_BOOT 1
+#define USB_INTERFACE_PROTOCOL_KEYBOARD 1
+#define USB_INTERFACE_PROTOCOL_MOUSE 2
+
+#define HID_REQ_GET_REPORT 0x01
+#define HID_REQ_GET_IDLE 0x02
+#define HID_REQ_GET_PROTOCOL 0x03
+#define HID_REQ_SET_REPORT 0x09
+#define HID_REQ_SET_IDLE 0x0A
+#define HID_REQ_SET_PROTOCOL 0x0B
+
+#endif // ush-hid.h
--- /dev/null
+// Code for handling standard USB hubs.
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_USB_HUB
+#include "usb-hub.h" // struct usb_hub_descriptor
+#include "usb.h" // struct usb_s
+
+static int
+get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_GET_DESCRIPTOR;
+ req.wValue = USB_DT_HUB<<8;
+ req.wIndex = 0;
+ req.wLength = sizeof(*desc);
+ return send_default_control(pipe, &req, desc);
+}
+
+static int
+set_port_feature(struct usbhub_s *hub, int port, int feature)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
+ req.bRequest = USB_REQ_SET_FEATURE;
+ req.wValue = feature;
+ req.wIndex = port + 1;
+ req.wLength = 0;
+ mutex_lock(&hub->lock);
+ int ret = send_default_control(hub->pipe, &req, NULL);
+ mutex_unlock(&hub->lock);
+ return ret;
+}
+
+static int
+clear_port_feature(struct usbhub_s *hub, int port, int feature)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER;
+ req.bRequest = USB_REQ_CLEAR_FEATURE;
+ req.wValue = feature;
+ req.wIndex = port + 1;
+ req.wLength = 0;
+ mutex_lock(&hub->lock);
+ int ret = send_default_control(hub->pipe, &req, NULL);
+ mutex_unlock(&hub->lock);
+ return ret;
+}
+
+static int
+get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER;
+ req.bRequest = USB_REQ_GET_STATUS;
+ req.wValue = 0;
+ req.wIndex = port + 1;
+ req.wLength = sizeof(*sts);
+ mutex_lock(&hub->lock);
+ int ret = send_default_control(hub->pipe, &req, sts);
+ mutex_unlock(&hub->lock);
+ return ret;
+}
+
+// Check if device attached to port
+static int
+usb_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ // Turn on power to port.
+ int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER);
+ if (ret)
+ goto fail;
+
+ // Wait for port power to stabilize.
+ msleep(hub->powerwait);
+
+ // Check periodically for a device connect.
+ struct usb_port_status sts;
+ u64 end = calc_future_tsc(USB_TIME_SIGATT);
+ for (;;) {
+ ret = get_port_status(hub, port, &sts);
+ if (ret)
+ goto fail;
+ if (sts.wPortStatus & USB_PORT_STAT_CONNECTION)
+ // Device connected.
+ break;
+ if (check_tsc(end))
+ // No device found.
+ return -1;
+ msleep(5);
+ }
+
+ // XXX - wait USB_TIME_ATTDB time?
+
+ return 0;
+
+fail:
+ dprintf(1, "Failure on hub port %d detect\n", port);
+ return -1;
+}
+
+// Disable port
+static void
+usb_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE);
+ if (ret)
+ dprintf(1, "Failure on hub port %d disconnect\n", port);
+}
+
+// Reset device on port
+static int
+usb_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET);
+ if (ret)
+ goto fail;
+
+ // Wait for reset to complete.
+ struct usb_port_status sts;
+ u64 end = calc_future_tsc(USB_TIME_DRST * 2);
+ for (;;) {
+ ret = get_port_status(hub, port, &sts);
+ if (ret)
+ goto fail;
+ if (!(sts.wPortStatus & USB_PORT_STAT_RESET))
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ goto fail;
+ }
+ msleep(5);
+ }
+
+ // Reset complete.
+ if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION))
+ // Device no longer present
+ return -1;
+
+ return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK)
+ >> USB_PORT_STAT_SPEED_SHIFT);
+
+fail:
+ dprintf(1, "Failure on hub port %d reset\n", port);
+ usb_hub_disconnect(hub, port);
+ return -1;
+}
+
+static struct usbhub_op_s HubOp = {
+ .detect = usb_hub_detect,
+ .reset = usb_hub_reset,
+ .disconnect = usb_hub_disconnect,
+};
+
+// Configure a usb hub and then find devices connected to it.
+int
+usb_hub_init(struct usb_pipe *pipe)
+{
+ ASSERT32FLAT();
+ if (!CONFIG_USB_HUB)
+ return -1;
+
+ struct usb_hub_descriptor desc;
+ int ret = get_hub_desc(pipe, &desc);
+ if (ret)
+ return ret;
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.pipe = pipe;
+ hub.cntl = pipe->cntl;
+ hub.powerwait = desc.bPwrOn2PwrGood * 2;
+ hub.portcount = desc.bNbrPorts;
+ hub.op = &HubOp;
+ usb_enumerate(&hub);
+
+ dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount);
+ if (hub.devcount)
+ return 0;
+ return -1;
+}
--- /dev/null
+#ifndef __USB_HUB_H
+#define __USB_HUB_H
+
+// usb-hub.c
+struct usb_pipe;
+int usb_hub_init(struct usb_pipe *pipe);
+
+
+/****************************************************************
+ * hub flags
+ ****************************************************************/
+
+#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
+
+struct usb_hub_descriptor {
+ u8 bDescLength;
+ u8 bDescriptorType;
+ u8 bNbrPorts;
+ u16 wHubCharacteristics;
+ u8 bPwrOn2PwrGood;
+ u8 bHubContrCurrent;
+ // Variable length fields for DeviceRemovable[], PortPwrCtrlMask[] follow.
+} PACKED;
+
+#define USB_PORT_FEAT_CONNECTION 0
+#define USB_PORT_FEAT_ENABLE 1
+#define USB_PORT_FEAT_SUSPEND 2
+#define USB_PORT_FEAT_OVER_CURRENT 3
+#define USB_PORT_FEAT_RESET 4
+#define USB_PORT_FEAT_POWER 8
+#define USB_PORT_FEAT_LOWSPEED 9
+#define USB_PORT_FEAT_C_CONNECTION 16
+#define USB_PORT_FEAT_C_ENABLE 17
+#define USB_PORT_FEAT_C_SUSPEND 18
+#define USB_PORT_FEAT_C_OVER_CURRENT 19
+#define USB_PORT_FEAT_C_RESET 20
+#define USB_PORT_FEAT_TEST 21
+#define USB_PORT_FEAT_INDICATOR 22
+#define USB_PORT_FEAT_C_PORT_L1 23
+
+struct usb_port_status {
+ u16 wPortStatus;
+ u16 wPortChange;
+} PACKED;
+
+#define USB_PORT_STAT_CONNECTION 0x0001
+#define USB_PORT_STAT_ENABLE 0x0002
+#define USB_PORT_STAT_SUSPEND 0x0004
+#define USB_PORT_STAT_OVERCURRENT 0x0008
+#define USB_PORT_STAT_RESET 0x0010
+#define USB_PORT_STAT_L1 0x0020
+#define USB_PORT_STAT_POWER 0x0100
+#define USB_PORT_STAT_SPEED_SHIFT 9
+#define USB_PORT_STAT_SPEED_MASK (0x3 << USB_PORT_STAT_SPEED_SHIFT)
+#define USB_PORT_STAT_LOW_SPEED 0x0200
+#define USB_PORT_STAT_HIGH_SPEED 0x0400
+#define USB_PORT_STAT_TEST 0x0800
+#define USB_PORT_STAT_INDICATOR 0x1000
+
+#endif // ush-hid.h
--- /dev/null
+// Code for handling USB Mass Storage Controller devices.
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_USB_MSC
+#include "usb-msc.h" // usb_msc_init
+#include "usb.h" // struct usb_s
+#include "biosvar.h" // GET_GLOBAL
+#include "blockcmd.h" // cdb_read
+#include "disk.h" // DTYPE_USB
+#include "boot.h" // boot_add_hd
+
+struct usbdrive_s {
+ struct drive_s drive;
+ struct usb_pipe *bulkin, *bulkout;
+};
+
+
+/****************************************************************
+ * Bulk-only drive command processing
+ ****************************************************************/
+
+#define USB_CDB_SIZE 12
+
+#define CBW_SIGNATURE 0x43425355 // USBC
+
+struct cbw_s {
+ u32 dCBWSignature;
+ u32 dCBWTag;
+ u32 dCBWDataTransferLength;
+ u8 bmCBWFlags;
+ u8 bCBWLUN;
+ u8 bCBWCBLength;
+ u8 CBWCB[16];
+} PACKED;
+
+#define CSW_SIGNATURE 0x53425355 // USBS
+
+struct csw_s {
+ u32 dCSWSignature;
+ u32 dCSWTag;
+ u32 dCSWDataResidue;
+ u8 bCSWStatus;
+} PACKED;
+
+// Low-level usb command transmit function.
+int
+usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ if (!CONFIG_USB_MSC)
+ return 0;
+
+ dprintf(16, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
+ , op->drive_g, 0, op->count, blocksize, op->buf_fl);
+ struct usbdrive_s *udrive_g = container_of(
+ op->drive_g, struct usbdrive_s, drive);
+ struct usb_pipe *bulkin = GET_GLOBAL(udrive_g->bulkin);
+ struct usb_pipe *bulkout = GET_GLOBAL(udrive_g->bulkout);
+
+ // Setup command block wrapper.
+ u32 bytes = blocksize * op->count;
+ struct cbw_s cbw;
+ memset(&cbw, 0, sizeof(cbw));
+ cbw.dCBWSignature = CBW_SIGNATURE;
+ cbw.dCBWTag = 999; // XXX
+ cbw.dCBWDataTransferLength = bytes;
+ cbw.bmCBWFlags = USB_DIR_IN; // XXX
+ cbw.bCBWLUN = 0; // XXX
+ cbw.bCBWCBLength = USB_CDB_SIZE;
+ memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE);
+
+ // Transfer cbw to device.
+ int ret = usb_send_bulk(bulkout, USB_DIR_OUT
+ , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw));
+ if (ret)
+ goto fail;
+
+ // Transfer data from device.
+ ret = usb_send_bulk(bulkin, USB_DIR_IN, op->buf_fl, bytes);
+ if (ret)
+ goto fail;
+
+ // Transfer csw info.
+ struct csw_s csw;
+ ret = usb_send_bulk(bulkin, USB_DIR_IN
+ , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw));
+ if (ret)
+ goto fail;
+
+ if (!csw.bCSWStatus)
+ return DISK_RET_SUCCESS;
+ if (csw.bCSWStatus == 2)
+ goto fail;
+
+ op->count -= csw.dCSWDataResidue / blocksize;
+ return DISK_RET_EBADTRACK;
+
+fail:
+ // XXX - reset connection
+ dprintf(1, "USB transmission failed\n");
+ op->count = 0;
+ return DISK_RET_EBADTRACK;
+}
+
+
+/****************************************************************
+ * Drive ops
+ ****************************************************************/
+
+// 16bit command demuxer for ATAPI cdroms.
+int
+process_usb_op(struct disk_op_s *op)
+{
+ if (!CONFIG_USB_MSC)
+ return 0;
+ switch (op->command) {
+ case CMD_READ:
+ return cdb_read(op);
+ case CMD_FORMAT:
+ case CMD_WRITE:
+ return DISK_RET_EWRITEPROTECT;
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static int
+setup_drive_cdrom(struct disk_op_s *op, char *desc)
+{
+ op->drive_g->blksize = CDROM_SECTOR_SIZE;
+ op->drive_g->sectors = (u64)-1;
+ struct usb_pipe *pipe = container_of(
+ op->drive_g, struct usbdrive_s, drive)->bulkout;
+ int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path);
+ boot_add_cd(op->drive_g, desc, prio);
+ return 0;
+}
+
+static int
+setup_drive_hd(struct disk_op_s *op, char *desc)
+{
+ struct cdbres_read_capacity info;
+ int ret = cdb_read_capacity(op, &info);
+ if (ret)
+ return ret;
+ // XXX - retry for some timeout?
+
+ u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
+ if (blksize != DISK_SECTOR_SIZE) {
+ if (blksize == CDROM_SECTOR_SIZE)
+ return setup_drive_cdrom(op, desc);
+ dprintf(1, "Unsupported USB MSC block size %d\n", blksize);
+ return -1;
+ }
+ op->drive_g->blksize = blksize;
+ op->drive_g->sectors = sectors;
+ dprintf(1, "USB MSC blksize=%d sectors=%d\n", blksize, sectors);
+
+ // Register with bcv system.
+ struct usb_pipe *pipe = container_of(
+ op->drive_g, struct usbdrive_s, drive)->bulkout;
+ int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path);
+ boot_add_hd(op->drive_g, desc, prio);
+
+ return 0;
+}
+
+// Configure a usb msc device.
+int
+usb_msc_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax)
+{
+ if (!CONFIG_USB_MSC)
+ return -1;
+
+ // Verify right kind of device
+ if ((iface->bInterfaceSubClass != US_SC_SCSI &&
+ iface->bInterfaceSubClass != US_SC_ATAPI_8070 &&
+ iface->bInterfaceSubClass != US_SC_ATAPI_8020)
+ || iface->bInterfaceProtocol != US_PR_BULK) {
+ dprintf(1, "Unsupported MSC USB device (subclass=%02x proto=%02x)\n"
+ , iface->bInterfaceSubClass, iface->bInterfaceProtocol);
+ return -1;
+ }
+
+ // Allocate drive structure.
+ struct usbdrive_s *udrive_g = malloc_fseg(sizeof(*udrive_g));
+ if (!udrive_g) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(udrive_g, 0, sizeof(*udrive_g));
+ udrive_g->drive.type = DTYPE_USB;
+
+ // Find bulk in and bulk out endpoints.
+ struct usb_endpoint_descriptor *indesc = findEndPointDesc(
+ iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_IN);
+ struct usb_endpoint_descriptor *outdesc = findEndPointDesc(
+ iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
+ if (!indesc || !outdesc)
+ goto fail;
+ udrive_g->bulkin = alloc_bulk_pipe(pipe, indesc);
+ udrive_g->bulkout = alloc_bulk_pipe(pipe, outdesc);
+ if (!udrive_g->bulkin || !udrive_g->bulkout)
+ goto fail;
+
+ // Validate drive and find block size and sector count.
+ struct disk_op_s dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_g = &udrive_g->drive;
+ struct cdbres_inquiry data;
+ int ret = cdb_get_inquiry(&dop, &data);
+ if (ret)
+ goto fail;
+ char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
+ char rev[sizeof(data.rev)+1];
+ strtcpy(vendor, data.vendor, sizeof(vendor));
+ nullTrailingSpace(vendor);
+ strtcpy(product, data.product, sizeof(product));
+ nullTrailingSpace(product);
+ strtcpy(rev, data.rev, sizeof(rev));
+ nullTrailingSpace(rev);
+ int pdt = data.pdt & 0x1f;
+ int removable = !!(data.removable & 0x80);
+ dprintf(1, "USB MSC vendor='%s' product='%s' rev='%s' type=%d removable=%d\n"
+ , vendor, product, rev, pdt, removable);
+ udrive_g->drive.removable = removable;
+
+ if (pdt == USB_MSC_TYPE_CDROM) {
+ char *desc = znprintf(MAXDESCSIZE, "DVD/CD [USB Drive %s %s %s]"
+ , vendor, product, rev);
+ ret = setup_drive_cdrom(&dop, desc);
+ } else {
+ char *desc = znprintf(MAXDESCSIZE, "USB Drive %s %s %s"
+ , vendor, product, rev);
+ ret = setup_drive_hd(&dop, desc);
+ }
+ if (ret)
+ goto fail;
+
+ return 0;
+fail:
+ dprintf(1, "Unable to configure USB MSC device.\n");
+ free(udrive_g);
+ return -1;
+}
--- /dev/null
+#ifndef __USB_MSC_H
+#define __USB_MSC_H
+
+// usb-msc.c
+struct disk_op_s;
+int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+struct usb_interface_descriptor;
+struct usb_pipe;
+int usb_msc_init(struct usb_pipe *pipe
+ , struct usb_interface_descriptor *iface, int imax);
+int process_usb_op(struct disk_op_s *op);
+
+
+/****************************************************************
+ * MSC flags
+ ****************************************************************/
+
+#define US_SC_ATAPI_8020 0x02
+#define US_SC_ATAPI_8070 0x05
+#define US_SC_SCSI 0x06
+
+#define US_PR_BULK 0x50
+
+#define USB_MSC_TYPE_DISK 0x00
+#define USB_MSC_TYPE_CDROM 0x05
+
+#endif // ush-msc.h
--- /dev/null
+// Code for handling OHCI USB controllers.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "usb-ohci.h" // struct ohci_hcca
+#include "pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+
+#define FIT (1 << 31)
+
+struct usb_ohci_s {
+ struct usb_s usb;
+ struct ohci_regs *regs;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+// Check if device attached to port
+static int
+ohci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ u32 sts = readl(&cntl->regs->roothub_portstatus[port]);
+ if (!(sts & RH_PS_CCS))
+ // No device.
+ return -1;
+
+ // XXX - need to wait for USB_TIME_ATTDB if just powered up?
+
+ return 0;
+}
+
+// Disable port
+static void
+ohci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ writel(&cntl->regs->roothub_portstatus[port], RH_PS_CCS|RH_PS_LSDA);
+}
+
+// Reset device on port
+static int
+ohci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb);
+ writel(&cntl->regs->roothub_portstatus[port], RH_PS_PRS);
+ u32 sts;
+ u64 end = calc_future_tsc(USB_TIME_DRSTR * 2);
+ for (;;) {
+ sts = readl(&cntl->regs->roothub_portstatus[port]);
+ if (!(sts & RH_PS_PRS))
+ // XXX - need to ensure USB_TIME_DRSTR time in reset?
+ break;
+ if (check_tsc(end)) {
+ // Timeout.
+ warn_timeout();
+ ohci_hub_disconnect(hub, port);
+ return -1;
+ }
+ yield();
+ }
+
+ if ((sts & (RH_PS_CCS|RH_PS_PES)) != (RH_PS_CCS|RH_PS_PES))
+ // Device no longer present
+ return -1;
+
+ return !!(sts & RH_PS_LSDA);
+}
+
+static struct usbhub_op_s ohci_HubOp = {
+ .detect = ohci_hub_detect,
+ .reset = ohci_hub_reset,
+ .disconnect = ohci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_ohci_ports(struct usb_ohci_s *cntl)
+{
+ ASSERT32FLAT();
+ // Turn on power for all devices on roothub.
+ u32 rha = readl(&cntl->regs->roothub_a);
+ rha &= ~(RH_A_PSM | RH_A_OCPM);
+ writel(&cntl->regs->roothub_status, RH_HS_LPSC);
+ writel(&cntl->regs->roothub_b, RH_B_PPCM);
+ msleep((rha >> 24) * 2);
+ // XXX - need to sleep for USB_TIME_SIGATT if just powered up?
+
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &cntl->usb;
+ hub.portcount = rha & RH_A_NDP;
+ hub.op = &ohci_HubOp;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static int
+start_ohci(struct usb_ohci_s *cntl, struct ohci_hcca *hcca)
+{
+ u32 oldfminterval = readl(&cntl->regs->fminterval);
+ u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC;
+
+ // XXX - check if already running?
+
+ // Do reset
+ writel(&cntl->regs->control, OHCI_USB_RESET | oldrwc);
+ readl(&cntl->regs->control); // flush writes
+ msleep(USB_TIME_DRSTR);
+
+ // Do software init (min 10us, max 2ms)
+ u64 end = calc_future_tsc_usec(10);
+ writel(&cntl->regs->cmdstatus, OHCI_HCR);
+ for (;;) {
+ u32 status = readl(&cntl->regs->cmdstatus);
+ if (! status & OHCI_HCR)
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ }
+
+ // Init memory
+ writel(&cntl->regs->ed_controlhead, 0);
+ writel(&cntl->regs->ed_bulkhead, 0);
+ writel(&cntl->regs->hcca, (u32)hcca);
+
+ // Init fminterval
+ u32 fi = oldfminterval & 0x3fff;
+ writel(&cntl->regs->fminterval
+ , (((oldfminterval & FIT) ^ FIT)
+ | fi | (((6 * (fi - 210)) / 7) << 16)));
+ writel(&cntl->regs->periodicstart, ((9 * fi) / 10) & 0x3fff);
+ readl(&cntl->regs->control); // flush writes
+
+ // XXX - verify that fminterval was setup correctly.
+
+ // Go into operational state
+ writel(&cntl->regs->control
+ , (OHCI_CTRL_CBSR | OHCI_CTRL_CLE | OHCI_CTRL_PLE
+ | OHCI_USB_OPER | oldrwc));
+ readl(&cntl->regs->control); // flush writes
+
+ return 0;
+}
+
+static void
+stop_ohci(struct usb_ohci_s *cntl)
+{
+ u32 oldrwc = readl(&cntl->regs->control) & OHCI_CTRL_RWC;
+ writel(&cntl->regs->control, oldrwc);
+ readl(&cntl->regs->control); // flush writes
+}
+
+static void
+configure_ohci(void *data)
+{
+ struct usb_ohci_s *cntl = data;
+
+ // Allocate memory
+ struct ohci_hcca *hcca = memalign_high(256, sizeof(*hcca));
+ struct ohci_ed *intr_ed = malloc_high(sizeof(*intr_ed));
+ if (!hcca || !intr_ed) {
+ warn_noalloc();
+ goto free;
+ }
+ memset(hcca, 0, sizeof(*hcca));
+ memset(intr_ed, 0, sizeof(*intr_ed));
+ intr_ed->hwINFO = ED_SKIP;
+ int i;
+ for (i=0; i<ARRAY_SIZE(hcca->int_table); i++)
+ hcca->int_table[i] = (u32)intr_ed;
+
+ int ret = start_ohci(cntl, hcca);
+ if (ret)
+ goto err;
+
+ int count = check_ohci_ports(cntl);
+ free_pipe(cntl->usb.defaultpipe);
+ if (! count)
+ goto err;
+ return;
+
+err:
+ stop_ohci(cntl);
+free:
+ free(hcca);
+ free(intr_ed);
+}
+
+void
+ohci_init(struct pci_device *pci, int busid)
+{
+ if (! CONFIG_USB_OHCI)
+ return;
+ struct usb_ohci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+ if (!cntl) {
+ warn_noalloc();
+ return;
+ }
+ memset(cntl, 0, sizeof(*cntl));
+ cntl->usb.busid = busid;
+ cntl->usb.pci = pci;
+ cntl->usb.type = USB_TYPE_OHCI;
+
+ u16 bdf = pci->bdf;
+ u32 baseaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0);
+ cntl->regs = (void*)(baseaddr & PCI_BASE_ADDRESS_MEM_MASK);
+
+ dprintf(1, "OHCI init on dev %02x:%02x.%x (regs=%p)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf), cntl->regs);
+
+ // Enable bus mastering and memory access.
+ pci_config_maskw(bdf, PCI_COMMAND
+ , 0, PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY);
+
+ // XXX - check for and disable SMM control?
+
+ // Disable interrupts
+ writel(&cntl->regs->intrdisable, ~0);
+ writel(&cntl->regs->intrstatus, ~0);
+
+ run_thread(configure_ohci, cntl);
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+wait_ed(struct ohci_ed *ed)
+{
+ // XXX - 500ms just a guess
+ u64 end = calc_future_tsc(500);
+ for (;;) {
+ if (ed->hwHeadP == ed->hwTailP)
+ return 0;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+}
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+ohci_waittick(struct usb_ohci_s *cntl)
+{
+ barrier();
+ struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+ u32 startframe = hcca->frame_no;
+ u64 end = calc_future_tsc(1000 * 5);
+ for (;;) {
+ if (hcca->frame_no != startframe)
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+}
+
+static void
+signal_freelist(struct usb_ohci_s *cntl)
+{
+ u32 v = readl(&cntl->regs->control);
+ if (v & OHCI_CTRL_CLE) {
+ writel(&cntl->regs->control, v & ~(OHCI_CTRL_CLE|OHCI_CTRL_BLE));
+ ohci_waittick(cntl);
+ writel(&cntl->regs->ed_controlcurrent, 0);
+ writel(&cntl->regs->ed_bulkcurrent, 0);
+ writel(&cntl->regs->control, v);
+ } else {
+ ohci_waittick(cntl);
+ }
+}
+
+struct ohci_pipe {
+ struct ohci_ed ed;
+ struct usb_pipe pipe;
+ void *data;
+ int count;
+ struct ohci_td *tds;
+};
+
+void
+ohci_free_pipe(struct usb_pipe *p)
+{
+ if (! CONFIG_USB_OHCI)
+ return;
+ dprintf(7, "ohci_free_pipe %p\n", p);
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+ struct usb_ohci_s *cntl = container_of(
+ pipe->pipe.cntl, struct usb_ohci_s, usb);
+
+ u32 *pos = &cntl->regs->ed_controlhead;
+ for (;;) {
+ struct ohci_ed *next = (void*)*pos;
+ if (!next) {
+ // Not found?! Exit without freeing.
+ warn_internalerror();
+ return;
+ }
+ if (next == &pipe->ed) {
+ *pos = next->hwNextED;
+ signal_freelist(cntl);
+ free(pipe);
+ return;
+ }
+ pos = &next->hwNextED;
+ }
+}
+
+struct usb_pipe *
+ohci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+ if (! CONFIG_USB_OHCI)
+ return NULL;
+ struct usb_ohci_s *cntl = container_of(
+ dummy->cntl, struct usb_ohci_s, usb);
+ dprintf(7, "ohci_alloc_control_pipe %p\n", &cntl->usb);
+
+ // Allocate a queue head.
+ struct ohci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->ed.hwINFO = ED_SKIP;
+
+ // Add queue head to controller list.
+ pipe->ed.hwNextED = cntl->regs->ed_controlhead;
+ barrier();
+ cntl->regs->ed_controlhead = (u32)&pipe->ed;
+ return &pipe->pipe;
+}
+
+int
+ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+ , void *data, int datasize)
+{
+ if (! CONFIG_USB_OHCI)
+ return -1;
+ dprintf(5, "ohci_control %p\n", p);
+ if (datasize > 4096) {
+ // XXX - should support larger sizes.
+ warn_noalloc();
+ return -1;
+ }
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+ struct usb_ohci_s *cntl = container_of(
+ pipe->pipe.cntl, struct usb_ohci_s, usb);
+ int maxpacket = pipe->pipe.maxpacket;
+ int lowspeed = pipe->pipe.speed;
+ int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+
+ // Setup transfer descriptors
+ struct ohci_td *tds = malloc_tmphigh(sizeof(*tds) * 3);
+ if (!tds) {
+ warn_noalloc();
+ return -1;
+ }
+ struct ohci_td *td = tds;
+ td->hwINFO = TD_DP_SETUP | TD_T_DATA0 | TD_CC;
+ td->hwCBP = (u32)cmd;
+ td->hwNextTD = (u32)&td[1];
+ td->hwBE = (u32)cmd + cmdsize - 1;
+ td++;
+ if (datasize) {
+ td->hwINFO = (dir ? TD_DP_IN : TD_DP_OUT) | TD_T_DATA1 | TD_CC;
+ td->hwCBP = (u32)data;
+ td->hwNextTD = (u32)&td[1];
+ td->hwBE = (u32)data + datasize - 1;
+ td++;
+ }
+ td->hwINFO = (dir ? TD_DP_OUT : TD_DP_IN) | TD_T_DATA1 | TD_CC;
+ td->hwCBP = 0;
+ td->hwNextTD = (u32)&td[1];
+ td->hwBE = 0;
+ td++;
+
+ // Transfer data
+ pipe->ed.hwINFO = ED_SKIP;
+ barrier();
+ pipe->ed.hwHeadP = (u32)tds;
+ pipe->ed.hwTailP = (u32)td;
+ barrier();
+ pipe->ed.hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+ writel(&cntl->regs->cmdstatus, OHCI_CLF);
+
+ int ret = wait_ed(&pipe->ed);
+ pipe->ed.hwINFO = ED_SKIP;
+ if (ret)
+ ohci_waittick(cntl);
+ free(tds);
+ return ret;
+}
+
+struct usb_pipe *
+ohci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+ if (! CONFIG_USB_OHCI)
+ return NULL;
+ dprintf(1, "OHCI Bulk transfers not supported.\n");
+ return NULL;
+}
+
+int
+ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
+{
+ return -1;
+}
+
+struct usb_pipe *
+ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+ if (! CONFIG_USB_OHCI)
+ return NULL;
+ struct usb_ohci_s *cntl = container_of(
+ dummy->cntl, struct usb_ohci_s, usb);
+ dprintf(7, "ohci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+ if (frameexp > 5)
+ frameexp = 5;
+ int maxpacket = dummy->maxpacket;
+ int lowspeed = dummy->speed;
+ int devaddr = dummy->devaddr | (dummy->ep << 7);
+ // Determine number of entries needed for 2 timer ticks.
+ int ms = 1<<frameexp;
+ int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms)+1;
+ struct ohci_pipe *pipe = malloc_low(sizeof(*pipe));
+ struct ohci_td *tds = malloc_low(sizeof(*tds) * count);
+ void *data = malloc_low(maxpacket * count);
+ if (!pipe || !tds || !data)
+ goto err;
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->data = data;
+ pipe->count = count;
+ pipe->tds = tds;
+
+ struct ohci_ed *ed = &pipe->ed;
+ ed->hwHeadP = (u32)&tds[0];
+ ed->hwTailP = (u32)&tds[count-1];
+ ed->hwINFO = devaddr | (maxpacket << 16) | (lowspeed ? ED_LOWSPEED : 0);
+
+ int i;
+ for (i=0; i<count-1; i++) {
+ tds[i].hwINFO = TD_DP_IN | TD_T_TOGGLE | TD_CC;
+ tds[i].hwCBP = (u32)data + maxpacket * i;
+ tds[i].hwNextTD = (u32)&tds[i+1];
+ tds[i].hwBE = tds[i].hwCBP + maxpacket - 1;
+ }
+
+ // Add to interrupt schedule.
+ barrier();
+ struct ohci_hcca *hcca = (void*)cntl->regs->hcca;
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct ohci_ed *intr_ed = (void*)hcca->int_table[0];
+ ed->hwNextED = intr_ed->hwNextED;
+ intr_ed->hwNextED = (u32)ed;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ ed->hwNextED = hcca->int_table[startpos];
+ for (i=startpos; i<ARRAY_SIZE(hcca->int_table); i+=ms)
+ hcca->int_table[i] = (u32)ed;
+ }
+
+ return &pipe->pipe;
+
+err:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
+}
+
+int
+ohci_poll_intr(struct usb_pipe *p, void *data)
+{
+ ASSERT16();
+ if (! CONFIG_USB_OHCI)
+ return -1;
+
+ struct ohci_pipe *pipe = container_of(p, struct ohci_pipe, pipe);
+ struct ohci_td *tds = GET_FLATPTR(pipe->tds);
+ struct ohci_td *head = (void*)(GET_FLATPTR(pipe->ed.hwHeadP) & ~(ED_C|ED_H));
+ struct ohci_td *tail = (void*)GET_FLATPTR(pipe->ed.hwTailP);
+ int count = GET_FLATPTR(pipe->count);
+ int pos = (tail - tds + 1) % count;
+ struct ohci_td *next = &tds[pos];
+ if (head == next)
+ // No intrs found.
+ return -1;
+ // XXX - check for errors.
+
+ // Copy data.
+ int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+ void *pipedata = GET_FLATPTR(pipe->data);
+ void *intrdata = pipedata + maxpacket * pos;
+ memcpy_far(GET_SEG(SS), data
+ , FLATPTR_TO_SEG(intrdata), (void*)FLATPTR_TO_OFFSET(intrdata)
+ , maxpacket);
+
+ // Reenable this td.
+ SET_FLATPTR(tail->hwINFO, TD_DP_IN | TD_T_TOGGLE | TD_CC);
+ intrdata = pipedata + maxpacket * (tail-tds);
+ SET_FLATPTR(tail->hwCBP, (u32)intrdata);
+ SET_FLATPTR(tail->hwNextTD, (u32)next);
+ SET_FLATPTR(tail->hwBE, (u32)intrdata + maxpacket - 1);
+ barrier();
+ SET_FLATPTR(pipe->ed.hwTailP, (u32)next);
+
+ return 0;
+}
--- /dev/null
+#ifndef __USB_OHCI_H
+#define __USB_OHCI_H
+
+// usb-ohci.c
+void ohci_init(struct pci_device *pci, int busid);
+struct usb_pipe;
+void ohci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *ohci_alloc_control_pipe(struct usb_pipe *dummy);
+int ohci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+ , void *data, int datasize);
+struct usb_pipe *ohci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int ohci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *ohci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+int ohci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * ohci structs and flags
+ ****************************************************************/
+
+struct ohci_ed {
+ u32 hwINFO;
+ u32 hwTailP;
+ u32 hwHeadP;
+ u32 hwNextED;
+} PACKED;
+
+#define ED_ISO (1 << 15)
+#define ED_SKIP (1 << 14)
+#define ED_LOWSPEED (1 << 13)
+#define ED_OUT (0x01 << 11)
+#define ED_IN (0x02 << 11)
+
+#define ED_C (0x02)
+#define ED_H (0x01)
+
+struct ohci_td {
+ u32 hwINFO;
+ u32 hwCBP;
+ u32 hwNextTD;
+ u32 hwBE;
+} PACKED;
+
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_DI 0x00E00000
+
+#define TD_DONE 0x00020000
+#define TD_ISO 0x00010000
+
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_R 0x00040000
+
+struct ohci_hcca {
+ u32 int_table[32];
+ u32 frame_no;
+ u32 done_head;
+ u8 reserved[120];
+} PACKED;
+
+struct ohci_regs {
+ u32 revision;
+ u32 control;
+ u32 cmdstatus;
+ u32 intrstatus;
+ u32 intrenable;
+ u32 intrdisable;
+
+ u32 hcca;
+ u32 ed_periodcurrent;
+ u32 ed_controlhead;
+ u32 ed_controlcurrent;
+ u32 ed_bulkhead;
+ u32 ed_bulkcurrent;
+ u32 donehead;
+
+ u32 fminterval;
+ u32 fmremaining;
+ u32 fmnumber;
+ u32 periodicstart;
+ u32 lsthresh;
+
+ u32 roothub_a;
+ u32 roothub_b;
+ u32 roothub_status;
+ u32 roothub_portstatus[15];
+} PACKED;
+
+#define OHCI_CTRL_CBSR (3 << 0)
+#define OHCI_CTRL_PLE (1 << 2)
+#define OHCI_CTRL_CLE (1 << 4)
+#define OHCI_CTRL_BLE (1 << 5)
+#define OHCI_CTRL_HCFS (3 << 6)
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_OPER (2 << 6)
+#define OHCI_CTRL_RWC (1 << 9)
+
+#define OHCI_HCR (1 << 0)
+#define OHCI_CLF (1 << 1)
+
+#define OHCI_INTR_MIE (1 << 31)
+
+#define RH_PS_CCS 0x00000001
+#define RH_PS_PES 0x00000002
+#define RH_PS_PSS 0x00000004
+#define RH_PS_POCI 0x00000008
+#define RH_PS_PRS 0x00000010
+#define RH_PS_PPS 0x00000100
+#define RH_PS_LSDA 0x00000200
+#define RH_PS_CSC 0x00010000
+#define RH_PS_PESC 0x00020000
+#define RH_PS_PSSC 0x00040000
+#define RH_PS_OCIC 0x00080000
+#define RH_PS_PRSC 0x00100000
+
+#define RH_HS_LPS 0x00000001
+#define RH_HS_OCI 0x00000002
+#define RH_HS_DRWE 0x00008000
+#define RH_HS_LPSC 0x00010000
+#define RH_HS_OCIC 0x00020000
+#define RH_HS_CRWE 0x80000000
+
+#define RH_B_DR 0x0000ffff
+#define RH_B_PPCM 0xffff0000
+
+#define RH_A_NDP (0xff << 0)
+#define RH_A_PSM (1 << 8)
+#define RH_A_NPS (1 << 9)
+#define RH_A_DT (1 << 10)
+#define RH_A_OCPM (1 << 11)
+#define RH_A_NOCP (1 << 12)
+#define RH_A_POTPGT (0xff << 24)
+
+#endif // usb-ohci.h
--- /dev/null
+// Code for handling UHCI USB controllers.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // pci_bdf_to_bus
+#include "config.h" // CONFIG_*
+#include "ioport.h" // outw
+#include "usb-uhci.h" // USBLEGSUP
+#include "pci_regs.h" // PCI_BASE_ADDRESS_4
+#include "usb.h" // struct usb_s
+#include "farptr.h" // GET_FLATPTR
+
+struct usb_uhci_s {
+ struct usb_s usb;
+ u16 iobase;
+ struct uhci_qh *control_qh, *bulk_qh;
+ struct uhci_framelist *framelist;
+};
+
+
+/****************************************************************
+ * Root hub
+ ****************************************************************/
+
+// Check if device attached to a given port
+static int
+uhci_hub_detect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+ u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+
+ u16 status = inw(ioport);
+ if (!(status & USBPORTSC_CCS))
+ // No device
+ return -1;
+
+ // XXX - if just powered up, need to wait for USB_TIME_ATTDB?
+
+ // Begin reset on port
+ outw(USBPORTSC_PR, ioport);
+ msleep(USB_TIME_DRSTR);
+ return 0;
+}
+
+// Reset device on port
+static int
+uhci_hub_reset(struct usbhub_s *hub, u32 port)
+{
+ struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+ u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+
+ // Finish reset on port
+ outw(0, ioport);
+ udelay(6); // 64 high-speed bit times
+ u16 status = inw(ioport);
+ if (!(status & USBPORTSC_CCS))
+ // No longer connected
+ return -1;
+ outw(USBPORTSC_PE, ioport);
+ return !!(status & USBPORTSC_LSDA);
+}
+
+// Disable port
+static void
+uhci_hub_disconnect(struct usbhub_s *hub, u32 port)
+{
+ struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb);
+ u16 ioport = cntl->iobase + USBPORTSC1 + port * 2;
+ outw(0, ioport);
+}
+
+static struct usbhub_op_s uhci_HubOp = {
+ .detect = uhci_hub_detect,
+ .reset = uhci_hub_reset,
+ .disconnect = uhci_hub_disconnect,
+};
+
+// Find any devices connected to the root hub.
+static int
+check_uhci_ports(struct usb_uhci_s *cntl)
+{
+ ASSERT32FLAT();
+ struct usbhub_s hub;
+ memset(&hub, 0, sizeof(hub));
+ hub.cntl = &cntl->usb;
+ hub.portcount = 2;
+ hub.op = &uhci_HubOp;
+ usb_enumerate(&hub);
+ return hub.devcount;
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static void
+reset_uhci(struct usb_uhci_s *cntl, u16 bdf)
+{
+ // XXX - don't reset if not needed.
+
+ // Reset PIRQ and SMI
+ pci_config_writew(bdf, USBLEGSUP, USBLEGSUP_RWC);
+
+ // Reset the HC
+ outw(USBCMD_HCRESET, cntl->iobase + USBCMD);
+ udelay(5);
+
+ // Disable interrupts and commands (just to be safe).
+ outw(0, cntl->iobase + USBINTR);
+ outw(0, cntl->iobase + USBCMD);
+}
+
+static void
+configure_uhci(void *data)
+{
+ struct usb_uhci_s *cntl = data;
+
+ // Allocate ram for schedule storage
+ struct uhci_td *term_td = malloc_high(sizeof(*term_td));
+ struct uhci_framelist *fl = memalign_high(sizeof(*fl), sizeof(*fl));
+ struct uhci_qh *intr_qh = malloc_high(sizeof(*intr_qh));
+ struct uhci_qh *term_qh = malloc_high(sizeof(*term_qh));
+ if (!term_td || !fl || !intr_qh || !term_qh) {
+ warn_noalloc();
+ goto fail;
+ }
+
+ // Work around for PIIX errata
+ memset(term_td, 0, sizeof(*term_td));
+ term_td->link = UHCI_PTR_TERM;
+ term_td->token = (uhci_explen(0) | (0x7f << TD_TOKEN_DEVADDR_SHIFT)
+ | USB_PID_IN);
+ memset(term_qh, 0, sizeof(*term_qh));
+ term_qh->element = (u32)term_td;
+ term_qh->link = UHCI_PTR_TERM;
+
+ // Set schedule to point to primary intr queue head
+ memset(intr_qh, 0, sizeof(*intr_qh));
+ intr_qh->element = UHCI_PTR_TERM;
+ intr_qh->link = (u32)term_qh | UHCI_PTR_QH;
+ int i;
+ for (i=0; i<ARRAY_SIZE(fl->links); i++)
+ fl->links[i] = (u32)intr_qh | UHCI_PTR_QH;
+ cntl->framelist = fl;
+ cntl->control_qh = cntl->bulk_qh = intr_qh;
+ barrier();
+
+ // Set the frame length to the default: 1 ms exactly
+ outb(USBSOF_DEFAULT, cntl->iobase + USBSOF);
+
+ // Store the frame list base address
+ outl((u32)fl->links, cntl->iobase + USBFLBASEADD);
+
+ // Set the current frame number
+ outw(0, cntl->iobase + USBFRNUM);
+
+ // Mark as configured and running with a 64-byte max packet.
+ outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, cntl->iobase + USBCMD);
+
+ // Find devices
+ int count = check_uhci_ports(cntl);
+ free_pipe(cntl->usb.defaultpipe);
+ if (count)
+ // Success
+ return;
+
+ // No devices found - shutdown and free controller.
+ outw(0, cntl->iobase + USBCMD);
+fail:
+ free(term_td);
+ free(fl);
+ free(intr_qh);
+ free(term_qh);
+ free(cntl);
+}
+
+void
+uhci_init(struct pci_device *pci, int busid)
+{
+ if (! CONFIG_USB_UHCI)
+ return;
+ u16 bdf = pci->bdf;
+ struct usb_uhci_s *cntl = malloc_tmphigh(sizeof(*cntl));
+ if (!cntl) {
+ warn_noalloc();
+ return;
+ }
+ memset(cntl, 0, sizeof(*cntl));
+ cntl->usb.busid = busid;
+ cntl->usb.pci = pci;
+ cntl->usb.type = USB_TYPE_UHCI;
+ cntl->iobase = (pci_config_readl(bdf, PCI_BASE_ADDRESS_4)
+ & PCI_BASE_ADDRESS_IO_MASK);
+
+ dprintf(1, "UHCI init on dev %02x:%02x.%x (io=%x)\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)
+ , pci_bdf_to_fn(bdf), cntl->iobase);
+
+ pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+
+ reset_uhci(cntl, bdf);
+
+ run_thread(configure_uhci, cntl);
+}
+
+
+/****************************************************************
+ * End point communication
+ ****************************************************************/
+
+static int
+wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh)
+{
+ // XXX - 500ms just a guess
+ u64 end = calc_future_tsc(500);
+ for (;;) {
+ if (qh->element & UHCI_PTR_TERM)
+ return 0;
+ if (check_tsc(end)) {
+ warn_timeout();
+ struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS);
+ dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n"
+ , qh, td, td->status
+ , inw(cntl->iobase + USBCMD)
+ , inw(cntl->iobase + USBSTS));
+ return -1;
+ }
+ yield();
+ }
+}
+
+// Wait for next USB frame to start - for ensuring safe memory release.
+static void
+uhci_waittick(u16 iobase)
+{
+ barrier();
+ u16 startframe = inw(iobase + USBFRNUM);
+ u64 end = calc_future_tsc(1000 * 5);
+ for (;;) {
+ if (inw(iobase + USBFRNUM) != startframe)
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return;
+ }
+ yield();
+ }
+}
+
+struct uhci_pipe {
+ struct uhci_qh qh;
+ struct uhci_td *next_td;
+ struct usb_pipe pipe;
+ u16 iobase;
+ u8 toggle;
+};
+
+void
+uhci_free_pipe(struct usb_pipe *p)
+{
+ if (! CONFIG_USB_UHCI)
+ return;
+ dprintf(7, "uhci_free_pipe %p\n", p);
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ struct usb_uhci_s *cntl = container_of(
+ pipe->pipe.cntl, struct usb_uhci_s, usb);
+
+ struct uhci_qh *pos = (void*)(cntl->framelist->links[0] & ~UHCI_PTR_BITS);
+ for (;;) {
+ u32 link = pos->link;
+ if (link == UHCI_PTR_TERM) {
+ // Not found?! Exit without freeing.
+ warn_internalerror();
+ return;
+ }
+ struct uhci_qh *next = (void*)(link & ~UHCI_PTR_BITS);
+ if (next == &pipe->qh) {
+ pos->link = next->link;
+ if (cntl->control_qh == next)
+ cntl->control_qh = pos;
+ if (cntl->bulk_qh == next)
+ cntl->bulk_qh = pos;
+ uhci_waittick(cntl->iobase);
+ free(pipe);
+ return;
+ }
+ pos = next;
+ }
+}
+
+struct usb_pipe *
+uhci_alloc_control_pipe(struct usb_pipe *dummy)
+{
+ if (! CONFIG_USB_UHCI)
+ return NULL;
+ struct usb_uhci_s *cntl = container_of(
+ dummy->cntl, struct usb_uhci_s, usb);
+ dprintf(7, "uhci_alloc_control_pipe %p\n", &cntl->usb);
+
+ // Allocate a queue head.
+ struct uhci_pipe *pipe = malloc_tmphigh(sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->qh.element = UHCI_PTR_TERM;
+ pipe->iobase = cntl->iobase;
+
+ // Add queue head to controller list.
+ struct uhci_qh *control_qh = cntl->control_qh;
+ pipe->qh.link = control_qh->link;
+ barrier();
+ control_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+ if (cntl->bulk_qh == control_qh)
+ cntl->bulk_qh = &pipe->qh;
+ return &pipe->pipe;
+}
+
+int
+uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+ , void *data, int datasize)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_USB_UHCI)
+ return -1;
+ dprintf(5, "uhci_control %p\n", p);
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ struct usb_uhci_s *cntl = container_of(
+ pipe->pipe.cntl, struct usb_uhci_s, usb);
+
+ int maxpacket = pipe->pipe.maxpacket;
+ int lowspeed = pipe->pipe.speed;
+ int devaddr = pipe->pipe.devaddr | (pipe->pipe.ep << 7);
+
+ // Setup transfer descriptors
+ int count = 2 + DIV_ROUND_UP(datasize, maxpacket);
+ struct uhci_td *tds = malloc_tmphigh(sizeof(*tds) * count);
+ if (!tds) {
+ warn_noalloc();
+ return -1;
+ }
+
+ tds[0].link = (u32)&tds[1] | UHCI_PTR_DEPTH;
+ tds[0].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ tds[0].token = (uhci_explen(cmdsize) | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | USB_PID_SETUP);
+ tds[0].buffer = (void*)cmd;
+ int toggle = TD_TOKEN_TOGGLE;
+ int i;
+ for (i=1; i<count-1; i++) {
+ tds[i].link = (u32)&tds[i+1] | UHCI_PTR_DEPTH;
+ tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ int len = (i == count-2 ? (datasize - (i-1)*maxpacket) : maxpacket);
+ tds[i].token = (uhci_explen(len) | toggle
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | (dir ? USB_PID_IN : USB_PID_OUT));
+ tds[i].buffer = data + (i-1) * maxpacket;
+ toggle ^= TD_TOKEN_TOGGLE;
+ }
+ tds[i].link = UHCI_PTR_TERM;
+ tds[i].status = (uhci_maxerr(0) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ tds[i].token = (uhci_explen(0) | TD_TOKEN_TOGGLE
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | (dir ? USB_PID_OUT : USB_PID_IN));
+ tds[i].buffer = 0;
+
+ // Transfer data
+ barrier();
+ pipe->qh.element = (u32)&tds[0];
+ int ret = wait_qh(cntl, &pipe->qh);
+ if (ret) {
+ pipe->qh.element = UHCI_PTR_TERM;
+ uhci_waittick(pipe->iobase);
+ }
+ free(tds);
+ return ret;
+}
+
+struct usb_pipe *
+uhci_alloc_bulk_pipe(struct usb_pipe *dummy)
+{
+ if (! CONFIG_USB_UHCI)
+ return NULL;
+ struct usb_uhci_s *cntl = container_of(
+ dummy->cntl, struct usb_uhci_s, usb);
+ dprintf(7, "uhci_alloc_bulk_pipe %p\n", &cntl->usb);
+
+ // Allocate a queue head.
+ struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+ if (!pipe) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->qh.element = UHCI_PTR_TERM;
+ pipe->iobase = cntl->iobase;
+
+ // Add queue head to controller list.
+ struct uhci_qh *bulk_qh = cntl->bulk_qh;
+ pipe->qh.link = bulk_qh->link;
+ barrier();
+ bulk_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+
+ return &pipe->pipe;
+}
+
+static int
+wait_td(struct uhci_td *td)
+{
+ u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+ u32 status;
+ for (;;) {
+ status = td->status;
+ if (!(status & TD_CTRL_ACTIVE))
+ break;
+ if (check_tsc(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ if (status & TD_CTRL_ANY_ERROR) {
+ dprintf(1, "wait_td error - status=%x\n", status);
+ return -2;
+ }
+ return 0;
+}
+
+#define STACKTDS 4
+#define TDALIGN 16
+
+int
+uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize)
+{
+ if (! CONFIG_USB_UHCI)
+ return -1;
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ dprintf(7, "uhci_send_bulk qh=%p dir=%d data=%p size=%d\n"
+ , &pipe->qh, dir, data, datasize);
+ int maxpacket = GET_FLATPTR(pipe->pipe.maxpacket);
+ int lowspeed = GET_FLATPTR(pipe->pipe.speed);
+ int devaddr = (GET_FLATPTR(pipe->pipe.devaddr)
+ | (GET_FLATPTR(pipe->pipe.ep) << 7));
+ int toggle = GET_FLATPTR(pipe->toggle) ? TD_TOKEN_TOGGLE : 0;
+
+ // Allocate 4 tds on stack (16byte aligned)
+ u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1];
+ struct uhci_td *tds = (void*)ALIGN((u32)tdsbuf, TDALIGN);
+ memset(tds, 0, sizeof(*tds) * STACKTDS);
+
+ // Enable tds
+ barrier();
+ SET_FLATPTR(pipe->qh.element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+
+ int tdpos = 0;
+ while (datasize) {
+ struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+ int ret = wait_td(td);
+ if (ret)
+ goto fail;
+
+ int transfer = datasize;
+ if (transfer > maxpacket)
+ transfer = maxpacket;
+ struct uhci_td *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
+ , &tds[tdpos % STACKTDS]);
+ td->link = (transfer==datasize ? UHCI_PTR_TERM : (u32)nexttd_fl);
+ td->token = (uhci_explen(transfer) | toggle
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | (dir ? USB_PID_IN : USB_PID_OUT));
+ td->buffer = data;
+ barrier();
+ td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ toggle ^= TD_TOKEN_TOGGLE;
+
+ data += transfer;
+ datasize -= transfer;
+ }
+ int i;
+ for (i=0; i<STACKTDS; i++) {
+ struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+ int ret = wait_td(td);
+ if (ret)
+ goto fail;
+ }
+
+ SET_FLATPTR(pipe->toggle, !!toggle);
+ return 0;
+fail:
+ dprintf(1, "uhci_send_bulk failed\n");
+ SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM);
+ uhci_waittick(GET_FLATPTR(pipe->iobase));
+ return -1;
+}
+
+struct usb_pipe *
+uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp)
+{
+ if (! CONFIG_USB_UHCI)
+ return NULL;
+ struct usb_uhci_s *cntl = container_of(
+ dummy->cntl, struct usb_uhci_s, usb);
+ dprintf(7, "uhci_alloc_intr_pipe %p %d\n", &cntl->usb, frameexp);
+
+ if (frameexp > 10)
+ frameexp = 10;
+ int maxpacket = dummy->maxpacket;
+ int lowspeed = dummy->speed;
+ int devaddr = dummy->devaddr | (dummy->ep << 7);
+ // Determine number of entries needed for 2 timer ticks.
+ int ms = 1<<frameexp;
+ int count = DIV_ROUND_UP(PIT_TICK_INTERVAL * 1000 * 2, PIT_TICK_RATE * ms);
+ count = ALIGN(count, 2);
+ struct uhci_pipe *pipe = malloc_low(sizeof(*pipe));
+ struct uhci_td *tds = malloc_low(sizeof(*tds) * count);
+ void *data = malloc_low(maxpacket * count);
+ if (!pipe || !tds || !data) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(pipe, 0, sizeof(*pipe));
+ memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe));
+ pipe->qh.element = (u32)tds;
+ pipe->next_td = &tds[0];
+ pipe->iobase = cntl->iobase;
+
+ int toggle = 0;
+ int i;
+ for (i=0; i<count; i++) {
+ tds[i].link = (i==count-1 ? (u32)&tds[0] : (u32)&tds[i+1]);
+ tds[i].status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ tds[i].token = (uhci_explen(maxpacket) | toggle
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | USB_PID_IN);
+ tds[i].buffer = data + maxpacket * i;
+ toggle ^= TD_TOKEN_TOGGLE;
+ }
+
+ // Add to interrupt schedule.
+ struct uhci_framelist *fl = cntl->framelist;
+ if (frameexp == 0) {
+ // Add to existing interrupt entry.
+ struct uhci_qh *intr_qh = (void*)(fl->links[0] & ~UHCI_PTR_BITS);
+ pipe->qh.link = intr_qh->link;
+ barrier();
+ intr_qh->link = (u32)&pipe->qh | UHCI_PTR_QH;
+ if (cntl->control_qh == intr_qh)
+ cntl->control_qh = &pipe->qh;
+ if (cntl->bulk_qh == intr_qh)
+ cntl->bulk_qh = &pipe->qh;
+ } else {
+ int startpos = 1<<(frameexp-1);
+ pipe->qh.link = fl->links[startpos];
+ barrier();
+ for (i=startpos; i<ARRAY_SIZE(fl->links); i+=ms)
+ fl->links[i] = (u32)&pipe->qh | UHCI_PTR_QH;
+ }
+
+ return &pipe->pipe;
+fail:
+ free(pipe);
+ free(tds);
+ free(data);
+ return NULL;
+}
+
+int
+uhci_poll_intr(struct usb_pipe *p, void *data)
+{
+ ASSERT16();
+ if (! CONFIG_USB_UHCI)
+ return -1;
+
+ struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe);
+ struct uhci_td *td = GET_FLATPTR(pipe->next_td);
+ u32 status = GET_FLATPTR(td->status);
+ u32 token = GET_FLATPTR(td->token);
+ if (status & TD_CTRL_ACTIVE)
+ // No intrs found.
+ return -1;
+ // XXX - check for errors.
+
+ // Copy data.
+ void *tddata = GET_FLATPTR(td->buffer);
+ memcpy_far(GET_SEG(SS), data
+ , FLATPTR_TO_SEG(tddata), (void*)FLATPTR_TO_OFFSET(tddata)
+ , uhci_expected_length(token));
+
+ // Reenable this td.
+ struct uhci_td *next = (void*)(GET_FLATPTR(td->link) & ~UHCI_PTR_BITS);
+ SET_FLATPTR(pipe->next_td, next);
+ barrier();
+ SET_FLATPTR(td->status, (uhci_maxerr(0) | (status & TD_CTRL_LS)
+ | TD_CTRL_ACTIVE));
+
+ return 0;
+}
--- /dev/null
+#ifndef __USB_UHCI_H
+#define __USB_UHCI_H
+
+// usb-uhci.c
+void uhci_init(struct pci_device *pci, int busid);
+struct usb_pipe;
+void uhci_free_pipe(struct usb_pipe *p);
+struct usb_pipe *uhci_alloc_control_pipe(struct usb_pipe *dummy);
+int uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize
+ , void *data, int datasize);
+struct usb_pipe *uhci_alloc_bulk_pipe(struct usb_pipe *dummy);
+int uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize);
+struct usb_pipe *uhci_alloc_intr_pipe(struct usb_pipe *dummy, int frameexp);
+int uhci_poll_intr(struct usb_pipe *p, void *data);
+
+
+/****************************************************************
+ * uhci structs and flags
+ ****************************************************************/
+
+/* USB port status and control registers */
+#define USBPORTSC1 16
+#define USBPORTSC2 18
+#define USBPORTSC_CCS 0x0001 /* Current Connect Status
+ * ("device present") */
+#define USBPORTSC_CSC 0x0002 /* Connect Status Change */
+#define USBPORTSC_PE 0x0004 /* Port Enable */
+#define USBPORTSC_PEC 0x0008 /* Port Enable Change */
+#define USBPORTSC_DPLUS 0x0010 /* D+ high (line status) */
+#define USBPORTSC_DMINUS 0x0020 /* D- high (line status) */
+#define USBPORTSC_RD 0x0040 /* Resume Detect */
+#define USBPORTSC_RES1 0x0080 /* reserved, always 1 */
+#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */
+#define USBPORTSC_PR 0x0200 /* Port Reset */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
+
+/* Command register */
+#define USBCMD 0
+#define USBCMD_RS 0x0001 /* Run/Stop */
+#define USBCMD_HCRESET 0x0002 /* Host reset */
+#define USBCMD_GRESET 0x0004 /* Global reset */
+#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */
+#define USBCMD_FGR 0x0010 /* Force Global Resume */
+#define USBCMD_SWDBG 0x0020 /* SW Debug mode */
+#define USBCMD_CF 0x0040 /* Config Flag (sw only) */
+#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS 2
+#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */
+#define USBSTS_ERROR 0x0002 /* Interrupt due to error */
+#define USBSTS_RD 0x0004 /* Resume Detect */
+#define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */
+#define USBSTS_HCPE 0x0010 /* Host Controller Process Error:
+ * the schedule is buggy */
+#define USBSTS_HCH 0x0020 /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR 4
+#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */
+#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */
+#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */
+#define USBINTR_SP 0x0008 /* Short packet interrupt enable */
+
+#define USBFRNUM 6
+#define USBFLBASEADD 8
+#define USBSOF 12
+#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */
+
+struct uhci_framelist {
+ u32 links[1024];
+} PACKED;
+
+#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT 27
+#define TD_CTRL_LS (1 << 26) /* Low Speed Device */
+#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */
+#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */
+#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */
+#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */
+#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */
+#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */
+#define TD_CTRL_NAK (1 << 19) /* NAK Received */
+#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+ TD_CTRL_BABBLE | TD_CTRL_CRCTIMEO | \
+ TD_CTRL_BITSTUFF)
+#define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT)
+
+#define TD_TOKEN_DEVADDR_SHIFT 8
+#define TD_TOKEN_TOGGLE_SHIFT 19
+#define TD_TOKEN_TOGGLE (1 << 19)
+#define TD_TOKEN_EXPLEN_SHIFT 21
+#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */
+#define TD_TOKEN_PID_MASK 0xFF
+
+#define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
+ TD_TOKEN_EXPLEN_SHIFT)
+
+#define uhci_expected_length(token) ((((token) >> TD_TOKEN_EXPLEN_SHIFT) + \
+ 1) & TD_TOKEN_EXPLEN_MASK)
+
+struct uhci_td {
+ u32 link;
+ u32 status;
+ u32 token;
+ void *buffer;
+} PACKED;
+
+struct uhci_qh {
+ u32 link;
+ u32 element;
+} PACKED;
+
+#define UHCI_PTR_BITS 0x000F
+#define UHCI_PTR_TERM 0x0001
+#define UHCI_PTR_QH 0x0002
+#define UHCI_PTR_DEPTH 0x0004
+#define UHCI_PTR_BREADTH 0x0000
+
+#endif // usb-uhci.h
--- /dev/null
+// Main code for handling USB controllers and devices.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "config.h" // CONFIG_*
+#include "pci_regs.h" // PCI_CLASS_REVISION
+#include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI
+#include "usb-uhci.h" // uhci_init
+#include "usb-ohci.h" // ohci_init
+#include "usb-ehci.h" // ehci_init
+#include "usb-hid.h" // usb_keyboard_setup
+#include "usb-hub.h" // usb_hub_init
+#include "usb-msc.h" // usb_msc_init
+#include "usb.h" // struct usb_s
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Controller function wrappers
+ ****************************************************************/
+
+// Free an allocated control or bulk pipe.
+void
+free_pipe(struct usb_pipe *pipe)
+{
+ ASSERT32FLAT();
+ if (!pipe)
+ return;
+ switch (pipe->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_free_pipe(pipe);
+ case USB_TYPE_OHCI:
+ return ohci_free_pipe(pipe);
+ case USB_TYPE_EHCI:
+ return ehci_free_pipe(pipe);
+ }
+}
+
+// Allocate a control pipe to a default endpoint (which can only be
+// used by 32bit code)
+static struct usb_pipe *
+alloc_default_control_pipe(struct usb_pipe *dummy)
+{
+ switch (dummy->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_alloc_control_pipe(dummy);
+ case USB_TYPE_OHCI:
+ return ohci_alloc_control_pipe(dummy);
+ case USB_TYPE_EHCI:
+ return ehci_alloc_control_pipe(dummy);
+ }
+}
+
+// Send a message on a control pipe using the default control descriptor.
+static int
+send_control(struct usb_pipe *pipe, int dir, const void *cmd, int cmdsize
+ , void *data, int datasize)
+{
+ ASSERT32FLAT();
+ switch (pipe->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_control(pipe, dir, cmd, cmdsize, data, datasize);
+ case USB_TYPE_OHCI:
+ return ohci_control(pipe, dir, cmd, cmdsize, data, datasize);
+ case USB_TYPE_EHCI:
+ return ehci_control(pipe, dir, cmd, cmdsize, data, datasize);
+ }
+}
+
+// Fill "pipe" endpoint info from an endpoint descriptor.
+static void
+desc2pipe(struct usb_pipe *newpipe, struct usb_pipe *origpipe
+ , struct usb_endpoint_descriptor *epdesc)
+{
+ memcpy(newpipe, origpipe, sizeof(*newpipe));
+ newpipe->ep = epdesc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ newpipe->maxpacket = epdesc->wMaxPacketSize;
+}
+
+struct usb_pipe *
+alloc_bulk_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+ struct usb_pipe dummy;
+ desc2pipe(&dummy, pipe, epdesc);
+ switch (pipe->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_alloc_bulk_pipe(&dummy);
+ case USB_TYPE_OHCI:
+ return ohci_alloc_bulk_pipe(&dummy);
+ case USB_TYPE_EHCI:
+ return ehci_alloc_bulk_pipe(&dummy);
+ }
+}
+
+int
+usb_send_bulk(struct usb_pipe *pipe_fl, int dir, void *data, int datasize)
+{
+ switch (GET_FLATPTR(pipe_fl->type)) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_send_bulk(pipe_fl, dir, data, datasize);
+ case USB_TYPE_OHCI:
+ return ohci_send_bulk(pipe_fl, dir, data, datasize);
+ case USB_TYPE_EHCI:
+ return ehci_send_bulk(pipe_fl, dir, data, datasize);
+ }
+}
+
+struct usb_pipe *
+alloc_intr_pipe(struct usb_pipe *pipe, struct usb_endpoint_descriptor *epdesc)
+{
+ struct usb_pipe dummy;
+ desc2pipe(&dummy, pipe, epdesc);
+ // Find the exponential period of the requested time.
+ int period = epdesc->bInterval;
+ int frameexp;
+ if (pipe->speed != USB_HIGHSPEED)
+ frameexp = (period <= 0) ? 0 : __fls(period);
+ else
+ frameexp = (period <= 4) ? 0 : period - 4;
+ switch (pipe->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_alloc_intr_pipe(&dummy, frameexp);
+ case USB_TYPE_OHCI:
+ return ohci_alloc_intr_pipe(&dummy, frameexp);
+ case USB_TYPE_EHCI:
+ return ehci_alloc_intr_pipe(&dummy, frameexp);
+ }
+}
+
+int noinline
+usb_poll_intr(struct usb_pipe *pipe_fl, void *data)
+{
+ switch (GET_FLATPTR(pipe_fl->type)) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_poll_intr(pipe_fl, data);
+ case USB_TYPE_OHCI:
+ return ohci_poll_intr(pipe_fl, data);
+ case USB_TYPE_EHCI:
+ return ehci_poll_intr(pipe_fl, data);
+ }
+}
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+// Find the first endpoing of a given type in an interface description.
+struct usb_endpoint_descriptor *
+findEndPointDesc(struct usb_interface_descriptor *iface, int imax
+ , int type, int dir)
+{
+ struct usb_endpoint_descriptor *epdesc = (void*)&iface[1];
+ for (;;) {
+ if ((void*)epdesc >= (void*)iface + imax
+ || epdesc->bDescriptorType == USB_DT_INTERFACE) {
+ return NULL;
+ }
+ if (epdesc->bDescriptorType == USB_DT_ENDPOINT
+ && (epdesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir
+ && (epdesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type)
+ return epdesc;
+ epdesc = (void*)epdesc + epdesc->bLength;
+ }
+}
+
+// Send a message to the default control pipe of a device.
+int
+send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+ , void *data)
+{
+ return send_control(pipe, req->bRequestType & USB_DIR_IN
+ , req, sizeof(*req), data, req->wLength);
+}
+
+// Get the first 8 bytes of the device descriptor.
+static int
+get_device_info8(struct usb_pipe *pipe, struct usb_device_descriptor *dinfo)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_GET_DESCRIPTOR;
+ req.wValue = USB_DT_DEVICE<<8;
+ req.wIndex = 0;
+ req.wLength = 8;
+ return send_default_control(pipe, &req, dinfo);
+}
+
+static struct usb_config_descriptor *
+get_device_config(struct usb_pipe *pipe)
+{
+ struct usb_config_descriptor cfg;
+
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_GET_DESCRIPTOR;
+ req.wValue = USB_DT_CONFIG<<8;
+ req.wIndex = 0;
+ req.wLength = sizeof(cfg);
+ int ret = send_default_control(pipe, &req, &cfg);
+ if (ret)
+ return NULL;
+
+ void *config = malloc_tmphigh(cfg.wTotalLength);
+ if (!config)
+ return NULL;
+ req.wLength = cfg.wTotalLength;
+ ret = send_default_control(pipe, &req, config);
+ if (ret)
+ return NULL;
+ //hexdump(config, cfg.wTotalLength);
+ return config;
+}
+
+static int
+set_configuration(struct usb_pipe *pipe, u16 val)
+{
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_SET_CONFIGURATION;
+ req.wValue = val;
+ req.wIndex = 0;
+ req.wLength = 0;
+ return send_default_control(pipe, &req, NULL);
+}
+
+
+/****************************************************************
+ * Initialization and enumeration
+ ****************************************************************/
+
+// Assign an address to a device in the default state on the given
+// controller.
+static struct usb_pipe *
+usb_set_address(struct usbhub_s *hub, int port, int speed)
+{
+ ASSERT32FLAT();
+ struct usb_s *cntl = hub->cntl;
+ dprintf(3, "set_address %p\n", cntl);
+ if (cntl->maxaddr >= USB_MAXADDR)
+ return NULL;
+
+ struct usb_pipe *defpipe = cntl->defaultpipe;
+ if (!defpipe) {
+ // Create a pipe for the default address.
+ struct usb_pipe dummy;
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.cntl = cntl;
+ dummy.type = cntl->type;
+ dummy.maxpacket = 8;
+ dummy.path = (u64)-1;
+ cntl->defaultpipe = defpipe = alloc_default_control_pipe(&dummy);
+ if (!defpipe)
+ return NULL;
+ }
+ defpipe->speed = speed;
+ if (hub->pipe) {
+ if (hub->pipe->speed == USB_HIGHSPEED) {
+ defpipe->tt_devaddr = hub->pipe->devaddr;
+ defpipe->tt_port = port;
+ } else {
+ defpipe->tt_devaddr = hub->pipe->tt_devaddr;
+ defpipe->tt_port = hub->pipe->tt_port;
+ }
+ } else {
+ defpipe->tt_devaddr = defpipe->tt_port = 0;
+ }
+
+ msleep(USB_TIME_RSTRCY);
+
+ struct usb_ctrlrequest req;
+ req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
+ req.bRequest = USB_REQ_SET_ADDRESS;
+ req.wValue = cntl->maxaddr + 1;
+ req.wIndex = 0;
+ req.wLength = 0;
+ int ret = send_default_control(defpipe, &req, NULL);
+ if (ret)
+ return NULL;
+
+ msleep(USB_TIME_SETADDR_RECOVERY);
+
+ cntl->maxaddr++;
+ defpipe->devaddr = cntl->maxaddr;
+ struct usb_pipe *pipe = alloc_default_control_pipe(defpipe);
+ defpipe->devaddr = 0;
+ if (hub->pipe)
+ pipe->path = hub->pipe->path;
+ pipe->path = (pipe->path << 8) | port;
+ return pipe;
+}
+
+// Called for every found device - see if a driver is available for
+// this device and do setup if so.
+static int
+configure_usb_device(struct usb_pipe *pipe)
+{
+ ASSERT32FLAT();
+ dprintf(3, "config_usb: %p\n", pipe);
+
+ // Set the max packet size for endpoint 0 of this device.
+ struct usb_device_descriptor dinfo;
+ int ret = get_device_info8(pipe, &dinfo);
+ if (ret)
+ return 0;
+ dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n"
+ , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass
+ , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0);
+ if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64)
+ return 0;
+ pipe->maxpacket = dinfo.bMaxPacketSize0;
+
+ // Get configuration
+ struct usb_config_descriptor *config = get_device_config(pipe);
+ if (!config)
+ return 0;
+
+ // Determine if a driver exists for this device - only look at the
+ // first interface of the first configuration.
+ struct usb_interface_descriptor *iface = (void*)(&config[1]);
+ if (iface->bInterfaceClass != USB_CLASS_HID
+ && iface->bInterfaceClass != USB_CLASS_MASS_STORAGE
+ && iface->bInterfaceClass != USB_CLASS_HUB)
+ // Not a supported device.
+ goto fail;
+
+ // Set the configuration.
+ ret = set_configuration(pipe, config->bConfigurationValue);
+ if (ret)
+ goto fail;
+
+ // Configure driver.
+ int imax = (void*)config + config->wTotalLength - (void*)iface;
+ if (iface->bInterfaceClass == USB_CLASS_HUB)
+ ret = usb_hub_init(pipe);
+ else if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
+ ret = usb_msc_init(pipe, iface, imax);
+ else
+ ret = usb_hid_init(pipe, iface, imax);
+ if (ret)
+ goto fail;
+
+ free(config);
+ return 1;
+fail:
+ free(config);
+ return 0;
+}
+
+static void
+usb_init_hub_port(void *data)
+{
+ struct usbhub_s *hub = data;
+ u32 port = hub->port; // XXX - find better way to pass port
+
+ // Detect if device present (and possibly start reset)
+ int ret = hub->op->detect(hub, port);
+ if (ret)
+ // No device present
+ goto done;
+
+ // Reset port and determine device speed
+ mutex_lock(&hub->cntl->resetlock);
+ ret = hub->op->reset(hub, port);
+ if (ret < 0)
+ // Reset failed
+ goto resetfail;
+
+ // Set address of port
+ struct usb_pipe *pipe = usb_set_address(hub, port, ret);
+ if (!pipe) {
+ hub->op->disconnect(hub, port);
+ goto resetfail;
+ }
+ mutex_unlock(&hub->cntl->resetlock);
+
+ // Configure the device
+ int count = configure_usb_device(pipe);
+ free_pipe(pipe);
+ if (!count)
+ hub->op->disconnect(hub, port);
+ hub->devcount += count;
+done:
+ hub->threads--;
+ return;
+
+resetfail:
+ mutex_unlock(&hub->cntl->resetlock);
+ goto done;
+}
+
+void
+usb_enumerate(struct usbhub_s *hub)
+{
+ u32 portcount = hub->portcount;
+ hub->threads = portcount;
+
+ // Launch a thread for every port.
+ int i;
+ for (i=0; i<portcount; i++) {
+ hub->port = i;
+ run_thread(usb_init_hub_port, hub);
+ }
+
+ // Wait for threads to complete.
+ while (hub->threads)
+ yield();
+}
+
+void
+usb_setup(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_USB)
+ return;
+
+ dprintf(3, "init usb\n");
+
+ // Look for USB controllers
+ int count = 0;
+ struct pci_device *ehcipci = PCIDevices;
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->class != PCI_CLASS_SERIAL_USB)
+ continue;
+
+ if (pci->bdf >= ehcipci->bdf) {
+ // Check to see if this device has an ehci controller
+ int found = 0;
+ ehcipci = pci;
+ for (;;) {
+ if (pci_classprog(ehcipci) == PCI_CLASS_SERIAL_USB_EHCI) {
+ // Found an ehci controller.
+ int ret = ehci_init(ehcipci, count++, pci);
+ if (ret)
+ // Error
+ break;
+ count += found;
+ pci = ehcipci;
+ break;
+ }
+ if (ehcipci->class == PCI_CLASS_SERIAL_USB)
+ found++;
+ ehcipci = ehcipci->next;
+ if (!ehcipci || (pci_bdf_to_busdev(ehcipci->bdf)
+ != pci_bdf_to_busdev(pci->bdf)))
+ // No ehci controller found.
+ break;
+ }
+ }
+
+ if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_UHCI)
+ uhci_init(pci, count++);
+ else if (pci_classprog(pci) == PCI_CLASS_SERIAL_USB_OHCI)
+ ohci_init(pci, count++);
+ }
+}
--- /dev/null
+// USB functions and data.
+#ifndef __USB_H
+#define __USB_H
+
+#include "util.h" // struct mutex_s
+
+// Information on a USB end point.
+struct usb_pipe {
+ struct usb_s *cntl;
+ u64 path;
+ u8 type;
+ u8 ep;
+ u8 devaddr;
+ u8 speed;
+ u16 maxpacket;
+ u8 tt_devaddr;
+ u8 tt_port;
+};
+
+// Common information for usb controllers.
+struct usb_s {
+ struct usb_pipe *defaultpipe;
+ struct mutex_s resetlock;
+ struct pci_device *pci;
+ int busid;
+ u8 type;
+ u8 maxaddr;
+};
+
+// Information for enumerating USB hubs
+struct usbhub_s {
+ struct usbhub_op_s *op;
+ struct usb_pipe *pipe;
+ struct usb_s *cntl;
+ struct mutex_s lock;
+ u32 powerwait;
+ u32 port;
+ u32 threads;
+ u32 portcount;
+ u32 devcount;
+};
+
+// Hub callback (32bit) info
+struct usbhub_op_s {
+ int (*detect)(struct usbhub_s *hub, u32 port);
+ int (*reset)(struct usbhub_s *hub, u32 port);
+ void (*disconnect)(struct usbhub_s *hub, u32 port);
+};
+
+#define USB_TYPE_UHCI 1
+#define USB_TYPE_OHCI 2
+#define USB_TYPE_EHCI 3
+
+#define USB_FULLSPEED 0
+#define USB_LOWSPEED 1
+#define USB_HIGHSPEED 2
+
+#define USB_MAXADDR 127
+
+
+/****************************************************************
+ * usb structs and flags
+ ****************************************************************/
+
+// USB mandated timings (in ms)
+#define USB_TIME_SIGATT 100
+#define USB_TIME_ATTDB 100
+#define USB_TIME_DRST 10
+#define USB_TIME_DRSTR 50
+#define USB_TIME_RSTRCY 10
+
+#define USB_TIME_SETADDR_RECOVERY 2
+
+#define USB_PID_OUT 0xe1
+#define USB_PID_IN 0x69
+#define USB_PID_SETUP 0x2d
+
+#define USB_DIR_OUT 0 /* to device */
+#define USB_DIR_IN 0x80 /* to host */
+
+#define USB_TYPE_MASK (0x03 << 5)
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+#define USB_RECIP_MASK 0x1f
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+struct usb_ctrlrequest {
+ u8 bRequestType;
+ u8 bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+} PACKED;
+
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+#define USB_DT_DEVICE_QUALIFIER 0x06
+#define USB_DT_OTHER_SPEED_CONFIG 0x07
+
+struct usb_device_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u16 bcdUSB;
+ u8 bDeviceClass;
+ u8 bDeviceSubClass;
+ u8 bDeviceProtocol;
+ u8 bMaxPacketSize0;
+ u16 idVendor;
+ u16 idProduct;
+ u16 bcdDevice;
+ u8 iManufacturer;
+ u8 iProduct;
+ u8 iSerialNumber;
+ u8 bNumConfigurations;
+} PACKED;
+
+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PHYSICAL 5
+#define USB_CLASS_STILL_IMAGE 6
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+
+struct usb_config_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u16 wTotalLength;
+ u8 bNumInterfaces;
+ u8 bConfigurationValue;
+ u8 iConfiguration;
+ u8 bmAttributes;
+ u8 bMaxPower;
+} PACKED;
+
+struct usb_interface_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u8 bInterfaceNumber;
+ u8 bAlternateSetting;
+ u8 bNumEndpoints;
+ u8 bInterfaceClass;
+ u8 bInterfaceSubClass;
+ u8 bInterfaceProtocol;
+ u8 iInterface;
+} PACKED;
+
+struct usb_endpoint_descriptor {
+ u8 bLength;
+ u8 bDescriptorType;
+
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+ u16 wMaxPacketSize;
+ u8 bInterval;
+} PACKED;
+
+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL 0
+#define USB_ENDPOINT_XFER_ISOC 1
+#define USB_ENDPOINT_XFER_BULK 2
+#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
+
+
+/****************************************************************
+ * function defs
+ ****************************************************************/
+
+// usb.c
+void usb_setup(void);
+void usb_enumerate(struct usbhub_s *hub);
+int send_default_control(struct usb_pipe *pipe, const struct usb_ctrlrequest *req
+ , void *data);
+int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
+void free_pipe(struct usb_pipe *pipe);
+struct usb_pipe *alloc_bulk_pipe(struct usb_pipe *pipe
+ , struct usb_endpoint_descriptor *epdesc);
+struct usb_pipe *alloc_intr_pipe(struct usb_pipe *pipe
+ , struct usb_endpoint_descriptor *epdesc);
+int usb_poll_intr(struct usb_pipe *pipe, void *data);
+struct usb_endpoint_descriptor *findEndPointDesc(
+ struct usb_interface_descriptor *iface, int imax, int type, int dir);
+u32 mkendpFromDesc(struct usb_pipe *pipe
+ , struct usb_endpoint_descriptor *epdesc);
+
+#endif // usb.h
--- /dev/null
+// Misc utility functions.
+//
+// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // call16
+#include "bregs.h" // struct bregs
+#include "config.h" // BUILD_STACK_ADDR
+
+
+/****************************************************************
+ * 16bit calls
+ ****************************************************************/
+
+// Call a function with a specified register state. Note that on
+// return, the interrupt enable/disable flag may be altered.
+inline void
+call16(struct bregs *callregs)
+{
+ if (!MODESEGMENT && getesp() > BUILD_STACK_ADDR)
+ panic("call16 with invalid stack\n");
+ asm volatile(
+#if MODE16 == 1
+ "calll __call16\n"
+ "cli\n"
+ "cld"
+#else
+ "calll __call16_from32"
+#endif
+ : "+a" (callregs), "+m" (*callregs)
+ :
+ : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+call16big(struct bregs *callregs)
+{
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
+ panic("call16 with invalid stack\n");
+ asm volatile(
+ "calll __call16big_from32"
+ : "+a" (callregs), "+m" (*callregs)
+ :
+ : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+}
+
+inline void
+__call16_int(struct bregs *callregs, u16 offset)
+{
+ if (MODESEGMENT)
+ callregs->code.seg = GET_SEG(CS);
+ else
+ callregs->code.seg = SEG_BIOS;
+ callregs->code.offset = offset;
+ call16(callregs);
+}
+
+
+/****************************************************************
+ * String ops
+ ****************************************************************/
+
+// Sum the bytes in the specified area.
+u8
+checksum_far(u16 buf_seg, void *buf_far, u32 len)
+{
+ SET_SEG(ES, buf_seg);
+ u32 i;
+ u8 sum = 0;
+ for (i=0; i<len; i++)
+ sum += GET_VAR(ES, ((u8*)buf_far)[i]);
+ return sum;
+}
+
+u8
+checksum(void *buf, u32 len)
+{
+ return checksum_far(GET_SEG(SS), buf, len);
+}
+
+size_t
+strlen(const char *s)
+{
+ if (__builtin_constant_p(s))
+ return __builtin_strlen(s);
+ const char *p = s;
+ while (*p)
+ p++;
+ return p-s;
+}
+
+// Compare two areas of memory.
+int
+memcmp(const void *s1, const void *s2, size_t n)
+{
+ while (n) {
+ if (*(u8*)s1 != *(u8*)s2)
+ return *(u8*)s1 < *(u8*)s2 ? -1 : 1;
+ s1++;
+ s2++;
+ n--;
+ }
+ return 0;
+}
+
+// Compare two strings.
+int
+strcmp(const char *s1, const char *s2)
+{
+ for (;;) {
+ if (*s1 != *s2)
+ return *s1 < *s2 ? -1 : 1;
+ if (! *s1)
+ return 0;
+ s1++;
+ s2++;
+ }
+}
+
+inline void
+memset_far(u16 d_seg, void *d_far, u8 c, size_t len)
+{
+ SET_SEG(ES, d_seg);
+ asm volatile(
+ "rep stosb %%es:(%%di)"
+ : "+c"(len), "+D"(d_far)
+ : "a"(c)
+ : "cc", "memory");
+}
+
+inline void
+memset16_far(u16 d_seg, void *d_far, u16 c, size_t len)
+{
+ len /= 2;
+ SET_SEG(ES, d_seg);
+ asm volatile(
+ "rep stosw %%es:(%%di)"
+ : "+c"(len), "+D"(d_far)
+ : "a"(c)
+ : "cc", "memory");
+}
+
+void *
+memset(void *s, int c, size_t n)
+{
+ while (n)
+ ((char *)s)[--n] = c;
+ return s;
+}
+
+void memset_fl(void *ptr, u8 val, size_t size)
+{
+ if (MODESEGMENT)
+ memset_far(FLATPTR_TO_SEG(ptr), (void*)(FLATPTR_TO_OFFSET(ptr)),
+ val, size);
+ else
+ memset(ptr, val, size);
+}
+
+inline void
+memcpy_far(u16 d_seg, void *d_far, u16 s_seg, const void *s_far, size_t len)
+{
+ SET_SEG(ES, d_seg);
+ u16 bkup_ds;
+ asm volatile(
+ "movw %%ds, %w0\n"
+ "movw %w4, %%ds\n"
+ "rep movsb (%%si),%%es:(%%di)\n"
+ "movw %w0, %%ds"
+ : "=&r"(bkup_ds), "+c"(len), "+S"(s_far), "+D"(d_far)
+ : "r"(s_seg)
+ : "cc", "memory");
+}
+
+inline void
+memcpy_fl(void *d_fl, const void *s_fl, size_t len)
+{
+ if (MODESEGMENT)
+ memcpy_far(FLATPTR_TO_SEG(d_fl), (void*)FLATPTR_TO_OFFSET(d_fl)
+ , FLATPTR_TO_SEG(s_fl), (void*)FLATPTR_TO_OFFSET(s_fl)
+ , len);
+ else
+ memcpy(d_fl, s_fl, len);
+}
+
+void *
+#undef memcpy
+memcpy(void *d1, const void *s1, size_t len)
+#if MODESEGMENT == 0
+#define memcpy __builtin_memcpy
+#endif
+{
+ SET_SEG(ES, GET_SEG(SS));
+ void *d = d1;
+ if (((u32)d1 | (u32)s1 | len) & 3) {
+ // non-aligned memcpy
+ asm volatile(
+ "rep movsb (%%esi),%%es:(%%edi)"
+ : "+c"(len), "+S"(s1), "+D"(d)
+ : : "cc", "memory");
+ return d1;
+ }
+ // Common case - use 4-byte copy
+ len /= 4;
+ asm volatile(
+ "rep movsl (%%esi),%%es:(%%edi)"
+ : "+c"(len), "+S"(s1), "+D"(d)
+ : : "cc", "memory");
+ return d1;
+}
+
+// Copy to/from memory mapped IO. IO mem is very slow, so yield
+// periodically.
+void
+iomemcpy(void *d, const void *s, u32 len)
+{
+ yield();
+ while (len > 3) {
+ u32 copylen = len;
+ if (copylen > 2048)
+ copylen = 2048;
+ copylen /= 4;
+ len -= copylen * 4;
+ asm volatile(
+ "rep movsl (%%esi),%%es:(%%edi)"
+ : "+c"(copylen), "+S"(s), "+D"(d)
+ : : "cc", "memory");
+ yield();
+ }
+ if (len)
+ // Copy any remaining bytes.
+ memcpy(d, s, len);
+}
+
+void *
+memmove(void *d, const void *s, size_t len)
+{
+ if (s >= d)
+ return memcpy(d, s, len);
+
+ d += len-1;
+ s += len-1;
+ while (len--) {
+ *(char*)d = *(char*)s;
+ d--;
+ s--;
+ }
+
+ return d;
+}
+
+// Copy a string - truncating it if necessary.
+char *
+strtcpy(char *dest, const char *src, size_t len)
+{
+ char *d = dest;
+ while (--len && *src != '\0')
+ *d++ = *src++;
+ *d = '\0';
+ return dest;
+}
+
+// locate first occurance of character c in the string s
+char *
+strchr(const char *s, int c)
+{
+ for (; *s; s++)
+ if (*s == c)
+ return (char*)s;
+ return NULL;
+}
+
+// Remove any trailing blank characters (spaces, new lines, carriage returns)
+void
+nullTrailingSpace(char *buf)
+{
+ int len = strlen(buf);
+ char *end = &buf[len-1];
+ while (end >= buf && *end <= ' ')
+ *(end--) = '\0';
+}
+
+/****************************************************************
+ * Keyboard calls
+ ****************************************************************/
+
+// See if a keystroke is pending in the keyboard buffer.
+static int
+check_for_keystroke(void)
+{
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ br.ah = 1;
+ call16_int(0x16, &br);
+ return !(br.flags & F_ZF);
+}
+
+// Return a keystroke - waiting forever if necessary.
+static int
+get_raw_keystroke(void)
+{
+ struct bregs br;
+ memset(&br, 0, sizeof(br));
+ br.flags = F_IF;
+ call16_int(0x16, &br);
+ return br.ah;
+}
+
+// Read a keystroke - waiting up to 'msec' milliseconds.
+int
+get_keystroke(int msec)
+{
+ u32 end = calc_future_timer(msec);
+ for (;;) {
+ if (check_for_keystroke())
+ return get_raw_keystroke();
+ if (check_timer(end))
+ return -1;
+ wait_irq();
+ }
+}
--- /dev/null
+// Basic x86 asm functions and function defs.
+//
+// Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include "types.h" // u32
+
+static inline void irq_disable(void)
+{
+ asm volatile("cli": : :"memory");
+}
+
+static inline void irq_enable(void)
+{
+ asm volatile("sti": : :"memory");
+}
+
+static inline unsigned long irq_save(void)
+{
+ unsigned long flags;
+ asm volatile("pushfl ; popl %0" : "=g" (flags): :"memory");
+ irq_disable();
+ return flags;
+}
+
+static inline void irq_restore(unsigned long flags)
+{
+ asm volatile("pushl %0 ; popfl" : : "g" (flags) : "memory", "cc");
+}
+
+static inline void cpu_relax(void)
+{
+ asm volatile("rep ; nop": : :"memory");
+}
+
+static inline void nop(void)
+{
+ asm volatile("nop");
+}
+
+static inline void hlt(void)
+{
+ asm volatile("hlt": : :"memory");
+}
+
+static inline void wbinvd(void)
+{
+ asm volatile("wbinvd": : :"memory");
+}
+
+#define CPUID_MSR (1 << 5)
+#define CPUID_APIC (1 << 9)
+#define CPUID_MTRR (1 << 12)
+static inline void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ asm("cpuid"
+ : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+ : "0" (index));
+}
+
+static inline u32 getcr0(void) {
+ u32 cr0;
+ asm("movl %%cr0, %0" : "=r"(cr0));
+ return cr0;
+}
+static inline void setcr0(u32 cr0) {
+ asm("movl %0, %%cr0" : : "r"(cr0));
+}
+
+static inline u64 rdmsr(u32 index)
+{
+ u64 ret;
+ asm ("rdmsr" : "=A"(ret) : "c"(index));
+ return ret;
+}
+
+static inline void wrmsr(u32 index, u64 val)
+{
+ asm volatile ("wrmsr" : : "c"(index), "A"(val));
+}
+
+static inline u64 rdtscll(void)
+{
+ u64 val;
+ asm volatile("rdtsc" : "=A" (val));
+ return val;
+}
+
+static inline u32 __ffs(u32 word)
+{
+ asm("bsf %1,%0"
+ : "=r" (word)
+ : "rm" (word));
+ return word;
+}
+static inline u32 __fls(u32 word)
+{
+ asm("bsr %1,%0"
+ : "=r" (word)
+ : "rm" (word));
+ return word;
+}
+
+static inline u16 __htons_constant(u16 val) {
+ return (val<<8) | (val>>8);
+}
+static inline u32 __htonl_constant(u32 val) {
+ return (val<<24) | ((val&0xff00)<<8) | ((val&0xff0000)>>8) | (val>>24);
+}
+static inline u32 __htonl(u32 val) {
+ asm("bswapl %0" : "+r"(val));
+ return val;
+}
+#define htonl(x) (__builtin_constant_p((u32)(x)) ? __htonl_constant(x) : __htonl(x))
+#define ntohl(x) htonl(x)
+#define htons(x) __htons_constant(x)
+#define ntohs(x) htons(x)
+
+static inline u16 cpu_to_le16(u16 x)
+{
+ return x;
+}
+
+static inline u32 cpu_to_le32(u32 x)
+{
+ return x;
+}
+
+static inline u32 getesp(void) {
+ u32 esp;
+ asm("movl %%esp, %0" : "=rm"(esp));
+ return esp;
+}
+
+static inline void writel(void *addr, u32 val) {
+ *(volatile u32 *)addr = val;
+}
+static inline void writew(void *addr, u16 val) {
+ *(volatile u16 *)addr = val;
+}
+static inline void writeb(void *addr, u8 val) {
+ *(volatile u8 *)addr = val;
+}
+static inline u32 readl(const void *addr) {
+ return *(volatile const u32 *)addr;
+}
+static inline u16 readw(const void *addr) {
+ return *(volatile const u16 *)addr;
+}
+static inline u8 readb(const void *addr) {
+ return *(volatile const u8 *)addr;
+}
+
+#define call16_simpint(nr, peax, pflags) do { \
+ ASSERT16(); \
+ asm volatile( \
+ "pushl %%ebp\n" \
+ "sti\n" \
+ "stc\n" \
+ "int %2\n" \
+ "pushfl\n" \
+ "popl %1\n" \
+ "cli\n" \
+ "cld\n" \
+ "popl %%ebp" \
+ : "+a"(*peax), "=c"(*pflags) \
+ : "i"(nr) \
+ : "ebx", "edx", "esi", "edi", "cc", "memory"); \
+ } while (0)
+
+// GDT bits
+#define GDT_CODE (0x9bULL << 40) // Code segment - P,R,A bits also set
+#define GDT_DATA (0x93ULL << 40) // Data segment - W,A bits also set
+#define GDT_B (0x1ULL << 54) // Big flag
+#define GDT_G (0x1ULL << 55) // Granularity flag
+// GDT bits for segment base
+#define GDT_BASE(v) ((((u64)(v) & 0xff000000) << 32) \
+ | (((u64)(v) & 0x00ffffff) << 16))
+// GDT bits for segment limit (0-1Meg)
+#define GDT_LIMIT(v) ((((u64)(v) & 0x000f0000) << 32) \
+ | (((u64)(v) & 0x0000ffff) << 0))
+// GDT bits for segment limit (0-4Gig in 4K chunks)
+#define GDT_GRANLIMIT(v) (GDT_G | GDT_LIMIT((v) >> 12))
+
+struct descloc_s {
+ u16 length;
+ u32 addr;
+} PACKED;
+
+// util.c
+struct bregs;
+inline void call16(struct bregs *callregs);
+inline void call16big(struct bregs *callregs);
+inline void __call16_int(struct bregs *callregs, u16 offset);
+#define call16_int(nr, callregs) do { \
+ extern void irq_trampoline_ ##nr (); \
+ __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \
+ } while (0)
+u8 checksum_far(u16 buf_seg, void *buf_far, u32 len);
+u8 checksum(void *buf, u32 len);
+size_t strlen(const char *s);
+int memcmp(const void *s1, const void *s2, size_t n);
+int strcmp(const char *s1, const char *s2);
+inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len);
+inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len);
+void *memset(void *s, int c, size_t n);
+void memset_fl(void *ptr, u8 val, size_t size);
+inline void memcpy_far(u16 d_seg, void *d_far
+ , u16 s_seg, const void *s_far, size_t len);
+void memcpy_fl(void *d_fl, const void *s_fl, size_t len);
+void *memcpy(void *d1, const void *s1, size_t len);
+#if MODESEGMENT == 0
+#define memcpy __builtin_memcpy
+#endif
+void iomemcpy(void *d, const void *s, u32 len);
+void *memmove(void *d, const void *s, size_t len);
+char *strtcpy(char *dest, const char *src, size_t len);
+char *strchr(const char *s, int c);
+void nullTrailingSpace(char *buf);
+int get_keystroke(int msec);
+
+// stacks.c
+u32 call32(void *func, u32 eax, u32 errret);
+inline u32 stack_hop(u32 eax, u32 edx, void *func);
+extern struct thread_info MainThread;
+extern int CanPreempt;
+struct thread_info *getCurThread(void);
+void yield(void);
+void wait_irq(void);
+void run_thread(void (*func)(void*), void *data);
+void wait_threads(void);
+struct mutex_s { u32 isLocked; };
+void mutex_lock(struct mutex_s *mutex);
+void mutex_unlock(struct mutex_s *mutex);
+void start_preempt(void);
+void finish_preempt(void);
+int wait_preempt(void);
+void check_preempt(void);
+
+// output.c
+void debug_serial_setup(void);
+void panic(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2))) __noreturn;
+void printf(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+int snprintf(char *str, size_t size, const char *fmt, ...)
+ __attribute__ ((format (printf, 3, 4)));
+char * znprintf(size_t size, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+void __dprintf(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+void __debug_enter(struct bregs *regs, const char *fname);
+void __debug_isr(const char *fname);
+void __debug_stub(struct bregs *regs, int lineno, const char *fname);
+void __warn_invalid(struct bregs *regs, int lineno, const char *fname);
+void __warn_unimplemented(struct bregs *regs, int lineno, const char *fname);
+void __warn_internalerror(int lineno, const char *fname);
+void __warn_noalloc(int lineno, const char *fname);
+void __warn_timeout(int lineno, const char *fname);
+void __set_invalid(struct bregs *regs, int lineno, const char *fname);
+void __set_unimplemented(struct bregs *regs, int lineno, const char *fname);
+void __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname);
+void __set_code_unimplemented(struct bregs *regs, u32 linecode
+ , const char *fname);
+void hexdump(const void *d, int len);
+
+#define dprintf(lvl, fmt, args...) do { \
+ if (CONFIG_DEBUG_LEVEL && (lvl) <= CONFIG_DEBUG_LEVEL) \
+ __dprintf((fmt) , ##args ); \
+ } while (0)
+#define debug_enter(regs, lvl) do { \
+ if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL) \
+ __debug_enter((regs), __func__); \
+ } while (0)
+#define debug_isr(lvl) do { \
+ if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL) \
+ __debug_isr(__func__); \
+ } while (0)
+#define debug_stub(regs) \
+ __debug_stub((regs), __LINE__, __func__)
+#define warn_invalid(regs) \
+ __warn_invalid((regs), __LINE__, __func__)
+#define warn_unimplemented(regs) \
+ __warn_unimplemented((regs), __LINE__, __func__)
+#define warn_internalerror() \
+ __warn_internalerror(__LINE__, __func__)
+#define warn_noalloc() \
+ __warn_noalloc(__LINE__, __func__)
+#define warn_timeout() \
+ __warn_timeout(__LINE__, __func__)
+#define set_invalid(regs) \
+ __set_invalid((regs), __LINE__, __func__)
+#define set_code_invalid(regs, code) \
+ __set_code_invalid((regs), (code) | (__LINE__ << 8), __func__)
+#define set_unimplemented(regs) \
+ __set_unimplemented((regs), __LINE__, __func__)
+#define set_code_unimplemented(regs, code) \
+ __set_code_unimplemented((regs), (code) | (__LINE__ << 8), __func__)
+
+// kbd.c
+void kbd_setup(void);
+void handle_15c2(struct bregs *regs);
+void process_key(u8 key);
+
+// mouse.c
+void mouse_setup(void);
+void process_mouse(u8 data);
+
+// system.c
+extern u32 RamSize;
+extern u64 RamSizeOver4G;
+void mathcp_setup(void);
+
+// serial.c
+void serial_setup(void);
+void lpt_setup(void);
+
+// clock.c
+#define PIT_TICK_RATE 1193180 // Underlying HZ of PIT
+#define PIT_TICK_INTERVAL 65536 // Default interval for 18.2Hz timer
+static inline int check_tsc(u64 end) {
+ return (s64)(rdtscll() - end) > 0;
+}
+void timer_setup(void);
+void ndelay(u32 count);
+void udelay(u32 count);
+void mdelay(u32 count);
+void nsleep(u32 count);
+void usleep(u32 count);
+void msleep(u32 count);
+u64 calc_future_tsc(u32 msecs);
+u64 calc_future_tsc_usec(u32 usecs);
+u32 calc_future_timer_ticks(u32 count);
+u32 calc_future_timer(u32 msecs);
+int check_timer(u32 end);
+void handle_1583(struct bregs *regs);
+void handle_1586(struct bregs *regs);
+void useRTC(void);
+void releaseRTC(void);
+
+// apm.c
+void apm_shutdown(void);
+void handle_1553(struct bregs *regs);
+
+// pcibios.c
+void handle_1ab1(struct bregs *regs);
+void bios32_setup(void);
+
+// shadow.c
+void make_bios_writable(void);
+void make_bios_readonly(void);
+void qemu_prep_reset(void);
+
+// pciinit.c
+extern const u8 pci_irqs[4];
+void pci_setup(void);
+
+// smm.c
+void smm_init(void);
+
+// smp.c
+extern u32 CountCPUs;
+extern u32 MaxCountCPUs;
+void wrmsr_smp(u32 index, u64 val);
+void smp_probe(void);
+
+// coreboot.c
+extern const char *CBvendor, *CBpart;
+struct cbfs_file;
+struct cbfs_file *cbfs_finddatafile(const char *fname);
+struct cbfs_file *cbfs_findprefix(const char *prefix, struct cbfs_file *last);
+u32 cbfs_datasize(struct cbfs_file *file);
+const char *cbfs_filename(struct cbfs_file *file);
+int cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen);
+void cbfs_run_payload(struct cbfs_file *file);
+void coreboot_copy_biostable(void);
+void cbfs_payload_setup(void);
+void coreboot_setup(void);
+
+// biostable.c
+void copy_pir(void *pos);
+void copy_mptable(void *pos);
+void copy_acpi_rsdp(void *pos);
+void copy_smbios(void *pos);
+
+// vgahooks.c
+void handle_155f(struct bregs *regs);
+struct pci_device;
+void vgahook_setup(struct pci_device *pci);
+
+// optionroms.c
+void call_bcv(u16 seg, u16 ip);
+void optionrom_setup(void);
+void vga_setup(void);
+void s3_resume_vga_init(void);
+extern u32 RomEnd;
+extern int ScreenAndDebug;
+
+// bootsplash.c
+void enable_vga_console(void);
+void enable_bootsplash(void);
+void disable_bootsplash(void);
+
+// resume.c
+extern int HaveRunPost;
+void init_dma(void);
+
+// pnpbios.c
+#define PNP_SIGNATURE 0x506e5024 // $PnP
+u16 get_pnp_offset(void);
+void pnp_setup(void);
+
+// pmm.c
+extern struct zone_s ZoneLow, ZoneHigh, ZoneFSeg, ZoneTmpLow, ZoneTmpHigh;
+void malloc_setup(void);
+void malloc_fixupreloc(void);
+void malloc_finalize(void);
+void *pmm_malloc(struct zone_s *zone, u32 handle, u32 size, u32 align);
+int pmm_free(void *data);
+void pmm_setup(void);
+void pmm_finalize(void);
+#define PMM_DEFAULT_HANDLE 0xFFFFFFFF
+// Minimum alignment of malloc'd memory
+#define MALLOC_MIN_ALIGN 16
+// Helper functions for memory allocation.
+static inline void *malloc_low(u32 size) {
+ return pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_high(u32 size) {
+ return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_fseg(u32 size) {
+ return pmm_malloc(&ZoneFSeg, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmplow(u32 size) {
+ return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmphigh(u32 size) {
+ return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, size, MALLOC_MIN_ALIGN);
+}
+static inline void *malloc_tmp(u32 size) {
+ void *ret = malloc_tmphigh(size);
+ if (ret)
+ return ret;
+ return malloc_tmplow(size);
+}
+static inline void *memalign_low(u32 align, u32 size) {
+ return pmm_malloc(&ZoneLow, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_high(u32 align, u32 size) {
+ return pmm_malloc(&ZoneHigh, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmplow(u32 align, u32 size) {
+ return pmm_malloc(&ZoneTmpLow, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmphigh(u32 align, u32 size) {
+ return pmm_malloc(&ZoneTmpHigh, PMM_DEFAULT_HANDLE, size, align);
+}
+static inline void *memalign_tmp(u32 align, u32 size) {
+ void *ret = memalign_tmphigh(align, size);
+ if (ret)
+ return ret;
+ return memalign_tmplow(align, size);
+}
+static inline void free(void *data) {
+ pmm_free(data);
+}
+
+// mtrr.c
+void mtrr_setup(void);
+
+// romlayout.S
+void reset_vector(void) __noreturn;
+
+// misc.c
+extern u8 BiosChecksum;
+
+// version (auto generated file out/version.c)
+extern const char VERSION[];
+
+#endif // util.h
--- /dev/null
+// Hooks for via vgabios calls into main bios.
+//
+// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "bregs.h" // set_code_invalid
+#include "biosvar.h" // GET_GLOBAL
+#include "pci.h" // pci_find_device
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "pci_ids.h" // PCI_VENDOR_ID_VIA
+#include "util.h" // handle_155f
+#include "config.h" // CONFIG_*
+
+#define VH_VIA 1
+#define VH_INTEL 2
+
+int VGAHookHandlerType VAR16VISIBLE;
+
+static void
+handle_155fXX(struct bregs *regs)
+{
+ set_code_unimplemented(regs, RET_EUNSUPPORTED);
+}
+
+
+/****************************************************************
+ * Via hooks
+ ****************************************************************/
+
+int ViaFBsize VAR16VISIBLE, ViaRamSpeed VAR16VISIBLE;
+
+static void
+via_155f01(struct bregs *regs)
+{
+ regs->eax = 0x5f;
+ regs->cl = 2; // panel type = 2 = 1024 * 768
+ set_success(regs);
+ dprintf(1, "Warning: VGA panel type is hardcoded\n");
+}
+
+static void
+via_155f02(struct bregs *regs)
+{
+ regs->eax = 0x5f;
+ regs->bx = 2;
+ regs->cx = 0x401; // PAL + crt only
+ regs->dx = 0; // TV Layout - default
+ set_success(regs);
+ dprintf(1, "Warning: VGA TV/CRT output type is hardcoded\n");
+}
+
+static void
+via_155f18(struct bregs *regs)
+{
+ int fbsize = GET_GLOBAL(ViaFBsize), ramspeed = GET_GLOBAL(ViaRamSpeed);
+ if (fbsize < 0 || ramspeed < 0) {
+ set_code_invalid(regs, RET_EUNSUPPORTED);
+ return;
+ }
+ regs->eax = 0x5f;
+ regs->ebx = 0x500 | (ramspeed << 4) | fbsize;
+ regs->ecx = 0x060;
+ set_success(regs);
+}
+
+static void
+via_155f19(struct bregs *regs)
+{
+ set_invalid_silent(regs);
+}
+
+static void
+via_155f(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x01: via_155f01(regs); break;
+ case 0x02: via_155f02(regs); break;
+ case 0x18: via_155f18(regs); break;
+ case 0x19: via_155f19(regs); break;
+ default: handle_155fXX(regs); break;
+ }
+}
+
+static int
+getFBSize(struct pci_device *pci)
+{
+ /* FB config */
+ u8 reg = pci_config_readb(pci->bdf, 0xa1);
+
+ /* GFX disabled ? */
+ if (!(reg & 0x80))
+ return -1;
+
+ static u8 mem_power[] = {0, 3, 4, 5, 6, 7, 8, 9};
+ return mem_power[(reg >> 4) & 0x7];
+}
+
+static int
+getViaRamSpeed(struct pci_device *pci)
+{
+ return (pci_config_readb(pci->bdf, 0x90) & 0x07) + 3;
+}
+
+static int
+getAMDRamSpeed(void)
+{
+ struct pci_device *pci = pci_find_device(PCI_VENDOR_ID_AMD
+ , PCI_DEVICE_ID_AMD_K8_NB_MEMCTL);
+ if (!pci)
+ return -1;
+
+ /* mem clk 0 = DDR2 400 */
+ return (pci_config_readb(pci->bdf, 0x94) & 0x7) + 6;
+}
+
+/* int 0x15 - 5f18
+
+ ECX = unknown/dont care
+ EBX[3..0] Frame Buffer Size 2^N MiB
+ EBX[7..4] Memory speed:
+ 0: SDR 66Mhz
+ 1: SDR 100Mhz
+ 2: SDR 133Mhz
+ 3: DDR 100Mhz (PC1600 or DDR200)
+ 4: DDR 133Mhz (PC2100 or DDR266)
+ 5: DDR 166Mhz (PC2700 or DDR333)
+ 6: DDR 200Mhz (PC3200 or DDR400)
+ 7: DDR2 133Mhz (DDR2 533)
+ 8: DDR2 166Mhz (DDR2 667)
+ 9: DDR2 200Mhz (DDR2 800)
+ A: DDR2 233Mhz (DDR2 1066)
+ B: and above: Unknown
+ EBX[?..8] Total memory size?
+ EAX = 0x5f for success
+*/
+
+#define PCI_DEVICE_ID_VIA_K8M890CE_3 0x3336
+#define PCI_DEVICE_ID_VIA_VX855_MEMCTRL 0x3409
+
+static void
+via_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_VIA;
+
+ struct pci_device *d = pci_find_device(PCI_VENDOR_ID_VIA
+ , PCI_DEVICE_ID_VIA_K8M890CE_3);
+ if (d) {
+ ViaFBsize = getFBSize(d);
+ ViaRamSpeed = getAMDRamSpeed();
+ return;
+ }
+ d = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_MEMCTRL);
+ if (d) {
+ ViaFBsize = getFBSize(d);
+ ViaRamSpeed = getViaRamSpeed(d);
+ return;
+ }
+
+ dprintf(1, "Warning: VGA memory size and speed is hardcoded\n");
+ ViaFBsize = 5; // 32M frame buffer
+ ViaRamSpeed = 4; // MCLK = DDR266
+}
+
+
+/****************************************************************
+ * Intel VGA hooks
+ ****************************************************************/
+
+u8 IntelDisplayType VAR16VISIBLE, IntelDisplayId VAR16VISIBLE;
+
+static void
+intel_155f35(struct bregs *regs)
+{
+ regs->ax = 0x005f;
+ regs->cl = GET_GLOBAL(IntelDisplayType);
+ set_success(regs);
+}
+
+static void
+intel_155f40(struct bregs *regs)
+{
+ regs->ax = 0x005f;
+ regs->cl = GET_GLOBAL(IntelDisplayId);
+ set_success(regs);
+}
+
+static void
+intel_155f(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x35: intel_155f35(regs); break;
+ case 0x40: intel_155f40(regs); break;
+ default: handle_155fXX(regs); break;
+ }
+}
+
+#define BOOT_DISPLAY_DEFAULT (0)
+#define BOOT_DISPLAY_CRT (1 << 0)
+#define BOOT_DISPLAY_TV (1 << 1)
+#define BOOT_DISPLAY_EFP (1 << 2)
+#define BOOT_DISPLAY_LCD (1 << 3)
+#define BOOT_DISPLAY_CRT2 (1 << 4)
+#define BOOT_DISPLAY_TV2 (1 << 5)
+#define BOOT_DISPLAY_EFP2 (1 << 6)
+#define BOOT_DISPLAY_LCD2 (1 << 7)
+
+static void
+roda_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_INTEL;
+ // IntelDisplayType = BOOT_DISPLAY_DEFAULT;
+ IntelDisplayType = BOOT_DISPLAY_LCD;
+ // IntelDisplayId = inb(0x60f) & 0x0f; // Correct according to Crete
+ IntelDisplayId = 3; // Correct according to empirical studies
+}
+
+static void
+kontron_setup(struct pci_device *pci)
+{
+ VGAHookHandlerType = VH_INTEL;
+ IntelDisplayType = BOOT_DISPLAY_CRT;
+ IntelDisplayId = 3;
+}
+
+static void
+getac_setup(struct pci_device *pci)
+{
+}
+
+
+/****************************************************************
+ * Entry and setup
+ ****************************************************************/
+
+// Main 16bit entry point
+void
+handle_155f(struct bregs *regs)
+{
+ if (!CONFIG_VGAHOOKS) {
+ handle_155fXX(regs);
+ return;
+ }
+
+ int htype = GET_GLOBAL(VGAHookHandlerType);
+ switch (htype) {
+ case VH_VIA: via_155f(regs); break;
+ case VH_INTEL: intel_155f(regs); break;
+ default: handle_155fXX(regs); break;
+ }
+}
+
+// Setup
+void
+vgahook_setup(struct pci_device *pci)
+{
+ if (!CONFIG_VGAHOOKS || !CBvendor || !CBpart)
+ return;
+
+ if (strcmp(CBvendor, "KONTRON") == 0 && strcmp(CBpart, "986LCD-M") == 0)
+ kontron_setup(pci);
+ else if (strcmp(CBvendor, "GETAC") == 0 && strcmp(CBpart, "P470") == 0)
+ getac_setup(pci);
+ else if (strcmp(CBvendor, "RODA") == 0 && strcmp(CBpart, "RK886EX") == 0)
+ roda_setup(pci);
+ else if (pci->vendor == PCI_VENDOR_ID_VIA)
+ via_setup(pci);
+}
--- /dev/null
+// Virtio block boot support.
+//
+// Copyright (C) 2010 Red Hat Inc.
+//
+// Authors:
+// Gleb Natapov <gnatapov@redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "boot.h" // boot_add_hd
+#include "virtio-pci.h"
+#include "virtio-ring.h"
+#include "virtio-blk.h"
+#include "disk.h"
+
+struct virtiodrive_s {
+ struct drive_s drive;
+ struct vring_virtqueue *vq;
+ u16 ioaddr;
+};
+
+static int
+virtio_blk_op(struct disk_op_s *op, int write)
+{
+ struct virtiodrive_s *vdrive_g =
+ container_of(op->drive_g, struct virtiodrive_s, drive);
+ struct vring_virtqueue *vq = GET_GLOBAL(vdrive_g->vq);
+ struct virtio_blk_outhdr hdr = {
+ .type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN,
+ .ioprio = 0,
+ .sector = op->lba,
+ };
+ u8 status = VIRTIO_BLK_S_UNSUPP;
+ struct vring_list sg[] = {
+ {
+ .addr = MAKE_FLATPTR(GET_SEG(SS), &hdr),
+ .length = sizeof(hdr),
+ },
+ {
+ .addr = op->buf_fl,
+ .length = GET_GLOBAL(vdrive_g->drive.blksize) * op->count,
+ },
+ {
+ .addr = MAKE_FLATPTR(GET_SEG(SS), &status),
+ .length = sizeof(status),
+ },
+ };
+
+ /* Add to virtqueue and kick host */
+ if (write)
+ vring_add_buf(vq, sg, 2, 1, 0, 0);
+ else
+ vring_add_buf(vq, sg, 1, 2, 0, 0);
+ vring_kick(GET_GLOBAL(vdrive_g->ioaddr), vq, 1);
+
+ /* Wait for reply */
+ while (!vring_more_used(vq))
+ usleep(5);
+
+ /* Reclaim virtqueue element */
+ vring_get_buf(vq, NULL);
+
+ /* Clear interrupt status register. Avoid leaving interrupts stuck if
+ * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised.
+ */
+ vp_get_isr(GET_GLOBAL(vdrive_g->ioaddr));
+
+ return status == VIRTIO_BLK_S_OK ? DISK_RET_SUCCESS : DISK_RET_EBADTRACK;
+}
+
+int
+process_virtio_op(struct disk_op_s *op)
+{
+ if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
+ return 0;
+ switch (op->command) {
+ case CMD_READ:
+ return virtio_blk_op(op, 0);
+ case CMD_WRITE:
+ return virtio_blk_op(op, 1);
+ case CMD_FORMAT:
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+static void
+init_virtio_blk(struct pci_device *pci)
+{
+ u16 bdf = pci->bdf;
+ dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf),
+ pci_bdf_to_dev(bdf));
+ struct virtiodrive_s *vdrive_g = malloc_fseg(sizeof(*vdrive_g));
+ struct vring_virtqueue *vq = memalign_low(PAGE_SIZE, sizeof(*vq));
+ if (!vdrive_g || !vq) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(vdrive_g, 0, sizeof(*vdrive_g));
+ memset(vq, 0, sizeof(*vq));
+ vdrive_g->drive.type = DTYPE_VIRTIO;
+ vdrive_g->drive.cntl_id = bdf;
+ vdrive_g->vq = vq;
+
+ u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
+ PCI_BASE_ADDRESS_IO_MASK;
+
+ vdrive_g->ioaddr = ioaddr;
+
+ vp_reset(ioaddr);
+ vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER );
+
+ if (vp_find_vq(ioaddr, 0, vdrive_g->vq) < 0 ) {
+ dprintf(1, "fail to find vq for virtio-blk %x:%x\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+ goto fail;
+ }
+
+ struct virtio_blk_config cfg;
+ vp_get(ioaddr, 0, &cfg, sizeof(cfg));
+
+ u32 f = vp_get_features(ioaddr);
+ vdrive_g->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
+ cfg.blk_size : DISK_SECTOR_SIZE;
+
+ vdrive_g->drive.sectors = cfg.capacity;
+ dprintf(3, "virtio-blk %x:%x blksize=%d sectors=%u\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive_g->drive.blksize, (u32)vdrive_g->drive.sectors);
+
+ if (vdrive_g->drive.blksize != DISK_SECTOR_SIZE) {
+ dprintf(1, "virtio-blk %x:%x block size %d is unsupported\n",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+ vdrive_g->drive.blksize);
+ goto fail;
+ }
+
+ vdrive_g->drive.pchs.cylinders = cfg.cylinders;
+ vdrive_g->drive.pchs.heads = cfg.heads;
+ vdrive_g->drive.pchs.spt = cfg.sectors;
+ char *desc = znprintf(MAXDESCSIZE, "Virtio disk PCI:%x:%x",
+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf));
+
+ boot_add_hd(&vdrive_g->drive, desc, bootprio_find_pci_device(pci));
+
+ vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
+ return;
+
+fail:
+ free(vdrive_g);
+ free(vq);
+}
+
+void
+virtio_blk_setup(void)
+{
+ ASSERT32FLAT();
+ if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT)
+ return;
+
+ dprintf(3, "init virtio-blk\n");
+
+ struct pci_device *pci;
+ foreachpci(pci) {
+ if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET
+ || pci->device != PCI_DEVICE_ID_VIRTIO_BLK)
+ continue;
+ init_virtio_blk(pci);
+ }
+}
--- /dev/null
+#ifndef _VIRTIO_BLK_H
+#define _VIRTIO_BLK_H
+
+struct virtio_blk_config
+{
+ u64 capacity;
+ u32 size_max;
+ u32 seg_max;
+ u16 cylinders;
+ u8 heads;
+ u8 sectors;
+ u32 blk_size;
+ u8 physical_block_exp;
+ u8 alignment_offset;
+ u16 min_io_size;
+ u32 opt_io_size;
+} __attribute__((packed));
+
+#define VIRTIO_BLK_F_BLK_SIZE 6
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN 0
+#define VIRTIO_BLK_T_OUT 1
+
+/* This is the first element of the read scatter-gather list. */
+struct virtio_blk_outhdr {
+ /* VIRTIO_BLK_T* */
+ u32 type;
+ /* io priority. */
+ u32 ioprio;
+ /* Sector (ie. 512 byte offset) */
+ u64 sector;
+};
+
+#define VIRTIO_BLK_S_OK 0
+#define VIRTIO_BLK_S_IOERR 1
+#define VIRTIO_BLK_S_UNSUPP 2
+
+struct disk_op_s;
+int process_virtio_op(struct disk_op_s *op);
+void virtio_blk_setup(void);
+
+#endif /* _VIRTIO_BLK_H */
--- /dev/null
+/* virtio-pci.c - pci interface for virtio interface
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * some parts from Linux Virtio PCI driver
+ *
+ * Copyright IBM Corp. 2007
+ * Authors: Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * Adopted for Seabios: Gleb Natapov <gleb@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPLv3
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "virtio-ring.h"
+#include "virtio-pci.h"
+#include "config.h" // CONFIG_DEBUG_LEVEL
+#include "util.h" // dprintf
+
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+ struct vring_virtqueue *vq)
+{
+ struct vring * vr = &vq->vring;
+ u16 num;
+
+ ASSERT32FLAT();
+ /* select the queue */
+
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ /* check if the queue is available */
+
+ num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
+ if (!num) {
+ dprintf(1, "ERROR: queue size is 0\n");
+ return -1;
+ }
+
+ if (num > MAX_QUEUE_NUM) {
+ dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
+ return -1;
+ }
+
+ /* check if the queue is already active */
+
+ if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
+ dprintf(1, "ERROR: queue already active\n");
+ return -1;
+ }
+
+ vq->queue_index = queue_index;
+
+ /* initialize the queue */
+
+ vring_init(vr, num, (unsigned char*)&vq->queue);
+
+ /* activate the queue
+ *
+ * NOTE: vr->desc is initialized by vring_init()
+ */
+
+ outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
+ ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+ return num;
+}
--- /dev/null
+#ifndef _VIRTIO_PCI_H
+#define _VIRTIO_PCI_H
+
+#include "ioport.h" // inl
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES 0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES 4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN 8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM 12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL 14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY 16
+
+/* An 8-bit device status register. */
+#define VIRTIO_PCI_STATUS 18
+
+/* An 8-bit r/o interrupt status register. Reading the value will return the
+ * current contents of the ISR and will also clear it. This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR 19
+
+/* The bit of the ISR which indicates a device configuration change. */
+#define VIRTIO_PCI_ISR_CONFIG 0x2
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG 20
+
+/* Virtio ABI version, this must match exactly */
+#define VIRTIO_PCI_ABI_VERSION 0
+
+static inline u32 vp_get_features(unsigned int ioaddr)
+{
+ return inl(ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+static inline void vp_set_features(unsigned int ioaddr, u32 features)
+{
+ outl(features, ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+}
+
+static inline void vp_get(unsigned int ioaddr, unsigned offset,
+ void *buf, unsigned len)
+{
+ u8 *ptr = buf;
+ unsigned i;
+
+ for (i = 0; i < len; i++)
+ ptr[i] = inb(ioaddr + VIRTIO_PCI_CONFIG + offset + i);
+}
+
+static inline u8 vp_get_status(unsigned int ioaddr)
+{
+ return inb(ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline void vp_set_status(unsigned int ioaddr, u8 status)
+{
+ if (status == 0) /* reset */
+ return;
+ outb(status, ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static inline u8 vp_get_isr(unsigned int ioaddr)
+{
+ return inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_reset(unsigned int ioaddr)
+{
+ outb(0, ioaddr + VIRTIO_PCI_STATUS);
+ (void)inb(ioaddr + VIRTIO_PCI_ISR);
+}
+
+static inline void vp_notify(unsigned int ioaddr, int queue_index)
+{
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+}
+
+static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
+{
+ /* select the queue */
+
+ outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ /* deactivate the queue */
+
+ outl(0, ioaddr + VIRTIO_PCI_QUEUE_PFN);
+}
+
+struct vring_virtqueue;
+int vp_find_vq(unsigned int ioaddr, int queue_index,
+ struct vring_virtqueue *vq);
+#endif /* _VIRTIO_PCI_H_ */
--- /dev/null
+/* virtio-pci.c - virtio ring management
+ *
+ * (c) Copyright 2008 Bull S.A.S.
+ *
+ * Author: Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * some parts from Linux Virtio Ring
+ *
+ * Copyright Rusty Russell IBM Corporation 2007
+ *
+ * Adopted for Seabios: Gleb Natapov <gleb@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPLv3
+ * See the COPYING file in the top-level directory.
+ *
+ *
+ */
+
+#include "virtio-ring.h"
+#include "virtio-pci.h"
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // dprintf
+
+#define BUG() do { \
+ dprintf(1, "BUG: failure at %s:%d/%s()!\n", \
+ __FILE__, __LINE__, __func__); \
+ while(1); \
+ } while (0)
+#define BUG_ON(condition) do { if (condition) BUG(); } while (0)
+
+/*
+ * vring_more_used
+ *
+ * is there some used buffers ?
+ *
+ */
+
+int vring_more_used(struct vring_virtqueue *vq)
+{
+ struct vring_used *used = GET_FLATPTR(vq->vring.used);
+ int more = GET_FLATPTR(vq->last_used_idx) != GET_FLATPTR(used->idx);
+ /* Make sure ring reads are done after idx read above. */
+ smp_rmb();
+ return more;
+}
+
+/*
+ * vring_free
+ *
+ * put at the begin of the free list the current desc[head]
+ */
+
+void vring_detach(struct vring_virtqueue *vq, unsigned int head)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_desc *desc = GET_FLATPTR(vr->desc);
+ unsigned int i;
+
+ /* find end of given descriptor */
+
+ i = head;
+ while (GET_FLATPTR(desc[i].flags) & VRING_DESC_F_NEXT)
+ i = GET_FLATPTR(desc[i].next);
+
+ /* link it with free list and point to it */
+
+ SET_FLATPTR(desc[i].next, GET_FLATPTR(vq->free_head));
+ SET_FLATPTR(vq->free_head, head);
+}
+
+/*
+ * vring_get_buf
+ *
+ * get a buffer from the used list
+ *
+ */
+
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_used_elem *elem;
+ struct vring_used *used = GET_FLATPTR(vq->vring.used);
+ u32 id;
+ int ret;
+
+// BUG_ON(!vring_more_used(vq));
+
+ elem = &used->ring[GET_FLATPTR(vq->last_used_idx) % GET_FLATPTR(vr->num)];
+ id = GET_FLATPTR(elem->id);
+ if (len != NULL)
+ *len = GET_FLATPTR(elem->len);
+
+ ret = GET_FLATPTR(vq->vdata[id]);
+
+ vring_detach(vq, id);
+
+ SET_FLATPTR(vq->last_used_idx, GET_FLATPTR(vq->last_used_idx) + 1);
+
+ return ret;
+}
+
+void vring_add_buf(struct vring_virtqueue *vq,
+ struct vring_list list[],
+ unsigned int out, unsigned int in,
+ int index, int num_added)
+{
+ struct vring *vr = &vq->vring;
+ int i, av, head, prev;
+ struct vring_desc *desc = GET_FLATPTR(vr->desc);
+ struct vring_avail *avail = GET_FLATPTR(vr->avail);
+
+ BUG_ON(out + in == 0);
+
+ prev = 0;
+ head = GET_FLATPTR(vq->free_head);
+ for (i = head; out; i = GET_FLATPTR(desc[i].next), out--) {
+ SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT);
+ SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
+ SET_FLATPTR(desc[i].len, list->length);
+ prev = i;
+ list++;
+ }
+ for ( ; in; i = GET_FLATPTR(desc[i].next), in--) {
+ SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
+ SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
+ SET_FLATPTR(desc[i].len, list->length);
+ prev = i;
+ list++;
+ }
+ SET_FLATPTR(desc[prev].flags,
+ GET_FLATPTR(desc[prev].flags) & ~VRING_DESC_F_NEXT);
+
+ SET_FLATPTR(vq->free_head, i);
+
+ SET_FLATPTR(vq->vdata[head], index);
+
+ av = (GET_FLATPTR(avail->idx) + num_added) % GET_FLATPTR(vr->num);
+ SET_FLATPTR(avail->ring[av], head);
+}
+
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
+{
+ struct vring *vr = &vq->vring;
+ struct vring_avail *avail = GET_FLATPTR(vr->avail);
+
+ /* Make sure idx update is done after ring write. */
+ smp_wmb();
+ SET_FLATPTR(avail->idx, GET_FLATPTR(avail->idx) + num_added);
+
+ vp_notify(ioaddr, GET_FLATPTR(vq->queue_index));
+}
--- /dev/null
+#ifndef _VIRTIO_RING_H
+#define _VIRTIO_RING_H
+
+#include "types.h" // u64
+#include "memmap.h" // PAGE_SIZE
+
+#define PAGE_SHIFT 12
+#define PAGE_MASK (PAGE_SIZE-1)
+
+#define virt_to_phys(v) (unsigned long)(v)
+#define phys_to_virt(p) (void*)(p)
+/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER 2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK 4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED 0x80
+
+#define MAX_QUEUE_NUM (128)
+
+#define VRING_DESC_F_NEXT 1
+#define VRING_DESC_F_WRITE 2
+
+#define VRING_AVAIL_F_NO_INTERRUPT 1
+
+#define VRING_USED_F_NO_NOTIFY 1
+
+struct vring_desc
+{
+ u64 addr;
+ u32 len;
+ u16 flags;
+ u16 next;
+};
+
+struct vring_avail
+{
+ u16 flags;
+ u16 idx;
+ u16 ring[0];
+};
+
+struct vring_used_elem
+{
+ u32 id;
+ u32 len;
+};
+
+struct vring_used
+{
+ u16 flags;
+ u16 idx;
+ struct vring_used_elem ring[];
+};
+
+struct vring {
+ unsigned int num;
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
+};
+
+#define vring_size(num) \
+ (((((sizeof(struct vring_desc) * num) + \
+ (sizeof(struct vring_avail) + sizeof(u16) * num)) \
+ + PAGE_MASK) & ~PAGE_MASK) + \
+ (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
+
+typedef unsigned char virtio_queue_t[vring_size(MAX_QUEUE_NUM)];
+
+struct vring_virtqueue {
+ virtio_queue_t queue;
+ struct vring vring;
+ u16 free_head;
+ u16 last_used_idx;
+ u16 vdata[MAX_QUEUE_NUM];
+ /* PCI */
+ int queue_index;
+};
+
+struct vring_list {
+ char *addr;
+ unsigned int length;
+};
+
+static inline void vring_init(struct vring *vr,
+ unsigned int num, unsigned char *queue)
+{
+ unsigned int i;
+ unsigned long pa;
+
+ ASSERT32FLAT();
+ vr->num = num;
+
+ /* physical address of desc must be page aligned */
+
+ pa = virt_to_phys(queue);
+ pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+ vr->desc = phys_to_virt(pa);
+
+ vr->avail = (struct vring_avail *)&vr->desc[num];
+ /* disable interrupts */
+ vr->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+
+ /* physical address of used must be page aligned */
+
+ pa = virt_to_phys(&vr->avail->ring[num]);
+ pa = (pa + PAGE_MASK) & ~PAGE_MASK;
+ vr->used = phys_to_virt(pa);
+
+ for (i = 0; i < num - 1; i++)
+ vr->desc[i].next = i + 1;
+ vr->desc[i].next = 0;
+}
+
+int vring_more_used(struct vring_virtqueue *vq);
+void vring_detach(struct vring_virtqueue *vq, unsigned int head);
+int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len);
+void vring_add_buf(struct vring_virtqueue *vq, struct vring_list list[],
+ unsigned int out, unsigned int in,
+ int index, int num_added);
+void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added);
+
+#endif /* _VIRTIO_RING_H_ */
--- /dev/null
+// Xen HVM support
+//
+// Copyright (C) 2011 Citrix Systems.
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h"
+#include "xen.h"
+
+#include "memmap.h" // add_e820
+#include "types.h" // ASM32FLAT
+#include "util.h" // copy_acpi_rsdp
+
+#define INFO_PHYSICAL_ADDRESS 0x00001000
+
+u32 xen_cpuid_base = 0;
+
+struct xen_seabios_info {
+ char signature[14]; /* XenHVMSeaBIOS\0 */
+ u8 length; /* Length of this struct */
+ u8 checksum; /* Set such that the sum over bytes 0..length == 0 */
+ /*
+ * Physical address of an array of tables_nr elements.
+ *
+ * Each element is a 32 bit value contianing the physical address
+ * of a BIOS table.
+ */
+ u32 tables;
+ u32 tables_nr;
+ /*
+ * Physical address of the e820 table, contains e820_nr entries.
+ */
+ u32 e820;
+ u32 e820_nr;
+} PACKED;
+
+static void validate_info(struct xen_seabios_info *t)
+{
+ if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) )
+ panic("Bad Xen info signature\n");
+
+ if ( t->length < sizeof(struct xen_seabios_info) )
+ panic("Bad Xen info length\n");
+
+ if (checksum(t, t->length) != 0)
+ panic("Bad Xen info checksum\n");
+}
+
+void xen_probe(void)
+{
+ u32 base, eax, ebx, ecx, edx;
+ char signature[13];
+
+ if (!CONFIG_XEN)
+ return;
+
+ for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+ cpuid(base, &eax, &ebx, &ecx, &edx);
+ memcpy(signature + 0, &ebx, 4);
+ memcpy(signature + 4, &ecx, 4);
+ memcpy(signature + 8, &edx, 4);
+ signature[12] = 0;
+
+ dprintf(1, "Found hypervisor signature \"%s\" at %x\n",
+ signature, base);
+ if (strcmp(signature, "XenVMMXenVMM") == 0) {
+ if ((eax - base) < 2)
+ panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
+ eax, base);
+ xen_cpuid_base = base;
+ break;
+ }
+ }
+}
+
+static int hypercall_xen_version( int cmd, void *arg)
+{
+ return _hypercall2(int, xen_version, cmd, arg);
+}
+
+/* Fill in hypercall transfer pages. */
+void xen_init_hypercalls(void)
+{
+ u32 eax, ebx, ecx, edx;
+ xen_extraversion_t extraversion;
+ unsigned long i;
+
+ if (!usingXen())
+ return;
+
+ cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx);
+
+ xen_hypercall_page = (unsigned long)memalign_high(PAGE_SIZE, eax*PAGE_SIZE);
+ if (!xen_hypercall_page)
+ panic("unable to allocate Xen hypercall page\n");
+
+ dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page);
+ for ( i = 0; i < eax; i++ )
+ wrmsr(ebx, xen_hypercall_page + (i << 12) + i);
+
+ /* Print version information. */
+ cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx);
+ hypercall_xen_version(XENVER_extraversion, extraversion);
+ dprintf(1, "Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
+}
+
+void xen_copy_biostables(void)
+{
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ u32 *tables = (u32 *)info->tables;
+ int i;
+
+ dprintf(1, "xen: copy BIOS tables...\n");
+ for (i=0; i<info->tables_nr; i++) {
+ void *table = (void *)tables[i];
+ copy_acpi_rsdp(table);
+ copy_mptable(table);
+ copy_pir(table);
+ copy_smbios(table);
+ }
+}
+
+void xen_setup(void)
+{
+ u64 maxram = 0, maxram_over4G = 0;
+ int i;
+ struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
+ struct e820entry *e820 = (struct e820entry *)info->e820;
+ validate_info(info);
+
+ dprintf(1, "xen: copy e820...\n");
+
+ for (i = 0; i < info->e820_nr; i++) {
+ struct e820entry *e = &e820[i];
+ if (e->type == E820_ACPI || e->type == E820_RAM) {
+ u64 end = e->start + e->size;
+ if (end > 0x100000000ull) {
+ end -= 0x100000000ull;
+ if (end > maxram_over4G)
+ maxram_over4G = end;
+ } else if (end > maxram)
+ maxram = end;
+ }
+ add_e820(e->start, e->size, e->type);
+ }
+
+ RamSize = maxram;
+ RamSizeOver4G = maxram_over4G;
+}
--- /dev/null
+#ifndef __XEN_H
+#define __XEN_H
+
+#include "util.h"
+
+extern u32 xen_cpuid_base;
+
+void xen_probe(void);
+void xen_setup(void);
+void xen_init_hypercalls(void);
+void xen_copy_biostables(void);
+
+static inline int usingXen(void) {
+ if (!CONFIG_XEN)
+ return 0;
+ return (xen_cpuid_base != 0);
+}
+
+unsigned long xen_hypercall_page;
+
+#define _hypercall0(type, name) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res) \
+ : "0" (__hentry) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall1(type, name, a1) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1) \
+ : "0" (__hentry), "1" ((long)(a1)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall2(type, name, a1, a2) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall3(type, name, a1, a2, a3) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
+({ \
+ unsigned long __hentry = xen_hypercall_page+__HYPERVISOR_##name*32; \
+ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
+ asm volatile ( \
+ "call *%%eax" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
+ : "0" (__hentry), "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ "5" ((long)(a5)) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+/******************************************************************************
+ *
+ * The following interface definitions are taken from Xen and have the
+ * following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* xen.h */
+
+#define __HYPERVISOR_xen_version 17
+
+/* version.h */
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+typedef char xen_extraversion_t[16];
+#define XEN_EXTRAVERSION_LEN (sizeof(xen_extraversion_t))
+
+#endif
--- /dev/null
+#!/usr/bin/env python
+# Fill in checksum/size of an option rom, and pad it to proper length.
+#
+# Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+def alignpos(pos, alignbytes):
+ mask = alignbytes - 1
+ return (pos + mask) & ~mask
+
+def checksum(data):
+ ords = map(ord, data)
+ return sum(ords)
+
+def main():
+ inname = sys.argv[1]
+ outname = sys.argv[2]
+
+ # Read data in
+ f = open(inname, 'rb')
+ data = f.read()
+ count = len(data)
+
+ # Pad to a 512 byte boundary
+ data += "\0" * (alignpos(count, 512) - count)
+ count = len(data)
+
+ # Fill in size field; clear checksum field
+ data = data[:2] + chr(count/512) + data[3:6] + "\0" + data[7:]
+
+ # Checksum rom
+ newsum = (256 - checksum(data)) & 0xff
+ data = data[:6] + chr(newsum) + data[7:]
+
+ # Write new rom
+ f = open(outname, 'wb')
+ f.write(data)
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+#!/usr/bin/env python
+# Script to check a bios image and report info on it.
+#
+# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import layoutrom
+
+def main():
+ # Get args
+ objinfo, rawfile, outfile = sys.argv[1:]
+
+ # Read in symbols
+ objinfofile = open(objinfo, 'rb')
+ symbols = layoutrom.parseObjDump(objinfofile, 'in')[1]
+
+ # Read in raw file
+ f = open(rawfile, 'rb')
+ rawdata = f.read()
+ f.close()
+ datasize = len(rawdata)
+ finalsize = 64*1024
+ if datasize > 64*1024:
+ finalsize = 128*1024
+ if datasize > 128*1024:
+ finalsize = 256*1024
+
+ # Sanity checks
+ start = symbols['code32flat_start'].offset
+ end = symbols['code32flat_end'].offset
+ expend = layoutrom.BUILD_BIOS_ADDR + layoutrom.BUILD_BIOS_SIZE
+ if end != expend:
+ print "Error! Code does not end at 0x%x (got 0x%x)" % (
+ expend, end)
+ sys.exit(1)
+ if datasize > finalsize:
+ print "Error! Code is too big (0x%x vs 0x%x)" % (
+ datasize, finalsize)
+ sys.exit(1)
+ expdatasize = end - start
+ if datasize != expdatasize:
+ print "Error! Unknown extra data (0x%x vs 0x%x)" % (
+ datasize, expdatasize)
+ sys.exit(1)
+
+ # Print statistics
+ runtimesize = datasize
+ if '_reloc_abs_start' in symbols:
+ runtimesize = end - symbols['code32init_end'].offset
+ print "Total size: %d Fixed: %d Free: %d (used %.1f%% of %dKiB rom)" % (
+ datasize, runtimesize, finalsize - datasize
+ , (datasize / float(finalsize)) * 100.0
+ , finalsize / 1024)
+
+ # Write final file
+ f = open(outfile, 'wb')
+ f.write(("\0" * (finalsize - datasize)) + rawdata)
+ f.close()
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+#!/usr/bin/env python
+# Script that tries to find how much stack space each function in an
+# object is using.
+#
+# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Usage:
+# objdump -m i386 -M i8086 -M suffix -d out/rom16.o | tools/checkstack.py
+
+import sys
+import re
+
+# Functions that change stacks
+STACKHOP = ['__send_disk_op']
+# List of functions we can assume are never called.
+#IGNORE = ['panic', '__dprintf']
+IGNORE = ['panic']
+
+OUTPUTDESC = """
+#funcname1[preamble_stack_usage,max_usage_with_callers]:
+# insn_addr:called_function [usage_at_call_point+caller_preamble,total_usage]
+#
+#funcname2[p,m,max_usage_to_yield_point]:
+# insn_addr:called_function [u+c,t,usage_to_yield_point]
+"""
+
+# Find out maximum stack usage for a function
+def calcmaxstack(funcs, funcaddr):
+ info = funcs[funcaddr]
+ # Find max of all nested calls.
+ maxusage = info[1]
+ maxyieldusage = doesyield = 0
+ if info[3] is not None:
+ maxyieldusage = info[3]
+ doesyield = 1
+ info[2] = maxusage
+ info[4] = info[3]
+ seenbefore = {}
+ totcalls = 0
+ for insnaddr, calladdr, usage in info[6]:
+ callinfo = funcs.get(calladdr)
+ if callinfo is None:
+ continue
+ if callinfo[2] is None:
+ calcmaxstack(funcs, calladdr)
+ if callinfo[0] not in seenbefore:
+ seenbefore[callinfo[0]] = 1
+ totcalls += 1 + callinfo[5]
+ funcnameroot = callinfo[0].split('.')[0]
+ if funcnameroot in IGNORE:
+ # This called function is ignored - don't contribute it to
+ # the max stack.
+ continue
+ if funcnameroot in STACKHOP:
+ if usage > maxusage:
+ maxusage = usage
+ if callinfo[4] is not None:
+ doesyield = 1
+ if usage > maxyieldusage:
+ maxyieldusage = usage
+ continue
+ totusage = usage + callinfo[2]
+ if totusage > maxusage:
+ maxusage = totusage
+ if callinfo[4] is not None:
+ doesyield = 1
+ totyieldusage = usage + callinfo[4]
+ if totyieldusage > maxyieldusage:
+ maxyieldusage = totyieldusage
+ info[2] = maxusage
+ if doesyield:
+ info[4] = maxyieldusage
+ info[5] = totcalls
+
+# Try to arrange output so that functions that call each other are
+# near each other.
+def orderfuncs(funcaddrs, availfuncs):
+ l = [(availfuncs[funcaddr][5], availfuncs[funcaddr][0], funcaddr)
+ for funcaddr in funcaddrs if funcaddr in availfuncs]
+ l.sort()
+ l.reverse()
+ out = []
+ while l:
+ count, name, funcaddr = l.pop(0)
+ if funcaddr not in availfuncs:
+ continue
+ calladdrs = [calls[1] for calls in availfuncs[funcaddr][6]]
+ del availfuncs[funcaddr]
+ out = out + orderfuncs(calladdrs, availfuncs) + [funcaddr]
+ return out
+
+# Update function info with a found "yield" point.
+def noteYield(info, stackusage):
+ prevyield = info[3]
+ if prevyield is None or prevyield < stackusage:
+ info[3] = stackusage
+
+# Update function info with a found "call" point.
+def noteCall(info, subfuncs, insnaddr, calladdr, stackusage):
+ if (calladdr, stackusage) in subfuncs:
+ # Already noted a nearly identical call - ignore this one.
+ return
+ info[6].append((insnaddr, calladdr, stackusage))
+ subfuncs[(calladdr, stackusage)] = 1
+
+hex_s = r'[0-9a-f]+'
+re_func = re.compile(r'^(?P<funcaddr>' + hex_s + r') <(?P<func>.*)>:$')
+re_asm = re.compile(
+ r'^[ ]*(?P<insnaddr>' + hex_s
+ + r'):\t.*\t(addr32 )?(?P<insn>.+?)[ ]*((?P<calladdr>' + hex_s
+ + r') <(?P<ref>.*)>)?$')
+re_usestack = re.compile(
+ r'^(push[f]?[lw])|(sub.* [$](?P<num>0x' + hex_s + r'),%esp)$')
+
+def calc():
+ # funcs[funcaddr] = [funcname, basicstackusage, maxstackusage
+ # , yieldusage, maxyieldusage, totalcalls
+ # , [(insnaddr, calladdr, stackusage), ...]]
+ funcs = {-1: ['<indirect>', 0, 0, None, None, 0, []]}
+ cur = None
+ atstart = 0
+ stackusage = 0
+
+ # Parse input lines
+ for line in sys.stdin.readlines():
+ m = re_func.match(line)
+ if m is not None:
+ # Found function
+ funcaddr = int(m.group('funcaddr'), 16)
+ funcs[funcaddr] = cur = [m.group('func'), 0, None, None, None, 0, []]
+ stackusage = 0
+ atstart = 1
+ subfuncs = {}
+ continue
+ m = re_asm.match(line)
+ if m is not None:
+ insn = m.group('insn')
+
+ im = re_usestack.match(insn)
+ if im is not None:
+ if insn.startswith('pushl') or insn.startswith('pushfl'):
+ stackusage += 4
+ continue
+ elif insn.startswith('pushw') or insn.startswith('pushfw'):
+ stackusage += 2
+ continue
+ stackusage += int(im.group('num'), 16)
+
+ if atstart:
+ if insn == 'movl %esp,%ebp':
+ # Still part of initial header
+ continue
+ cur[1] = stackusage
+ atstart = 0
+
+ insnaddr = m.group('insnaddr')
+ calladdr = m.group('calladdr')
+ if calladdr is None:
+ if insn.startswith('lcallw'):
+ noteCall(cur, subfuncs, insnaddr, -1, stackusage + 4)
+ noteYield(cur, stackusage + 4)
+ elif insn.startswith('int'):
+ noteCall(cur, subfuncs, insnaddr, -1, stackusage + 6)
+ noteYield(cur, stackusage + 6)
+ elif insn.startswith('sti'):
+ noteYield(cur, stackusage)
+ else:
+ # misc instruction
+ continue
+ else:
+ # Jump or call insn
+ calladdr = int(calladdr, 16)
+ ref = m.group('ref')
+ if '+' in ref:
+ # Inter-function jump.
+ pass
+ elif insn.startswith('j'):
+ # Tail call
+ noteCall(cur, subfuncs, insnaddr, calladdr, 0)
+ elif insn.startswith('calll'):
+ noteCall(cur, subfuncs, insnaddr, calladdr, stackusage + 4)
+ else:
+ print "unknown call", ref
+ noteCall(cur, subfuncs, insnaddr, calladdr, stackusage)
+ # Reset stack usage to preamble usage
+ stackusage = cur[1]
+
+ #print "other", repr(line)
+
+ # Calculate maxstackusage
+ for funcaddr, info in funcs.items():
+ if info[2] is not None:
+ continue
+ calcmaxstack(funcs, funcaddr)
+
+ # Sort functions for output
+ funcaddrs = orderfuncs(funcs.keys(), funcs.copy())
+
+ # Show all functions
+ print OUTPUTDESC
+ for funcaddr in funcaddrs:
+ name, basicusage, maxusage, yieldusage, maxyieldusage, count, calls = \
+ funcs[funcaddr]
+ if maxusage == 0 and maxyieldusage is None:
+ continue
+ yieldstr = ""
+ if maxyieldusage is not None:
+ yieldstr = ",%d" % maxyieldusage
+ print "\n%s[%d,%d%s]:" % (name, basicusage, maxusage, yieldstr)
+ for insnaddr, calladdr, stackusage in calls:
+ callinfo = funcs.get(calladdr, ("<unknown>", 0, 0, 0, None))
+ yieldstr = ""
+ if callinfo[4] is not None:
+ yieldstr = ",%d" % (stackusage + callinfo[4])
+ print " %04s:%-40s [%d+%d,%d%s]" % (
+ insnaddr, callinfo[0], stackusage, callinfo[1]
+ , stackusage+callinfo[2], yieldstr)
+
+def main():
+ calc()
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+#!/usr/bin/env python
+# Script to report the checksum of a file.
+#
+# Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+def main():
+ data = sys.stdin.read()
+ ords = map(ord, data)
+ print "sum=%x\n" % sum(ords)
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+#!/usr/bin/env python
+# Encode an integer in little endian format in a file.
+#
+# Copyright (C) 2011 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import struct
+
+def main():
+ filename = sys.argv[1]
+ value = int(sys.argv[2])
+
+ outval = struct.pack('<Q', value)
+ f = open(filename, 'wb')
+ f.write(outval)
+ f.close()
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+:
+# Extract definitions from an assembler file. This is based on code
+# from the Linux Kernel.
+INFILE=$1
+OUTFILE=$2
+cat > "$OUTFILE" <<EOF
+// This is an auto-generated file. DO NOT EDIT!
+// Generated with "$0 $@"
+#ifndef __ASM_OFFSETS_H
+#define __ASM_OFFSETS_H
+EOF
+sed -ne "/^->/{s:->#\(.*\):/* \1 */:; \
+ s:^->\([^ ]*\) [\$\#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+ s:->::; p;}" < "$INFILE" >> "$OUTFILE"
+cat >> "$OUTFILE" <<EOF
+#endif // asm-offsets.h
+EOF
--- /dev/null
+#
+# Generated files
+#
+config*
+lex.*.c
+*.tab.c
+*.tab.h
+zconf.hash.c
+*.moc
+lkc_defs.h
+gconf.glade.h
+*.pot
+*.mo
+
+#
+# configuration programs
+#
+conf
+mconf
+nconf
+qconf
+gconf
+kxgettext
--- /dev/null
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
+ localmodconfig localyesconfig
+
+ifdef KBUILD_KCONFIG
+Kconfig := $(KBUILD_KCONFIG)
+else
+Kconfig := Kconfig
+endif
+
+xconfig: $(obj)/qconf
+ $< $(Kconfig)
+
+gconfig: $(obj)/gconf
+ $< $(Kconfig)
+
+menuconfig: $(obj)/mconf
+ $< $(Kconfig)
+
+config: $(obj)/conf
+ $< --oldaskconfig $(Kconfig)
+
+nconfig: $(obj)/nconf
+ $< $(Kconfig)
+
+oldconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
+
+silentoldconfig: $(obj)/conf
+ @echo " Build Kconfig config file"
+ $(Q)mkdir -p include/generated
+ $(Q)$< --$@ $(Kconfig)
+
+# if no path is given, then use src directory to find file
+ifdef LSMOD
+LSMOD_F := $(LSMOD)
+ifeq ($(findstring /,$(LSMOD)),)
+ LSMOD_F := $(objtree)/$(LSMOD)
+endif
+endif
+
+localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
+ $(Q)mkdir -p include/generated
+ $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
+ $(Q)if [ -f .config ]; then \
+ cmp -s .tmp.config .config || \
+ (mv -f .config .config.old.1; \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ mv -f .config.old.1 .config.old) \
+ else \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ fi
+ $(Q)rm -f .tmp.config
+
+localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
+ $(Q)mkdir -p include/generated
+ $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
+ $(Q)sed -i s/=m/=y/ .tmp.config
+ $(Q)if [ -f .config ]; then \
+ cmp -s .tmp.config .config || \
+ (mv -f .config .config.old.1; \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ mv -f .config.old.1 .config.old) \
+ else \
+ mv -f .tmp.config .config; \
+ $(obj)/conf --silentoldconfig $(Kconfig); \
+ fi
+ $(Q)rm -f .tmp.config
+
+# Create new linux.pot file
+# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
+# The symlink is used to repair a deficiency in arch/um
+update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
+ $(Q)echo " GEN config"
+ $(Q)xgettext --default-domain=linux \
+ --add-comments --keyword=_ --keyword=N_ \
+ --from-code=UTF-8 \
+ --files-from=tools/kconfig/POTFILES.in \
+ --output $(obj)/config.pot
+ $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+ $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
+ $(Q)(for i in `ls arch/*/Kconfig`; \
+ do \
+ echo " GEN $$i"; \
+ $(obj)/kxgettext $$i \
+ >> $(obj)/config.pot; \
+ done )
+ $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+ --output $(obj)/linux.pot
+ $(Q)rm -f arch/um/Kconfig.arch
+ $(Q)rm -f $(obj)/config.pot
+
+PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
+
+allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
+
+PHONY += listnewconfig oldnoconfig savedefconfig defconfig
+
+listnewconfig oldnoconfig: $(obj)/conf
+ $< --$@ $(Kconfig)
+
+savedefconfig: $(obj)/conf
+ $< --$@=defconfig $(Kconfig)
+
+defconfig: $(obj)/conf
+ @echo " Build default config"
+ $(Q)$< --defconfig=/dev/null $(Kconfig)
+
+# Help text used by make help
+help:
+ @echo ' config - Update current config utilising a line-oriented program'
+ @echo ' nconfig - Update current config utilising a ncurses menu based program'
+ @echo ' menuconfig - Update current config utilising a menu based program'
+ @echo ' xconfig - Update current config utilising a QT based front-end'
+ @echo ' gconfig - Update current config utilising a GTK based front-end'
+ @echo ' oldconfig - Update current config utilising a provided .config as base'
+ @echo ' localmodconfig - Update current config disabling modules not loaded'
+ @echo ' localyesconfig - Update current config converting local mods to core'
+ @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
+ @echo ' defconfig - New config with default from ARCH supplied defconfig'
+ @echo ' savedefconfig - Save current config as ./defconfig (minimal config)'
+ @echo ' allnoconfig - New config where all options are answered with no'
+ @echo ' allyesconfig - New config where all options are accepted with yes'
+ @echo ' allmodconfig - New config selecting modules when possible'
+ @echo ' alldefconfig - New config with all symbols set to default'
+ @echo ' randconfig - New config with random answer to all options'
+ @echo ' listnewconfig - List new options'
+ @echo ' oldnoconfig - Same as silentoldconfig but set new symbols to n (unset)'
+
+# lxdialog stuff
+check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
+
+# Use recursively expanded variables so we do not call gcc unless
+# we really need to do so. (Do not call gcc as part of make mrproper)
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+ -DLOCALE
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf: Used for defconfig, oldconfig and related targets
+# nconf: Used for the nconfig target.
+# Utilizes ncurses
+# mconf: Used for the menuconfig target
+# Utilizes the lxdialog package
+# qconf: Used for the xconfig target
+# Based on QT which needs to be installed to compile it
+# gconf: Used for the gconfig target
+# Based on GTK which needs to be installed to compile it
+# object files used by all kconfig flavours
+
+lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
+lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
+conf-objs := conf.o zconf.tab.o
+mconf-objs := mconf.o zconf.tab.o $(lxdialog)
+nconf-objs := nconf.o zconf.tab.o nconf.gui.o
+kxgettext-objs := kxgettext.o zconf.tab.o
+
+hostprogs-y := conf qconf gconf kxgettext
+
+ifeq ($(MAKECMDGOALS),nconfig)
+ hostprogs-y += nconf
+endif
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+ hostprogs-y += mconf
+endif
+
+ifeq ($(MAKECMDGOALS),xconfig)
+ qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+ gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+qconf-cxxobjs := qconf.o
+qconf-objs := kconfig_load.o zconf.tab.o
+endif
+
+ifeq ($(gconf-target),1)
+gconf-objs := gconf.o kconfig_load.o zconf.tab.o
+endif
+
+clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \
+ .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files += mconf qconf gconf nconf
+clean-files += config.pot linux.pot
+
+# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
+PHONY += $(obj)/dochecklxdialog
+$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
+$(obj)/dochecklxdialog:
+ $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
+
+always := dochecklxdialog
+
+# Add environment specific flags
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
+
+# generated files seem to need this to find local include files
+HOSTCFLAGS_lex.zconf.o := -I$(src)
+HOSTCFLAGS_zconf.tab.o := -I$(src)
+
+HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -ldl
+HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
+HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+ -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOSTLOADLIBES_nconf = -lmenu -lpanel -lncurses
+$(obj)/qconf.o: $(obj)/.tmp_qtcheck
+
+ifeq ($(qconf-target),1)
+$(obj)/.tmp_qtcheck: $(src)/Makefile
+-include $(obj)/.tmp_qtcheck
+
+# QT needs some extra effort...
+$(obj)/.tmp_qtcheck:
+ @set -e; echo " CHECK qt"; dir=""; pkg=""; \
+ if ! pkg-config --exists QtCore 2> /dev/null; then \
+ echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \
+ pkg-config --exists qt 2> /dev/null && pkg=qt; \
+ pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
+ if [ -n "$$pkg" ]; then \
+ cflags="\$$(shell pkg-config $$pkg --cflags)"; \
+ libs="\$$(shell pkg-config $$pkg --libs)"; \
+ moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
+ dir="$$(pkg-config $$pkg --variable=prefix)"; \
+ else \
+ for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
+ if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
+ done; \
+ if [ -z "$$dir" ]; then \
+ echo "*"; \
+ echo "* Unable to find any QT installation. Please make sure that"; \
+ echo "* the QT4 or QT3 development package is correctly installed and"; \
+ echo "* either qmake can be found or install pkg-config or set"; \
+ echo "* the QTDIR environment variable to the correct location."; \
+ echo "*"; \
+ false; \
+ fi; \
+ libpath=$$dir/lib; lib=qt; osdir=""; \
+ $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+ osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
+ test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
+ test -f $$libpath/libqt-mt.so && lib=qt-mt; \
+ cflags="-I$$dir/include"; \
+ libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
+ moc="$$dir/bin/moc"; \
+ fi; \
+ if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
+ echo "*"; \
+ echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
+ echo "*"; \
+ moc="/usr/bin/moc"; \
+ fi; \
+ else \
+ cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
+ libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
+ binpath="\$$(shell pkg-config QtCore --variable=prefix)"; \
+ moc="$$binpath/bin/moc"; \
+ fi; \
+ echo "KC_QT_CFLAGS=$$cflags" > $@; \
+ echo "KC_QT_LIBS=$$libs" >> $@; \
+ echo "KC_QT_MOC=$$moc" >> $@
+endif
+
+$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
+
+ifeq ($(gconf-target),1)
+-include $(obj)/.tmp_gtkcheck
+
+# GTK needs some extra effort, too...
+$(obj)/.tmp_gtkcheck:
+ @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \
+ if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \
+ touch $@; \
+ else \
+ echo "*"; \
+ echo "* GTK+ is present but version >= 2.0.0 is required."; \
+ echo "*"; \
+ false; \
+ fi \
+ else \
+ echo "*"; \
+ echo "* Unable to find the GTK+ installation. Please make sure that"; \
+ echo "* the GTK+ 2.0 development package is correctly installed..."; \
+ echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \
+ echo "*"; \
+ false; \
+ fi
+endif
+
+$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
+
+$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
+
+$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
+
+$(obj)/gconf.o: $(obj)/lkc_defs.h
+
+$(obj)/%.moc: $(src)/%.h
+ $(KC_QT_MOC) -i $< -o $@
+
+$(obj)/lkc_defs.h: $(src)/lkc_proto.h
+ sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+# Extract gconf menu items for I18N support
+$(obj)/gconf.glade.h: $(obj)/gconf.glade
+ intltool-extract --type=gettext/glade $(obj)/gconf.glade
+
+###
+# The following requires flex/bison/gperf
+# By default we use the _shipped versions, uncomment the following line if
+# you are modifying the flex/bison src.
+# LKC_GENPARSER := 1
+
+ifdef LKC_GENPARSER
+
+$(obj)/zconf.tab.c: $(src)/zconf.y
+$(obj)/lex.zconf.c: $(src)/zconf.l
+$(obj)/zconf.hash.c: $(src)/zconf.gperf
+
+%.tab.c: %.y
+ bison -l -b $* -p $(notdir $*) $<
+ cp $@ $@_shipped
+
+lex.%.c: %.l
+ flex -L -P$(notdir $*) -o$@ $<
+ cp $@ $@_shipped
+
+%.hash.c: %.gperf
+ gperf < $< > $@
+ cp $@ $@_shipped
+
+endif
+
+VPATH := $(srctree)
+
+$(obj)/%:: $(src)/%_shipped
+ $(Q)cat $< > $@
+
+host-cobjs := $(sort $(foreach m,$(hostprogs-y),$($(m)-objs)))
+host-cobjs := $(addprefix $(obj)/,$(host-cobjs))
+hostprogs-y := $(addprefix $(obj)/,$(hostprogs-y))
+$(host-cobjs) : $(obj)/%.o : $(src)/%.c
+ $(Q)$(HOSTCC) -I$(obj) -I$(srctree)/$(src) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $(HOST_EXTRACFLAGS) -c -o $@ $<
+$(hostprogs-y) : $(obj)/% : $(host-cobjs)
+ $(Q)$(HOSTCC) $(HOSTLDFLAGS) -o $@ $(addprefix $(obj)/,$($(@F)-objs)) $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
--- /dev/null
+tools/kconfig/lxdialog/checklist.c
+tools/kconfig/lxdialog/inputbox.c
+tools/kconfig/lxdialog/menubox.c
+tools/kconfig/lxdialog/textbox.c
+tools/kconfig/lxdialog/util.c
+tools/kconfig/lxdialog/yesno.c
+tools/kconfig/mconf.c
+tools/kconfig/conf.c
+tools/kconfig/confdata.c
+tools/kconfig/gconf.c
+tools/kconfig/gconf.glade.h
+tools/kconfig/qconf.cc
--- /dev/null
+#!/bin/sh
+# Needed for systems without gettext
+$* -xc -o /dev/null - > /dev/null 2>&1 << EOF
+#include <libintl.h>
+int main()
+{
+ gettext("");
+ return 0;
+}
+EOF
+if [ ! "$?" -eq "0" ]; then
+ echo -DKBUILD_NO_NLS;
+fi
+
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <locale.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+ oldaskconfig,
+ silentoldconfig,
+ oldconfig,
+ allnoconfig,
+ allyesconfig,
+ allmodconfig,
+ alldefconfig,
+ randconfig,
+ defconfig,
+ savedefconfig,
+ listnewconfig,
+ oldnoconfig,
+} input_mode = oldaskconfig;
+
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ printf("\n%s\n", str_get(&help));
+ str_free(&help);
+}
+
+static void strip(char *str)
+{
+ char *p = str;
+ int l;
+
+ while ((isspace(*p)))
+ p++;
+ l = strlen(p);
+ if (p != str)
+ memmove(str, p, l + 1);
+ if (!l)
+ return;
+ p = str + l - 1;
+ while ((isspace(*p)))
+ *p-- = 0;
+}
+
+static void check_stdin(void)
+{
+ if (!valid_stdin) {
+ printf(_("aborted!\n\n"));
+ printf(_("Console input/output is redirected. "));
+ printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+ exit(1);
+ }
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+ enum symbol_type type = sym_get_type(sym);
+
+ if (!sym_has_value(sym))
+ printf(_("(NEW) "));
+
+ line[0] = '\n';
+ line[1] = 0;
+
+ if (!sym_is_changable(sym)) {
+ printf("%s\n", def);
+ line[0] = '\n';
+ line[1] = 0;
+ return 0;
+ }
+
+ switch (input_mode) {
+ case oldconfig:
+ case silentoldconfig:
+ if (sym_has_value(sym)) {
+ printf("%s\n", def);
+ return 0;
+ }
+ check_stdin();
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, 128, stdin);
+ return 1;
+ default:
+ break;
+ }
+
+ switch (type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ printf("%s\n", def);
+ return 1;
+ default:
+ ;
+ }
+ printf("%s", line);
+ return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ const char *def;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+ printf("(%s) ", sym->name);
+ def = sym_get_string_value(sym);
+ if (sym_get_string_value(sym))
+ printf("[%s] ", def);
+ if (!conf_askvalue(sym, def))
+ return 0;
+ switch (line[0]) {
+ case '\n':
+ break;
+ case '?':
+ /* print help */
+ if (line[1] == '\n') {
+ print_help(menu);
+ def = NULL;
+ break;
+ }
+ default:
+ line[strlen(line)-1] = 0;
+ def = line;
+ }
+ if (def && sym_set_string_value(sym, def))
+ return 0;
+ }
+}
+
+static int conf_sym(struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ while (1) {
+ printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+ if (sym->name)
+ printf("(%s) ", sym->name);
+ putchar('[');
+ oldval = sym_get_tristate_value(sym);
+ switch (oldval) {
+ case no:
+ putchar('N');
+ break;
+ case mod:
+ putchar('M');
+ break;
+ case yes:
+ putchar('Y');
+ break;
+ }
+ if (oldval != no && sym_tristate_within_range(sym, no))
+ printf("/n");
+ if (oldval != mod && sym_tristate_within_range(sym, mod))
+ printf("/m");
+ if (oldval != yes && sym_tristate_within_range(sym, yes))
+ printf("/y");
+ if (menu_has_help(menu))
+ printf("/?");
+ printf("] ");
+ if (!conf_askvalue(sym, sym_get_string_value(sym)))
+ return 0;
+ strip(line);
+
+ switch (line[0]) {
+ case 'n':
+ case 'N':
+ newval = no;
+ if (!line[1] || !strcmp(&line[1], "o"))
+ break;
+ continue;
+ case 'm':
+ case 'M':
+ newval = mod;
+ if (!line[1])
+ break;
+ continue;
+ case 'y':
+ case 'Y':
+ newval = yes;
+ if (!line[1] || !strcmp(&line[1], "es"))
+ break;
+ continue;
+ case 0:
+ newval = oldval;
+ break;
+ case '?':
+ goto help;
+ default:
+ continue;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ return 0;
+help:
+ print_help(menu);
+ }
+}
+
+static int conf_choice(struct menu *menu)
+{
+ struct symbol *sym, *def_sym;
+ struct menu *child;
+ bool is_new;
+
+ sym = menu->sym;
+ is_new = !sym_has_value(sym);
+ if (sym_is_changable(sym)) {
+ conf_sym(menu);
+ sym_calc_value(sym);
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ return 0;
+ case yes:
+ break;
+ }
+ } else {
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ return 1;
+ case mod:
+ printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+ return 0;
+ case yes:
+ break;
+ }
+ }
+
+ while (1) {
+ int cnt, def;
+
+ printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+ def_sym = sym_get_choice_value(sym);
+ cnt = def = 0;
+ line[0] = 0;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (!child->sym) {
+ printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
+ continue;
+ }
+ cnt++;
+ if (child->sym == def_sym) {
+ def = cnt;
+ printf("%*c", indent, '>');
+ } else
+ printf("%*c", indent, ' ');
+ printf(" %d. %s", cnt, _(menu_get_prompt(child)));
+ if (child->sym->name)
+ printf(" (%s)", child->sym->name);
+ if (!sym_has_value(child->sym))
+ printf(_(" (NEW)"));
+ printf("\n");
+ }
+ printf(_("%*schoice"), indent - 1, "");
+ if (cnt == 1) {
+ printf("[1]: 1\n");
+ goto conf_childs;
+ }
+ printf("[1-%d", cnt);
+ if (menu_has_help(menu))
+ printf("?");
+ printf("]: ");
+ switch (input_mode) {
+ case oldconfig:
+ case silentoldconfig:
+ if (!is_new) {
+ cnt = def;
+ printf("%d\n", cnt);
+ break;
+ }
+ check_stdin();
+ case oldaskconfig:
+ fflush(stdout);
+ xfgets(line, 128, stdin);
+ strip(line);
+ if (line[0] == '?') {
+ print_help(menu);
+ continue;
+ }
+ if (!line[0])
+ cnt = def;
+ else if (isdigit(line[0]))
+ cnt = atoi(line);
+ else
+ continue;
+ break;
+ default:
+ break;
+ }
+
+ conf_childs:
+ for (child = menu->list; child; child = child->next) {
+ if (!child->sym || !menu_is_visible(child))
+ continue;
+ if (!--cnt)
+ break;
+ }
+ if (!child)
+ continue;
+ if (line[strlen(line) - 1] == '?') {
+ print_help(child);
+ continue;
+ }
+ sym_set_choice_value(sym, child->sym);
+ for (child = child->list; child; child = child->next) {
+ indent += 2;
+ conf(child);
+ indent -= 2;
+ }
+ return 1;
+ }
+}
+
+static void conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (prop) {
+ const char *prompt;
+
+ switch (prop->type) {
+ case P_MENU:
+ if ((input_mode == silentoldconfig ||
+ input_mode == listnewconfig ||
+ input_mode == oldnoconfig) &&
+ rootEntry != menu) {
+ check_conf(menu);
+ return;
+ }
+ case P_COMMENT:
+ prompt = menu_get_prompt(menu);
+ if (prompt)
+ printf("%*c\n%*c %s\n%*c\n",
+ indent, '*',
+ indent, '*', _(prompt),
+ indent, '*');
+ default:
+ ;
+ }
+ }
+
+ if (!sym)
+ goto conf_childs;
+
+ if (sym_is_choice(sym)) {
+ conf_choice(menu);
+ if (sym->curr.tri != mod)
+ return;
+ goto conf_childs;
+ }
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ conf_string(menu);
+ break;
+ default:
+ conf_sym(menu);
+ break;
+ }
+
+conf_childs:
+ if (sym)
+ indent += 2;
+ for (child = menu->list; child; child = child->next)
+ conf(child);
+ if (sym)
+ indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct menu *child;
+
+ if (!menu_is_visible(menu))
+ return;
+
+ sym = menu->sym;
+ if (sym && !sym_has_value(sym)) {
+ if (sym_is_changable(sym) ||
+ (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+ if (input_mode == listnewconfig) {
+ if (sym->name && !sym_is_choice_value(sym)) {
+ printf("%s%s\n", CONFIG_, sym->name);
+ }
+ } else if (input_mode != oldnoconfig) {
+ if (!conf_cnt++)
+ printf(_("*\n* Restart config...\n*\n"));
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ }
+ }
+ }
+
+ for (child = menu->list; child; child = child->next)
+ check_conf(child);
+}
+
+static struct option long_opts[] = {
+ {"oldaskconfig", no_argument, NULL, oldaskconfig},
+ {"oldconfig", no_argument, NULL, oldconfig},
+ {"silentoldconfig", no_argument, NULL, silentoldconfig},
+ {"defconfig", optional_argument, NULL, defconfig},
+ {"savedefconfig", required_argument, NULL, savedefconfig},
+ {"allnoconfig", no_argument, NULL, allnoconfig},
+ {"allyesconfig", no_argument, NULL, allyesconfig},
+ {"allmodconfig", no_argument, NULL, allmodconfig},
+ {"alldefconfig", no_argument, NULL, alldefconfig},
+ {"randconfig", no_argument, NULL, randconfig},
+ {"listnewconfig", no_argument, NULL, listnewconfig},
+ {"oldnoconfig", no_argument, NULL, oldnoconfig},
+ {NULL, 0, NULL, 0}
+};
+
+int main(int ac, char **av)
+{
+ int opt;
+ const char *name;
+ struct stat tmpstat;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
+ input_mode = (enum input_mode)opt;
+ switch (opt) {
+ case silentoldconfig:
+ sync_kconfig = 1;
+ break;
+ case defconfig:
+ case savedefconfig:
+ defconfig_file = optarg;
+ break;
+ case randconfig:
+ {
+ struct timeval now;
+ unsigned int seed;
+
+ /*
+ * Use microseconds derived seed,
+ * compensate for systems where it may be zero
+ */
+ gettimeofday(&now, NULL);
+
+ seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
+ srand(seed);
+ break;
+ }
+ case '?':
+ fprintf(stderr, _("See README for usage info\n"));
+ exit(1);
+ break;
+ }
+ }
+ if (ac == optind) {
+ printf(_("%s: Kconfig file missing\n"), av[0]);
+ exit(1);
+ }
+ name = av[optind];
+ conf_parse(name);
+ //zconfdump(stdout);
+ if (sync_kconfig) {
+ name = conf_get_configname();
+ if (stat(name, &tmpstat)) {
+ fprintf(stderr, _("***\n"
+ "*** Configuration file \"%s\" not found!\n"
+ "***\n"
+ "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+ "*** \"make menuconfig\" or \"make xconfig\").\n"
+ "***\n"), name);
+ exit(1);
+ }
+ }
+
+ switch (input_mode) {
+ case defconfig:
+ if (!defconfig_file)
+ defconfig_file = conf_get_default_confname();
+ if (conf_read(defconfig_file)) {
+ printf(_("***\n"
+ "*** Can't find default configuration \"%s\"!\n"
+ "***\n"), defconfig_file);
+ exit(1);
+ }
+ break;
+ case savedefconfig:
+ case silentoldconfig:
+ case oldaskconfig:
+ case oldconfig:
+ case listnewconfig:
+ case oldnoconfig:
+ conf_read(NULL);
+ break;
+ case allnoconfig:
+ case allyesconfig:
+ case allmodconfig:
+ case alldefconfig:
+ case randconfig:
+ name = getenv("KCONFIG_ALLCONFIG");
+ if (name && !stat(name, &tmpstat)) {
+ conf_read_simple(name, S_DEF_USER);
+ break;
+ }
+ switch (input_mode) {
+ case allnoconfig: name = "allno.config"; break;
+ case allyesconfig: name = "allyes.config"; break;
+ case allmodconfig: name = "allmod.config"; break;
+ case alldefconfig: name = "alldef.config"; break;
+ case randconfig: name = "allrandom.config"; break;
+ default: break;
+ }
+ if (!stat(name, &tmpstat))
+ conf_read_simple(name, S_DEF_USER);
+ else if (!stat("all.config", &tmpstat))
+ conf_read_simple("all.config", S_DEF_USER);
+ break;
+ default:
+ break;
+ }
+
+ if (sync_kconfig) {
+ if (conf_get_changed()) {
+ name = getenv("KCONFIG_NOSILENTUPDATE");
+ if (name && *name) {
+ fprintf(stderr,
+ _("\n*** The configuration requires explicit update.\n\n"));
+ return 1;
+ }
+ }
+ valid_stdin = isatty(0) && isatty(1) && isatty(2);
+ }
+
+ switch (input_mode) {
+ case allnoconfig:
+ conf_set_all_new_symbols(def_no);
+ break;
+ case allyesconfig:
+ conf_set_all_new_symbols(def_yes);
+ break;
+ case allmodconfig:
+ conf_set_all_new_symbols(def_mod);
+ break;
+ case alldefconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case randconfig:
+ conf_set_all_new_symbols(def_random);
+ break;
+ case defconfig:
+ conf_set_all_new_symbols(def_default);
+ break;
+ case savedefconfig:
+ break;
+ case oldaskconfig:
+ rootEntry = &rootmenu;
+ conf(&rootmenu);
+ input_mode = silentoldconfig;
+ /* fall through */
+ case oldconfig:
+ case listnewconfig:
+ case oldnoconfig:
+ case silentoldconfig:
+ /* Update until a loop caused no more changes */
+ do {
+ conf_cnt = 0;
+ check_conf(&rootmenu);
+ } while (conf_cnt &&
+ (input_mode != listnewconfig &&
+ input_mode != oldnoconfig));
+ break;
+ }
+
+ if (sync_kconfig) {
+ /* silentoldconfig is used during the build so we shall update autoconf.
+ * All other commands are only used to generate a config.
+ */
+ if (conf_get_changed() && conf_write(NULL)) {
+ fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+ exit(1);
+ }
+ if (conf_write_autoconf()) {
+ fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
+ return 1;
+ }
+ } else if (input_mode == savedefconfig) {
+ if (conf_write_defconfig(defconfig_file)) {
+ fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+ defconfig_file);
+ return 1;
+ }
+ } else if (input_mode != listnewconfig) {
+ if (conf_write(NULL)) {
+ fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+ exit(1);
+ }
+ }
+ return 0;
+}
+/*
+ * Helper function to facilitate fgets() by Jean Sacren.
+ */
+void xfgets(str, size, in)
+ char *str;
+ int size;
+ FILE *in;
+{
+ if (fgets(str, size, in) == NULL)
+ fprintf(stderr, "\nError in reading or end of file.\n");
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+static void conf_warning(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *fmt, va_list ap)
+{
+ printf("#\n# ");
+ vprintf(fmt, ap);
+ printf("\n#\n");
+}
+
+static void (*conf_message_callback) (const char *fmt, va_list ap) =
+ conf_default_message_callback;
+void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
+{
+ conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (conf_message_callback)
+ conf_message_callback(fmt, ap);
+}
+
+const char *conf_get_configname(void)
+{
+ char *name = getenv("KCONFIG_CONFIG");
+
+ return name ? name : ".config";
+}
+
+const char *conf_get_autoconfig_name(void)
+{
+ char *name = getenv("KCONFIG_AUTOCONFIG");
+
+ return name ? name : "include/config/auto.conf";
+}
+
+static char *conf_expand_value(const char *in)
+{
+ struct symbol *sym;
+ const char *src;
+ static char res_value[SYMBOL_MAXLENGTH];
+ char *dst, name[SYMBOL_MAXLENGTH];
+
+ res_value[0] = 0;
+ dst = name;
+ while ((src = strchr(in, '$'))) {
+ strncat(res_value, in, src - in);
+ src++;
+ dst = name;
+ while (isalnum(*src) || *src == '_')
+ *dst++ = *src++;
+ *dst = 0;
+ sym = sym_lookup(name, 0);
+ sym_calc_value(sym);
+ strcat(res_value, sym_get_string_value(sym));
+ in = src;
+ }
+ strcat(res_value, in);
+
+ return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+ struct stat buf;
+ static char fullname[PATH_MAX+1];
+ char *env, *name;
+
+ name = conf_expand_value(conf_defname);
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ if (!stat(fullname, &buf))
+ return fullname;
+ }
+ return name;
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+ char *p2;
+
+ switch (sym->type) {
+ case S_TRISTATE:
+ if (p[0] == 'm') {
+ sym->def[def].tri = mod;
+ sym->flags |= def_flags;
+ break;
+ }
+ case S_BOOLEAN:
+ if (p[0] == 'y') {
+ sym->def[def].tri = yes;
+ sym->flags |= def_flags;
+ break;
+ }
+ if (p[0] == 'n') {
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ }
+ conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+ break;
+ case S_OTHER:
+ if (*p != '"') {
+ for (p2 = p; *p2 && !isspace(*p2); p2++)
+ ;
+ sym->type = S_STRING;
+ goto done;
+ }
+ case S_STRING:
+ if (*p++ != '"')
+ break;
+ for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+ if (*p2 == '"') {
+ *p2 = 0;
+ break;
+ }
+ memmove(p2, p2 + 1, strlen(p2));
+ }
+ if (!p2) {
+ conf_warning("invalid string found");
+ return 1;
+ }
+ case S_INT:
+ case S_HEX:
+ done:
+ if (sym_string_valid(sym, p)) {
+ sym->def[def].val = strdup(p);
+ sym->flags |= def_flags;
+ } else {
+ conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+ return 1;
+ }
+ break;
+ default:
+ ;
+ }
+ return 0;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char line[1024];
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ if (name) {
+ in = zconf_fopen(name);
+ } else {
+ struct property *prop;
+
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ goto load;
+ sym_add_change_count(1);
+ if (!sym_defconfig_list) {
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+ return 1;
+ }
+
+ for_all_defaults(sym_defconfig_list, prop) {
+ if (expr_calc_value(prop->visible.expr) == no ||
+ prop->expr->type != E_SYMBOL)
+ continue;
+ name = conf_expand_value(prop->expr->left.sym->name);
+ in = zconf_fopen(name);
+ if (in) {
+ conf_message(_("using defaults found in %s"),
+ name);
+ goto load;
+ }
+ }
+ }
+ if (!in)
+ return 1;
+
+load:
+ conf_filename = name;
+ conf_lineno = 0;
+ conf_warnings = 0;
+ conf_unsaved = 0;
+
+ def_flags = SYMBOL_DEF << def;
+ for_all_symbols(i, sym) {
+ sym->flags |= SYMBOL_CHANGED;
+ sym->flags &= ~(def_flags|SYMBOL_VALID);
+ if (sym_is_choice(sym))
+ sym->flags |= def_flags;
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (sym->def[def].val)
+ free(sym->def[def].val);
+ default:
+ sym->def[def].val = NULL;
+ sym->def[def].tri = no;
+ }
+ }
+
+ while (fgets(line, sizeof(line), in)) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#') {
+ if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+ continue;
+ p = strchr(line + 2 + strlen(CONFIG_), ' ');
+ if (!p)
+ continue;
+ *p++ = 0;
+ if (strncmp(p, "is not set", 10))
+ continue;
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + 2 + strlen(CONFIG_));
+ if (!sym) {
+ sym_add_change_count(1);
+ goto setsym;
+ }
+ } else {
+ sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_BOOLEAN;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ sym->def[def].tri = no;
+ sym->flags |= def_flags;
+ break;
+ default:
+ ;
+ }
+ } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+ if (def == S_DEF_USER) {
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym) {
+ sym_add_change_count(1);
+ goto setsym;
+ }
+ } else {
+ sym = sym_lookup(line + strlen(CONFIG_), 0);
+ if (sym->type == S_UNKNOWN)
+ sym->type = S_OTHER;
+ }
+ if (sym->flags & def_flags) {
+ conf_warning("override: reassigning to symbol %s", sym->name);
+ }
+ if (conf_set_sym_val(sym, def, def_flags, p))
+ continue;
+ } else {
+ if (line[0] != '\r' && line[0] != '\n')
+ conf_warning("unexpected data");
+ continue;
+ }
+setsym:
+ if (sym && sym_is_choice_value(sym)) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ switch (sym->def[def].tri) {
+ case no:
+ break;
+ case mod:
+ if (cs->def[def].tri == yes) {
+ conf_warning("%s creates inconsistent choice state", sym->name);
+ cs->flags &= ~def_flags;
+ }
+ break;
+ case yes:
+ if (cs->def[def].tri != no)
+ conf_warning("override: %s changes choice state", sym->name);
+ cs->def[def].val = sym;
+ break;
+ }
+ cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+ }
+ }
+ fclose(in);
+
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+ return 0;
+}
+
+int conf_read(const char *name)
+{
+ struct symbol *sym, *choice_sym;
+ struct property *prop;
+ struct expr *e;
+ int i, flags;
+
+ sym_set_change_count(0);
+
+ if (conf_read_simple(name, S_DEF_USER))
+ return 1;
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+ goto sym_ok;
+ if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+ /* check that calculated value agrees with saved value */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+ break;
+ if (!sym_is_choice(sym))
+ goto sym_ok;
+ default:
+ if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+ goto sym_ok;
+ break;
+ }
+ } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+ /* no previous value and not saved */
+ goto sym_ok;
+ conf_unsaved++;
+ /* maybe print value in verbose mode... */
+ sym_ok:
+ if (!sym_is_choice(sym))
+ continue;
+ /* The choice symbol only has a set value (and thus is not new)
+ * if all its visible childs have values.
+ */
+ prop = sym_get_choice_prop(sym);
+ flags = sym->flags;
+ expr_list_for_each_sym(prop->expr, e, choice_sym)
+ if (choice_sym->visible != no)
+ flags &= choice_sym->flags;
+ sym->flags &= flags | ~SYMBOL_DEF_USER;
+ }
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
+ sym->flags &= ~SYMBOL_DEF_USER;
+ switch (sym->type) {
+ case S_STRING:
+ case S_INT:
+ case S_HEX:
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ sym_add_change_count(conf_warnings || conf_unsaved);
+
+ return 0;
+}
+
+/* Write a S_STRING */
+static void conf_write_string(bool headerfile, const char *name,
+ const char *str, FILE *out)
+{
+ int l;
+ if (headerfile)
+ fprintf(out, "#define %s%s \"", CONFIG_, name);
+ else
+ fprintf(out, "%s%s=\"", CONFIG_, name);
+
+ while (1) {
+ l = strcspn(str, "\"\\");
+ if (l) {
+ xfwrite(str, l, 1, out);
+ str += l;
+ }
+ if (!*str)
+ break;
+ fprintf(out, "\\%c", *str++);
+ }
+ fputs("\"\n", out);
+}
+
+static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
+{
+ const char *str;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ if (write_no)
+ fprintf(out, "# %s%s is not set\n",
+ CONFIG_, sym->name);
+ break;
+ case mod:
+ fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
+ break;
+ case yes:
+ fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
+ break;
+ }
+ break;
+ case S_STRING:
+ conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+ break;
+ case S_HEX:
+ case S_INT:
+ str = sym_get_string_value(sym);
+ fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
+ break;
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ }
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+ struct symbol *sym;
+ struct menu *menu;
+ FILE *out;
+
+ out = fopen(filename, "w");
+ if (!out)
+ return 1;
+
+ sym_clear_all_valid();
+
+ /* Traverse all menus to find all relevant symbols */
+ menu = rootmenu.list;
+
+ while (menu != NULL)
+ {
+ sym = menu->sym;
+ if (sym == NULL) {
+ if (!menu_is_visible(menu))
+ goto next_menu;
+ } else if (!sym_is_choice(sym)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next_menu;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* If we cannot change the symbol - skip */
+ if (!sym_is_changable(sym))
+ goto next_menu;
+ /* If symbol equals to default value - skip */
+ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+ goto next_menu;
+
+ /*
+ * If symbol is a choice value and equals to the
+ * default for a choice - skip.
+ * But only if value is bool and equal to "y" and
+ * choice is not "optional".
+ * (If choice is "optional" then all values can be "n")
+ */
+ if (sym_is_choice_value(sym)) {
+ struct symbol *cs;
+ struct symbol *ds;
+
+ cs = prop_get_symbol(sym_get_choice_prop(sym));
+ ds = sym_choice_default(cs);
+ if (!sym_is_optional(cs) && sym == ds) {
+ if ((sym->type == S_BOOLEAN) &&
+ sym_get_tristate_value(sym) == yes)
+ goto next_menu;
+ }
+ }
+ conf_write_symbol(sym, out, true);
+ }
+next_menu:
+ if (menu->list != NULL) {
+ menu = menu->list;
+ }
+ else if (menu->next != NULL) {
+ menu = menu->next;
+ } else {
+ while ((menu = menu->parent)) {
+ if (menu->next != NULL) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ }
+ fclose(out);
+ return 0;
+}
+
+int conf_write(const char *name)
+{
+ FILE *out;
+ struct symbol *sym;
+ struct menu *menu;
+ const char *basename;
+ const char *str;
+ char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
+ time_t now;
+ int use_timestamp = 1;
+ char *env;
+
+ dirname[0] = 0;
+ if (name && name[0]) {
+ struct stat st;
+ char *slash;
+
+ if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+ strcpy(dirname, name);
+ strcat(dirname, "/");
+ basename = conf_get_configname();
+ } else if ((slash = strrchr(name, '/'))) {
+ int size = slash - name + 1;
+ memcpy(dirname, name, size);
+ dirname[size] = 0;
+ if (slash[1])
+ basename = slash + 1;
+ else
+ basename = conf_get_configname();
+ } else
+ basename = name;
+ } else
+ basename = conf_get_configname();
+
+ sprintf(newname, "%s%s", dirname, basename);
+ env = getenv("KCONFIG_OVERWRITECONFIG");
+ if (!env || !*env) {
+ sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+ out = fopen(tmpname, "w");
+ } else {
+ *tmpname = 0;
+ out = fopen(newname, "w");
+ }
+ if (!out)
+ return 1;
+
+ time(&now);
+ env = getenv("KCONFIG_NOTIMESTAMP");
+ if (env && *env)
+ use_timestamp = 0;
+
+ fprintf(out, _("#\n"
+ "# Automatically generated make config: don't edit\n"
+ "# %s\n"
+ "%s%s"
+ "#\n"),
+ rootmenu.prompt->text,
+ use_timestamp ? "# " : "",
+ use_timestamp ? ctime(&now) : "");
+
+ if (!conf_get_changed())
+ sym_clear_all_valid();
+
+ menu = rootmenu.list;
+ while (menu) {
+ sym = menu->sym;
+ if (!sym) {
+ if (!menu_is_visible(menu))
+ goto next;
+ str = menu_get_prompt(menu);
+ fprintf(out, "\n"
+ "#\n"
+ "# %s\n"
+ "#\n", str);
+ } else if (!(sym->flags & SYMBOL_CHOICE)) {
+ sym_calc_value(sym);
+ if (!(sym->flags & SYMBOL_WRITE))
+ goto next;
+ sym->flags &= ~SYMBOL_WRITE;
+ /* Write config symbol to file */
+ conf_write_symbol(sym, out, true);
+ }
+
+next:
+ if (menu->list) {
+ menu = menu->list;
+ continue;
+ }
+ if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+ fclose(out);
+
+ if (*tmpname) {
+ strcat(dirname, basename);
+ strcat(dirname, ".old");
+ rename(newname, dirname);
+ if (rename(tmpname, newname))
+ return 1;
+ }
+
+ conf_message(_("configuration written to %s"), newname);
+
+ sym_set_change_count(0);
+
+ return 0;
+}
+
+static int conf_split_config(void)
+{
+ const char *name;
+ char path[PATH_MAX+1];
+ char *s, *d, c;
+ struct symbol *sym;
+ struct stat sb;
+ int res, i, fd;
+
+ name = conf_get_autoconfig_name();
+ conf_read_simple(name, S_DEF_AUTO);
+
+ if (chdir("include/config"))
+ return 1;
+
+ res = 0;
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+ continue;
+ if (sym->flags & SYMBOL_WRITE) {
+ if (sym->flags & SYMBOL_DEF_AUTO) {
+ /*
+ * symbol has old and new value,
+ * so compare them...
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) ==
+ sym->def[S_DEF_AUTO].tri)
+ continue;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (!strcmp(sym_get_string_value(sym),
+ sym->def[S_DEF_AUTO].val))
+ continue;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /*
+ * If there is no old value, only 'no' (unset)
+ * is allowed as new value.
+ */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_get_tristate_value(sym) == no)
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+ /* There is neither an old nor a new value. */
+ continue;
+ /* else
+ * There is an old value, but no new value ('no' (unset)
+ * isn't saved in auto.conf, so the old value is always
+ * different from 'no').
+ */
+
+ /* Replace all '_' and append ".h" */
+ s = sym->name;
+ d = path;
+ while ((c = *s++)) {
+ c = tolower(c);
+ *d++ = (c == '_') ? '/' : c;
+ }
+ strcpy(d, ".h");
+
+ /* Assume directory path already exists. */
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ res = 1;
+ break;
+ }
+ /*
+ * Create directory components,
+ * unless they exist already.
+ */
+ d = path;
+ while ((d = strchr(d, '/'))) {
+ *d = 0;
+ if (stat(path, &sb) && mkdir(path, 0755)) {
+ res = 1;
+ goto out;
+ }
+ *d++ = '/';
+ }
+ /* Try it again. */
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ res = 1;
+ break;
+ }
+ }
+ close(fd);
+ }
+out:
+ if (chdir("../.."))
+ return 1;
+
+ return res;
+}
+
+int conf_write_autoconf(void)
+{
+ struct symbol *sym;
+ const char *str;
+ const char *name;
+ FILE *out, *tristate, *out_h;
+ time_t now;
+ int i;
+
+ sym_clear_all_valid();
+
+ file_write_dep("include/config/auto.conf.cmd");
+
+ if (conf_split_config())
+ return 1;
+
+ out = fopen(".tmpconfig", "w");
+ if (!out)
+ return 1;
+
+ tristate = fopen(".tmpconfig_tristate", "w");
+ if (!tristate) {
+ fclose(out);
+ return 1;
+ }
+
+ out_h = fopen(".tmpconfig.h", "w");
+ if (!out_h) {
+ fclose(out);
+ fclose(tristate);
+ return 1;
+ }
+
+ time(&now);
+ fprintf(out, "#\n"
+ "# Automatically generated make config: don't edit\n"
+ "# %s\n"
+ "# %s"
+ "#\n",
+ rootmenu.prompt->text, ctime(&now));
+ fprintf(tristate, "#\n"
+ "# Automatically generated - do not edit\n"
+ "\n");
+ fprintf(out_h, "/*\n"
+ " * Automatically generated C config: don't edit\n"
+ " * %s\n"
+ " * %s"
+ " */\n",
+ rootmenu.prompt->text, ctime(&now));
+
+ for_all_symbols(i, sym) {
+ sym_calc_value(sym);
+ if (!sym->name)
+ continue;
+ if (!(sym->flags & SYMBOL_WRITE)) {
+ if (sym->type == S_BOOLEAN || sym->type == S_HEX
+ || sym->type == S_INT)
+ fprintf(out_h, "#define %s%s 0\n",
+ CONFIG_, sym->name);
+ continue;
+ }
+
+ /* write symbol to config file */
+ conf_write_symbol(sym, out, false);
+
+ /* update autoconf and tristate files */
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (sym_get_tristate_value(sym)) {
+ case no:
+ fprintf(out_h, "#define %s%s 0\n",
+ CONFIG_, sym->name);
+ break;
+ case mod:
+ fprintf(tristate, "%s%s=M\n",
+ CONFIG_, sym->name);
+ fprintf(out_h, "#define %s%s_MODULE 1\n",
+ CONFIG_, sym->name);
+ break;
+ case yes:
+ if (sym->type == S_TRISTATE)
+ fprintf(tristate,"%s%s=Y\n",
+ CONFIG_, sym->name);
+ fprintf(out_h, "#define %s%s 1\n",
+ CONFIG_, sym->name);
+ break;
+ }
+ break;
+ case S_STRING:
+ conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
+ break;
+ case S_HEX:
+ str = sym_get_string_value(sym);
+ if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+ fprintf(out_h, "#define %s%s 0x%s\n",
+ CONFIG_, sym->name, str);
+ break;
+ }
+ case S_INT:
+ str = sym_get_string_value(sym);
+ fprintf(out_h, "#define %s%s %s\n",
+ CONFIG_, sym->name, str);
+ break;
+ default:
+ break;
+ }
+ }
+ fclose(out);
+ fclose(tristate);
+ fclose(out_h);
+
+ name = getenv("KCONFIG_AUTOHEADER");
+ if (!name)
+ name = "include/generated/autoconf.h";
+ if (rename(".tmpconfig.h", name))
+ return 1;
+ name = getenv("KCONFIG_TRISTATE");
+ if (!name)
+ name = "include/config/tristate.conf";
+ if (rename(".tmpconfig_tristate", name))
+ return 1;
+ name = conf_get_autoconfig_name();
+ /*
+ * This must be the last step, kbuild has a dependency on auto.conf
+ * and this marks the successful completion of the previous steps.
+ */
+ if (rename(".tmpconfig", name))
+ return 1;
+
+ return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+ int _sym_change_count = sym_change_count;
+ sym_change_count = count;
+ if (conf_changed_callback &&
+ (bool)_sym_change_count != (bool)count)
+ conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+ sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+ return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+ conf_changed_callback = fn;
+}
+
+static void randomize_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+ int cnt, def;
+
+ /*
+ * If choice is mod then we may have more items selected
+ * and if no then no-one.
+ * In both cases stop.
+ */
+ if (csym->curr.tri != yes)
+ return;
+
+ prop = sym_get_choice_prop(csym);
+
+ /* count entries in choice block */
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym)
+ cnt++;
+
+ /*
+ * find a random value and set it to yes,
+ * set the rest to no so we have only one set
+ */
+ def = (rand() % cnt);
+
+ cnt = 0;
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (def == cnt++) {
+ sym->def[S_DEF_USER].tri = yes;
+ csym->def[S_DEF_USER].val = sym;
+ }
+ else {
+ sym->def[S_DEF_USER].tri = no;
+ }
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID);
+}
+
+static void set_all_choice_values(struct symbol *csym)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct expr *e;
+
+ prop = sym_get_choice_prop(csym);
+
+ /*
+ * Set all non-assinged choice values to no
+ */
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ if (!sym_has_value(sym))
+ sym->def[S_DEF_USER].tri = no;
+ }
+ csym->flags |= SYMBOL_DEF_USER;
+ /* clear VALID to get value calculated */
+ csym->flags &= ~(SYMBOL_VALID);
+}
+
+void conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+ struct symbol *sym, *csym;
+ int i, cnt;
+
+ for_all_symbols(i, sym) {
+ if (sym_has_value(sym))
+ continue;
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (mode) {
+ case def_yes:
+ sym->def[S_DEF_USER].tri = yes;
+ break;
+ case def_mod:
+ sym->def[S_DEF_USER].tri = mod;
+ break;
+ case def_no:
+ sym->def[S_DEF_USER].tri = no;
+ break;
+ case def_random:
+ cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
+ sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
+ break;
+ default:
+ continue;
+ }
+ if (!(sym_is_choice(sym) && mode == def_random))
+ sym->flags |= SYMBOL_DEF_USER;
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ sym_clear_all_valid();
+
+ /*
+ * We have different type of choice blocks.
+ * If curr.tri equals to mod then we can select several
+ * choice symbols in one block.
+ * In this case we do nothing.
+ * If curr.tri equals yes then only one symbol can be
+ * selected in a choice block and we set it to yes,
+ * and the rest to no.
+ */
+ for_all_symbols(i, csym) {
+ if (sym_has_value(csym) || !sym_is_choice(csym))
+ continue;
+
+ sym_calc_value(csym);
+ if (mode == def_random)
+ randomize_choice_values(csym);
+ else
+ set_all_choice_values(csym);
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR 0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = E_SYMBOL;
+ e->left.sym = sym;
+ return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = type;
+ e->left.expr = ce;
+ return e;
+}
+
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = type;
+ e->left.expr = e1;
+ e->right.expr = e2;
+ return e;
+}
+
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
+{
+ struct expr *e = malloc(sizeof(*e));
+ memset(e, 0, sizeof(*e));
+ e->type = type;
+ e->left.sym = s1;
+ e->right.sym = s2;
+ return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+ if (!e1)
+ return e2;
+ return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(const struct expr *org)
+{
+ struct expr *e;
+
+ if (!org)
+ return NULL;
+
+ e = malloc(sizeof(*org));
+ memcpy(e, org, sizeof(*org));
+ switch (org->type) {
+ case E_SYMBOL:
+ e->left = org->left;
+ break;
+ case E_NOT:
+ e->left.expr = expr_copy(org->left.expr);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ e->left.sym = org->left.sym;
+ e->right.sym = org->right.sym;
+ break;
+ case E_AND:
+ case E_OR:
+ case E_LIST:
+ e->left.expr = expr_copy(org->left.expr);
+ e->right.expr = expr_copy(org->right.expr);
+ break;
+ default:
+ printf("can't copy type %d\n", e->type);
+ free(e);
+ e = NULL;
+ break;
+ }
+
+ return e;
+}
+
+void expr_free(struct expr *e)
+{
+ if (!e)
+ return;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ break;
+ case E_NOT:
+ expr_free(e->left.expr);
+ return;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ break;
+ case E_OR:
+ case E_AND:
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ break;
+ default:
+ printf("how to free type %d?\n", e->type);
+ break;
+ }
+ free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+ if (e1->type == type) {
+ __expr_eliminate_eq(type, &e1->left.expr, &e2);
+ __expr_eliminate_eq(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ __expr_eliminate_eq(type, &e1, &e2->left.expr);
+ __expr_eliminate_eq(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym &&
+ (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+ return;
+ if (!expr_eq(e1, e2))
+ return;
+ trans_count++;
+ expr_free(e1); expr_free(e2);
+ switch (type) {
+ case E_OR:
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ break;
+ case E_AND:
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ break;
+ default:
+ ;
+ }
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+ if (!e1 || !e2)
+ return;
+ switch (e1->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e1->type, ep1, ep2);
+ default:
+ ;
+ }
+ if (e1->type != e2->type) switch (e2->type) {
+ case E_OR:
+ case E_AND:
+ __expr_eliminate_eq(e2->type, ep1, ep2);
+ default:
+ ;
+ }
+ e1 = expr_eliminate_yn(e1);
+ e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+ int res, old_count;
+
+ if (e1->type != e2->type)
+ return 0;
+ switch (e1->type) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+ case E_SYMBOL:
+ return e1->left.sym == e2->left.sym;
+ case E_NOT:
+ return expr_eq(e1->left.expr, e2->left.expr);
+ case E_AND:
+ case E_OR:
+ e1 = expr_copy(e1);
+ e2 = expr_copy(e2);
+ old_count = trans_count;
+ expr_eliminate_eq(&e1, &e2);
+ res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+ e1->left.sym == e2->left.sym);
+ expr_free(e1);
+ expr_free(e2);
+ trans_count = old_count;
+ return res;
+ case E_LIST:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+
+ if (DEBUG_EXPR) {
+ expr_fprint(e1, stdout);
+ printf(" = ");
+ expr_fprint(e2, stdout);
+ printf(" ?\n");
+ }
+
+ return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (e) switch (e->type) {
+ case E_AND:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.expr = NULL;
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ }
+ }
+ break;
+ case E_OR:
+ e->left.expr = expr_eliminate_yn(e->left.expr);
+ e->right.expr = expr_eliminate_yn(e->right.expr);
+ if (e->left.expr->type == E_SYMBOL) {
+ if (e->left.expr->left.sym == &symbol_no) {
+ free(e->left.expr);
+ tmp = e->right.expr;
+ *e = *(e->right.expr);
+ free(tmp);
+ return e;
+ } else if (e->left.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ if (e->right.expr->type == E_SYMBOL) {
+ if (e->right.expr->left.sym == &symbol_no) {
+ free(e->right.expr);
+ tmp = e->left.expr;
+ *e = *(e->left.expr);
+ free(tmp);
+ return e;
+ } else if (e->right.expr->left.sym == &symbol_yes) {
+ expr_free(e->left.expr);
+ expr_free(e->right.expr);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.expr = NULL;
+ return e;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_AND:
+ case E_OR:
+ case E_NOT:
+ e->left.expr = expr_trans_bool(e->left.expr);
+ e->right.expr = expr_trans_bool(e->right.expr);
+ break;
+ case E_UNEQUAL:
+ // FOO!=n -> FOO
+ if (e->left.sym->type == S_TRISTATE) {
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return expr_copy(e1);
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='m') -> (a!='n')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+ // (a='y') || (a='n') -> (a!='m')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+ }
+ if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+ // (a='m') || (a='n') -> (a!='y')
+ return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+ }
+ }
+ if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+ if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+ (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+ return expr_alloc_symbol(&symbol_yes);
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") || (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ return NULL;
+}
+
+static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+ struct expr *tmp;
+ struct symbol *sym1, *sym2;
+
+ if (expr_eq(e1, e2))
+ return expr_copy(e1);
+ if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+ return NULL;
+ if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+ return NULL;
+ if (e1->type == E_NOT) {
+ tmp = e1->left.expr;
+ if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+ return NULL;
+ sym1 = tmp->left.sym;
+ } else
+ sym1 = e1->left.sym;
+ if (e2->type == E_NOT) {
+ if (e2->left.expr->type != E_SYMBOL)
+ return NULL;
+ sym2 = e2->left.expr->left.sym;
+ } else
+ sym2 = e2->left.sym;
+ if (sym1 != sym2)
+ return NULL;
+ if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+ return NULL;
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+ // (a) && (a='y') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+ // (a) && (a!='n') -> (a)
+ return expr_alloc_symbol(sym1);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+ // (a) && (a!='m') -> (a='y')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if (sym1->type == S_TRISTATE) {
+ if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e1->right.sym;
+ if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+ // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+ sym2 = e2->right.sym;
+ if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+ return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+ : expr_alloc_symbol(&symbol_no);
+ }
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+ (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+ // (a!='y') && (a!='m') -> (a='n')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+ if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+ ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+ (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+ // (a!='m') && (a!='n') -> (a='m')
+ return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+ if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+ (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+ (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+ (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+ return NULL;
+ }
+
+ if (DEBUG_EXPR) {
+ printf("optimize (");
+ expr_fprint(e1, stdout);
+ printf(") && (");
+ expr_fprint(e2, stdout);
+ printf(")?\n");
+ }
+ return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp;
+
+ if (e1->type == type) {
+ expr_eliminate_dups1(type, &e1->left.expr, &e2);
+ expr_eliminate_dups1(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups1(type, &e1, &e2->left.expr);
+ expr_eliminate_dups1(type, &e1, &e2->right.expr);
+ return;
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e1->type, &e1, &e1);
+ default:
+ ;
+ }
+
+ switch (type) {
+ case E_OR:
+ tmp = expr_join_or(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ case E_AND:
+ tmp = expr_join_and(e1, e2);
+ if (tmp) {
+ expr_free(e1); expr_free(e2);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = tmp;
+ trans_count++;
+ }
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ struct expr *tmp, *tmp1, *tmp2;
+
+ if (e1->type == type) {
+ expr_eliminate_dups2(type, &e1->left.expr, &e2);
+ expr_eliminate_dups2(type, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_eliminate_dups2(type, &e1, &e2->left.expr);
+ expr_eliminate_dups2(type, &e1, &e2->right.expr);
+ }
+ if (e1 == e2)
+ return;
+
+ switch (e1->type) {
+ case E_OR:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO || BAR) && (!FOO && !BAR) -> n
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_and(&tmp1, &tmp2);
+ if (expr_is_yes(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_no);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ case E_AND:
+ expr_eliminate_dups2(e1->type, &e1, &e1);
+ // (FOO && BAR) || (!FOO || !BAR) -> y
+ tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+ tmp2 = expr_copy(e2);
+ tmp = expr_extract_eq_or(&tmp1, &tmp2);
+ if (expr_is_no(tmp1)) {
+ expr_free(e1);
+ e1 = expr_alloc_symbol(&symbol_yes);
+ trans_count++;
+ }
+ expr_free(tmp2);
+ expr_free(tmp1);
+ expr_free(tmp);
+ break;
+ default:
+ ;
+ }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+ int oldcount;
+ if (!e)
+ return e;
+
+ oldcount = trans_count;
+ while (1) {
+ trans_count = 0;
+ switch (e->type) {
+ case E_OR: case E_AND:
+ expr_eliminate_dups1(e->type, &e, &e);
+ expr_eliminate_dups2(e->type, &e, &e);
+ default:
+ ;
+ }
+ if (!trans_count)
+ break;
+ e = expr_eliminate_yn(e);
+ }
+ trans_count = oldcount;
+ return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+ struct expr *tmp;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ case E_SYMBOL:
+ case E_LIST:
+ break;
+ default:
+ e->left.expr = expr_transform(e->left.expr);
+ e->right.expr = expr_transform(e->right.expr);
+ }
+
+ switch (e->type) {
+ case E_EQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->type != S_BOOLEAN)
+ break;
+ if (e->right.sym == &symbol_no) {
+ e->type = E_SYMBOL;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_mod) {
+ printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ e->right.sym = NULL;
+ break;
+ }
+ if (e->right.sym == &symbol_yes) {
+ e->type = E_NOT;
+ e->left.expr = expr_alloc_symbol(e->left.sym);
+ e->right.sym = NULL;
+ break;
+ }
+ break;
+ case E_NOT:
+ switch (e->left.expr->type) {
+ case E_NOT:
+ // !!a -> a
+ tmp = e->left.expr->left.expr;
+ free(e->left.expr);
+ free(e);
+ e = tmp;
+ e = expr_transform(e);
+ break;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ // !a='x' -> a!='x'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+ break;
+ case E_OR:
+ // !(a || b) -> !a && !b
+ tmp = e->left.expr;
+ e->type = E_AND;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_AND:
+ // !(a && b) -> !a || !b
+ tmp = e->left.expr;
+ e->type = E_OR;
+ e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+ tmp->type = E_NOT;
+ tmp->right.expr = NULL;
+ e = expr_transform(e);
+ break;
+ case E_SYMBOL:
+ if (e->left.expr->left.sym == &symbol_yes) {
+ // !'y' -> 'n'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_no;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_mod) {
+ // !'m' -> 'm'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_mod;
+ break;
+ }
+ if (e->left.expr->left.sym == &symbol_no) {
+ // !'n' -> 'y'
+ tmp = e->left.expr;
+ free(e);
+ e = tmp;
+ e->type = E_SYMBOL;
+ e->left.sym = &symbol_yes;
+ break;
+ }
+ break;
+ default:
+ ;
+ }
+ break;
+ default:
+ ;
+ }
+ return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return 0;
+
+ switch (dep->type) {
+ case E_AND:
+ case E_OR:
+ return expr_contains_symbol(dep->left.expr, sym) ||
+ expr_contains_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ case E_UNEQUAL:
+ return dep->left.sym == sym ||
+ dep->right.sym == sym;
+ case E_NOT:
+ return expr_contains_symbol(dep->left.expr, sym);
+ default:
+ ;
+ }
+ return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+ if (!dep)
+ return false;
+
+ switch (dep->type) {
+ case E_AND:
+ return expr_depends_symbol(dep->left.expr, sym) ||
+ expr_depends_symbol(dep->right.expr, sym);
+ case E_SYMBOL:
+ return dep->left.sym == sym;
+ case E_EQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+ return true;
+ }
+ break;
+ case E_UNEQUAL:
+ if (dep->left.sym == sym) {
+ if (dep->right.sym == &symbol_no)
+ return true;
+ }
+ break;
+ default:
+ ;
+ }
+ return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_AND, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+ struct expr *tmp = NULL;
+ expr_extract_eq(E_OR, &tmp, ep1, ep2);
+ if (tmp) {
+ *ep1 = expr_eliminate_yn(*ep1);
+ *ep2 = expr_eliminate_yn(*ep2);
+ }
+ return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+ if (e1->type == type) {
+ expr_extract_eq(type, ep, &e1->left.expr, &e2);
+ expr_extract_eq(type, ep, &e1->right.expr, &e2);
+ return;
+ }
+ if (e2->type == type) {
+ expr_extract_eq(type, ep, ep1, &e2->left.expr);
+ expr_extract_eq(type, ep, ep1, &e2->right.expr);
+ return;
+ }
+ if (expr_eq(e1, e2)) {
+ *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+ expr_free(e2);
+ if (type == E_AND) {
+ e1 = expr_alloc_symbol(&symbol_yes);
+ e2 = expr_alloc_symbol(&symbol_yes);
+ } else if (type == E_OR) {
+ e1 = expr_alloc_symbol(&symbol_no);
+ e2 = expr_alloc_symbol(&symbol_no);
+ }
+ }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+ struct expr *e1, *e2;
+
+ if (!e) {
+ e = expr_alloc_symbol(sym);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ }
+ switch (e->type) {
+ case E_AND:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_OR:
+ e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+ e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+ if (sym == &symbol_yes)
+ e = expr_alloc_two(E_OR, e1, e2);
+ if (sym == &symbol_no)
+ e = expr_alloc_two(E_AND, e1, e2);
+ if (type == E_UNEQUAL)
+ e = expr_alloc_one(E_NOT, e);
+ return e;
+ case E_NOT:
+ return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+ case E_UNEQUAL:
+ case E_EQUAL:
+ if (type == E_EQUAL) {
+ if (sym == &symbol_yes)
+ return expr_copy(e);
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_no);
+ if (sym == &symbol_no)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ } else {
+ if (sym == &symbol_yes)
+ return expr_alloc_one(E_NOT, expr_copy(e));
+ if (sym == &symbol_mod)
+ return expr_alloc_symbol(&symbol_yes);
+ if (sym == &symbol_no)
+ return expr_copy(e);
+ }
+ break;
+ case E_SYMBOL:
+ return expr_alloc_comp(type, e->left.sym, sym);
+ case E_LIST:
+ case E_RANGE:
+ case E_NONE:
+ /* panic */;
+ }
+ return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+ tristate val1, val2;
+ const char *str1, *str2;
+
+ if (!e)
+ return yes;
+
+ switch (e->type) {
+ case E_SYMBOL:
+ sym_calc_value(e->left.sym);
+ return e->left.sym->curr.tri;
+ case E_AND:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return EXPR_AND(val1, val2);
+ case E_OR:
+ val1 = expr_calc_value(e->left.expr);
+ val2 = expr_calc_value(e->right.expr);
+ return EXPR_OR(val1, val2);
+ case E_NOT:
+ val1 = expr_calc_value(e->left.expr);
+ return EXPR_NOT(val1);
+ case E_EQUAL:
+ sym_calc_value(e->left.sym);
+ sym_calc_value(e->right.sym);
+ str1 = sym_get_string_value(e->left.sym);
+ str2 = sym_get_string_value(e->right.sym);
+ return !strcmp(str1, str2) ? yes : no;
+ case E_UNEQUAL:
+ sym_calc_value(e->left.sym);
+ sym_calc_value(e->right.sym);
+ str1 = sym_get_string_value(e->left.sym);
+ str2 = sym_get_string_value(e->right.sym);
+ return !strcmp(str1, str2) ? no : yes;
+ default:
+ printf("expr_calc_value: %d?\n", e->type);
+ return no;
+ }
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+ return 1;
+#else
+ if (t1 == t2)
+ return 0;
+ switch (t1) {
+ case E_EQUAL:
+ case E_UNEQUAL:
+ if (t2 == E_NOT)
+ return 1;
+ case E_NOT:
+ if (t2 == E_AND)
+ return 1;
+ case E_AND:
+ if (t2 == E_OR)
+ return 1;
+ case E_OR:
+ if (t2 == E_LIST)
+ return 1;
+ case E_LIST:
+ if (t2 == 0)
+ return 1;
+ default:
+ return -1;
+ }
+ printf("[%dgt%d?]", t1, t2);
+ return 0;
+#endif
+}
+
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+ if (e == NULL)
+ return NULL;
+
+ while (e->type != E_SYMBOL)
+ e = e->left.expr;
+
+ return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+ struct expr *ret;
+
+ switch (e1->type) {
+ case E_OR:
+ return expr_alloc_and(
+ expr_simplify_unmet_dep(e1->left.expr, e2),
+ expr_simplify_unmet_dep(e1->right.expr, e2));
+ case E_AND: {
+ struct expr *e;
+ e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+ e = expr_eliminate_dups(e);
+ ret = (!expr_eq(e, e1)) ? e1 : NULL;
+ expr_free(e);
+ break;
+ }
+ default:
+ ret = e1;
+ break;
+ }
+
+ return expr_get_leftmost_symbol(ret);
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
+{
+ if (!e) {
+ fn(data, NULL, "y");
+ return;
+ }
+
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, NULL, "(");
+ switch (e->type) {
+ case E_SYMBOL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ break;
+ case E_NOT:
+ fn(data, NULL, "!");
+ expr_print(e->left.expr, fn, data, E_NOT);
+ break;
+ case E_EQUAL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, "=");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_UNEQUAL:
+ if (e->left.sym->name)
+ fn(data, e->left.sym, e->left.sym->name);
+ else
+ fn(data, NULL, "<choice>");
+ fn(data, NULL, "!=");
+ fn(data, e->right.sym, e->right.sym->name);
+ break;
+ case E_OR:
+ expr_print(e->left.expr, fn, data, E_OR);
+ fn(data, NULL, " || ");
+ expr_print(e->right.expr, fn, data, E_OR);
+ break;
+ case E_AND:
+ expr_print(e->left.expr, fn, data, E_AND);
+ fn(data, NULL, " && ");
+ expr_print(e->right.expr, fn, data, E_AND);
+ break;
+ case E_LIST:
+ fn(data, e->right.sym, e->right.sym->name);
+ if (e->left.expr) {
+ fn(data, NULL, " ^ ");
+ expr_print(e->left.expr, fn, data, E_LIST);
+ }
+ break;
+ case E_RANGE:
+ fn(data, NULL, "[");
+ fn(data, e->left.sym, e->left.sym->name);
+ fn(data, NULL, " ");
+ fn(data, e->right.sym, e->right.sym->name);
+ fn(data, NULL, "]");
+ break;
+ default:
+ {
+ char buf[32];
+ sprintf(buf, "<unknown type %d>", e->type);
+ fn(data, NULL, buf);
+ break;
+ }
+ }
+ if (expr_compare_type(prevtoken, e->type) > 0)
+ fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+ xfwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+ expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
+{
+ struct gstr *gs = (struct gstr*)data;
+ const char *sym_str = NULL;
+
+ if (sym)
+ sym_str = sym_get_string_value(sym);
+
+ if (gs->max_width) {
+ unsigned extra_length = strlen(str);
+ const char *last_cr = strrchr(gs->s, '\n');
+ unsigned last_line_length;
+
+ if (sym_str)
+ extra_length += 4 + strlen(sym_str);
+
+ if (!last_cr)
+ last_cr = gs->s;
+
+ last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+ if ((last_line_length + extra_length) > gs->max_width)
+ str_append(gs, "\\\n");
+ }
+
+ str_append(gs, str);
+ if (sym && sym->type != S_UNKNOWN)
+ str_printf(gs, " [=%s]", sym_str);
+}
+
+void expr_gstr_print(struct expr *e, struct gstr *gs)
+{
+ expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+ struct file *next;
+ struct file *parent;
+ const char *name;
+ int lineno;
+ int flags;
+};
+
+#define FILE_BUSY 0x0001
+#define FILE_SCANNED 0x0002
+
+typedef enum tristate {
+ no, mod, yes
+} tristate;
+
+enum expr_type {
+ E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+ struct expr *expr;
+ struct symbol *sym;
+};
+
+struct expr {
+ enum expr_type type;
+ union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep) (2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+ for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+struct expr_value {
+ struct expr *expr;
+ tristate tri;
+};
+
+struct symbol_value {
+ void *val;
+ tristate tri;
+};
+
+enum symbol_type {
+ S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+/* enum values are used as index to symbol.def[] */
+enum {
+ S_DEF_USER, /* main user value */
+ S_DEF_AUTO, /* values read from auto.conf */
+ S_DEF_DEF3, /* Reserved for UI usage */
+ S_DEF_DEF4, /* Reserved for UI usage */
+ S_DEF_COUNT
+};
+
+struct symbol {
+ struct symbol *next;
+ char *name;
+ enum symbol_type type;
+ struct symbol_value curr;
+ struct symbol_value def[S_DEF_COUNT];
+ tristate visible;
+ int flags;
+ struct property *prop;
+ struct expr_value dir_dep;
+ struct expr_value rev_dep;
+};
+
+#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+
+#define SYMBOL_CONST 0x0001 /* symbol is const */
+#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
+#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */
+#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */
+#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */
+#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
+#define SYMBOL_WRITE 0x0200 /* ? */
+#define SYMBOL_CHANGED 0x0400 /* ? */
+#define SYMBOL_AUTO 0x1000 /* value from environment variable */
+#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
+#define SYMBOL_WARNED 0x8000 /* warning has been issued */
+
+/* Set when symbol.def[] is used */
+#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */
+#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */
+#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */
+#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */
+#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
+
+#define SYMBOL_MAXLENGTH 256
+#define SYMBOL_HASHSIZE 9973
+
+/* A property represent the config options that can be associated
+ * with a config "symbol".
+ * Sample:
+ * config FOO
+ * default y
+ * prompt "foo prompt"
+ * select BAR
+ * config BAZ
+ * int "BAZ Value"
+ * range 1..255
+ */
+enum prop_type {
+ P_UNKNOWN,
+ P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */
+ P_COMMENT, /* text associated with a comment */
+ P_MENU, /* prompt associated with a menuconfig option */
+ P_DEFAULT, /* default y */
+ P_CHOICE, /* choice value */
+ P_SELECT, /* select BAR */
+ P_RANGE, /* range 7..100 (for a symbol) */
+ P_ENV, /* value from environment variable */
+ P_SYMBOL, /* where a symbol is defined */
+};
+
+struct property {
+ struct property *next; /* next property - null if last */
+ struct symbol *sym; /* the symbol for which the property is associated */
+ enum prop_type type; /* type of property */
+ const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
+ struct expr_value visible;
+ struct expr *expr; /* the optional conditional part of the property */
+ struct menu *menu; /* the menu the property are associated with
+ * valid for: P_SELECT, P_RANGE, P_CHOICE,
+ * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+ struct file *file; /* what file was this property defined */
+ int lineno; /* what lineno was this property defined */
+};
+
+#define for_all_properties(sym, st, tok) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+ for (st = sym->prop; st; st = st->next) \
+ if (st->text)
+
+struct menu {
+ struct menu *next;
+ struct menu *parent;
+ struct menu *list;
+ struct symbol *sym;
+ struct property *prompt;
+ struct expr *visibility;
+ struct expr *dep;
+ unsigned int flags;
+ char *help;
+ struct file *file;
+ int lineno;
+ void *data;
+};
+
+#define MENU_CHANGED 0x0001
+#define MENU_ROOT 0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(const struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+ return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+ return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
--- /dev/null
+/* Hey EMACS -*- linux-c -*- */
+/*
+ *
+ * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "lkc.h"
+#include "images.c"
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+
+//#define DEBUG
+
+enum {
+ SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
+};
+
+enum {
+ OPT_NORMAL, OPT_ALL, OPT_PROMPT
+};
+
+static gint view_mode = FULL_VIEW;
+static gboolean show_name = TRUE;
+static gboolean show_range = TRUE;
+static gboolean show_value = TRUE;
+static gboolean resizeable = FALSE;
+static int opt_mode = OPT_NORMAL;
+
+GtkWidget *main_wnd = NULL;
+GtkWidget *tree1_w = NULL; // left frame
+GtkWidget *tree2_w = NULL; // right frame
+GtkWidget *text_w = NULL;
+GtkWidget *hpaned = NULL;
+GtkWidget *vpaned = NULL;
+GtkWidget *back_btn = NULL;
+GtkWidget *save_btn = NULL;
+GtkWidget *save_menu_item = NULL;
+
+GtkTextTag *tag1, *tag2;
+GdkColor color;
+
+GtkTreeStore *tree1, *tree2, *tree;
+GtkTreeModel *model1, *model2;
+static GtkTreeIter *parents[256];
+static gint indent;
+
+static struct menu *current; // current node for SINGLE view
+static struct menu *browsed; // browsed node for SPLIT view
+
+enum {
+ COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
+ COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
+ COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
+ COL_NUMBER
+};
+
+static void display_list(void);
+static void display_tree(struct menu *menu);
+static void display_tree_part(void);
+static void update_tree(struct menu *src, GtkTreeIter * dst);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static gchar **fill_row(struct menu *menu);
+static void conf_changed(void);
+
+/* Helping/Debugging Functions */
+
+const char *dbg_sym_flags(int val)
+{
+ static char buf[256];
+
+ bzero(buf, 256);
+
+ if (val & SYMBOL_CONST)
+ strcat(buf, "const/");
+ if (val & SYMBOL_CHECK)
+ strcat(buf, "check/");
+ if (val & SYMBOL_CHOICE)
+ strcat(buf, "choice/");
+ if (val & SYMBOL_CHOICEVAL)
+ strcat(buf, "choiceval/");
+ if (val & SYMBOL_VALID)
+ strcat(buf, "valid/");
+ if (val & SYMBOL_OPTIONAL)
+ strcat(buf, "optional/");
+ if (val & SYMBOL_WRITE)
+ strcat(buf, "write/");
+ if (val & SYMBOL_CHANGED)
+ strcat(buf, "changed/");
+ if (val & SYMBOL_AUTO)
+ strcat(buf, "auto/");
+
+ buf[strlen(buf) - 1] = '\0';
+
+ return buf;
+}
+
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+ GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+ GdkPixmap *pixmap;
+ GdkBitmap *mask;
+ GtkToolButton *button;
+ GtkWidget *image;
+
+ pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+ &style->bg[GTK_STATE_NORMAL],
+ xpm);
+
+ button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+ image = gtk_image_new_from_pixmap(pixmap, mask);
+ gtk_widget_show(image);
+ gtk_tool_button_set_icon_widget(button, image);
+}
+
+/* Main Window Initialization */
+void init_main_window(const gchar * glade_file)
+{
+ GladeXML *xml;
+ GtkWidget *widget;
+ GtkTextBuffer *txtbuf;
+ GtkStyle *style;
+
+ xml = glade_xml_new(glade_file, "window1", NULL);
+ if (!xml)
+ g_error(_("GUI loading failed !\n"));
+ glade_xml_signal_autoconnect(xml);
+
+ main_wnd = glade_xml_get_widget(xml, "window1");
+ hpaned = glade_xml_get_widget(xml, "hpaned1");
+ vpaned = glade_xml_get_widget(xml, "vpaned1");
+ tree1_w = glade_xml_get_widget(xml, "treeview1");
+ tree2_w = glade_xml_get_widget(xml, "treeview2");
+ text_w = glade_xml_get_widget(xml, "textview3");
+
+ back_btn = glade_xml_get_widget(xml, "button1");
+ gtk_widget_set_sensitive(back_btn, FALSE);
+
+ widget = glade_xml_get_widget(xml, "show_name1");
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+ show_name);
+
+ widget = glade_xml_get_widget(xml, "show_range1");
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+ show_range);
+
+ widget = glade_xml_get_widget(xml, "show_data1");
+ gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+ show_value);
+
+ save_btn = glade_xml_get_widget(xml, "button3");
+ save_menu_item = glade_xml_get_widget(xml, "save1");
+ conf_set_changed_callback(conf_changed);
+
+ style = gtk_widget_get_style(main_wnd);
+ widget = glade_xml_get_widget(xml, "toolbar1");
+
+#if 0 /* Use stock Gtk icons instead */
+ replace_button_icon(xml, main_wnd->window, style,
+ "button1", (gchar **) xpm_back);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button2", (gchar **) xpm_load);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button3", (gchar **) xpm_save);
+#endif
+ replace_button_icon(xml, main_wnd->window, style,
+ "button4", (gchar **) xpm_single_view);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button5", (gchar **) xpm_split_view);
+ replace_button_icon(xml, main_wnd->window, style,
+ "button6", (gchar **) xpm_tree_view);
+
+#if 0
+ switch (view_mode) {
+ case SINGLE_VIEW:
+ widget = glade_xml_get_widget(xml, "button4");
+ g_signal_emit_by_name(widget, "clicked");
+ break;
+ case SPLIT_VIEW:
+ widget = glade_xml_get_widget(xml, "button5");
+ g_signal_emit_by_name(widget, "clicked");
+ break;
+ case FULL_VIEW:
+ widget = glade_xml_get_widget(xml, "button6");
+ g_signal_emit_by_name(widget, "clicked");
+ break;
+ }
+#endif
+ txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+ tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
+ "foreground", "red",
+ "weight", PANGO_WEIGHT_BOLD,
+ NULL);
+ tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
+ /*"style", PANGO_STYLE_OBLIQUE, */
+ NULL);
+
+ gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
+
+ gtk_widget_show(main_wnd);
+}
+
+void init_tree_model(void)
+{
+ gint i;
+
+ tree = tree2 = gtk_tree_store_new(COL_NUMBER,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_POINTER, GDK_TYPE_COLOR,
+ G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN);
+ model2 = GTK_TREE_MODEL(tree2);
+
+ for (parents[0] = NULL, i = 1; i < 256; i++)
+ parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
+
+ tree1 = gtk_tree_store_new(COL_NUMBER,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_POINTER, GDK_TYPE_COLOR,
+ G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN);
+ model1 = GTK_TREE_MODEL(tree1);
+}
+
+void init_left_tree(void)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *sel;
+ GtkTreeViewColumn *column;
+
+ gtk_tree_view_set_model(view, model1);
+ gtk_tree_view_set_headers_visible(view, TRUE);
+ gtk_tree_view_set_rules_hint(view, FALSE);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_append_column(view, column);
+ gtk_tree_view_column_set_title(column, _("Options"));
+
+ renderer = gtk_cell_renderer_toggle_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "active", COL_BTNACT,
+ "inconsistent", COL_BTNINC,
+ "visible", COL_BTNVIS,
+ "radio", COL_BTNRAD, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "text", COL_OPTION,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+
+ sel = gtk_tree_view_get_selection(view);
+ gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+ gtk_widget_realize(tree1_w);
+}
+
+static void renderer_edited(GtkCellRendererText * cell,
+ const gchar * path_string,
+ const gchar * new_text, gpointer user_data);
+static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+ gchar * arg1, gpointer user_data);
+
+void init_right_tree(void)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *sel;
+ GtkTreeViewColumn *column;
+ gint i;
+
+ gtk_tree_view_set_model(view, model2);
+ gtk_tree_view_set_headers_visible(view, TRUE);
+ gtk_tree_view_set_rules_hint(view, FALSE);
+
+ column = gtk_tree_view_column_new();
+ gtk_tree_view_append_column(view, column);
+ gtk_tree_view_column_set_title(column, _("Options"));
+
+ renderer = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "pixbuf", COL_PIXBUF,
+ "visible", COL_PIXVIS, NULL);
+ renderer = gtk_cell_renderer_toggle_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "active", COL_BTNACT,
+ "inconsistent", COL_BTNINC,
+ "visible", COL_BTNVIS,
+ "radio", COL_BTNRAD, NULL);
+ /*g_signal_connect(G_OBJECT(renderer), "toggled",
+ G_CALLBACK(renderer_toggled), NULL); */
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+ renderer, FALSE);
+ gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+ renderer,
+ "text", COL_OPTION,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ _("Name"), renderer,
+ "text", COL_NAME,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ "N", renderer,
+ "text", COL_NO,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ "M", renderer,
+ "text", COL_MOD,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ "Y", renderer,
+ "text", COL_YES,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(view, -1,
+ _("Value"), renderer,
+ "text", COL_VALUE,
+ "editable",
+ COL_EDIT,
+ "foreground-gdk",
+ COL_COLOR, NULL);
+ g_signal_connect(G_OBJECT(renderer), "edited",
+ G_CALLBACK(renderer_edited), NULL);
+
+ column = gtk_tree_view_get_column(view, COL_NAME);
+ gtk_tree_view_column_set_visible(column, show_name);
+ column = gtk_tree_view_get_column(view, COL_NO);
+ gtk_tree_view_column_set_visible(column, show_range);
+ column = gtk_tree_view_get_column(view, COL_MOD);
+ gtk_tree_view_column_set_visible(column, show_range);
+ column = gtk_tree_view_get_column(view, COL_YES);
+ gtk_tree_view_column_set_visible(column, show_range);
+ column = gtk_tree_view_get_column(view, COL_VALUE);
+ gtk_tree_view_column_set_visible(column, show_value);
+
+ if (resizeable) {
+ for (i = 0; i < COL_VALUE; i++) {
+ column = gtk_tree_view_get_column(view, i);
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ }
+ }
+
+ sel = gtk_tree_view_get_selection(view);
+ gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+}
+
+
+/* Utility Functions */
+
+
+static void text_insert_help(struct menu *menu)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+ const char *prompt = _(menu_get_prompt(menu));
+ struct gstr help = str_new();
+
+ menu_get_ext_help(menu, &help);
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+ gtk_text_buffer_get_bounds(buffer, &start, &end);
+ gtk_text_buffer_delete(buffer, &start, &end);
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
+ NULL);
+ gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
+ NULL);
+ str_free(&help);
+}
+
+
+static void text_insert_msg(const char *title, const char *message)
+{
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
+ const char *msg = message;
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+ gtk_text_buffer_get_bounds(buffer, &start, &end);
+ gtk_text_buffer_delete(buffer, &start, &end);
+ gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
+ NULL);
+ gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+ gtk_text_buffer_get_end_iter(buffer, &end);
+ gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
+ NULL);
+}
+
+
+/* Main Windows Callbacks */
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
+gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
+ gpointer user_data)
+{
+ GtkWidget *dialog, *label;
+ gint result;
+
+ if (!conf_get_changed())
+ return FALSE;
+
+ dialog = gtk_dialog_new_with_buttons(_("Warning !"),
+ GTK_WINDOW(main_wnd),
+ (GtkDialogFlags)
+ (GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT),
+ GTK_STOCK_OK,
+ GTK_RESPONSE_YES,
+ GTK_STOCK_NO,
+ GTK_RESPONSE_NO,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL, NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+ GTK_RESPONSE_CANCEL);
+
+ label = gtk_label_new(_("\nSave configuration ?\n"));
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+ gtk_widget_show(label);
+
+ result = gtk_dialog_run(GTK_DIALOG(dialog));
+ switch (result) {
+ case GTK_RESPONSE_YES:
+ on_save_activate(NULL, NULL);
+ return FALSE;
+ case GTK_RESPONSE_NO:
+ return FALSE;
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ default:
+ gtk_widget_destroy(dialog);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+void on_window1_destroy(GtkObject * object, gpointer user_data)
+{
+ gtk_main_quit();
+}
+
+
+void
+on_window1_size_request(GtkWidget * widget,
+ GtkRequisition * requisition, gpointer user_data)
+{
+ static gint old_h;
+ gint w, h;
+
+ if (widget->window == NULL)
+ gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+ else
+ gdk_window_get_size(widget->window, &w, &h);
+
+ if (h == old_h)
+ return;
+ old_h = h;
+
+ gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
+}
+
+
+/* Menu & Toolbar Callbacks */
+
+
+static void
+load_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+ const gchar *fn;
+
+ fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+ (user_data));
+
+ if (conf_read(fn))
+ text_insert_msg(_("Error"), _("Unable to load configuration !"));
+ else
+ display_tree(&rootmenu);
+}
+
+void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *fs;
+
+ fs = gtk_file_selection_new(_("Load file..."));
+ g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked",
+ G_CALLBACK(load_filename), (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->cancel_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ gtk_widget_show(fs);
+}
+
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ if (conf_write(NULL))
+ text_insert_msg(_("Error"), _("Unable to save configuration !"));
+}
+
+
+static void
+store_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+ const gchar *fn;
+
+ fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+ (user_data));
+
+ if (conf_write(fn))
+ text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+ gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *fs;
+
+ fs = gtk_file_selection_new(_("Save file as..."));
+ g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked",
+ G_CALLBACK(store_filename), (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->ok_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ g_signal_connect_swapped(GTK_OBJECT
+ (GTK_FILE_SELECTION(fs)->cancel_button),
+ "clicked", G_CALLBACK(gtk_widget_destroy),
+ (gpointer) fs);
+ gtk_widget_show(fs);
+}
+
+
+void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ if (!on_window1_delete_event(NULL, NULL, NULL))
+ gtk_widget_destroy(GTK_WIDGET(main_wnd));
+}
+
+
+void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkTreeViewColumn *col;
+
+ show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_name);
+}
+
+
+void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkTreeViewColumn *col;
+
+ show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_range);
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_range);
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_range);
+
+}
+
+
+void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkTreeViewColumn *col;
+
+ show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
+ if (col)
+ gtk_tree_view_column_set_visible(col, show_value);
+}
+
+
+void
+on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+ opt_mode = OPT_NORMAL;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
+}
+
+
+void
+on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+ opt_mode = OPT_ALL;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
+}
+
+
+void
+on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+ opt_mode = OPT_PROMPT;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
+}
+
+
+void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *dialog;
+ const gchar *intro_text = _(
+ "Welcome to gkc, the GTK+ graphical configuration tool\n"
+ "For each option, a blank box indicates the feature is disabled, a\n"
+ "check indicates it is enabled, and a dot indicates that it is to\n"
+ "be compiled as a module. Clicking on the box will cycle through the three states.\n"
+ "\n"
+ "If you do not see an option (e.g., a device driver) that you\n"
+ "believe should be present, try turning on Show All Options\n"
+ "under the Options menu.\n"
+ "Although there is no cross reference yet to help you figure out\n"
+ "what other options must be enabled to support the option you\n"
+ "are interested in, you can still view the help of a grayed-out\n"
+ "option.\n"
+ "\n"
+ "Toggling Show Debug Info under the Options menu will show \n"
+ "the dependencies, which you can then match by examining other options.");
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, intro_text);
+ g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(dialog));
+ gtk_widget_show_all(dialog);
+}
+
+
+void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *dialog;
+ const gchar *about_text =
+ _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
+ "Based on the source code from Roman Zippel.\n");
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, about_text);
+ g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(dialog));
+ gtk_widget_show_all(dialog);
+}
+
+
+void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ GtkWidget *dialog;
+ const gchar *license_text =
+ _("gkc is released under the terms of the GNU GPL v2.\n"
+ "For more information, please see the source code or\n"
+ "visit http://www.fsf.org/licenses/licenses.html\n");
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE, license_text);
+ g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+ G_CALLBACK(gtk_widget_destroy),
+ GTK_OBJECT(dialog));
+ gtk_widget_show_all(dialog);
+}
+
+
+void on_back_clicked(GtkButton * button, gpointer user_data)
+{
+ enum prop_type ptype;
+
+ current = current->parent;
+ ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+ if (ptype != P_MENU)
+ current = current->parent;
+ display_tree_part();
+
+ if (current == &rootmenu)
+ gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_load_clicked(GtkButton * button, gpointer user_data)
+{
+ on_load1_activate(NULL, user_data);
+}
+
+
+void on_single_clicked(GtkButton * button, gpointer user_data)
+{
+ view_mode = SINGLE_VIEW;
+ gtk_paned_set_position(GTK_PANED(hpaned), 0);
+ gtk_widget_hide(tree1_w);
+ current = &rootmenu;
+ display_tree_part();
+}
+
+
+void on_split_clicked(GtkButton * button, gpointer user_data)
+{
+ gint w, h;
+ view_mode = SPLIT_VIEW;
+ gtk_widget_show(tree1_w);
+ gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+ gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
+ if (tree2)
+ gtk_tree_store_clear(tree2);
+ display_list();
+
+ /* Disable back btn, like in full mode. */
+ gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_full_clicked(GtkButton * button, gpointer user_data)
+{
+ view_mode = FULL_VIEW;
+ gtk_paned_set_position(GTK_PANED(hpaned), 0);
+ gtk_widget_hide(tree1_w);
+ if (tree2)
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu);
+ gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
+{
+ gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+void on_expand_clicked(GtkButton * button, gpointer user_data)
+{
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+/* CTree Callbacks */
+
+/* Change hex/int/string value in the cell */
+static void renderer_edited(GtkCellRendererText * cell,
+ const gchar * path_string,
+ const gchar * new_text, gpointer user_data)
+{
+ GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+ GtkTreeIter iter;
+ const char *old_def, *new_def;
+ struct menu *menu;
+ struct symbol *sym;
+
+ if (!gtk_tree_model_get_iter(model2, &iter, path))
+ return;
+
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+ sym = menu->sym;
+
+ gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
+ new_def = new_text;
+
+ sym_set_string_value(sym, new_def);
+
+ update_tree(&rootmenu, NULL);
+
+ gtk_tree_path_free(path);
+}
+
+/* Change the value of a symbol and update the tree */
+static void change_sym_value(struct menu *menu, gint col)
+{
+ struct symbol *sym = menu->sym;
+ tristate oldval, newval;
+
+ if (!sym)
+ return;
+
+ if (col == COL_NO)
+ newval = no;
+ else if (col == COL_MOD)
+ newval = mod;
+ else if (col == COL_YES)
+ newval = yes;
+ else
+ return;
+
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ oldval = sym_get_tristate_value(sym);
+ if (!sym_tristate_within_range(sym, newval))
+ newval = yes;
+ sym_set_tristate_value(sym, newval);
+ if (view_mode == FULL_VIEW)
+ update_tree(&rootmenu, NULL);
+ else if (view_mode == SPLIT_VIEW) {
+ update_tree(browsed, NULL);
+ display_list();
+ }
+ else if (view_mode == SINGLE_VIEW)
+ display_tree_part(); //fixme: keep exp/coll
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ default:
+ break;
+ }
+}
+
+static void toggle_sym_value(struct menu *menu)
+{
+ if (!menu->sym)
+ return;
+
+ sym_toggle_tristate_value(menu->sym);
+ if (view_mode == FULL_VIEW)
+ update_tree(&rootmenu, NULL);
+ else if (view_mode == SPLIT_VIEW) {
+ update_tree(browsed, NULL);
+ display_list();
+ }
+ else if (view_mode == SINGLE_VIEW)
+ display_tree_part(); //fixme: keep exp/coll
+}
+
+static void renderer_toggled(GtkCellRendererToggle * cell,
+ gchar * path_string, gpointer user_data)
+{
+ GtkTreePath *path, *sel_path = NULL;
+ GtkTreeIter iter, sel_iter;
+ GtkTreeSelection *sel;
+ struct menu *menu;
+
+ path = gtk_tree_path_new_from_string(path_string);
+ if (!gtk_tree_model_get_iter(model2, &iter, path))
+ return;
+
+ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
+ if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
+ sel_path = gtk_tree_model_get_path(model2, &sel_iter);
+ if (!sel_path)
+ goto out1;
+ if (gtk_tree_path_compare(path, sel_path))
+ goto out2;
+
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+ toggle_sym_value(menu);
+
+ out2:
+ gtk_tree_path_free(sel_path);
+ out1:
+ gtk_tree_path_free(path);
+}
+
+static gint column2index(GtkTreeViewColumn * column)
+{
+ gint i;
+
+ for (i = 0; i < COL_NUMBER; i++) {
+ GtkTreeViewColumn *col;
+
+ col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
+ if (col == column)
+ return i;
+ }
+
+ return -1;
+}
+
+
+/* User click: update choice (full) or goes down (single) */
+gboolean
+on_treeview2_button_press_event(GtkWidget * widget,
+ GdkEventButton * event, gpointer user_data)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(widget);
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ struct menu *menu;
+ gint col;
+
+#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
+ gint tx = (gint) event->x;
+ gint ty = (gint) event->y;
+ gint cx, cy;
+
+ gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+ &cy);
+#else
+ gtk_tree_view_get_cursor(view, &path, &column);
+#endif
+ if (path == NULL)
+ return FALSE;
+
+ if (!gtk_tree_model_get_iter(model2, &iter, path))
+ return FALSE;
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+ col = column2index(column);
+ if (event->type == GDK_2BUTTON_PRESS) {
+ enum prop_type ptype;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+ if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
+ // goes down into menu
+ current = menu;
+ display_tree_part();
+ gtk_widget_set_sensitive(back_btn, TRUE);
+ } else if ((col == COL_OPTION)) {
+ toggle_sym_value(menu);
+ gtk_tree_view_expand_row(view, path, TRUE);
+ }
+ } else {
+ if (col == COL_VALUE) {
+ toggle_sym_value(menu);
+ gtk_tree_view_expand_row(view, path, TRUE);
+ } else if (col == COL_NO || col == COL_MOD
+ || col == COL_YES) {
+ change_sym_value(menu, col);
+ gtk_tree_view_expand_row(view, path, TRUE);
+ }
+ }
+
+ return FALSE;
+}
+
+/* Key pressed: update choice */
+gboolean
+on_treeview2_key_press_event(GtkWidget * widget,
+ GdkEventKey * event, gpointer user_data)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(widget);
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ struct menu *menu;
+ gint col;
+
+ gtk_tree_view_get_cursor(view, &path, &column);
+ if (path == NULL)
+ return FALSE;
+
+ if (event->keyval == GDK_space) {
+ if (gtk_tree_view_row_expanded(view, path))
+ gtk_tree_view_collapse_row(view, path);
+ else
+ gtk_tree_view_expand_row(view, path, FALSE);
+ return TRUE;
+ }
+ if (event->keyval == GDK_KP_Enter) {
+ }
+ if (widget == tree1_w)
+ return FALSE;
+
+ gtk_tree_model_get_iter(model2, &iter, path);
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+ if (!strcasecmp(event->string, "n"))
+ col = COL_NO;
+ else if (!strcasecmp(event->string, "m"))
+ col = COL_MOD;
+ else if (!strcasecmp(event->string, "y"))
+ col = COL_YES;
+ else
+ col = -1;
+ change_sym_value(menu, col);
+
+ return FALSE;
+}
+
+
+/* Row selection changed: update help */
+void
+on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ struct menu *menu;
+
+ selection = gtk_tree_view_get_selection(treeview);
+ if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
+ gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+ text_insert_help(menu);
+ }
+}
+
+
+/* User click: display sub-tree in the right frame. */
+gboolean
+on_treeview1_button_press_event(GtkWidget * widget,
+ GdkEventButton * event, gpointer user_data)
+{
+ GtkTreeView *view = GTK_TREE_VIEW(widget);
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ struct menu *menu;
+
+ gint tx = (gint) event->x;
+ gint ty = (gint) event->y;
+ gint cx, cy;
+
+ gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+ &cy);
+ if (path == NULL)
+ return FALSE;
+
+ gtk_tree_model_get_iter(model1, &iter, path);
+ gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
+
+ if (event->type == GDK_2BUTTON_PRESS) {
+ toggle_sym_value(menu);
+ current = menu;
+ display_tree_part();
+ } else {
+ browsed = menu;
+ display_tree_part();
+ }
+
+ gtk_widget_realize(tree2_w);
+ gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+ gtk_widget_grab_focus(tree2_w);
+
+ return FALSE;
+}
+
+
+/* Fill a row of strings */
+static gchar **fill_row(struct menu *menu)
+{
+ static gchar *row[COL_NUMBER];
+ struct symbol *sym = menu->sym;
+ const char *def;
+ int stype;
+ tristate val;
+ enum prop_type ptype;
+ int i;
+
+ for (i = COL_OPTION; i <= COL_COLOR; i++)
+ g_free(row[i]);
+ bzero(row, sizeof(row));
+
+ row[COL_OPTION] =
+ g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
+ sym && !sym_has_value(sym) ? "(NEW)" : "");
+
+ if (opt_mode == OPT_ALL && !menu_is_visible(menu))
+ row[COL_COLOR] = g_strdup("DarkGray");
+ else if (opt_mode == OPT_PROMPT &&
+ menu_has_prompt(menu) && !menu_is_visible(menu))
+ row[COL_COLOR] = g_strdup("DarkGray");
+ else
+ row[COL_COLOR] = g_strdup("Black");
+
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ switch (ptype) {
+ case P_MENU:
+ row[COL_PIXBUF] = (gchar *) xpm_menu;
+ if (view_mode == SINGLE_VIEW)
+ row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+ break;
+ case P_COMMENT:
+ row[COL_PIXBUF] = (gchar *) xpm_void;
+ row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+ break;
+ default:
+ row[COL_PIXBUF] = (gchar *) xpm_void;
+ row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+ break;
+ }
+
+ if (!sym)
+ return row;
+ row[COL_NAME] = g_strdup(sym->name);
+
+ sym_calc_value(sym);
+ sym->flags &= ~SYMBOL_CHANGED;
+
+ if (sym_is_choice(sym)) { // parse childs for getting final value
+ struct menu *child;
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child)
+ && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ if (def_menu)
+ row[COL_VALUE] =
+ g_strdup(_(menu_get_prompt(def_menu)));
+ }
+ if (sym->flags & SYMBOL_CHOICEVAL)
+ row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
+
+ stype = sym_get_type(sym);
+ switch (stype) {
+ case S_BOOLEAN:
+ if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+ row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+ if (sym_is_choice(sym))
+ break;
+ case S_TRISTATE:
+ val = sym_get_tristate_value(sym);
+ switch (val) {
+ case no:
+ row[COL_NO] = g_strdup("N");
+ row[COL_VALUE] = g_strdup("N");
+ row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
+ row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+ break;
+ case mod:
+ row[COL_MOD] = g_strdup("M");
+ row[COL_VALUE] = g_strdup("M");
+ row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
+ break;
+ case yes:
+ row[COL_YES] = g_strdup("Y");
+ row[COL_VALUE] = g_strdup("Y");
+ row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
+ row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+ break;
+ }
+
+ if (val != no && sym_tristate_within_range(sym, no))
+ row[COL_NO] = g_strdup("_");
+ if (val != mod && sym_tristate_within_range(sym, mod))
+ row[COL_MOD] = g_strdup("_");
+ if (val != yes && sym_tristate_within_range(sym, yes))
+ row[COL_YES] = g_strdup("_");
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ def = sym_get_string_value(sym);
+ row[COL_VALUE] = g_strdup(def);
+ row[COL_EDIT] = GINT_TO_POINTER(TRUE);
+ row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+ break;
+ }
+
+ return row;
+}
+
+
+/* Set the node content with a row of strings */
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
+{
+ GdkColor color;
+ gboolean success;
+ GdkPixbuf *pix;
+
+ pix = gdk_pixbuf_new_from_xpm_data((const char **)
+ row[COL_PIXBUF]);
+
+ gdk_color_parse(row[COL_COLOR], &color);
+ gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
+ FALSE, FALSE, &success);
+
+ gtk_tree_store_set(tree, node,
+ COL_OPTION, row[COL_OPTION],
+ COL_NAME, row[COL_NAME],
+ COL_NO, row[COL_NO],
+ COL_MOD, row[COL_MOD],
+ COL_YES, row[COL_YES],
+ COL_VALUE, row[COL_VALUE],
+ COL_MENU, (gpointer) menu,
+ COL_COLOR, &color,
+ COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
+ COL_PIXBUF, pix,
+ COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
+ COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
+ COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
+ COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+ COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
+ -1);
+
+ g_object_unref(pix);
+}
+
+
+/* Add a node to the tree */
+static void place_node(struct menu *menu, char **row)
+{
+ GtkTreeIter *parent = parents[indent - 1];
+ GtkTreeIter *node = parents[indent];
+
+ gtk_tree_store_append(tree, node, parent);
+ set_node(node, menu, row);
+}
+
+
+/* Find a node in the GTK+ tree */
+static GtkTreeIter found;
+
+/*
+ * Find a menu in the GtkTree starting at parent.
+ */
+GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
+ struct menu *tofind)
+{
+ GtkTreeIter iter;
+ GtkTreeIter *child = &iter;
+ gboolean valid;
+ GtkTreeIter *ret;
+
+ valid = gtk_tree_model_iter_children(model2, child, parent);
+ while (valid) {
+ struct menu *menu;
+
+ gtk_tree_model_get(model2, child, 6, &menu, -1);
+
+ if (menu == tofind) {
+ memcpy(&found, child, sizeof(GtkTreeIter));
+ return &found;
+ }
+
+ ret = gtktree_iter_find_node(child, tofind);
+ if (ret)
+ return ret;
+
+ valid = gtk_tree_model_iter_next(model2, child);
+ }
+
+ return NULL;
+}
+
+
+/*
+ * Update the tree by adding/removing entries
+ * Does not change other nodes
+ */
+static void update_tree(struct menu *src, GtkTreeIter * dst)
+{
+ struct menu *child1;
+ GtkTreeIter iter, tmp;
+ GtkTreeIter *child2 = &iter;
+ gboolean valid;
+ GtkTreeIter *sibling;
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *menu1, *menu2;
+
+ if (src == &rootmenu)
+ indent = 1;
+
+ valid = gtk_tree_model_iter_children(model2, child2, dst);
+ for (child1 = src->list; child1; child1 = child1->next) {
+
+ prop = child1->prompt;
+ sym = child1->sym;
+
+ reparse:
+ menu1 = child1;
+ if (valid)
+ gtk_tree_model_get(model2, child2, COL_MENU,
+ &menu2, -1);
+ else
+ menu2 = NULL; // force adding of a first child
+
+#ifdef DEBUG
+ printf("%*c%s | %s\n", indent, ' ',
+ menu1 ? menu_get_prompt(menu1) : "nil",
+ menu2 ? menu_get_prompt(menu2) : "nil");
+#endif
+
+ if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
+ (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
+ (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
+
+ /* remove node */
+ if (gtktree_iter_find_node(dst, menu1) != NULL) {
+ memcpy(&tmp, child2, sizeof(GtkTreeIter));
+ valid = gtk_tree_model_iter_next(model2,
+ child2);
+ gtk_tree_store_remove(tree2, &tmp);
+ if (!valid)
+ return; /* next parent */
+ else
+ goto reparse; /* next child */
+ } else
+ continue;
+ }
+
+ if (menu1 != menu2) {
+ if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
+ if (!valid && !menu2)
+ sibling = NULL;
+ else
+ sibling = child2;
+ gtk_tree_store_insert_before(tree2,
+ child2,
+ dst, sibling);
+ set_node(child2, menu1, fill_row(menu1));
+ if (menu2 == NULL)
+ valid = TRUE;
+ } else { // remove node
+ memcpy(&tmp, child2, sizeof(GtkTreeIter));
+ valid = gtk_tree_model_iter_next(model2,
+ child2);
+ gtk_tree_store_remove(tree2, &tmp);
+ if (!valid)
+ return; // next parent
+ else
+ goto reparse; // next child
+ }
+ } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+ set_node(child2, menu1, fill_row(menu1));
+ }
+
+ indent++;
+ update_tree(child1, child2);
+ indent--;
+
+ valid = gtk_tree_model_iter_next(model2, child2);
+ }
+}
+
+
+/* Display the whole tree (single/split/full view) */
+static void display_tree(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ enum prop_type ptype;
+
+ if (menu == &rootmenu) {
+ indent = 1;
+ current = &rootmenu;
+ }
+
+ for (child = menu->list; child; child = child->next) {
+ prop = child->prompt;
+ sym = child->sym;
+ ptype = prop ? prop->type : P_UNKNOWN;
+
+ if (sym)
+ sym->flags &= ~SYMBOL_CHANGED;
+
+ if ((view_mode == SPLIT_VIEW)
+ && !(child->flags & MENU_ROOT) && (tree == tree1))
+ continue;
+
+ if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+ && (tree == tree2))
+ continue;
+
+ if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
+ (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
+ (opt_mode == OPT_ALL && menu_get_prompt(child)))
+ place_node(child, fill_row(child));
+#ifdef DEBUG
+ printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
+ printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
+ printf("%s", prop_get_type_name(ptype));
+ printf(" | ");
+ if (sym) {
+ printf("%s", sym_type_name(sym->type));
+ printf(" | ");
+ printf("%s", dbg_sym_flags(sym->flags));
+ printf("\n");
+ } else
+ printf("\n");
+#endif
+ if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
+ && (tree == tree2))
+ continue;
+/*
+ if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+ || (view_mode == FULL_VIEW)
+ || (view_mode == SPLIT_VIEW))*/
+ if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
+ || (view_mode == FULL_VIEW)
+ || (view_mode == SPLIT_VIEW)) {
+ indent++;
+ display_tree(child);
+ indent--;
+ }
+ }
+}
+
+/* Display a part of the tree starting at current node (single/split view) */
+static void display_tree_part(void)
+{
+ if (tree2)
+ gtk_tree_store_clear(tree2);
+ if (view_mode == SINGLE_VIEW)
+ display_tree(current);
+ else if (view_mode == SPLIT_VIEW)
+ display_tree(browsed);
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+/* Display the list in the left frame (split view) */
+static void display_list(void)
+{
+ if (tree1)
+ gtk_tree_store_clear(tree1);
+
+ tree = tree1;
+ display_tree(&rootmenu);
+ gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
+ tree = tree2;
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+ struct menu *child;
+ static int menu_cnt = 0;
+
+ menu->flags |= MENU_ROOT;
+ for (child = menu->list; child; child = child->next) {
+ if (child->prompt && child->prompt->type == P_MENU) {
+ menu_cnt++;
+ fixup_rootmenu(child);
+ menu_cnt--;
+ } else if (!menu_cnt)
+ fixup_rootmenu(child);
+ }
+}
+
+
+/* Main */
+int main(int ac, char *av[])
+{
+ const char *name;
+ char *env;
+ gchar *glade_file;
+
+#ifndef LKC_DIRECT_LINK
+ kconfig_load();
+#endif
+
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset(PACKAGE, "UTF-8");
+ textdomain(PACKAGE);
+
+ /* GTK stuffs */
+ gtk_set_locale();
+ gtk_init(&ac, &av);
+ glade_init();
+
+ //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
+ //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
+
+ /* Determine GUI path */
+ env = getenv(SRCTREE);
+ if (env)
+ glade_file = g_strconcat(env, "/tools/kconfig/gconf.glade", NULL);
+ else if (av[0][0] == '/')
+ glade_file = g_strconcat(av[0], ".glade", NULL);
+ else
+ glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
+
+ /* Conf stuffs */
+ if (ac > 1 && av[1][0] == '-') {
+ switch (av[1][1]) {
+ case 'a':
+ //showAll = 1;
+ break;
+ case 'h':
+ case '?':
+ printf("%s <config>\n", av[0]);
+ exit(0);
+ }
+ name = av[2];
+ } else
+ name = av[1];
+
+ conf_parse(name);
+ fixup_rootmenu(&rootmenu);
+ conf_read(NULL);
+
+ /* Load the interface and connect signals */
+ init_main_window(glade_file);
+ init_tree_model();
+ init_left_tree();
+ init_right_tree();
+
+ switch (view_mode) {
+ case SINGLE_VIEW:
+ display_tree_part();
+ break;
+ case SPLIT_VIEW:
+ display_list();
+ break;
+ case FULL_VIEW:
+ display_tree(&rootmenu);
+ break;
+ }
+
+ gtk_main();
+
+ return 0;
+}
+
+static void conf_changed(void)
+{
+ bool changed = conf_get_changed();
+ gtk_widget_set_sensitive(save_btn, changed);
+ gtk_widget_set_sensitive(save_menu_item, changed);
+}
--- /dev/null
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Gtk Kernel Configurator</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">640</property>
+ <property name="default_height">480</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <signal name="destroy" handler="on_window1_destroy" object="window1"/>
+ <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
+ <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="file1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="file1_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="load1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Load a config file</property>
+ <property name="label" translatable="yes">_Load</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_load1_activate"/>
+ <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image39">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="save1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Save the config in .config</property>
+ <property name="label" translatable="yes">_Save</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_save_activate"/>
+ <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image40">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="save_as1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Save the config in a file</property>
+ <property name="label" translatable="yes">Save _as</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_save_as1_activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image41">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save-as</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="quit1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Quit</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_quit1_activate"/>
+ <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image42">
+ <property name="visible">True</property>
+ <property name="stock">gtk-quit</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="options1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Options</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="options1_menu">
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="show_name1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show name</property>
+ <property name="label" translatable="yes">Show _name</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_show_name1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="show_range1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
+ <property name="label" translatable="yes">Show _range</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_show_range1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="show_data1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show value of the option</property>
+ <property name="label" translatable="yes">Show _data</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="on_show_data1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkRadioMenuItem" id="set_option_mode1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show normal options</property>
+ <property name="label" translatable="yes">Show normal options</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <signal name="activate" handler="on_set_option_mode1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkRadioMenuItem" id="set_option_mode2">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show all options</property>
+ <property name="label" translatable="yes">Show all _options</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <property name="group">set_option_mode1</property>
+ <signal name="activate" handler="on_set_option_mode2_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkRadioMenuItem" id="set_option_mode3">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show all options with prompts</property>
+ <property name="label" translatable="yes">Show all prompt options</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <property name="group">set_option_mode1</property>
+ <signal name="activate" handler="on_set_option_mode3_activate"/>
+ </widget>
+ </child>
+
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="help1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="help1_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="introduction1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Introduction</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+ <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image43">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-question</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="about1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_About</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+ <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image44">
+ <property name="visible">True</property>
+ <property name="stock">gtk-properties</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="license1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_License</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image45">
+ <property name="visible">True</property>
+ <property name="stock">gtk-justify-fill</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHandleBox" id="handlebox1">
+ <property name="visible">True</property>
+ <property name="shadow_type">GTK_SHADOW_OUT</property>
+ <property name="handle_position">GTK_POS_LEFT</property>
+ <property name="snap_edge">GTK_POS_TOP</property>
+
+ <child>
+ <widget class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+ <property name="tooltips">True</property>
+ <property name="show_arrow">True</property>
+
+ <child>
+ <widget class="GtkToolButton" id="button1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
+ <property name="label" translatable="yes">Back</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-undo</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_back_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem1">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkVSeparator" id="vseparator1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button2">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Load a config file</property>
+ <property name="label" translatable="yes">Load</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-open</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_load_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button3">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Save a config file</property>
+ <property name="label" translatable="yes">Save</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-save</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_save_activate"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem2">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkVSeparator" id="vseparator2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button4">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Single view</property>
+ <property name="label" translatable="yes">Single</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-missing-image</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button5">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Split view</property>
+ <property name="label" translatable="yes">Split</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-missing-image</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button6">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Full view</property>
+ <property name="label" translatable="yes">Full</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-missing-image</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem3">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkVSeparator" id="vseparator3">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button7">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
+ <property name="label" translatable="yes">Collapse</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-remove</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_collapse_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolButton" id="button8">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
+ <property name="label" translatable="yes">Expand</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-add</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+ <signal name="clicked" handler="on_expand_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHPaned" id="hpaned1">
+ <property name="width_request">1</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
+ <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
+ <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
+ <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
+ <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTextView" id="textview3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_WORD</property>
+ <property name="cursor_visible">True</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
+ <property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+static const char *xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+static const char *xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+static const char *xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+static const char *xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+static const char *xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+static const char *xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+static const char *xpm_symbol_no[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_symbol_mod[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_symbol_yes[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . . ",
+" . . . ",
+" . .. . ",
+" . . .. . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_choice_no[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "};
+
+static const char *xpm_choice_yes[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .... ",
+" .. .. ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .. .. ",
+" .... ",
+" "};
+
+static const char *xpm_menu[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_menu_inv[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" .......... ",
+" .. ...... ",
+" .. .... ",
+" .. .. ",
+" .. .. ",
+" .. .... ",
+" .. ...... ",
+" .......... ",
+" .......... ",
+" "};
+
+static const char *xpm_menuback[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" .......... ",
+" . . ",
+" . .. . ",
+" . .... . ",
+" . ...... . ",
+" . ...... . ",
+" . .... . ",
+" . .. . ",
+" . . ",
+" .......... ",
+" "};
+
+static const char *xpm_void[] = {
+"12 12 2 1",
+" c white",
+". c black",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
--- /dev/null
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+
+#define P(name,type,arg) type (*name ## _p) arg
+#include "lkc_proto.h"
+#undef P
+
+void kconfig_load(void)
+{
+ void *handle;
+ char *error;
+
+ handle = dlopen("./libkconfig.so", RTLD_LAZY);
+ if (!handle) {
+ handle = dlopen("./tools/kconfig/libkconfig.so", RTLD_LAZY);
+ if (!handle) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(1);
+ }
+ }
+
+#define P(name,type,arg) \
+{ \
+ name ## _p = dlsym(handle, #name); \
+ if ((error = dlerror())) { \
+ fprintf(stderr, "%s\n", error); \
+ exit(1); \
+ } \
+}
+#include "lkc_proto.h"
+#undef P
+}
--- /dev/null
+/*
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+ char *bfp = bf;
+ int multiline = strchr(text, '\n') != NULL;
+ int eol = 0;
+ int textlen = strlen(text);
+
+ if ((textlen > 0) && (text[textlen-1] == '\n'))
+ eol = 1;
+
+ *bfp++ = '"';
+ --len;
+
+ if (multiline) {
+ *bfp++ = '"';
+ *bfp++ = '\n';
+ *bfp++ = '"';
+ len -= 3;
+ }
+
+ while (*text != '\0' && len > 1) {
+ if (*text == '"')
+ *bfp++ = '\\';
+ else if (*text == '\n') {
+ *bfp++ = '\\';
+ *bfp++ = 'n';
+ *bfp++ = '"';
+ *bfp++ = '\n';
+ *bfp++ = '"';
+ len -= 5;
+ ++text;
+ goto next;
+ }
+ else if (*text == '\\') {
+ *bfp++ = '\\';
+ len--;
+ }
+ *bfp++ = *text++;
+next:
+ --len;
+ }
+
+ if (multiline && eol)
+ bfp -= 3;
+
+ *bfp++ = '"';
+ *bfp = '\0';
+
+ return bf;
+}
+
+struct file_line {
+ struct file_line *next;
+ const char *file;
+ int lineno;
+};
+
+static struct file_line *file_line__new(const char *file, int lineno)
+{
+ struct file_line *self = malloc(sizeof(*self));
+
+ if (self == NULL)
+ goto out;
+
+ self->file = file;
+ self->lineno = lineno;
+ self->next = NULL;
+out:
+ return self;
+}
+
+struct message {
+ const char *msg;
+ const char *option;
+ struct message *next;
+ struct file_line *files;
+};
+
+static struct message *message__list;
+
+static struct message *message__new(const char *msg, char *option,
+ const char *file, int lineno)
+{
+ struct message *self = malloc(sizeof(*self));
+
+ if (self == NULL)
+ goto out;
+
+ self->files = file_line__new(file, lineno);
+ if (self->files == NULL)
+ goto out_fail;
+
+ self->msg = strdup(msg);
+ if (self->msg == NULL)
+ goto out_fail_msg;
+
+ self->option = option;
+ self->next = NULL;
+out:
+ return self;
+out_fail_msg:
+ free(self->files);
+out_fail:
+ free(self);
+ self = NULL;
+ goto out;
+}
+
+static struct message *mesage__find(const char *msg)
+{
+ struct message *m = message__list;
+
+ while (m != NULL) {
+ if (strcmp(m->msg, msg) == 0)
+ break;
+ m = m->next;
+ }
+
+ return m;
+}
+
+static int message__add_file_line(struct message *self, const char *file,
+ int lineno)
+{
+ int rc = -1;
+ struct file_line *fl = file_line__new(file, lineno);
+
+ if (fl == NULL)
+ goto out;
+
+ fl->next = self->files;
+ self->files = fl;
+ rc = 0;
+out:
+ return rc;
+}
+
+static int message__add(const char *msg, char *option, const char *file,
+ int lineno)
+{
+ int rc = 0;
+ char bf[16384];
+ char *escaped = escape(msg, bf, sizeof(bf));
+ struct message *m = mesage__find(escaped);
+
+ if (m != NULL)
+ rc = message__add_file_line(m, file, lineno);
+ else {
+ m = message__new(escaped, option, file, lineno);
+
+ if (m != NULL) {
+ m->next = message__list;
+ message__list = m;
+ } else
+ rc = -1;
+ }
+ return rc;
+}
+
+static void menu_build_message_list(struct menu *menu)
+{
+ struct menu *child;
+
+ message__add(menu_get_prompt(menu), NULL,
+ menu->file == NULL ? "Root Menu" : menu->file->name,
+ menu->lineno);
+
+ if (menu->sym != NULL && menu_has_help(menu))
+ message__add(menu_get_help(menu), menu->sym->name,
+ menu->file == NULL ? "Root Menu" : menu->file->name,
+ menu->lineno);
+
+ for (child = menu->list; child != NULL; child = child->next)
+ if (child->prompt != NULL)
+ menu_build_message_list(child);
+}
+
+static void message__print_file_lineno(struct message *self)
+{
+ struct file_line *fl = self->files;
+
+ putchar('\n');
+ if (self->option != NULL)
+ printf("# %s:00000\n", self->option);
+
+ printf("#: %s:%d", fl->file, fl->lineno);
+ fl = fl->next;
+
+ while (fl != NULL) {
+ printf(", %s:%d", fl->file, fl->lineno);
+ fl = fl->next;
+ }
+
+ putchar('\n');
+}
+
+static void message__print_gettext_msgid_msgstr(struct message *self)
+{
+ message__print_file_lineno(self);
+
+ printf("msgid %s\n"
+ "msgstr \"\"\n", self->msg);
+}
+
+static void menu__xgettext(void)
+{
+ struct message *m = message__list;
+
+ while (m != NULL) {
+ /* skip empty lines ("") */
+ if (strlen(m->msg) > sizeof("\"\""))
+ message__print_gettext_msgid_msgstr(m);
+ m = m->next;
+ }
+}
+
+int main(int ac, char **av)
+{
+ conf_parse(av[1]);
+
+ menu_build_message_list(menu_get_root_menu(NULL));
+ menu__xgettext();
+ return 0;
+}
--- /dev/null
+
+#line 3 "scripts/kconfig/lex.zconf.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define yy_create_buffer zconf_create_buffer
+#define yy_delete_buffer zconf_delete_buffer
+#define yy_flex_debug zconf_flex_debug
+#define yy_init_buffer zconf_init_buffer
+#define yy_flush_buffer zconf_flush_buffer
+#define yy_load_buffer_state zconf_load_buffer_state
+#define yy_switch_to_buffer zconf_switch_to_buffer
+#define yyin zconfin
+#define yyleng zconfleng
+#define yylex zconflex
+#define yylineno zconflineno
+#define yyout zconfout
+#define yyrestart zconfrestart
+#define yytext zconftext
+#define yywrap zconfwrap
+#define yyalloc zconfalloc
+#define yyrealloc zconfrealloc
+#define yyfree zconffree
+
+#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)
+
+/* 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 (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 (((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 zconfrestart(zconfin )
+
+#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
+
+extern int zconfleng;
+
+extern FILE *zconfin, *zconfout;
+
+#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 zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#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 zconfrestart()), so that the user can continue scanning by
+ * just pointing zconfin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* 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 ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(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 (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when zconftext is formed. */
+static char yy_hold_char;
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+int zconfleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow zconfwrap()'s to do buffer switches
+ * instead of setting up a fresh zconfin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void zconfrestart (FILE *input_file );
+void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size );
+void zconf_delete_buffer (YY_BUFFER_STATE b );
+void zconf_flush_buffer (YY_BUFFER_STATE b );
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer );
+void zconfpop_buffer_state (void );
+
+static void zconfensure_buffer_stack (void );
+static void zconf_load_buffer_state (void );
+static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len );
+
+void *zconfalloc (yy_size_t );
+void *zconfrealloc (void *,yy_size_t );
+void zconffree (void * );
+
+#define yy_new_buffer zconf_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ zconfensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define zconfwrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int zconflineno;
+
+int zconflineno = 1;
+
+extern char *zconftext;
+#define yytext_ptr zconftext
+static yyconst flex_int16_t yy_nxt[][17] =
+ {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12
+ },
+
+ {
+ 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 16
+ },
+
+ {
+ 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 16
+
+ },
+
+ {
+ 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19
+ },
+
+ {
+ 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19
+ },
+
+ {
+ 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
+ 22, 22, 22, 22, 22, 25, 22
+ },
+
+ {
+ 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
+ 22, 22, 22, 22, 22, 25, 22
+ },
+
+ {
+ 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
+ 33, 34, 35, 35, 36, 37, 38
+
+ },
+
+ {
+ 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
+ 33, 34, 35, 35, 36, 37, 38
+ },
+
+ {
+ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+ -11, -11, -11, -11, -11, -11, -11
+ },
+
+ {
+ 11, -12, -12, -12, -12, -12, -12, -12, -12, -12,
+ -12, -12, -12, -12, -12, -12, -12
+ },
+
+ {
+ 11, -13, 39, 40, -13, -13, 41, -13, -13, -13,
+ -13, -13, -13, -13, -13, -13, -13
+ },
+
+ {
+ 11, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+ -14, -14, -14, -14, -14, -14, -14
+
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, -16, -16, -16, -16, -16, -16, -16, -16, -16,
+ -16, -16, -16, -16, -16, -16, -16
+ },
+
+ {
+ 11, -17, -17, -17, -17, -17, -17, -17, -17, -17,
+ -17, -17, -17, -17, -17, -17, -17
+ },
+
+ {
+ 11, -18, -18, -18, -18, -18, -18, -18, -18, -18,
+ -18, -18, -18, 44, -18, -18, -18
+ },
+
+ {
+ 11, 45, 45, -19, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45
+
+ },
+
+ {
+ 11, -20, 46, 47, -20, -20, -20, -20, -20, -20,
+ -20, -20, -20, -20, -20, -20, -20
+ },
+
+ {
+ 11, 48, -21, -21, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48
+ },
+
+ {
+ 11, 49, 49, 50, 49, -22, 49, 49, -22, 49,
+ 49, 49, 49, 49, 49, -22, 49
+ },
+
+ {
+ 11, -23, -23, -23, -23, -23, -23, -23, -23, -23,
+ -23, -23, -23, -23, -23, -23, -23
+ },
+
+ {
+ 11, -24, -24, -24, -24, -24, -24, -24, -24, -24,
+ -24, -24, -24, -24, -24, -24, -24
+
+ },
+
+ {
+ 11, 51, 51, 52, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51
+ },
+
+ {
+ 11, -26, -26, -26, -26, -26, -26, -26, -26, -26,
+ -26, -26, -26, -26, -26, -26, -26
+ },
+
+ {
+ 11, -27, -27, -27, -27, -27, -27, -27, -27, -27,
+ -27, -27, -27, -27, -27, -27, -27
+ },
+
+ {
+ 11, -28, -28, -28, -28, -28, -28, -28, -28, -28,
+ -28, -28, -28, -28, 53, -28, -28
+ },
+
+ {
+ 11, -29, -29, -29, -29, -29, -29, -29, -29, -29,
+ -29, -29, -29, -29, -29, -29, -29
+
+ },
+
+ {
+ 11, 54, 54, -30, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54
+ },
+
+ {
+ 11, -31, -31, -31, -31, -31, -31, 55, -31, -31,
+ -31, -31, -31, -31, -31, -31, -31
+ },
+
+ {
+ 11, -32, -32, -32, -32, -32, -32, -32, -32, -32,
+ -32, -32, -32, -32, -32, -32, -32
+ },
+
+ {
+ 11, -33, -33, -33, -33, -33, -33, -33, -33, -33,
+ -33, -33, -33, -33, -33, -33, -33
+ },
+
+ {
+ 11, -34, -34, -34, -34, -34, -34, -34, -34, -34,
+ -34, 56, 57, 57, -34, -34, -34
+
+ },
+
+ {
+ 11, -35, -35, -35, -35, -35, -35, -35, -35, -35,
+ -35, 57, 57, 57, -35, -35, -35
+ },
+
+ {
+ 11, -36, -36, -36, -36, -36, -36, -36, -36, -36,
+ -36, -36, -36, -36, -36, -36, -36
+ },
+
+ {
+ 11, -37, -37, 58, -37, -37, -37, -37, -37, -37,
+ -37, -37, -37, -37, -37, -37, -37
+ },
+
+ {
+ 11, -38, -38, -38, -38, -38, -38, -38, -38, -38,
+ -38, -38, -38, -38, -38, -38, 59
+ },
+
+ {
+ 11, -39, 39, 40, -39, -39, 41, -39, -39, -39,
+ -39, -39, -39, -39, -39, -39, -39
+
+ },
+
+ {
+ 11, -40, -40, -40, -40, -40, -40, -40, -40, -40,
+ -40, -40, -40, -40, -40, -40, -40
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42
+ },
+
+ {
+ 11, -43, -43, -43, -43, -43, -43, -43, -43, -43,
+ -43, -43, -43, -43, -43, -43, -43
+ },
+
+ {
+ 11, -44, -44, -44, -44, -44, -44, -44, -44, -44,
+ -44, -44, -44, 44, -44, -44, -44
+
+ },
+
+ {
+ 11, 45, 45, -45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45
+ },
+
+ {
+ 11, -46, 46, 47, -46, -46, -46, -46, -46, -46,
+ -46, -46, -46, -46, -46, -46, -46
+ },
+
+ {
+ 11, 48, -47, -47, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48
+ },
+
+ {
+ 11, -48, -48, -48, -48, -48, -48, -48, -48, -48,
+ -48, -48, -48, -48, -48, -48, -48
+ },
+
+ {
+ 11, 49, 49, 50, 49, -49, 49, 49, -49, 49,
+ 49, 49, 49, 49, 49, -49, 49
+
+ },
+
+ {
+ 11, -50, -50, -50, -50, -50, -50, -50, -50, -50,
+ -50, -50, -50, -50, -50, -50, -50
+ },
+
+ {
+ 11, -51, -51, 52, -51, -51, -51, -51, -51, -51,
+ -51, -51, -51, -51, -51, -51, -51
+ },
+
+ {
+ 11, -52, -52, -52, -52, -52, -52, -52, -52, -52,
+ -52, -52, -52, -52, -52, -52, -52
+ },
+
+ {
+ 11, -53, -53, -53, -53, -53, -53, -53, -53, -53,
+ -53, -53, -53, -53, -53, -53, -53
+ },
+
+ {
+ 11, 54, 54, -54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54
+
+ },
+
+ {
+ 11, -55, -55, -55, -55, -55, -55, -55, -55, -55,
+ -55, -55, -55, -55, -55, -55, -55
+ },
+
+ {
+ 11, -56, -56, -56, -56, -56, -56, -56, -56, -56,
+ -56, 60, 57, 57, -56, -56, -56
+ },
+
+ {
+ 11, -57, -57, -57, -57, -57, -57, -57, -57, -57,
+ -57, 57, 57, 57, -57, -57, -57
+ },
+
+ {
+ 11, -58, -58, -58, -58, -58, -58, -58, -58, -58,
+ -58, -58, -58, -58, -58, -58, -58
+ },
+
+ {
+ 11, -59, -59, -59, -59, -59, -59, -59, -59, -59,
+ -59, -59, -59, -59, -59, -59, -59
+
+ },
+
+ {
+ 11, -60, -60, -60, -60, -60, -60, -60, -60, -60,
+ -60, 57, 57, 57, -60, -60, -60
+ },
+
+ } ;
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up zconftext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ zconfleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+/* 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[61] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 34, 5, 4, 2, 3, 7, 8, 6, 32, 29,
+ 31, 24, 28, 27, 26, 22, 17, 13, 16, 20,
+ 22, 11, 12, 19, 19, 14, 22, 22, 4, 2,
+ 3, 3, 1, 6, 32, 29, 31, 30, 24, 23,
+ 26, 25, 15, 20, 9, 19, 19, 21, 10, 18
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 1, 1, 7, 8, 9,
+ 10, 1, 1, 1, 11, 12, 12, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 1, 1, 1,
+ 14, 1, 1, 1, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 1, 15, 1, 1, 13, 1, 13, 13, 13, 13,
+
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 1, 16, 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
+ } ;
+
+extern int zconf_flex_debug;
+int zconf_flex_debug = 0;
+
+/* 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
+char *zconftext;
+#define YY_NO_INPUT 1
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = malloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = realloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = malloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+
+#define INITIAL 0
+#define COMMAND 1
+#define HELP 2
+#define STRING 3
+#define PARAM 4
+
+#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
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int zconflex_destroy (void );
+
+int zconfget_debug (void );
+
+void zconfset_debug (int debug_flag );
+
+YY_EXTRA_TYPE zconfget_extra (void );
+
+void zconfset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *zconfget_in (void );
+
+void zconfset_in (FILE * in_str );
+
+FILE *zconfget_out (void );
+
+void zconfset_out (FILE * out_str );
+
+int zconfget_leng (void );
+
+char *zconfget_text (void );
+
+int zconfget_lineno (void );
+
+void zconfset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int zconfwrap (void );
+#else
+extern int zconfwrap (void );
+#endif
+#endif
+
+ static void yyunput (int c,char *buf_ptr );
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#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( zconftext, zconfleng, 1, zconfout )) {} } 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) \
+ errno=0; \
+ while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(zconfin); \
+ }\
+\
+
+#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 )
+#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 zconflex (void);
+
+#define YY_DECL int zconflex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after zconftext and zconfleng
+ * 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;
+
+ int str = 0;
+ int ts, i;
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! zconfin )
+ zconfin = stdin;
+
+ if ( ! zconfout )
+ zconfout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of zconftext. */
+ *yy_cp = (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 = (yy_start);
+yy_match:
+ while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
+ ++yy_cp;
+
+ yy_current_state = -yy_current_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 1:
+/* rule 1 can match eol */
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ return T_EOL;
+}
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+{
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{
+ unput(zconftext[0]);
+ BEGIN(COMMAND);
+}
+ YY_BREAK
+
+case 6:
+YY_RULE_SETUP
+{
+ struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+ BEGIN(PARAM);
+ current_pos.file = current_file;
+ current_pos.lineno = current_file->lineno;
+ if (id && id->flags & TF_COMMAND) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+
+ YY_BREAK
+case 8:
+/* rule 8 can match eol */
+YY_RULE_SETUP
+{
+ BEGIN(INITIAL);
+ current_file->lineno++;
+ return T_EOL;
+ }
+ YY_BREAK
+
+case 9:
+YY_RULE_SETUP
+return T_AND;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+return T_OR;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+return T_OPEN_PAREN;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+return T_CLOSE_PAREN;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+return T_NOT;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+return T_EQUAL;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+return T_UNEQUAL;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{
+ str = zconftext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ YY_BREAK
+case 17:
+/* rule 17 can match eol */
+YY_RULE_SETUP
+BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+/* ignore */
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{
+ struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+ if (id && id->flags & TF_PARAM) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+/* comment */
+ YY_BREAK
+case 21:
+/* rule 21 can match eol */
+YY_RULE_SETUP
+current_file->lineno++;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+
+ YY_BREAK
+case YY_STATE_EOF(PARAM):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 23:
+/* rule 23 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{
+ append_string(zconftext, zconfleng);
+ }
+ YY_BREAK
+case 25:
+/* rule 25 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{
+ append_string(zconftext + 1, zconfleng - 1);
+ }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{
+ if (str == zconftext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(zconftext, 1);
+ }
+ YY_BREAK
+case 28:
+/* rule 28 can match eol */
+YY_RULE_SETUP
+{
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ YY_BREAK
+case YY_STATE_EOF(STRING):
+{
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+case 29:
+YY_RULE_SETUP
+{
+ ts = 0;
+ for (i = 0; i < zconfleng; i++) {
+ if (zconftext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ YY_BREAK
+case 30:
+/* rule 30 can match eol */
+*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up zconftext again */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+case 31:
+/* rule 31 can match eol */
+YY_RULE_SETUP
+{
+ current_file->lineno++;
+ append_string("\n", 1);
+ }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{
+ while (zconfleng) {
+ if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+ break;
+ zconfleng--;
+ }
+ append_string(zconftext, zconfleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ YY_BREAK
+case YY_STATE_EOF(HELP):
+{
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ YY_BREAK
+
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMAND):
+{
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(zconfin);
+ yyterminate();
+}
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (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 zconfin at a new source and called
+ * zconflex(). 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.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
+ 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 ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* 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 );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( zconfwrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * zconftext, 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.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (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 zconflex */
+
+/* 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 (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(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 ( (yy_c_buf_p) - (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) ((yy_c_buf_p) - (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 = (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) ((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. */
+ zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ 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" );
+
+ (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]),
+ (yy_n_chars), (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ zconfrestart(zconfin );
+ }
+
+ 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) ((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 = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (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 (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
+ }
+
+ 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 )
+{
+ register int yy_is_jam;
+
+ yy_current_state = yy_nxt[yy_current_state][1];
+ yy_is_jam = (yy_current_state <= 0);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+ static void yyunput (int c, register char * yy_bp )
+{
+ register char *yy_cp;
+
+ yy_cp = (yy_c_buf_p);
+
+ /* undo effects of setting up zconftext */
+ *yy_cp = (yy_hold_char);
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = (yy_n_chars) + 2;
+ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+ register char *source =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+ (yytext_ptr) = yy_bp;
+ (yy_hold_char) = *yy_cp;
+ (yy_c_buf_p) = yy_cp;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(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 ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ int offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ 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. */
+ zconfrestart(zconfin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( zconfwrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve zconftext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void zconfrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ zconfensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ zconf_create_buffer(zconfin,YY_BUF_SIZE );
+ }
+
+ zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
+ zconf_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * zconfpop_buffer_state();
+ * zconfpush_buffer_state(new_buffer);
+ */
+ zconfensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ zconf_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (zconfwrap()) processing, but the only time this flag
+ * is looked at is after zconfwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void zconf_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(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.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_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 *) zconfalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ zconf_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with zconf_create_buffer()
+ *
+ */
+ void zconf_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ 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 )
+ zconffree((void *) b->yy_ch_buf );
+
+ zconffree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a zconfrestart() or at EOF.
+ */
+ static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ zconf_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then zconf_init_buffer was _probably_
+ * called from zconfrestart() 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 = 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.
+ *
+ */
+ void zconf_flush_buffer (YY_BUFFER_STATE b )
+{
+ 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 )
+ zconf_load_buffer_state( );
+}
+
+/** 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.
+ *
+ */
+void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ zconfensure_buffer_stack();
+
+ /* This block is copied from zconf_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from zconf_switch_to_buffer. */
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void zconfpop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ zconf_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void zconfensure_buffer_stack (void)
+{
+ int num_to_alloc;
+
+ if (!(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;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (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
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size )
+{
+ 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) zconfalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_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;
+
+ zconf_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to zconflex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * zconf_scan_bytes() instead.
+ */
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
+{
+
+ return zconf_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to zconflex() 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.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len )
+{
+ 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 *) zconfalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in zconf_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 = zconf_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in zconf_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 )
+{
+ (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 zconftext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ zconftext[zconfleng] = (yy_hold_char); \
+ (yy_c_buf_p) = zconftext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ zconfleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int zconfget_lineno (void)
+{
+
+ return zconflineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *zconfget_in (void)
+{
+ return zconfin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *zconfget_out (void)
+{
+ return zconfout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+int zconfget_leng (void)
+{
+ return zconfleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *zconfget_text (void)
+{
+ return zconftext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void zconfset_lineno (int line_number )
+{
+
+ zconflineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see zconf_switch_to_buffer
+ */
+void zconfset_in (FILE * in_str )
+{
+ zconfin = in_str ;
+}
+
+void zconfset_out (FILE * out_str )
+{
+ zconfout = out_str ;
+}
+
+int zconfget_debug (void)
+{
+ return zconf_flex_debug;
+}
+
+void zconfset_debug (int bdebug )
+{
+ zconf_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from zconflex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ zconfin = stdin;
+ zconfout = stdout;
+#else
+ zconfin = (FILE *) 0;
+ zconfout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * zconflex_init()
+ */
+ return 0;
+}
+
+/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
+int zconflex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ zconf_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ zconfpop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ zconffree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * zconflex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ 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 )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *zconfalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *zconfrealloc (void * ptr, yy_size_t size )
+{
+ /* 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 zconffree (void * ptr )
+{
+ free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.string = text;
+ BEGIN(INITIAL);
+}
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ zconfin = zconf_fopen(name);
+ if (!zconfin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = malloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+ current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *file = file_lookup(name);
+ struct buffer *buf = malloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ zconfin = zconf_fopen(file->name);
+ if (!zconfin) {
+ printf("%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ if (file->flags & FILE_BUSY) {
+ printf("%s:%d: do not source '%s' from itself\n",
+ zconf_curname(), zconf_lineno(), name);
+ exit(1);
+ }
+ if (file->flags & FILE_SCANNED) {
+ printf("%s:%d: file '%s' is already sourced from '%s'\n",
+ zconf_curname(), zconf_lineno(), name,
+ file->parent->name);
+ exit(1);
+ }
+ file->flags |= FILE_BUSY;
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file->flags |= FILE_SCANNED;
+ current_file->flags &= ~FILE_BUSY;
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(zconfin);
+ zconf_delete_buffer(YY_CURRENT_BUFFER);
+ zconf_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef LKC_H
+#define LKC_H
+
+#include "expr.h"
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+static inline const char *gettext(const char *txt) { return txt; }
+static inline void textdomain(const char *domainname) {}
+static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LKC_DIRECT_LINK
+#define P(name,type,arg) extern type name arg
+#else
+#include "lkc_defs.h"
+#define P(name,type,arg) extern type (*name ## _p) arg
+#endif
+#include "lkc_proto.h"
+#undef P
+
+#define SRCTREE "srctree"
+
+#ifndef PACKAGE
+#define PACKAGE "linux"
+#endif
+
+#define LOCALEDIR "/usr/share/locale"
+
+#define _(text) gettext(text)
+#define N_(text) (text)
+
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+
+#define TF_COMMAND 0x0001
+#define TF_PARAM 0x0002
+#define TF_OPTION 0x0004
+
+enum conf_def_mode {
+ def_default,
+ def_yes,
+ def_mod,
+ def_no,
+ def_random
+};
+
+#define T_OPT_MODULES 1
+#define T_OPT_DEFCONFIG_LIST 2
+#define T_OPT_ENV 3
+
+struct kconf_id {
+ int name;
+ int token;
+ unsigned int flags;
+ enum symbol_type stype;
+};
+
+#ifdef YYDEBUG
+extern int zconfdebug;
+#endif
+
+int zconfparse(void);
+void zconfdump(FILE *out);
+void zconf_starthelp(void);
+FILE *zconf_fopen(const char *name);
+void zconf_initscan(const char *name);
+void zconf_nextfile(const char *name);
+int zconf_lineno(void);
+const char *zconf_curname(void);
+
+/* conf.c */
+void xfgets(char *str, int size, FILE *in);
+
+/* confdata.c */
+const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
+char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+void conf_set_all_new_symbols(enum conf_def_mode mode);
+
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+ if (fwrite(str, len, count, out) < count)
+ fprintf(stderr, "\nError in writing or end of file.\n");
+}
+
+/* kconfig_load.c */
+void kconfig_load(void);
+
+/* menu.c */
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
+struct menu *menu_add_menu(void);
+void menu_end_menu(void);
+void menu_add_entry(struct symbol *sym);
+void menu_end_entry(void);
+void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
+void menu_finalize(struct menu *parent);
+void menu_set_type(int type);
+
+/* util.c */
+struct file *file_lookup(const char *name);
+int file_write_dep(const char *name);
+
+struct gstr {
+ size_t len;
+ char *s;
+ /*
+ * when max_width is not zero long lines in string s (if any) get
+ * wrapped not to exceed the max_width value
+ */
+ int max_width;
+};
+struct gstr str_new(void);
+struct gstr str_assign(const char *s);
+void str_free(struct gstr *gs);
+void str_append(struct gstr *gs, const char *s);
+void str_printf(struct gstr *gs, const char *fmt, ...);
+const char *str_get(struct gstr *gs);
+
+/* symbol.c */
+extern struct expr *sym_env_list;
+
+void sym_init(void);
+void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
+void sym_set_changed(struct symbol *sym);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
+struct symbol *sym_check_deps(struct symbol *sym);
+struct property *prop_alloc(enum prop_type type, struct symbol *sym);
+struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
+
+static inline tristate sym_get_tristate_value(struct symbol *sym)
+{
+ return sym->curr.tri;
+}
+
+
+static inline struct symbol *sym_get_choice_value(struct symbol *sym)
+{
+ return (struct symbol *)sym->curr.val;
+}
+
+static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
+{
+ return sym_set_tristate_value(chval, yes);
+}
+
+static inline bool sym_is_choice(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICE ? true : false;
+}
+
+static inline bool sym_is_choice_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_CHOICEVAL ? true : false;
+}
+
+static inline bool sym_is_optional(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_OPTIONAL ? true : false;
+}
+
+static inline bool sym_has_value(struct symbol *sym)
+{
+ return sym->flags & SYMBOL_DEF_USER ? true : false;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LKC_H */
--- /dev/null
+#include <stdarg.h>
+
+/* confdata.c */
+P(conf_parse,void,(const char *name));
+P(conf_read,int,(const char *name));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_write_defconfig,int,(const char *name));
+P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
+P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
+
+/* menu.c */
+P(rootmenu,struct menu,);
+
+P(menu_is_visible, bool, (struct menu *menu));
+P(menu_has_prompt, bool, (struct menu *menu));
+P(menu_get_prompt,const char *,(struct menu *menu));
+P(menu_get_root_menu,struct menu *,(struct menu *menu));
+P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+P(menu_has_help,bool,(struct menu *menu));
+P(menu_get_help,const char *,(struct menu *menu));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr));
+P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
+
+/* symbol.c */
+P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
+
+P(sym_lookup,struct symbol *,(const char *name, int flags));
+P(sym_find,struct symbol *,(const char *name));
+P(sym_expand_string_value,const char *,(const char *in));
+P(sym_re_search,struct symbol **,(const char *pattern));
+P(sym_type_name,const char *,(enum symbol_type type));
+P(sym_calc_value,void,(struct symbol *sym));
+P(sym_get_type,enum symbol_type,(struct symbol *sym));
+P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri));
+P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri));
+P(sym_toggle_tristate_value,tristate,(struct symbol *sym));
+P(sym_string_valid,bool,(struct symbol *sym, const char *newval));
+P(sym_string_within_range,bool,(struct symbol *sym, const char *str));
+P(sym_set_string_value,bool,(struct symbol *sym, const char *newval));
+P(sym_is_changable,bool,(struct symbol *sym));
+P(sym_get_choice_prop,struct property *,(struct symbol *sym));
+P(sym_get_default_prop,struct property *,(struct symbol *sym));
+P(sym_get_string_value,const char *,(struct symbol *sym));
+
+P(prop_get_type_name,const char *,(enum prop_type type));
+
+/* expr.c */
+P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2));
+P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken));
--- /dev/null
+#
+# Generated files
+#
+lxdialog
--- /dev/null
+This is NOT the official version of dialog. This version has been
+significantly modified from the original. It is for use by the Linux
+kernel configuration script. Please do not bother Savio Lam with
+questions about this program.
--- /dev/null
+#!/bin/sh
+# Check ncurses compatibility
+
+# What library to link
+ldflags()
+{
+ for ext in so a dylib ; do
+ for lib in ncursesw ncurses curses ; do
+ $cc -print-file-name=lib${lib}.${ext} | grep -q /
+ if [ $? -eq 0 ]; then
+ echo "-l${lib}"
+ exit
+ fi
+ done
+ done
+ exit 1
+}
+
+# Where is ncurses.h?
+ccflags()
+{
+ if [ -f /usr/include/ncurses/ncurses.h ]; then
+ echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
+ elif [ -f /usr/include/ncurses/curses.h ]; then
+ echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
+ elif [ -f /usr/include/ncursesw/curses.h ]; then
+ echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>"'
+ elif [ -f /usr/include/ncurses.h ]; then
+ echo '-DCURSES_LOC="<ncurses.h>"'
+ else
+ echo '-DCURSES_LOC="<curses.h>"'
+ fi
+}
+
+# Temp file, try to clean up after us
+tmp=.lxdialog.tmp
+trap "rm -f $tmp" 0 1 2 3 15
+
+# Check if we can link to ncurses
+check() {
+ $cc -xc - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
+ if [ $? != 0 ]; then
+ echo " *** Unable to find the ncurses libraries or the" 1>&2
+ echo " *** required header files." 1>&2
+ echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
+ echo " *** " 1>&2
+ echo " *** Install ncurses (ncurses-devel) and try again." 1>&2
+ echo " *** " 1>&2
+ exit 1
+ fi
+}
+
+usage() {
+ printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
+}
+
+if [ $# -eq 0 ]; then
+ usage
+ exit 1
+fi
+
+cc=""
+case "$1" in
+ "-check")
+ shift
+ cc="$@"
+ check
+ ;;
+ "-ccflags")
+ ccflags
+ ;;
+ "-ldflags")
+ shift
+ cc="$@"
+ ldflags
+ ;;
+ "*")
+ usage
+ exit 1
+ ;;
+esac
--- /dev/null
+/*
+ * checklist.c -- implements the checklist box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+ int i;
+ char *list_item = malloc(list_width + 1);
+
+ strncpy(list_item, item_str(), list_width - item_x);
+ list_item[list_width - item_x] = '\0';
+
+ /* Clear 'residue' of last item */
+ wattrset(win, dlg.menubox.atr);
+ wmove(win, choice, 0);
+ for (i = 0; i < list_width; i++)
+ waddch(win, ' ');
+
+ wmove(win, choice, check_x);
+ wattrset(win, selected ? dlg.check_selected.atr
+ : dlg.check.atr);
+ if (!item_is_tag(':'))
+ wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+ wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+ mvwaddch(win, choice, item_x, list_item[0]);
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ waddstr(win, list_item + 1);
+ if (selected) {
+ wmove(win, choice, check_x + 1);
+ wrefresh(win);
+ }
+ free(list_item);
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+ int y, int x, int height)
+{
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+
+ if ((height < item_no) && (scroll + choice < item_no - 1)) {
+ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+}
+
+/*
+ * Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button(dialog, gettext("Select"), y, x, selected == 0);
+ print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+ wmove(dialog, y, x + 1 + 14 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+ int width, int list_height)
+{
+ int i, x, y, box_x, box_y;
+ int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+ WINDOW *dialog, *list;
+
+ /* which item to highlight */
+ item_foreach() {
+ if (item_is_tag('X'))
+ choice = item_n();
+ if (item_is_selected()) {
+ choice = item_n();
+ break;
+ }
+ }
+
+do_resize:
+ if (getmaxy(stdscr) < (height + 6))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + 6))
+ return -ERRDISPLAYTOOSMALL;
+
+ max_choice = MIN(list_height, item_count());
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ list_width = width - 6;
+ box_y = height - list_height - 5;
+ box_x = (width - list_width) / 2 - 1;
+
+ /* create new window for the list */
+ list = subwin(dialog, list_height, list_width, y + box_y + 1,
+ x + box_x + 1);
+
+ keypad(list, TRUE);
+
+ /* draw a box around the list items */
+ draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+ dlg.menubox_border.atr, dlg.menubox.atr);
+
+ /* Find length of longest item in order to center checklist */
+ check_x = 0;
+ item_foreach()
+ check_x = MAX(check_x, strlen(item_str()) + 4);
+ check_x = MIN(check_x, list_width);
+
+ check_x = (list_width - check_x) / 2;
+ item_x = check_x + 4;
+
+ if (choice >= list_height) {
+ scroll = choice - list_height + 1;
+ choice -= scroll;
+ }
+
+ /* Print the list */
+ for (i = 0; i < max_choice; i++) {
+ item_set(scroll + i);
+ print_item(list, i, i == choice);
+ }
+
+ print_arrows(dialog, choice, item_count(), scroll,
+ box_y, box_x + check_x + 5, list_height);
+
+ print_buttons(dialog, height, width, 0);
+
+ wnoutrefresh(dialog);
+ wnoutrefresh(list);
+ doupdate();
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+ for (i = 0; i < max_choice; i++) {
+ item_set(i + scroll);
+ if (toupper(key) == toupper(item_str()[0]))
+ break;
+ }
+
+ if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+ key == '+' || key == '-') {
+ if (key == KEY_UP || key == '-') {
+ if (!choice) {
+ if (!scroll)
+ continue;
+ /* Scroll list down */
+ if (list_height > 1) {
+ /* De-highlight current first item */
+ item_set(scroll);
+ print_item(list, 0, FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, -1);
+ scrollok(list, FALSE);
+ }
+ scroll--;
+ item_set(scroll);
+ print_item(list, 0, TRUE);
+ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(list);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice - 1;
+ } else if (key == KEY_DOWN || key == '+') {
+ if (choice == max_choice - 1) {
+ if (scroll + choice >= item_count() - 1)
+ continue;
+ /* Scroll list up */
+ if (list_height > 1) {
+ /* De-highlight current last item before scrolling up */
+ item_set(scroll + max_choice - 1);
+ print_item(list,
+ max_choice - 1,
+ FALSE);
+ scrollok(list, TRUE);
+ wscrl(list, 1);
+ scrollok(list, FALSE);
+ }
+ scroll++;
+ item_set(scroll + max_choice - 1);
+ print_item(list, max_choice - 1, TRUE);
+
+ print_arrows(dialog, choice, item_count(),
+ scroll, box_y, box_x + check_x + 5, list_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(list);
+
+ continue; /* wait for another key press */
+ } else
+ i = choice + 1;
+ }
+ if (i != choice) {
+ /* De-highlight current item */
+ item_set(scroll + choice);
+ print_item(list, choice, FALSE);
+ /* Highlight new item */
+ choice = i;
+ item_set(scroll + choice);
+ print_item(list, choice, TRUE);
+ wnoutrefresh(dialog);
+ wrefresh(list);
+ }
+ continue; /* wait for another key press */
+ }
+ switch (key) {
+ case 'H':
+ case 'h':
+ case '?':
+ button = 1;
+ /* fall-through */
+ case 'S':
+ case 's':
+ case ' ':
+ case '\n':
+ item_foreach()
+ item_set_selected(0);
+ item_set(scroll + choice);
+ item_set_selected(1);
+ delwin(list);
+ delwin(dialog);
+ return button;
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(dialog);
+ break;
+ case 'X':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(list);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+
+ /* Now, update everything... */
+ doupdate();
+ }
+ delwin(list);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
--- /dev/null
+/*
+ * dialog.h -- common declarations for all dialog modules
+ *
+ * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include CURSES_LOC
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked. This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses. The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef wbkgdset
+#define wbkgdset(w,p) /*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ * Color definitions
+ */
+struct dialog_color {
+ chtype atr; /* Color attribute */
+ int fg; /* foreground */
+ int bg; /* background */
+ int hl; /* highlight this item */
+};
+
+struct dialog_info {
+ const char *backtitle;
+ struct dialog_color screen;
+ struct dialog_color shadow;
+ struct dialog_color dialog;
+ struct dialog_color title;
+ struct dialog_color border;
+ struct dialog_color button_active;
+ struct dialog_color button_inactive;
+ struct dialog_color button_key_active;
+ struct dialog_color button_key_inactive;
+ struct dialog_color button_label_active;
+ struct dialog_color button_label_inactive;
+ struct dialog_color inputbox;
+ struct dialog_color inputbox_border;
+ struct dialog_color searchbox;
+ struct dialog_color searchbox_title;
+ struct dialog_color searchbox_border;
+ struct dialog_color position_indicator;
+ struct dialog_color menubox;
+ struct dialog_color menubox_border;
+ struct dialog_color item;
+ struct dialog_color item_selected;
+ struct dialog_color tag;
+ struct dialog_color tag_selected;
+ struct dialog_color tag_key;
+ struct dialog_color tag_key_selected;
+ struct dialog_color check;
+ struct dialog_color check_selected;
+ struct dialog_color uarrow;
+ struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+ char str[MAXITEMSTR]; /* promtp displayed */
+ char tag;
+ void *data; /* pointer to menu item - used by menubox+checklist */
+ int selected; /* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+ struct dialog_item node;
+ struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+ for (item_cur = item_head ? item_head: item_cur; \
+ item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+ chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+ int width, int pause);
+int dialog_textbox(const char *title, const char *file, int height, int width);
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll);
+int dialog_checklist(const char *title, const char *prompt, int height,
+ int width, int list_height);
+extern char dialog_input_result[];
+int dialog_inputbox(const char *title, const char *prompt, int height,
+ int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ * -- the first 32 are used as numbers, in addition to '0'-'9'
+ * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ * -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
--- /dev/null
+/*
+ * inputbox.c -- implements the input box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ * Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 11;
+ int y = height - 2;
+
+ print_button(dialog, gettext(" Ok "), y, x, selected == 0);
+ print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+ wmove(dialog, y, x + 1 + 14 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+ const char *init)
+{
+ int i, x, y, box_y, box_x, box_width;
+ int input_x = 0, scroll = 0, key = 0, button = -1;
+ char *instr = dialog_input_result;
+ WINDOW *dialog;
+
+ if (!init)
+ instr[0] = '\0';
+ else
+ strcpy(instr, init);
+
+do_resize:
+ if (getmaxy(stdscr) <= (height - 2))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) <= (width - 2))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ /* Draw the input field box */
+ box_width = width - 6;
+ getyx(dialog, y, x);
+ box_y = y + 2;
+ box_x = (width - box_width) / 2;
+ draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+ dlg.dialog.atr, dlg.border.atr);
+
+ print_buttons(dialog, height, width, 0);
+
+ /* Set up the initial value */
+ wmove(dialog, box_y, box_x);
+ wattrset(dialog, dlg.inputbox.atr);
+
+ input_x = strlen(instr);
+
+ if (input_x >= box_width) {
+ scroll = input_x - box_width + 1;
+ input_x = box_width - 1;
+ for (i = 0; i < box_width - 1; i++)
+ waddch(dialog, instr[scroll + i]);
+ } else {
+ waddstr(dialog, instr);
+ }
+
+ wmove(dialog, box_y, box_x + input_x);
+
+ wrefresh(dialog);
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+
+ if (button == -1) { /* Input box selected */
+ switch (key) {
+ case TAB:
+ case KEY_UP:
+ case KEY_DOWN:
+ break;
+ case KEY_LEFT:
+ continue;
+ case KEY_RIGHT:
+ continue;
+ case KEY_BACKSPACE:
+ case 127:
+ if (input_x || scroll) {
+ wattrset(dialog, dlg.inputbox.atr);
+ if (!input_x) {
+ scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width; i++)
+ waddch(dialog,
+ instr[scroll + input_x + i] ?
+ instr[scroll + input_x + i] : ' ');
+ input_x = strlen(instr) - scroll;
+ } else
+ input_x--;
+ instr[scroll + input_x] = '\0';
+ mvwaddch(dialog, box_y, input_x + box_x, ' ');
+ wmove(dialog, box_y, input_x + box_x);
+ wrefresh(dialog);
+ }
+ continue;
+ default:
+ if (key < 0x100 && isprint(key)) {
+ if (scroll + input_x < MAX_LEN) {
+ wattrset(dialog, dlg.inputbox.atr);
+ instr[scroll + input_x] = key;
+ instr[scroll + input_x + 1] = '\0';
+ if (input_x == box_width - 1) {
+ scroll++;
+ wmove(dialog, box_y, box_x);
+ for (i = 0; i < box_width - 1; i++)
+ waddch(dialog, instr [scroll + i]);
+ } else {
+ wmove(dialog, box_y, input_x++ + box_x);
+ waddch(dialog, key);
+ }
+ wrefresh(dialog);
+ } else
+ flash(); /* Alarm user about overflow */
+ continue;
+ }
+ }
+ }
+ switch (key) {
+ case 'O':
+ case 'o':
+ delwin(dialog);
+ return 0;
+ case 'H':
+ case 'h':
+ delwin(dialog);
+ return 1;
+ case KEY_UP:
+ case KEY_LEFT:
+ switch (button) {
+ case -1:
+ button = 1; /* Indicates "Help" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 0:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove(dialog, box_y, box_x + input_x);
+ wrefresh(dialog);
+ break;
+ case 1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ }
+ break;
+ case TAB:
+ case KEY_DOWN:
+ case KEY_RIGHT:
+ switch (button) {
+ case -1:
+ button = 0; /* Indicates "OK" button is selected */
+ print_buttons(dialog, height, width, 0);
+ break;
+ case 0:
+ button = 1; /* Indicates "Help" button is selected */
+ print_buttons(dialog, height, width, 1);
+ break;
+ case 1:
+ button = -1; /* Indicates input box is selected */
+ print_buttons(dialog, height, width, 0);
+ wmove(dialog, box_y, box_x + input_x);
+ wrefresh(dialog);
+ break;
+ }
+ break;
+ case ' ':
+ case '\n':
+ delwin(dialog);
+ return (button == -1 ? 0 : button);
+ case 'X':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+ return KEY_ESC; /* ESC pressed */
+}
--- /dev/null
+/*
+ * menubox.c -- implements the menu box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Changes by Clifford Wolf (god@clifford.at)
+ *
+ * [ 1998-06-13 ]
+ *
+ * *) A bugfix for the Page-Down problem
+ *
+ * *) Formerly when I used Page Down and Page Up, the cursor would be set
+ * to the first position in the menu box. Now lxdialog is a bit
+ * smarter and works more like other menu systems (just have a look at
+ * it).
+ *
+ * *) Formerly if I selected something my scrolling would be broken because
+ * lxdialog is re-invoked by the Menuconfig shell script, can't
+ * remember the last scrolling position, and just sets it so that the
+ * cursor is at the bottom of the box. Now it writes the temporary file
+ * lxdialog.scrltmp which contains this information. The file is
+ * deleted by lxdialog if the user leaves a submenu or enters a new
+ * one, but it would be nice if Menuconfig could make another "rm -f"
+ * just to be sure. Just try it out - you will recognise a difference!
+ *
+ * [ 1998-06-14 ]
+ *
+ * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ * and menus change their size on the fly.
+ *
+ * *) If for some reason the last scrolling position is not saved by
+ * lxdialog, it sets the scrolling so that the selected item is in the
+ * middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+ int selected, int hotkey)
+{
+ int j;
+ char *menu_item = malloc(menu_width + 1);
+
+ strncpy(menu_item, item, menu_width - item_x);
+ menu_item[menu_width - item_x] = '\0';
+ j = first_alpha(menu_item, "YyNnMmHh");
+
+ /* Clear 'residue' of last item */
+ wattrset(win, dlg.menubox.atr);
+ wmove(win, line_y, 0);
+#if OLD_NCURSES
+ {
+ int i;
+ for (i = 0; i < menu_width; i++)
+ waddch(win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ mvwaddstr(win, line_y, item_x, menu_item);
+ if (hotkey) {
+ wattrset(win, selected ? dlg.tag_key_selected.atr
+ : dlg.tag_key.atr);
+ mvwaddch(win, line_y, item_x + j, menu_item[j]);
+ }
+ if (selected) {
+ wmove(win, line_y, item_x + 1);
+ }
+ free(menu_item);
+ wrefresh(win);
+}
+
+#define print_item(index, choice, selected) \
+do { \
+ item_set(index); \
+ do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+ int height)
+{
+ int cur_y, cur_x;
+
+ getyx(win, cur_y, cur_x);
+
+ wmove(win, y, x);
+
+ if (scroll > 0) {
+ wattrset(win, dlg.uarrow.atr);
+ waddch(win, ACS_UARROW);
+ waddstr(win, "(-)");
+ } else {
+ wattrset(win, dlg.menubox.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ y = y + height + 1;
+ wmove(win, y, x);
+ wrefresh(win);
+
+ if ((height < item_no) && (scroll + height < item_no)) {
+ wattrset(win, dlg.darrow.atr);
+ waddch(win, ACS_DARROW);
+ waddstr(win, "(+)");
+ } else {
+ wattrset(win, dlg.menubox_border.atr);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ waddch(win, ACS_HLINE);
+ }
+
+ wmove(win, cur_y, cur_x);
+ wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected)
+{
+ int x = width / 2 - 16;
+ int y = height - 2;
+
+ print_button(win, gettext("Select"), y, x, selected == 0);
+ print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+ print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+
+ wmove(win, y, x + 1 + 12 * selected);
+ wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+ /* Scroll menu up */
+ scrollok(win, TRUE);
+ wscrl(win, n);
+ scrollok(win, FALSE);
+ *scroll = *scroll + n;
+ wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+ */
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll)
+{
+ int i, j, x, y, box_x, box_y;
+ int height, width, menu_height;
+ int key = 0, button = 0, scroll = 0, choice = 0;
+ int first_item = 0, max_choice;
+ WINDOW *dialog, *menu;
+
+do_resize:
+ height = getmaxy(stdscr);
+ width = getmaxx(stdscr);
+ if (height < 15 || width < 65)
+ return -ERRDISPLAYTOOSMALL;
+
+ height -= 4;
+ width -= 5;
+ menu_height = height - 10;
+
+ max_choice = MIN(menu_height, item_count());
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ menu_width = width - 6;
+ box_y = height - menu_height - 5;
+ box_x = (width - menu_width) / 2 - 1;
+
+ /* create new window for the menu */
+ menu = subwin(dialog, menu_height, menu_width,
+ y + box_y + 1, x + box_x + 1);
+ keypad(menu, TRUE);
+
+ /* draw a box around the menu items */
+ draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+ dlg.menubox_border.atr, dlg.menubox.atr);
+
+ if (menu_width >= 80)
+ item_x = (menu_width - 70) / 2;
+ else
+ item_x = 4;
+
+ /* Set choice to default item */
+ item_foreach()
+ if (selected && (selected == item_data()))
+ choice = item_n();
+ /* get the saved scroll info */
+ scroll = *s_scroll;
+ if ((scroll <= choice) && (scroll + max_choice > choice) &&
+ (scroll >= 0) && (scroll + max_choice <= item_count())) {
+ first_item = scroll;
+ choice = choice - scroll;
+ } else {
+ scroll = 0;
+ }
+ if ((choice >= max_choice)) {
+ if (choice >= item_count() - max_choice / 2)
+ scroll = first_item = item_count() - max_choice;
+ else
+ scroll = first_item = choice - max_choice / 2;
+ choice = choice - scroll;
+ }
+
+ /* Print the menu */
+ for (i = 0; i < max_choice; i++) {
+ print_item(first_item + i, i, i == choice);
+ }
+
+ wnoutrefresh(menu);
+
+ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ print_buttons(dialog, height, width, 0);
+ wmove(menu, choice, item_x + 1);
+ wrefresh(menu);
+
+ while (key != KEY_ESC) {
+ key = wgetch(menu);
+
+ if (key < 256 && isalpha(key))
+ key = tolower(key);
+
+ if (strchr("ynmh", key))
+ i = max_choice;
+ else {
+ for (i = choice + 1; i < max_choice; i++) {
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
+ break;
+ }
+ if (i == max_choice)
+ for (i = 0; i < max_choice; i++) {
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
+ break;
+ }
+ }
+
+ if (i < max_choice ||
+ key == KEY_UP || key == KEY_DOWN ||
+ key == '-' || key == '+' ||
+ key == KEY_PPAGE || key == KEY_NPAGE) {
+ /* Remove highligt of current item */
+ print_item(scroll + choice, choice, FALSE);
+
+ if (key == KEY_UP || key == '-') {
+ if (choice < 2 && scroll) {
+ /* Scroll menu down */
+ do_scroll(menu, &scroll, -1);
+
+ print_item(scroll, 0, FALSE);
+ } else
+ choice = MAX(choice - 1, 0);
+
+ } else if (key == KEY_DOWN || key == '+') {
+ print_item(scroll+choice, choice, FALSE);
+
+ if ((choice > max_choice - 3) &&
+ (scroll + max_choice < item_count())) {
+ /* Scroll menu up */
+ do_scroll(menu, &scroll, 1);
+
+ print_item(scroll+max_choice - 1,
+ max_choice - 1, FALSE);
+ } else
+ choice = MIN(choice + 1, max_choice - 1);
+
+ } else if (key == KEY_PPAGE) {
+ scrollok(menu, TRUE);
+ for (i = 0; (i < max_choice); i++) {
+ if (scroll > 0) {
+ do_scroll(menu, &scroll, -1);
+ print_item(scroll, 0, FALSE);
+ } else {
+ if (choice > 0)
+ choice--;
+ }
+ }
+
+ } else if (key == KEY_NPAGE) {
+ for (i = 0; (i < max_choice); i++) {
+ if (scroll + max_choice < item_count()) {
+ do_scroll(menu, &scroll, 1);
+ print_item(scroll+max_choice-1,
+ max_choice - 1, FALSE);
+ } else {
+ if (choice + 1 < max_choice)
+ choice++;
+ }
+ }
+ } else
+ choice = i;
+
+ print_item(scroll + choice, choice, TRUE);
+
+ print_arrows(dialog, item_count(), scroll,
+ box_y, box_x + item_x + 1, menu_height);
+
+ wnoutrefresh(dialog);
+ wrefresh(menu);
+
+ continue; /* wait for another key press */
+ }
+
+ switch (key) {
+ case KEY_LEFT:
+ case TAB:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0)
+ ? 2 : (button > 2 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(menu);
+ break;
+ case ' ':
+ case 's':
+ case 'y':
+ case 'n':
+ case 'm':
+ case '/':
+ case 'h':
+ case '?':
+ case 'z':
+ case '\n':
+ /* save scroll info */
+ *s_scroll = scroll;
+ delwin(menu);
+ delwin(dialog);
+ item_set(scroll + choice);
+ item_set_selected(1);
+ switch (key) {
+ case 'h':
+ case '?':
+ return 2;
+ case 's':
+ case 'y':
+ return 3;
+ case 'n':
+ return 4;
+ case 'm':
+ return 5;
+ case ' ':
+ return 6;
+ case '/':
+ return 7;
+ case 'z':
+ return 8;
+ case '\n':
+ return button;
+ }
+ return 0;
+ case 'e':
+ case 'x':
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(menu);
+ break;
+ case KEY_RESIZE:
+ on_key_resize();
+ delwin(menu);
+ delwin(dialog);
+ goto do_resize;
+ }
+ }
+ delwin(menu);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
--- /dev/null
+/*
+ * textbox.c -- implements the text box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW * win, int height, int width);
+static void print_line(WINDOW * win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+ int cur_y, int cur_x)
+{
+ print_page(box, boxh, boxw);
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+}
+
+
+/*
+ * Display text from a file in a dialog box.
+ */
+int dialog_textbox(const char *title, const char *tbuf,
+ int initial_height, int initial_width)
+{
+ int i, x, y, cur_x, cur_y, key = 0;
+ int height, width, boxh, boxw;
+ int passed_end;
+ WINDOW *dialog, *box;
+
+ begin_reached = 1;
+ end_reached = 0;
+ page_length = 0;
+ hscroll = 0;
+ buf = tbuf;
+ page = buf; /* page is pointer to start of page to be displayed */
+
+do_resize:
+ getmaxyx(stdscr, height, width);
+ if (height < 8 || width < 8)
+ return -ERRDISPLAYTOOSMALL;
+ if (initial_height != 0)
+ height = initial_height;
+ else
+ if (height > 4)
+ height -= 4;
+ else
+ height = 0;
+ if (initial_width != 0)
+ width = initial_width;
+ else
+ if (width > 5)
+ width -= 5;
+ else
+ width = 0;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ /* Create window for box region, used for scrolling text */
+ boxh = height - 4;
+ boxw = width - 2;
+ box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+ wattrset(box, dlg.dialog.atr);
+ wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+ keypad(box, TRUE);
+
+ /* register the new window, along with its borders */
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
+ wnoutrefresh(dialog);
+ getyx(dialog, cur_y, cur_x); /* Save cursor position */
+
+ /* Print first page of text */
+ attr_clear(box, boxh, boxw, dlg.dialog.atr);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+
+ while ((key != KEY_ESC) && (key != '\n')) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'E': /* Exit */
+ case 'e':
+ case 'X':
+ case 'x':
+ delwin(box);
+ delwin(dialog);
+ return 0;
+ case 'g': /* First page */
+ case KEY_HOME:
+ if (!begin_reached) {
+ begin_reached = 1;
+ page = buf;
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
+ }
+ break;
+ case 'G': /* Last page */
+ case KEY_END:
+
+ end_reached = 1;
+ /* point to last char in buf */
+ page = buf + strlen(buf);
+ back_lines(boxh);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
+ break;
+ case 'K': /* Previous line */
+ case 'k':
+ case KEY_UP:
+ if (!begin_reached) {
+ back_lines(page_length + 1);
+
+ /* We don't call print_page() here but use
+ * scrolling to ensure faster screen update.
+ * However, 'end_reached' and 'page_length'
+ * should still be updated, and 'page' should
+ * point to start of next page. This is done
+ * by calling get_line() in the following
+ * 'for' loop. */
+ scrollok(box, TRUE);
+ wscrl(box, -1); /* Scroll box region down one line */
+ scrollok(box, FALSE);
+ page_length = 0;
+ passed_end = 0;
+ for (i = 0; i < boxh; i++) {
+ if (!i) {
+ /* print first line of page */
+ print_line(box, 0, boxw);
+ wnoutrefresh(box);
+ } else
+ /* Called to update 'end_reached' and 'page' */
+ get_line();
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case 'B': /* Previous page */
+ case 'b':
+ case KEY_PPAGE:
+ if (begin_reached)
+ break;
+ back_lines(page_length + boxh);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
+ break;
+ case 'J': /* Next line */
+ case 'j':
+ case KEY_DOWN:
+ if (!end_reached) {
+ begin_reached = 0;
+ scrollok(box, TRUE);
+ scroll(box); /* Scroll box region up one line */
+ scrollok(box, FALSE);
+ print_line(box, boxh - 1, boxw);
+ wnoutrefresh(box);
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+ }
+ break;
+ case KEY_NPAGE: /* Next page */
+ case ' ':
+ if (end_reached)
+ break;
+
+ begin_reached = 0;
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
+ break;
+ case '0': /* Beginning of line */
+ case 'H': /* Scroll left */
+ case 'h':
+ case KEY_LEFT:
+ if (hscroll <= 0)
+ break;
+
+ if (key == '0')
+ hscroll = 0;
+ else
+ hscroll--;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
+ break;
+ case 'L': /* Scroll right */
+ case 'l':
+ case KEY_RIGHT:
+ if (hscroll >= MAX_LEN)
+ break;
+ hscroll++;
+ /* Reprint current page to scroll horizontally */
+ back_lines(page_length);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ back_lines(height);
+ delwin(box);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+ delwin(box);
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+ int i;
+
+ begin_reached = 0;
+ /* Go back 'n' lines */
+ for (i = 0; i < n; i++) {
+ if (*page == '\0') {
+ if (end_reached) {
+ end_reached = 0;
+ continue;
+ }
+ }
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ do {
+ if (page == buf) {
+ begin_reached = 1;
+ return;
+ }
+ page--;
+ } while (*page != '\n');
+ page++;
+ }
+}
+
+/*
+ * Print a new page of text. Called by dialog_textbox().
+ */
+static void print_page(WINDOW * win, int height, int width)
+{
+ int i, passed_end = 0;
+
+ page_length = 0;
+ for (i = 0; i < height; i++) {
+ print_line(win, i, width);
+ if (!passed_end)
+ page_length++;
+ if (end_reached && !passed_end)
+ passed_end = 1;
+ }
+ wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text. Called by dialog_textbox() and print_page().
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+ int y, x;
+ char *line;
+
+ line = get_line();
+ line += MIN(strlen(line), hscroll); /* Scroll horizontally */
+ wmove(win, row, 0); /* move cursor to correct line */
+ waddch(win, ' ');
+ waddnstr(win, line, MIN(strlen(line), width - 2));
+
+ getyx(win, y, x);
+ /* Clear 'residue' of previous line */
+#if OLD_NCURSES
+ {
+ int i;
+ for (i = 0; i < width - x; i++)
+ waddch(win, ' ');
+ }
+#else
+ wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+ int i = 0;
+ static char line[MAX_LEN + 1];
+
+ end_reached = 0;
+ while (*page != '\n') {
+ if (*page == '\0') {
+ if (!end_reached) {
+ end_reached = 1;
+ break;
+ }
+ } else if (i < MAX_LEN)
+ line[i++] = *(page++);
+ else {
+ /* Truncate lines longer than MAX_LEN characters */
+ if (i == MAX_LEN)
+ line[i++] = '\0';
+ page++;
+ }
+ }
+ if (i <= MAX_LEN)
+ line[i] = '\0';
+ if (!end_reached)
+ page++; /* move pass '\n' */
+
+ return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+ int percent;
+
+ wattrset(win, dlg.position_indicator.atr);
+ wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+ percent = (page - buf) * 100 / strlen(buf);
+ wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+ wprintw(win, "(%3d%%)", percent);
+}
--- /dev/null
+/*
+ * util.c
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+
+#include "dialog.h"
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+ dlg.screen.atr = A_NORMAL;
+ dlg.shadow.atr = A_NORMAL;
+ dlg.dialog.atr = A_NORMAL;
+ dlg.title.atr = A_BOLD;
+ dlg.border.atr = A_NORMAL;
+ dlg.button_active.atr = A_REVERSE;
+ dlg.button_inactive.atr = A_DIM;
+ dlg.button_key_active.atr = A_REVERSE;
+ dlg.button_key_inactive.atr = A_BOLD;
+ dlg.button_label_active.atr = A_REVERSE;
+ dlg.button_label_inactive.atr = A_NORMAL;
+ dlg.inputbox.atr = A_NORMAL;
+ dlg.inputbox_border.atr = A_NORMAL;
+ dlg.searchbox.atr = A_NORMAL;
+ dlg.searchbox_title.atr = A_BOLD;
+ dlg.searchbox_border.atr = A_NORMAL;
+ dlg.position_indicator.atr = A_BOLD;
+ dlg.menubox.atr = A_NORMAL;
+ dlg.menubox_border.atr = A_NORMAL;
+ dlg.item.atr = A_NORMAL;
+ dlg.item_selected.atr = A_REVERSE;
+ dlg.tag.atr = A_BOLD;
+ dlg.tag_selected.atr = A_REVERSE;
+ dlg.tag_key.atr = A_BOLD;
+ dlg.tag_key_selected.atr = A_REVERSE;
+ dlg.check.atr = A_BOLD;
+ dlg.check_selected.atr = A_REVERSE;
+ dlg.uarrow.atr = A_BOLD;
+ dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do { \
+ dlg.dialog.fg = (f); \
+ dlg.dialog.bg = (b); \
+ dlg.dialog.hl = (h); \
+} while (0)
+
+static void set_classic_theme(void)
+{
+ DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
+ DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
+ DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
+ DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
+ DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
+}
+
+static void set_blackbg_theme(void)
+{
+ DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+ DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
+ DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
+ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
+
+ DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
+ DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
+
+ DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
+
+ DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+ set_classic_theme();
+ DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+ int use_color = 1;
+ if (!theme)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "classic") == 0)
+ set_classic_theme();
+ else if (strcmp(theme, "bluetitle") == 0)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "blackbg") == 0)
+ set_blackbg_theme();
+ else if (strcmp(theme, "mono") == 0)
+ use_color = 0;
+
+ return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+ static int pair = 0;
+
+ pair++;
+ init_pair(pair, color->fg, color->bg);
+ if (color->hl)
+ color->atr = A_BOLD | COLOR_PAIR(pair);
+ else
+ color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+ init_one_color(&dlg.screen);
+ init_one_color(&dlg.shadow);
+ init_one_color(&dlg.dialog);
+ init_one_color(&dlg.title);
+ init_one_color(&dlg.border);
+ init_one_color(&dlg.button_active);
+ init_one_color(&dlg.button_inactive);
+ init_one_color(&dlg.button_key_active);
+ init_one_color(&dlg.button_key_inactive);
+ init_one_color(&dlg.button_label_active);
+ init_one_color(&dlg.button_label_inactive);
+ init_one_color(&dlg.inputbox);
+ init_one_color(&dlg.inputbox_border);
+ init_one_color(&dlg.searchbox);
+ init_one_color(&dlg.searchbox_title);
+ init_one_color(&dlg.searchbox_border);
+ init_one_color(&dlg.position_indicator);
+ init_one_color(&dlg.menubox);
+ init_one_color(&dlg.menubox_border);
+ init_one_color(&dlg.item);
+ init_one_color(&dlg.item_selected);
+ init_one_color(&dlg.tag);
+ init_one_color(&dlg.tag_selected);
+ init_one_color(&dlg.tag_key);
+ init_one_color(&dlg.tag_key_selected);
+ init_one_color(&dlg.check);
+ init_one_color(&dlg.check_selected);
+ init_one_color(&dlg.uarrow);
+ init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+ int use_color;
+
+ use_color = set_theme(theme);
+ if (use_color && has_colors()) {
+ start_color();
+ init_dialog_colors();
+ } else
+ set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+ int i, j;
+
+ wattrset(win, attr);
+ for (i = 0; i < height; i++) {
+ wmove(win, i, 0);
+ for (j = 0; j < width; j++)
+ waddch(win, ' ');
+ }
+ touchwin(win);
+}
+
+void dialog_clear(void)
+{
+ attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+ /* Display background title if it exists ... - SLH */
+ if (dlg.backtitle != NULL) {
+ int i;
+
+ wattrset(stdscr, dlg.screen.atr);
+ mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+ wmove(stdscr, 1, 1);
+ for (i = 1; i < COLS - 1; i++)
+ waddch(stdscr, ACS_HLINE);
+ }
+ wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+ int height, width;
+
+ initscr(); /* Init curses */
+ getmaxyx(stdscr, height, width);
+ if (height < 19 || width < 80) {
+ endwin();
+ return -ERRDISPLAYTOOSMALL;
+ }
+
+ dlg.backtitle = backtitle;
+ color_setup(getenv("MENUCONFIG_COLOR"));
+
+ keypad(stdscr, TRUE);
+ cbreak();
+ noecho();
+ dialog_clear();
+
+ return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+ dlg.backtitle = backtitle;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+ /* move cursor back to original position */
+ move(y, x);
+ refresh();
+ endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+ if (title) {
+ int tlen = MIN(width - 2, strlen(title));
+ wattrset(dialog, dlg.title.atr);
+ mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+ mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+ waddch(dialog, ' ');
+ }
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces. We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+ int newl, cur_x, cur_y;
+ int i, prompt_len, room, wlen;
+ char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+
+ strcpy(tempstr, prompt);
+
+ prompt_len = strlen(tempstr);
+
+ /*
+ * Remove newlines
+ */
+ for (i = 0; i < prompt_len; i++) {
+ if (tempstr[i] == '\n')
+ tempstr[i] = ' ';
+ }
+
+ if (prompt_len <= width - x * 2) { /* If prompt is short */
+ wmove(win, y, (width - prompt_len) / 2);
+ waddstr(win, tempstr);
+ } else {
+ cur_x = x;
+ cur_y = y;
+ newl = 1;
+ word = tempstr;
+ while (word && *word) {
+ sp = strchr(word, ' ');
+ if (sp)
+ *sp++ = 0;
+
+ /* Wrap to next line if either the word does not fit,
+ or it is the first word of a new sentence, and it is
+ short, and the next word does not fit. */
+ room = width - cur_x;
+ wlen = strlen(word);
+ if (wlen > room ||
+ (newl && wlen < 4 && sp
+ && wlen + 1 + strlen(sp) > room
+ && (!(sp2 = strchr(sp, ' '))
+ || wlen + 1 + (sp2 - sp) > room))) {
+ cur_y++;
+ cur_x = x;
+ }
+ wmove(win, cur_y, cur_x);
+ waddstr(win, word);
+ getyx(win, cur_y, cur_x);
+ cur_x++;
+ if (sp && *sp == ' ') {
+ cur_x++; /* double space */
+ while (*++sp == ' ') ;
+ newl = 1;
+ } else
+ newl = 0;
+ word = sp;
+ }
+ }
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+ int i, temp;
+
+ wmove(win, y, x);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
+ waddstr(win, "<");
+ temp = strspn(label, " ");
+ label += temp;
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
+ for (i = 0; i < temp; i++)
+ waddch(win, ' ');
+ wattrset(win, selected ? dlg.button_key_active.atr
+ : dlg.button_key_inactive.atr);
+ waddch(win, label[0]);
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
+ waddstr(win, (char *)label + 1);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
+ waddstr(win, ">");
+ wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+ chtype box, chtype border)
+{
+ int i, j;
+
+ wattrset(win, 0);
+ for (i = 0; i < height; i++) {
+ wmove(win, y + i, x);
+ for (j = 0; j < width; j++)
+ if (!i && !j)
+ waddch(win, border | ACS_ULCORNER);
+ else if (i == height - 1 && !j)
+ waddch(win, border | ACS_LLCORNER);
+ else if (!i && j == width - 1)
+ waddch(win, box | ACS_URCORNER);
+ else if (i == height - 1 && j == width - 1)
+ waddch(win, box | ACS_LRCORNER);
+ else if (!i)
+ waddch(win, border | ACS_HLINE);
+ else if (i == height - 1)
+ waddch(win, box | ACS_HLINE);
+ else if (!j)
+ waddch(win, border | ACS_VLINE);
+ else if (j == width - 1)
+ waddch(win, box | ACS_VLINE);
+ else
+ waddch(win, box | ' ');
+ }
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+ int i;
+
+ if (has_colors()) { /* Whether terminal supports color? */
+ wattrset(win, dlg.shadow.atr);
+ wmove(win, y + height, x + 2);
+ for (i = 0; i < width; i++)
+ waddch(win, winch(win) & A_CHARTEXT);
+ for (i = y + 1; i < y + height + 1; i++) {
+ wmove(win, i, x + width);
+ waddch(win, winch(win) & A_CHARTEXT);
+ waddch(win, winch(win) & A_CHARTEXT);
+ }
+ wnoutrefresh(win);
+ }
+}
+
+/*
+ * Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+ int i, in_paren = 0, c;
+
+ for (i = 0; i < strlen(string); i++) {
+ c = tolower(string[i]);
+
+ if (strchr("<[(", c))
+ ++in_paren;
+ if (strchr(">])", c) && in_paren > 0)
+ --in_paren;
+
+ if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+ return i;
+ }
+
+ return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+ int key;
+ int key2;
+ int key3;
+
+ nodelay(win, TRUE);
+ keypad(win, FALSE);
+ key = wgetch(win);
+ key2 = wgetch(win);
+ do {
+ key3 = wgetch(win);
+ } while (key3 != ERR);
+ nodelay(win, FALSE);
+ keypad(win, TRUE);
+ if (key == KEY_ESC && key2 == ERR)
+ return KEY_ESC;
+ else if (key != ERR && key != KEY_ESC && key2 == ERR)
+ ungetch(key);
+
+ return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+ dialog_clear();
+ return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+ struct dialog_list *p, *next;
+
+ for (p = item_head; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+ item_head = NULL;
+ item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+ va_list ap;
+ struct dialog_list *p = malloc(sizeof(*p));
+
+ if (item_head)
+ item_cur->next = p;
+ else
+ item_head = p;
+ item_cur = p;
+ memset(p, 0, sizeof(*p));
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+ va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+ va_list ap;
+ size_t avail;
+
+ avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+ avail, fmt, ap);
+ item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+ va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+ item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+ item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+ item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+ item_foreach()
+ if (item_is_selected())
+ return 1;
+ return 0;
+}
+
+void *item_data(void)
+{
+ return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+ return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next)
+ n++;
+ return n;
+}
+
+void item_set(int n)
+{
+ int i = 0;
+ item_foreach()
+ if (i++ == n)
+ return;
+}
+
+int item_n(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next) {
+ if (p == item_cur)
+ return n;
+ n++;
+ }
+ return 0;
+}
+
+const char *item_str(void)
+{
+ return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+ return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+ return (item_cur->node.tag == tag);
+}
--- /dev/null
+/*
+ * yesno.c -- implements the yes/no box
+ *
+ * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.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 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+ int x = width / 2 - 10;
+ int y = height - 2;
+
+ print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+ print_button(dialog, gettext(" No "), y, x + 13, selected == 1);
+
+ wmove(dialog, y, x + 1 + 13 * selected);
+ wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+ int i, x, y, key = 0, button = 0;
+ WINDOW *dialog;
+
+do_resize:
+ if (getmaxy(stdscr) < (height + 4))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + 4))
+ return -ERRDISPLAYTOOSMALL;
+
+ /* center dialog box on screen */
+ x = (COLS - width) / 2;
+ y = (LINES - height) / 2;
+
+ draw_shadow(stdscr, y, x, height, width);
+
+ dialog = newwin(height, width, y, x);
+ keypad(dialog, TRUE);
+
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
+ mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+ for (i = 0; i < width - 2; i++)
+ waddch(dialog, ACS_HLINE);
+ wattrset(dialog, dlg.dialog.atr);
+ waddch(dialog, ACS_RTEE);
+
+ print_title(dialog, title, width);
+
+ wattrset(dialog, dlg.dialog.atr);
+ print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+ print_buttons(dialog, height, width, 0);
+
+ while (key != KEY_ESC) {
+ key = wgetch(dialog);
+ switch (key) {
+ case 'Y':
+ case 'y':
+ delwin(dialog);
+ return 0;
+ case 'N':
+ case 'n':
+ delwin(dialog);
+ return 1;
+
+ case TAB:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+ print_buttons(dialog, height, width, button);
+ wrefresh(dialog);
+ break;
+ case ' ':
+ case '\n':
+ delwin(dialog);
+ return button;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
+ break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
+ }
+ }
+
+ delwin(dialog);
+ return key; /* ESC pressed */
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
+ *
+ * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "lxdialog/dialog.h"
+
+static const char mconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"This interface let you select features and parameters for the build.\n"
+"Features can either be built-in, modularized, or ignored. Parameters\n"
+"must be entered in as decimal or hexadecimal numbers or text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+" [ ] can be built in or removed\n"
+" < > can be built in, modularized or removed\n"
+" { } can be built in or modularized (selected by other feature)\n"
+" - - are selected by other feature,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it. You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+" you wish to change or submenu wish to select and press <Enter>.\n"
+" Submenus are designated by \"--->\".\n"
+"\n"
+" Shortcut: Press the option's highlighted letter (hotkey).\n"
+" Pressing a hotkey more than once will sequence\n"
+" through all visible items which use that hotkey.\n"
+"\n"
+" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+" unseen options into view.\n"
+"\n"
+"o To exit a menu use the cursor keys to highlight the <Exit> button\n"
+" and press <ENTER>.\n"
+"\n"
+" Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
+" using those letters. You may press a single <ESC>, but\n"
+" there is a delayed response which you may find annoying.\n"
+"\n"
+" Also, the <TAB> and cursor keys will cycle between <Select>,\n"
+" <Exit> and <Help>.\n"
+"\n"
+"o To get help with an item, use the cursor keys to highlight <Help>\n"
+" and press <ENTER>.\n"
+"\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+"o To toggle the display of hidden options, press <Z>.\n"
+"\n"
+"\n"
+"Radiolists (Choice lists)\n"
+"-----------\n"
+"o Use the cursor keys to select the option you wish to set and press\n"
+" <S> or the <SPACE BAR>.\n"
+"\n"
+" Shortcut: Press the first letter of the option you wish to set then\n"
+" press <S> or <SPACE BAR>.\n"
+"\n"
+"o To see available help for the item, use the cursor keys to highlight\n"
+" <Help> and Press <ENTER>.\n"
+"\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+" Also, the <TAB> and cursor keys will cycle between <Select> and\n"
+" <Help>\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o Enter the requested information and press <ENTER>\n"
+" If you are entering hexadecimal values, it is not necessary to\n"
+" add the '0x' prefix to the entry.\n"
+"\n"
+"o For help, use the <TAB> or cursor keys to highlight the help option\n"
+" and press <ENTER>. You can try <TAB><H> as well.\n"
+"\n"
+"\n"
+"Text Box (Help Window)\n"
+"--------\n"
+"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
+" keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
+" who are familiar with less and lynx.\n"
+"\n"
+"o Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"Menuconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"At the end of the main menu you will find two options. One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a Menuconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting Menuconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use Menuconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, Menuconfig will look rather bad. Menuconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"Menuconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry. I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment. Some distributions\n"
+"export those variables via /etc/profile. Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single menu, rather\n"
+"than the default multimenu hierarchy, run the menuconfig with\n"
+"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make MENUCONFIG_MODE=single_menu menuconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono => selects colors suitable for monochrome displays\n"
+" blackbg => selects a color scheme with black background\n"
+" classic => theme with blue background. The classic look\n"
+" bluetitle => a LCD friendly version of classic. (default)\n"
+"\n"),
+menu_instructions[] = N_(
+ "Arrow keys navigate the menu. "
+ "<Enter> selects submenus --->. "
+ "Highlighted letters are hotkeys. "
+ "Pressing <Y> includes, <N> excludes, <M> modularizes features. "
+ "Press <Esc><Esc> to exit, <?> for Help, </> for Search. "
+ "Legend: [*] built-in [ ] excluded <M> module < > module capable"),
+radiolist_instructions[] = N_(
+ "Use the arrow keys to navigate this window or "
+ "press the hotkey of the item you wish to select "
+ "followed by the <SPACE BAR>. "
+ "Press <?> for additional information about this option."),
+inputbox_instructions_int[] = N_(
+ "Please enter a decimal value. "
+ "Fractions will not be accepted. "
+ "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_hex[] = N_(
+ "Please enter a hexadecimal value. "
+ "Use the <TAB> key to move from the input field to the buttons below it."),
+inputbox_instructions_string[] = N_(
+ "Please enter a string value. "
+ "Use the <TAB> key to move from the input field to the buttons below it."),
+setmod_text[] = N_(
+ "This feature depends on another which has been configured as a module.\n"
+ "As a result, this feature will be built as a module."),
+load_config_text[] = N_(
+ "Enter the name of the configuration file you wish to load. "
+ "Accept the name shown to restore the configuration you "
+ "last retrieved. Leave blank to abort."),
+load_config_help[] = N_(
+ "\n"
+ "For various reasons, one may wish to keep several different\n"
+ "configurations available on a single machine.\n"
+ "\n"
+ "If you have saved a previous configuration in a file other than the\n"
+ "default one, entering its name here will allow you to modify that\n"
+ "configuration.\n"
+ "\n"
+ "If you are uncertain, then you have probably never used alternate\n"
+ "configuration files. You should therefore leave this blank to abort.\n"),
+save_config_text[] = N_(
+ "Enter a filename to which this configuration should be saved "
+ "as an alternate. Leave blank to abort."),
+save_config_help[] = N_(
+ "\n"
+ "For various reasons, one may wish to keep different configurations\n"
+ "available on a single machine.\n"
+ "\n"
+ "Entering a file name here will allow you to later retrieve, modify\n"
+ "and use the current configuration as an alternate to whatever\n"
+ "configuration options you have selected at that time.\n"
+ "\n"
+ "If you are uncertain what all this means then you should probably\n"
+ "leave this blank.\n"),
+search_help[] = N_(
+ "\n"
+ "Search for symbols and display their relations.\n"
+ "Regular expressions are allowed.\n"
+ "Example: search for \"^FOO\"\n"
+ "Result:\n"
+ "-----------------------------------------------------------------\n"
+ "Symbol: FOO [=m]\n"
+ "Prompt: Foo bus is used to drive the bar HW\n"
+ "Defined at drivers/pci/Kconfig:47\n"
+ "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+ "Location:\n"
+ " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+ " -> PCI support (PCI [=y])\n"
+ " -> PCI access mode (<choice> [=y])\n"
+ "Selects: LIBCRC32\n"
+ "Selected by: BAR\n"
+ "-----------------------------------------------------------------\n"
+ "o The line 'Prompt:' shows the text used in the menu structure for\n"
+ " this symbol\n"
+ "o The 'Defined at' line tell at what file / line number the symbol\n"
+ " is defined\n"
+ "o The 'Depends on:' line tell what symbols needs to be defined for\n"
+ " this symbol to be visible in the menu (selectable)\n"
+ "o The 'Location:' lines tell where in the menu structure this symbol\n"
+ " is located\n"
+ " A location followed by a [=y] indicate that this is a selectable\n"
+ " menu item - and current value is displayed inside brackets.\n"
+ "o The 'Selects:' line tell what symbol will be automatically\n"
+ " selected if this symbol is selected (y or m)\n"
+ "o The 'Selected by' line tell what symbol has selected this symbol\n"
+ "\n"
+ "Only relevant lines are shown.\n"
+ "\n\n"
+ "Search examples:\n"
+ "Examples: USB => find all symbols containing USB\n"
+ " ^USB => find all symbols starting with USB\n"
+ " USB$ => find all symbols ending with USB\n"
+ "\n");
+
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+static int show_all_options;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_textbox(const char *title, const char *text, int r, int c);
+static void show_helptext(const char *title, const char *text);
+static void show_help(struct menu *menu);
+
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+ static char menu_backtitle[PATH_MAX+128];
+ int size;
+
+ size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+ "%s - %s", config_filename, rootmenu.prompt->text);
+ if (size >= sizeof(menu_backtitle))
+ menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+ set_dialog_backtitle(menu_backtitle);
+
+ size = snprintf(filename, sizeof(filename), "%s", config_filename);
+ if (size >= sizeof(filename))
+ filename[sizeof(filename)-1] = '\0';
+}
+
+
+static void search_conf(void)
+{
+ struct symbol **sym_arr;
+ struct gstr res;
+ char *dialog_input;
+ int dres;
+again:
+ dialog_clear();
+ dres = dialog_inputbox(_("Search Configuration Parameter"),
+ _("Enter " CONFIG_ " (sub)string to search for "
+ "(with or without \"" CONFIG_ "\")"),
+ 10, 75, "");
+ switch (dres) {
+ case 0:
+ break;
+ case 1:
+ show_helptext(_("Search Configuration"), search_help);
+ goto again;
+ default:
+ return;
+ }
+
+ /* strip the prefix if necessary */
+ dialog_input = dialog_input_result;
+ if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+ dialog_input += strlen(CONFIG_);
+
+ sym_arr = sym_re_search(dialog_input);
+ res = get_relations_str(sym_arr);
+ free(sym_arr);
+ show_textbox(_("Search Results"), str_get(&res), 0, 0);
+ str_free(&res);
+}
+
+static void build_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ int type, tmp, doint = 2;
+ tristate val;
+ char ch;
+ bool visible;
+
+ /*
+ * note: menu_is_visible() has side effect that it will
+ * recalc the value of the symbol.
+ */
+ visible = menu_is_visible(menu);
+ if (show_all_options && !menu_has_prompt(menu))
+ return;
+ else if (!show_all_options && !visible)
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (!sym) {
+ if (prop && menu != current_menu) {
+ const char *prompt = menu_get_prompt(menu);
+ switch (prop->type) {
+ case P_MENU:
+ child_count++;
+ prompt = _(prompt);
+ if (single_menu_mode) {
+ item_make("%s%*c%s",
+ menu->data ? "-->" : "++>",
+ indent + 1, ' ', prompt);
+ } else
+ item_make(" %*c%s --->", indent + 1, ' ', prompt);
+
+ item_set_tag('m');
+ item_set_data(menu);
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ case P_COMMENT:
+ if (prompt) {
+ child_count++;
+ item_make(" %*c*** %s ***", indent + 1, ' ', _(prompt));
+ item_set_tag(':');
+ item_set_data(menu);
+ }
+ break;
+ default:
+ if (prompt) {
+ child_count++;
+ item_make("---%*c%s", indent + 1, ' ', _(prompt));
+ item_set_tag(':');
+ item_set_data(menu);
+ }
+ }
+ } else
+ doint = 0;
+ goto conf_childs;
+ }
+
+ type = sym_get_type(sym);
+ if (sym_is_choice(sym)) {
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ child_count++;
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child) && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ val = sym_get_tristate_value(sym);
+ if (sym_is_changable(sym)) {
+ switch (type) {
+ case S_BOOLEAN:
+ item_make("[%c]", val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+ item_make("<%c>", ch);
+ break;
+ }
+ item_set_tag('t');
+ item_set_data(menu);
+ } else {
+ item_make(" ");
+ item_set_tag(def_menu ? 't' : ':');
+ item_set_data(menu);
+ }
+
+ item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+ if (val == yes) {
+ if (def_menu) {
+ item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
+ item_add_str(" --->");
+ if (def_menu->list) {
+ indent += 2;
+ build_conf(def_menu);
+ indent -= 2;
+ }
+ }
+ return;
+ }
+ } else {
+ if (menu == current_menu) {
+ item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
+ item_set_tag(':');
+ item_set_data(menu);
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ if (sym_is_choice_value(sym) && val == yes) {
+ item_make(" ");
+ item_set_tag(':');
+ item_set_data(menu);
+ } else {
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changable(sym))
+ item_make("[%c]", val == no ? ' ' : '*');
+ else
+ item_make("-%c-", val == no ? ' ' : '*');
+ item_set_tag('t');
+ item_set_data(menu);
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes: ch = '*'; break;
+ case mod: ch = 'M'; break;
+ default: ch = ' '; break;
+ }
+ if (sym_is_changable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make("{%c}", ch);
+ else
+ item_make("<%c>", ch);
+ } else
+ item_make("-%c-", ch);
+ item_set_tag('t');
+ item_set_data(menu);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+ item_make("(%s)", sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : _(" (NEW)"));
+ item_set_tag('s');
+ item_set_data(menu);
+ goto conf_childs;
+ }
+ }
+ item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : _(" (NEW)"));
+ if (menu->prompt->type == P_MENU) {
+ item_add_str(" --->");
+ return;
+ }
+ }
+
+conf_childs:
+ indent += doint;
+ for (child = menu->list; child; child = child->next)
+ build_conf(child);
+ indent -= doint;
+}
+
+static void conf(struct menu *menu)
+{
+ struct menu *submenu;
+ const char *prompt = menu_get_prompt(menu);
+ struct symbol *sym;
+ struct menu *active_menu = NULL;
+ int res;
+ int s_scroll = 0;
+
+ while (1) {
+ item_reset();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+ if (menu == &rootmenu) {
+ item_make("--- ");
+ item_set_tag(':');
+ item_make(_(" Load an Alternate Configuration File"));
+ item_set_tag('L');
+ item_make(_(" Save an Alternate Configuration File"));
+ item_set_tag('S');
+ }
+ dialog_clear();
+ res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
+ _(menu_instructions),
+ active_menu, &s_scroll);
+ if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
+ break;
+ if (!item_activate_selected())
+ continue;
+ if (!item_tag())
+ continue;
+
+ submenu = item_data();
+ active_menu = item_data();
+ if (submenu)
+ sym = submenu->sym;
+ else
+ sym = NULL;
+
+ switch (res) {
+ case 0:
+ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data = (void *) (long) !submenu->data;
+ else
+ conf(submenu);
+ break;
+ case 't':
+ if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
+ conf_choice(submenu);
+ else if (submenu->prompt->type == P_MENU)
+ conf(submenu);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ case 'L':
+ conf_load();
+ break;
+ case 'S':
+ conf_save();
+ break;
+ }
+ break;
+ case 2:
+ if (sym)
+ show_help(submenu);
+ else
+ show_helptext(_("README"), _(mconf_readme));
+ break;
+ case 3:
+ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ show_textbox(NULL, setmod_text, 6, 74);
+ }
+ break;
+ case 4:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 5:
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ case 6:
+ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+ else if (item_is_tag('m'))
+ conf(submenu);
+ break;
+ case 7:
+ search_conf();
+ break;
+ case 8:
+ show_all_options = !show_all_options;
+ break;
+ }
+ }
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+ dialog_clear();
+ dialog_textbox(title, text, r, c);
+}
+
+static void show_helptext(const char *title, const char *text)
+{
+ show_textbox(title, text, 0, 0);
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ help.max_width = getmaxx(stdscr) - 10;
+ menu_get_ext_help(menu, &help);
+
+ show_helptext(_(menu_get_prompt(menu)), str_get(&help));
+ str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+ const char *prompt = _(menu_get_prompt(menu));
+ struct menu *child;
+ struct symbol *active;
+
+ active = sym_get_choice_value(menu->sym);
+ while (1) {
+ int res;
+ int selected;
+ item_reset();
+
+ current_menu = menu;
+ for (child = menu->list; child; child = child->next) {
+ if (!menu_is_visible(child))
+ continue;
+ if (child->sym)
+ item_make("%s", _(menu_get_prompt(child)));
+ else {
+ item_make("*** %s ***", _(menu_get_prompt(child)));
+ item_set_tag(':');
+ }
+ item_set_data(child);
+ if (child->sym == active)
+ item_set_selected(1);
+ if (child->sym == sym_get_choice_value(menu->sym))
+ item_set_tag('X');
+ }
+ dialog_clear();
+ res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
+ _(radiolist_instructions),
+ 15, 70, 6);
+ selected = item_activate_selected();
+ switch (res) {
+ case 0:
+ if (selected) {
+ child = item_data();
+ if (!child->sym)
+ break;
+
+ sym_set_tristate_value(child->sym, yes);
+ }
+ return;
+ case 1:
+ if (selected) {
+ child = item_data();
+ show_help(child);
+ active = child->sym;
+ } else
+ show_help(menu);
+ break;
+ case KEY_ESC:
+ return;
+ case -ERRDISPLAYTOOSMALL:
+ return;
+ }
+ }
+}
+
+static void conf_string(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+
+ while (1) {
+ int res;
+ const char *heading;
+
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+ heading = _(inputbox_instructions_int);
+ break;
+ case S_HEX:
+ heading = _(inputbox_instructions_hex);
+ break;
+ case S_STRING:
+ heading = _(inputbox_instructions_string);
+ break;
+ default:
+ heading = _("Internal mconf error!");
+ }
+ dialog_clear();
+ res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
+ heading, 10, 75,
+ sym_get_string_value(menu->sym));
+ switch (res) {
+ case 0:
+ if (sym_set_string_value(menu->sym, dialog_input_result))
+ return;
+ show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static void conf_load(void)
+{
+
+ while (1) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, load_config_text,
+ 11, 55, filename);
+ switch(res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_read(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ sym_set_change_count(1);
+ return;
+ }
+ show_textbox(NULL, _("File does not exist!"), 5, 38);
+ break;
+ case 1:
+ show_helptext(_("Load Alternate Configuration"), load_config_help);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+static void conf_save(void)
+{
+ while (1) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, save_config_text,
+ 11, 55, filename);
+ switch(res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_write(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ return;
+ }
+ show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
+ break;
+ case 1:
+ show_helptext(_("Save Alternate Configuration"), save_config_help);
+ break;
+ case KEY_ESC:
+ return;
+ }
+ }
+}
+
+int main(int ac, char **av)
+{
+ int saved_x, saved_y;
+ char *mode;
+ int res;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ conf_parse(av[1]);
+ conf_read(NULL);
+
+ mode = getenv("MENUCONFIG_MODE");
+ if (mode) {
+ if (!strcasecmp(mode, "single_menu"))
+ single_menu_mode = 1;
+ }
+
+ initscr();
+
+ getyx(stdscr, saved_y, saved_x);
+ if (init_dialog(NULL)) {
+ fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+ fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+ return 1;
+ }
+
+ set_config_filename(conf_get_configname());
+ do {
+ conf(&rootmenu);
+ dialog_clear();
+ if (conf_get_changed())
+ res = dialog_yesno(NULL,
+ _("Do you wish to save your "
+ "new configuration?\n"
+ "<ESC><ESC> to continue."),
+ 6, 60);
+ else
+ res = -1;
+ } while (res == KEY_ESC);
+ end_dialog(saved_x, saved_y);
+
+ switch (res) {
+ case 0:
+ if (conf_write(filename)) {
+ fprintf(stderr, _("\n\n"
+ "Error while writing of the configuration.\n"
+ "Your configuration changes were NOT saved."
+ "\n\n"));
+ return 1;
+ }
+ case -1:
+ printf(_("\n\n"
+ "*** End of the configuration.\n"
+ "*** Execute 'make' to start the build or try 'make help'."
+ "\n\n"));
+ break;
+ default:
+ fprintf(stderr, _("\n\n"
+ "Your configuration changes were NOT saved."
+ "\n\n"));
+ }
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static const char nohelp_text[] = N_(
+ "There is no help available for this option.\n");
+
+struct menu rootmenu;
+static struct menu **last_entry_ptr;
+
+struct file *file_list;
+struct file *current_file;
+
+void menu_warn(struct menu *menu, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+static void prop_warn(struct property *prop, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+void _menu_init(void)
+{
+ current_entry = current_menu = &rootmenu;
+ last_entry_ptr = &rootmenu.list;
+}
+
+void menu_add_entry(struct symbol *sym)
+{
+ struct menu *menu;
+
+ menu = malloc(sizeof(*menu));
+ memset(menu, 0, sizeof(*menu));
+ menu->sym = sym;
+ menu->parent = current_menu;
+ menu->file = current_file;
+ menu->lineno = zconf_lineno();
+
+ *last_entry_ptr = menu;
+ last_entry_ptr = &menu->next;
+ current_entry = menu;
+ if (sym)
+ menu_add_symbol(P_SYMBOL, sym, NULL);
+}
+
+void menu_end_entry(void)
+{
+}
+
+struct menu *menu_add_menu(void)
+{
+ menu_end_entry();
+ last_entry_ptr = ¤t_entry->list;
+ return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+ last_entry_ptr = ¤t_menu->next;
+ current_menu = current_menu->parent;
+}
+
+static struct expr *menu_check_dep(struct expr *e)
+{
+ if (!e)
+ return e;
+
+ switch (e->type) {
+ case E_NOT:
+ e->left.expr = menu_check_dep(e->left.expr);
+ break;
+ case E_OR:
+ case E_AND:
+ e->left.expr = menu_check_dep(e->left.expr);
+ e->right.expr = menu_check_dep(e->right.expr);
+ break;
+ case E_SYMBOL:
+ /* change 'm' into 'm' && MODULES */
+ if (e->left.sym == &symbol_mod)
+ return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+ break;
+ default:
+ break;
+ }
+ return e;
+}
+
+void menu_add_dep(struct expr *dep)
+{
+ current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
+}
+
+void menu_set_type(int type)
+{
+ struct symbol *sym = current_entry->sym;
+
+ if (sym->type == type)
+ return;
+ if (sym->type == S_UNKNOWN) {
+ sym->type = type;
+ return;
+ }
+ menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
+ sym->name ? sym->name : "<choice>",
+ sym_type_name(sym->type), sym_type_name(type));
+}
+
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
+{
+ struct property *prop = prop_alloc(type, current_entry->sym);
+
+ prop->menu = current_entry;
+ prop->expr = expr;
+ prop->visible.expr = menu_check_dep(dep);
+
+ if (prompt) {
+ if (isspace(*prompt)) {
+ prop_warn(prop, "leading whitespace ignored");
+ while (isspace(*prompt))
+ prompt++;
+ }
+ if (current_entry->prompt && current_entry != &rootmenu)
+ prop_warn(prop, "prompt redefined");
+
+ /* Apply all upper menus' visibilities to actual prompts. */
+ if(type == P_PROMPT) {
+ struct menu *menu = current_entry;
+
+ while ((menu = menu->parent) != NULL) {
+ if (!menu->visibility)
+ continue;
+ prop->visible.expr
+ = expr_alloc_and(prop->visible.expr,
+ menu->visibility);
+ }
+ }
+
+ current_entry->prompt = prop;
+ }
+ prop->text = prompt;
+
+ return prop;
+}
+
+struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
+{
+ return menu_add_prop(type, prompt, NULL, dep);
+}
+
+void menu_add_visibility(struct expr *expr)
+{
+ current_entry->visibility = expr_alloc_and(current_entry->visibility,
+ expr);
+}
+
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
+}
+
+void menu_add_option(int token, char *arg)
+{
+ struct property *prop;
+
+ switch (token) {
+ case T_OPT_MODULES:
+ prop = prop_alloc(P_DEFAULT, modules_sym);
+ prop->expr = expr_alloc_symbol(current_entry->sym);
+ break;
+ case T_OPT_DEFCONFIG_LIST:
+ if (!sym_defconfig_list)
+ sym_defconfig_list = current_entry->sym;
+ else if (sym_defconfig_list != current_entry->sym)
+ zconf_error("trying to redefine defconfig symbol");
+ break;
+ case T_OPT_ENV:
+ prop_add_env(arg);
+ break;
+ }
+}
+
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
+{
+ return sym2->type == S_INT || sym2->type == S_HEX ||
+ (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
+}
+
+static void sym_check_prop(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *sym2;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ switch (prop->type) {
+ case P_DEFAULT:
+ if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+ prop->expr->type != E_SYMBOL)
+ prop_warn(prop,
+ "default for config symbol '%s'"
+ " must be a single symbol", sym->name);
+ if (prop->expr->type != E_SYMBOL)
+ break;
+ sym2 = prop_get_symbol(prop);
+ if (sym->type == S_HEX || sym->type == S_INT) {
+ if (!menu_validate_number(sym, sym2))
+ prop_warn(prop,
+ "'%s': number is invalid",
+ sym->name);
+ }
+ break;
+ case P_SELECT:
+ sym2 = prop_get_symbol(prop);
+ if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
+ prop_warn(prop,
+ "config symbol '%s' uses select, but is "
+ "not boolean or tristate", sym->name);
+ else if (sym2->type != S_UNKNOWN &&
+ sym2->type != S_BOOLEAN &&
+ sym2->type != S_TRISTATE)
+ prop_warn(prop,
+ "'%s' has wrong type. 'select' only "
+ "accept arguments of boolean and "
+ "tristate type", sym2->name);
+ break;
+ case P_RANGE:
+ if (sym->type != S_INT && sym->type != S_HEX)
+ prop_warn(prop, "range is only allowed "
+ "for int or hex symbols");
+ if (!menu_validate_number(sym, prop->expr->left.sym) ||
+ !menu_validate_number(sym, prop->expr->right.sym))
+ prop_warn(prop, "range is invalid");
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+void menu_finalize(struct menu *parent)
+{
+ struct menu *menu, *last_menu;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *parentdep, *basedep, *dep, *dep2, **ep;
+
+ sym = parent->sym;
+ if (parent->list) {
+ if (sym && sym_is_choice(sym)) {
+ if (sym->type == S_UNKNOWN) {
+ /* find the first choice value to find out choice type */
+ current_entry = parent;
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (menu->sym && menu->sym->type != S_UNKNOWN) {
+ menu_set_type(menu->sym->type);
+ break;
+ }
+ }
+ }
+ /* set the type of the remaining choice values */
+ for (menu = parent->list; menu; menu = menu->next) {
+ current_entry = menu;
+ if (menu->sym && menu->sym->type == S_UNKNOWN)
+ menu_set_type(sym->type);
+ }
+ parentdep = expr_alloc_symbol(sym);
+ } else if (parent->prompt)
+ parentdep = parent->prompt->visible.expr;
+ else
+ parentdep = parent->dep;
+
+ for (menu = parent->list; menu; menu = menu->next) {
+ basedep = expr_transform(menu->dep);
+ basedep = expr_alloc_and(expr_copy(parentdep), basedep);
+ basedep = expr_eliminate_dups(basedep);
+ menu->dep = basedep;
+ if (menu->sym)
+ prop = menu->sym->prop;
+ else
+ prop = menu->prompt;
+ for (; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ dep = expr_transform(prop->visible.expr);
+ dep = expr_alloc_and(expr_copy(basedep), dep);
+ dep = expr_eliminate_dups(dep);
+ if (menu->sym && menu->sym->type != S_TRISTATE)
+ dep = expr_trans_bool(dep);
+ prop->visible.expr = dep;
+ if (prop->type == P_SELECT) {
+ struct symbol *es = prop_get_symbol(prop);
+ es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
+ expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
+ }
+ }
+ }
+ for (menu = parent->list; menu; menu = menu->next)
+ menu_finalize(menu);
+ } else if (sym) {
+ basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
+ basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
+ basedep = expr_eliminate_dups(expr_transform(basedep));
+ last_menu = NULL;
+ for (menu = parent->next; menu; menu = menu->next) {
+ dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
+ if (!expr_contains_symbol(dep, sym))
+ break;
+ if (expr_depends_symbol(dep, sym))
+ goto next;
+ dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
+ dep = expr_eliminate_dups(expr_transform(dep));
+ dep2 = expr_copy(basedep);
+ expr_eliminate_eq(&dep, &dep2);
+ expr_free(dep);
+ if (!expr_is_yes(dep2)) {
+ expr_free(dep2);
+ break;
+ }
+ expr_free(dep2);
+ next:
+ menu_finalize(menu);
+ menu->parent = parent;
+ last_menu = menu;
+ }
+ if (last_menu) {
+ parent->list = parent->next;
+ parent->next = last_menu->next;
+ last_menu->next = NULL;
+ }
+
+ sym->dir_dep.expr = parent->dep;
+ }
+ for (menu = parent->list; menu; menu = menu->next) {
+ if (sym && sym_is_choice(sym) &&
+ menu->sym && !sym_is_choice_value(menu->sym)) {
+ current_entry = menu;
+ menu->sym->flags |= SYMBOL_CHOICEVAL;
+ if (!menu->prompt)
+ menu_warn(menu, "choice value must have a prompt");
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_DEFAULT)
+ prop_warn(prop, "defaults for choice "
+ "values not supported");
+ if (prop->menu == menu)
+ continue;
+ if (prop->type == P_PROMPT &&
+ prop->menu->parent->sym != sym)
+ prop_warn(prop, "choice value used outside its choice group");
+ }
+ /* Non-tristate choice values of tristate choices must
+ * depend on the choice being set to Y. The choice
+ * values' dependencies were propagated to their
+ * properties above, so the change here must be re-
+ * propagated.
+ */
+ if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+ basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+ menu->dep = expr_alloc_and(basedep, menu->dep);
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+ prop->visible.expr);
+ }
+ }
+ menu_add_symbol(P_CHOICE, sym, NULL);
+ prop = sym_get_choice_prop(sym);
+ for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
+ ;
+ *ep = expr_alloc_one(E_LIST, NULL);
+ (*ep)->right.sym = menu->sym;
+ }
+ if (menu->list && (!menu->prompt || !menu->prompt->text)) {
+ for (last_menu = menu->list; ; last_menu = last_menu->next) {
+ last_menu->parent = parent;
+ if (!last_menu->next)
+ break;
+ }
+ last_menu->next = menu->next;
+ menu->next = menu->list;
+ menu->list = NULL;
+ }
+ }
+
+ if (sym && !(sym->flags & SYMBOL_WARNED)) {
+ if (sym->type == S_UNKNOWN)
+ menu_warn(parent, "config symbol defined without type");
+
+ if (sym_is_choice(sym) && !parent->prompt)
+ menu_warn(parent, "choice must have a prompt");
+
+ /* Check properties connected to this symbol */
+ sym_check_prop(sym);
+ sym->flags |= SYMBOL_WARNED;
+ }
+
+ if (sym && !sym_is_optional(sym) && parent->prompt) {
+ sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
+ expr_alloc_and(parent->prompt->visible.expr,
+ expr_alloc_symbol(&symbol_mod)));
+ }
+}
+
+bool menu_has_prompt(struct menu *menu)
+{
+ if (!menu->prompt)
+ return false;
+ return true;
+}
+
+bool menu_is_visible(struct menu *menu)
+{
+ struct menu *child;
+ struct symbol *sym;
+ tristate visible;
+
+ if (!menu->prompt)
+ return false;
+
+ if (menu->visibility) {
+ if (expr_calc_value(menu->visibility) == no)
+ return no;
+ }
+
+ sym = menu->sym;
+ if (sym) {
+ sym_calc_value(sym);
+ visible = menu->prompt->visible.tri;
+ } else
+ visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+ if (visible != no)
+ return true;
+
+ if (!sym || sym_get_tristate_value(menu->sym) == no)
+ return false;
+
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child)) {
+ if (sym)
+ sym->flags |= SYMBOL_DEF_USER;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char *menu_get_prompt(struct menu *menu)
+{
+ if (menu->prompt)
+ return menu->prompt->text;
+ else if (menu->sym)
+ return menu->sym->name;
+ return NULL;
+}
+
+struct menu *menu_get_root_menu(struct menu *menu)
+{
+ return &rootmenu;
+}
+
+struct menu *menu_get_parent_menu(struct menu *menu)
+{
+ enum prop_type type;
+
+ for (; menu != &rootmenu; menu = menu->parent) {
+ type = menu->prompt ? menu->prompt->type : 0;
+ if (type == P_MENU)
+ break;
+ }
+ return menu;
+}
+
+bool menu_has_help(struct menu *menu)
+{
+ return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+ if (menu->help)
+ return menu->help;
+ else
+ return "";
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop)
+{
+ int i, j;
+ struct menu *submenu[8], *menu;
+
+ str_printf(r, _("Prompt: %s\n"), _(prop->text));
+ str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
+ prop->menu->lineno);
+ if (!expr_is_yes(prop->visible.expr)) {
+ str_append(r, _(" Depends on: "));
+ expr_gstr_print(prop->visible.expr, r);
+ str_append(r, "\n");
+ }
+ menu = prop->menu->parent;
+ for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
+ submenu[i++] = menu;
+ if (i > 0) {
+ str_printf(r, _(" Location:\n"));
+ for (j = 4; --i >= 0; j += 2) {
+ menu = submenu[i];
+ str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
+ if (menu->sym) {
+ str_printf(r, " (%s [=%s])", menu->sym->name ?
+ menu->sym->name : _("<choice>"),
+ sym_get_string_value(menu->sym));
+ }
+ str_append(r, "\n");
+ }
+ }
+}
+
+void get_symbol_str(struct gstr *r, struct symbol *sym)
+{
+ bool hit;
+ struct property *prop;
+
+ if (sym && sym->name) {
+ str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+ sym_get_string_value(sym));
+ str_printf(r, "Type : %s\n", sym_type_name(sym->type));
+ if (sym->type == S_INT || sym->type == S_HEX) {
+ prop = sym_get_range_prop(sym);
+ if (prop) {
+ str_printf(r, "Range : ");
+ expr_gstr_print(prop->expr, r);
+ str_append(r, "\n");
+ }
+ }
+ }
+ for_all_prompts(sym, prop)
+ get_prompt_str(r, prop);
+ hit = false;
+ for_all_properties(sym, prop, P_SELECT) {
+ if (!hit) {
+ str_append(r, " Selects: ");
+ hit = true;
+ } else
+ str_printf(r, " && ");
+ expr_gstr_print(prop->expr, r);
+ }
+ if (hit)
+ str_append(r, "\n");
+ if (sym->rev_dep.expr) {
+ str_append(r, _(" Selected by: "));
+ expr_gstr_print(sym->rev_dep.expr, r);
+ str_append(r, "\n");
+ }
+ str_append(r, "\n\n");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr)
+{
+ struct symbol *sym;
+ struct gstr res = str_new();
+ int i;
+
+ for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+ get_symbol_str(&res, sym);
+ if (!i)
+ str_append(&res, _("No matches found.\n"));
+ return res;
+}
+
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+ struct symbol *sym = menu->sym;
+
+ if (menu_has_help(menu)) {
+ if (sym->name) {
+ str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+ str_append(help, _(menu_get_help(menu)));
+ str_append(help, "\n");
+ }
+ } else {
+ str_append(help, nohelp_text);
+ }
+ if (sym)
+ get_symbol_str(help, sym);
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#define _GNU_SOURCE
+#include <string.h>
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "nconf.h"
+#include <ctype.h>
+
+static const char nconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"This interface let you select features and parameters for the build.\n"
+"Features can either be built-in, modularized, or ignored. Parameters\n"
+"must be entered in as decimal or hexadecimal numbers or text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+" [ ] can be built in or removed\n"
+" < > can be built in, modularized or removed\n"
+" { } can be built in or modularized (selected by other feature)\n"
+" - - are selected by other feature,\n"
+" XXX cannot be selected. Use Symbol Info to find out why,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it. You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+" you wish to change use <Enter> or <Space>. Goto submenu by \n"
+" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
+" Submenus are designated by \"--->\".\n"
+"\n"
+" Searching: pressing '/' triggers interactive search mode.\n"
+" nconfig performs a case insensitive search for the string\n"
+" in the menu prompts (no regex support).\n"
+" Pressing the up/down keys highlights the previous/next\n"
+" matching item. Backspace removes one character from the\n"
+" match string. Pressing either '/' again or ESC exits\n"
+" search mode. All other keys behave normally.\n"
+"\n"
+" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+" unseen options into view.\n"
+"\n"
+"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
+"\n"
+"o To get help with an item, press <F1>\n"
+" Shortcut: Press <h> or <?>.\n"
+"\n"
+"\n"
+"Radiolists (Choice lists)\n"
+"-----------\n"
+"o Use the cursor keys to select the option you wish to set and press\n"
+" <S> or the <SPACE BAR>.\n"
+"\n"
+" Shortcut: Press the first letter of the option you wish to set then\n"
+" press <S> or <SPACE BAR>.\n"
+"\n"
+"o To see available help for the item, press <F1>\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o Enter the requested information and press <ENTER>\n"
+" If you are entering hexadecimal values, it is not necessary to\n"
+" add the '0x' prefix to the entry.\n"
+"\n"
+"o For help, press <F1>.\n"
+"\n"
+"\n"
+"Text Box (Help Window)\n"
+"--------\n"
+"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
+" keys h,j,k,l function here as do <SPACE BAR> for those\n"
+" who are familiar with less and lynx.\n"
+"\n"
+"o Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"nconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different configurations.\n"
+"\n"
+"At the end of the main menu you will find two options. One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a nconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting nconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use nconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, nconfig will look rather bad. nconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"nconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry. I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment. Some distributions\n"
+"export those variables via /etc/profile. Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the options listed in a single menu, rather\n"
+"than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n"
+"environment variable set to single_menu. Example:\n"
+"\n"
+"make NCONFIG_MODE=single_menu nconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"),
+menu_no_f_instructions[] = N_(
+" You do not have function keys support. Please follow the\n"
+" following instructions:\n"
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options.\n"
+" Press <Esc> or <left-arrow> to go back one menu,\n"
+" <?> or <h> for Help, </> for Search.\n"
+" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
+" <Esc> always leaves the current window.\n"),
+menu_instructions[] = N_(
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options\n"
+" Press <Esc>, <F5> or <left-arrow> to go back one menu,\n"
+" <?>, <F1> or <h> for Help, </> for Search.\n"
+" <1> is interchangeable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
+" <Esc> always leaves the current window\n"),
+radiolist_instructions[] = N_(
+" Use the arrow keys to navigate this window or\n"
+" press the hotkey of the item you wish to select\n"
+" followed by the <SPACE BAR>.\n"
+" Press <?>, <F1> or <h> for additional information about this option.\n"),
+inputbox_instructions_int[] = N_(
+"Please enter a decimal value.\n"
+"Fractions will not be accepted.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_hex[] = N_(
+"Please enter a hexadecimal value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_string[] = N_(
+"Please enter a string value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+setmod_text[] = N_(
+"This feature depends on another which\n"
+"has been configured as a module.\n"
+"As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+"There is no help available for this option.\n"),
+load_config_text[] = N_(
+"Enter the name of the configuration file you wish to load.\n"
+"Accept the name shown to restore the configuration you\n"
+"last retrieved. Leave blank to abort."),
+load_config_help[] = N_(
+"\n"
+"For various reasons, one may wish to keep several different\n"
+"configurations available on a single machine.\n"
+"\n"
+"If you have saved a previous configuration in a file other than the\n"
+"default one, entering its name here will allow you to modify that\n"
+"configuration.\n"
+"\n"
+"If you are uncertain, then you have probably never used alternate\n"
+"configuration files. You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+"Enter a filename to which this configuration should be saved\n"
+"as an alternate. Leave blank to abort."),
+save_config_help[] = N_(
+"\n"
+"For various reasons, one may wish to keep different configurations\n"
+"available on a single machine.\n"
+"\n"
+"Entering a file name here will allow you to later retrieve, modify\n"
+"and use the current configuration as an alternate to whatever\n"
+"configuration options you have selected at that time.\n"
+"\n"
+"If you are uncertain what all this means then you should probably\n"
+"leave this blank.\n"),
+search_help[] = N_(
+"\n"
+"Search for symbols and display their relations. Regular expressions\n"
+"are allowed.\n"
+"Example: search for \"^FOO\"\n"
+"Result:\n"
+"-----------------------------------------------------------------\n"
+"Symbol: FOO [ = m]\n"
+"Prompt: Foo bus is used to drive the bar HW\n"
+"Defined at drivers/pci/Kconfig:47\n"
+"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+"Location:\n"
+" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+" -> PCI support (PCI [ = y])\n"
+" -> PCI access mode (<choice> [ = y])\n"
+"Selects: LIBCRC32\n"
+"Selected by: BAR\n"
+"-----------------------------------------------------------------\n"
+"o The line 'Prompt:' shows the text used in the menu structure for\n"
+" this symbol\n"
+"o The 'Defined at' line tell at what file / line number the symbol\n"
+" is defined\n"
+"o The 'Depends on:' line tell what symbols needs to be defined for\n"
+" this symbol to be visible in the menu (selectable)\n"
+"o The 'Location:' lines tell where in the menu structure this symbol\n"
+" is located\n"
+" A location followed by a [ = y] indicate that this is a selectable\n"
+" menu item - and current value is displayed inside brackets.\n"
+"o The 'Selects:' line tell what symbol will be automatically\n"
+" selected if this symbol is selected (y or m)\n"
+"o The 'Selected by' line tell what symbol has selected this symbol\n"
+"\n"
+"Only relevant lines are shown.\n"
+"\n\n"
+"Search examples:\n"
+"Examples: USB => find all symbols containing USB\n"
+" ^USB => find all symbols starting with USB\n"
+" USB$ => find all symbols ending with USB\n"
+"\n");
+
+struct mitem {
+ char str[256];
+ char tag;
+ void *usrptr;
+ int is_visible;
+};
+
+#define MAX_MENU_ITEMS 4096
+static int show_all_items;
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+/* the window in which all information appears */
+static WINDOW *main_window;
+/* the largest size of the menu window */
+static int mwin_max_lines;
+static int mwin_max_cols;
+/* the window in which we show option buttons */
+static MENU *curses_menu;
+static ITEM *curses_menu_items[MAX_MENU_ITEMS];
+static struct mitem k_menu_items[MAX_MENU_ITEMS];
+static int items_num;
+static int global_exit;
+/* the currently selected button */
+const char *current_instructions = menu_instructions;
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_help(struct menu *menu);
+static int do_exit(void);
+static void setup_windows(void);
+static void search_conf(void);
+
+typedef void (*function_key_handler_t)(int *key, struct menu *menu);
+static void handle_f1(int *key, struct menu *current_item);
+static void handle_f2(int *key, struct menu *current_item);
+static void handle_f3(int *key, struct menu *current_item);
+static void handle_f4(int *key, struct menu *current_item);
+static void handle_f5(int *key, struct menu *current_item);
+static void handle_f6(int *key, struct menu *current_item);
+static void handle_f7(int *key, struct menu *current_item);
+static void handle_f8(int *key, struct menu *current_item);
+static void handle_f9(int *key, struct menu *current_item);
+
+struct function_keys {
+ const char *key_str;
+ const char *func;
+ function_key key;
+ function_key_handler_t handler;
+};
+
+static const int function_keys_num = 9;
+struct function_keys function_keys[] = {
+ {
+ .key_str = "F1",
+ .func = "Help",
+ .key = F_HELP,
+ .handler = handle_f1,
+ },
+ {
+ .key_str = "F2",
+ .func = "Sym Info",
+ .key = F_SYMBOL,
+ .handler = handle_f2,
+ },
+ {
+ .key_str = "F3",
+ .func = "Insts",
+ .key = F_INSTS,
+ .handler = handle_f3,
+ },
+ {
+ .key_str = "F4",
+ .func = "Config",
+ .key = F_CONF,
+ .handler = handle_f4,
+ },
+ {
+ .key_str = "F5",
+ .func = "Back",
+ .key = F_BACK,
+ .handler = handle_f5,
+ },
+ {
+ .key_str = "F6",
+ .func = "Save",
+ .key = F_SAVE,
+ .handler = handle_f6,
+ },
+ {
+ .key_str = "F7",
+ .func = "Load",
+ .key = F_LOAD,
+ .handler = handle_f7,
+ },
+ {
+ .key_str = "F8",
+ .func = "Sym Search",
+ .key = F_SEARCH,
+ .handler = handle_f8,
+ },
+ {
+ .key_str = "F9",
+ .func = "Exit",
+ .key = F_EXIT,
+ .handler = handle_f9,
+ },
+};
+
+static void print_function_line(void)
+{
+ int i;
+ int offset = 1;
+ const int skip = 1;
+
+ for (i = 0; i < function_keys_num; i++) {
+ wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+ mvwprintw(main_window, LINES-3, offset,
+ "%s",
+ function_keys[i].key_str);
+ wattrset(main_window, attributes[FUNCTION_TEXT]);
+ offset += strlen(function_keys[i].key_str);
+ mvwprintw(main_window, LINES-3,
+ offset, "%s",
+ function_keys[i].func);
+ offset += strlen(function_keys[i].func) + skip;
+ }
+ wattrset(main_window, attributes[NORMAL]);
+}
+
+/* help */
+static void handle_f1(int *key, struct menu *current_item)
+{
+ show_scroll_win(main_window,
+ _("README"), _(nconf_readme));
+ return;
+}
+
+/* symbole help */
+static void handle_f2(int *key, struct menu *current_item)
+{
+ show_help(current_item);
+ return;
+}
+
+/* instructions */
+static void handle_f3(int *key, struct menu *current_item)
+{
+ show_scroll_win(main_window,
+ _("Instructions"),
+ _(current_instructions));
+ return;
+}
+
+/* config */
+static void handle_f4(int *key, struct menu *current_item)
+{
+ int res = btn_dialog(main_window,
+ _("Show all symbols?"),
+ 2,
+ " <Show All> ",
+ "<Don't show all>");
+ if (res == 0)
+ show_all_items = 1;
+ else if (res == 1)
+ show_all_items = 0;
+
+ return;
+}
+
+/* back */
+static void handle_f5(int *key, struct menu *current_item)
+{
+ *key = KEY_LEFT;
+ return;
+}
+
+/* save */
+static void handle_f6(int *key, struct menu *current_item)
+{
+ conf_save();
+ return;
+}
+
+/* load */
+static void handle_f7(int *key, struct menu *current_item)
+{
+ conf_load();
+ return;
+}
+
+/* search */
+static void handle_f8(int *key, struct menu *current_item)
+{
+ search_conf();
+ return;
+}
+
+/* exit */
+static void handle_f9(int *key, struct menu *current_item)
+{
+ do_exit();
+ return;
+}
+
+/* return != 0 to indicate the key was handles */
+static int process_special_keys(int *key, struct menu *menu)
+{
+ int i;
+
+ if (*key == KEY_RESIZE) {
+ setup_windows();
+ return 1;
+ }
+
+ for (i = 0; i < function_keys_num; i++) {
+ if (*key == KEY_F(function_keys[i].key) ||
+ *key == '0' + function_keys[i].key){
+ function_keys[i].handler(key, menu);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void clean_items(void)
+{
+ int i;
+ for (i = 0; curses_menu_items[i]; i++)
+ free_item(curses_menu_items[i]);
+ bzero(curses_menu_items, sizeof(curses_menu_items));
+ bzero(k_menu_items, sizeof(k_menu_items));
+ items_num = 0;
+}
+
+typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
+ FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
+
+/* return the index of the matched item, or -1 if no such item exists */
+static int get_mext_match(const char *match_str, match_f flag)
+{
+ int match_start = item_index(current_item(curses_menu));
+ int index;
+
+ if (flag == FIND_NEXT_MATCH_DOWN)
+ ++match_start;
+ else if (flag == FIND_NEXT_MATCH_UP)
+ --match_start;
+
+ index = match_start;
+ index = (index + items_num) % items_num;
+ while (true) {
+ char *str = k_menu_items[index].str;
+ if (strcasestr(str, match_str) != 0)
+ return index;
+ if (flag == FIND_NEXT_MATCH_UP ||
+ flag == MATCH_TINKER_PATTERN_UP)
+ --index;
+ else
+ ++index;
+ index = (index + items_num) % items_num;
+ if (index == match_start)
+ return -1;
+ }
+}
+
+/* Make a new item. */
+static void item_make(struct menu *menu, char tag, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (items_num > MAX_MENU_ITEMS-1)
+ return;
+
+ bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
+ k_menu_items[items_num].tag = tag;
+ k_menu_items[items_num].usrptr = menu;
+ if (menu != NULL)
+ k_menu_items[items_num].is_visible =
+ menu_is_visible(menu);
+ else
+ k_menu_items[items_num].is_visible = 1;
+
+ va_start(ap, fmt);
+ vsnprintf(k_menu_items[items_num].str,
+ sizeof(k_menu_items[items_num].str),
+ fmt, ap);
+ va_end(ap);
+
+ if (!k_menu_items[items_num].is_visible)
+ memcpy(k_menu_items[items_num].str, "XXX", 3);
+
+ curses_menu_items[items_num] = new_item(
+ k_menu_items[items_num].str,
+ k_menu_items[items_num].str);
+ set_item_userptr(curses_menu_items[items_num],
+ &k_menu_items[items_num]);
+ /*
+ if (!k_menu_items[items_num].is_visible)
+ item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
+ */
+
+ items_num++;
+ curses_menu_items[items_num] = NULL;
+}
+
+/* very hackish. adds a string to the last item added */
+static void item_add_str(const char *fmt, ...)
+{
+ va_list ap;
+ int index = items_num-1;
+ char new_str[256];
+ char tmp_str[256];
+
+ if (index < 0)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(new_str, sizeof(new_str), fmt, ap);
+ va_end(ap);
+ snprintf(tmp_str, sizeof(tmp_str), "%s%s",
+ k_menu_items[index].str, new_str);
+ strncpy(k_menu_items[index].str,
+ tmp_str,
+ sizeof(k_menu_items[index].str));
+
+ free_item(curses_menu_items[index]);
+ curses_menu_items[index] = new_item(
+ k_menu_items[index].str,
+ k_menu_items[index].str);
+ set_item_userptr(curses_menu_items[index],
+ &k_menu_items[index]);
+}
+
+/* get the tag of the currently selected item */
+static char item_tag(void)
+{
+ ITEM *cur;
+ struct mitem *mcur;
+
+ cur = current_item(curses_menu);
+ if (cur == NULL)
+ return 0;
+ mcur = (struct mitem *) item_userptr(cur);
+ return mcur->tag;
+}
+
+static int curses_item_index(void)
+{
+ return item_index(current_item(curses_menu));
+}
+
+static void *item_data(void)
+{
+ ITEM *cur;
+ struct mitem *mcur;
+
+ cur = current_item(curses_menu);
+ if (!cur)
+ return NULL;
+ mcur = (struct mitem *) item_userptr(cur);
+ return mcur->usrptr;
+
+}
+
+static int item_is_tag(char tag)
+{
+ return item_tag() == tag;
+}
+
+static char filename[PATH_MAX+1];
+static char menu_backtitle[PATH_MAX+128];
+static const char *set_config_filename(const char *config_filename)
+{
+ int size;
+
+ size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+ "%s - %s", config_filename, rootmenu.prompt->text);
+ if (size >= sizeof(menu_backtitle))
+ menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+
+ size = snprintf(filename, sizeof(filename), "%s", config_filename);
+ if (size >= sizeof(filename))
+ filename[sizeof(filename)-1] = '\0';
+ return menu_backtitle;
+}
+
+/* return = 0 means we are successful.
+ * -1 means go on doing what you were doing
+ */
+static int do_exit(void)
+{
+ int res;
+ if (!conf_get_changed()) {
+ global_exit = 1;
+ return 0;
+ }
+ res = btn_dialog(main_window,
+ _("Do you wish to save your new configuration?\n"
+ "<ESC> to cancel and resume nconfig."),
+ 2,
+ " <save> ",
+ "<don't save>");
+ if (res == KEY_EXIT) {
+ global_exit = 0;
+ return -1;
+ }
+
+ /* if we got here, the user really wants to exit */
+ switch (res) {
+ case 0:
+ res = conf_write(filename);
+ if (res)
+ btn_dialog(
+ main_window,
+ _("Error during writing of configuration.\n"
+ "Your configuration changes were NOT saved."),
+ 1,
+ "<OK>");
+ break;
+ default:
+ btn_dialog(
+ main_window,
+ _("Your configuration changes were NOT saved."),
+ 1,
+ "<OK>");
+ break;
+ }
+ global_exit = 1;
+ return 0;
+}
+
+
+static void search_conf(void)
+{
+ struct symbol **sym_arr;
+ struct gstr res;
+ char dialog_input_result[100];
+ char *dialog_input;
+ int dres;
+again:
+ dres = dialog_inputbox(main_window,
+ _("Search Configuration Parameter"),
+ _("Enter " CONFIG_ " (sub)string to search for "
+ "(with or without \"" CONFIG_ "\")"),
+ "", dialog_input_result, 99);
+ switch (dres) {
+ case 0:
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Search Configuration"), search_help);
+ goto again;
+ default:
+ return;
+ }
+
+ /* strip the prefix if necessary */
+ dialog_input = dialog_input_result;
+ if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+ dialog_input += strlen(CONFIG_);
+
+ sym_arr = sym_re_search(dialog_input);
+ res = get_relations_str(sym_arr);
+ free(sym_arr);
+ show_scroll_win(main_window,
+ _("Search Results"), str_get(&res));
+ str_free(&res);
+}
+
+
+static void build_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ int type, tmp, doint = 2;
+ tristate val;
+ char ch;
+
+ if (!menu || (!show_all_items && !menu_is_visible(menu)))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (!sym) {
+ if (prop && menu != current_menu) {
+ const char *prompt = menu_get_prompt(menu);
+ enum prop_type ptype;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ switch (ptype) {
+ case P_MENU:
+ child_count++;
+ prompt = _(prompt);
+ if (single_menu_mode) {
+ item_make(menu, 'm',
+ "%s%*c%s",
+ menu->data ? "-->" : "++>",
+ indent + 1, ' ', prompt);
+ } else
+ item_make(menu, 'm',
+ " %*c%s --->",
+ indent + 1,
+ ' ', prompt);
+
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ case P_COMMENT:
+ if (prompt) {
+ child_count++;
+ item_make(menu, ':',
+ " %*c*** %s ***",
+ indent + 1, ' ',
+ _(prompt));
+ }
+ break;
+ default:
+ if (prompt) {
+ child_count++;
+ item_make(menu, ':', "---%*c%s",
+ indent + 1, ' ',
+ _(prompt));
+ }
+ }
+ } else
+ doint = 0;
+ goto conf_childs;
+ }
+
+ type = sym_get_type(sym);
+ if (sym_is_choice(sym)) {
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ child_count++;
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child) && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ val = sym_get_tristate_value(sym);
+ if (sym_is_changable(sym)) {
+ switch (type) {
+ case S_BOOLEAN:
+ item_make(menu, 't', "[%c]",
+ val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
+ break;
+ case mod:
+ ch = 'M';
+ break;
+ default:
+ ch = ' ';
+ break;
+ }
+ item_make(menu, 't', "<%c>", ch);
+ break;
+ }
+ } else {
+ item_make(menu, def_menu ? 't' : ':', " ");
+ }
+
+ item_add_str("%*c%s", indent + 1,
+ ' ', _(menu_get_prompt(menu)));
+ if (val == yes) {
+ if (def_menu) {
+ item_add_str(" (%s)",
+ _(menu_get_prompt(def_menu)));
+ item_add_str(" --->");
+ if (def_menu->list) {
+ indent += 2;
+ build_conf(def_menu);
+ indent -= 2;
+ }
+ }
+ return;
+ }
+ } else {
+ if (menu == current_menu) {
+ item_make(menu, ':',
+ "---%*c%s", indent + 1,
+ ' ', _(menu_get_prompt(menu)));
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ if (sym_is_choice_value(sym) && val == yes) {
+ item_make(menu, ':', " ");
+ } else {
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changable(sym))
+ item_make(menu, 't', "[%c]",
+ val == no ? ' ' : '*');
+ else
+ item_make(menu, 't', "-%c-",
+ val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
+ break;
+ case mod:
+ ch = 'M';
+ break;
+ default:
+ ch = ' ';
+ break;
+ }
+ if (sym_is_changable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make(menu,
+ 't', "{%c}", ch);
+ else
+ item_make(menu,
+ 't', "<%c>", ch);
+ } else
+ item_make(menu, 't', "-%c-", ch);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym));
+ item_make(menu, 's', " (%s)",
+ sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ',
+ _(menu_get_prompt(menu)),
+ (sym_has_value(sym) ||
+ !sym_is_changable(sym)) ? "" :
+ _(" (NEW)"));
+ goto conf_childs;
+ }
+ }
+ item_add_str("%*c%s%s", indent + 1, ' ',
+ _(menu_get_prompt(menu)),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : _(" (NEW)"));
+ if (menu->prompt && menu->prompt->type == P_MENU) {
+ item_add_str(" --->");
+ return;
+ }
+ }
+
+conf_childs:
+ indent += doint;
+ for (child = menu->list; child; child = child->next)
+ build_conf(child);
+ indent -= doint;
+}
+
+static void reset_menu(void)
+{
+ unpost_menu(curses_menu);
+ clean_items();
+}
+
+/* adjust the menu to show this item.
+ * prefer not to scroll the menu if possible*/
+static void center_item(int selected_index, int *last_top_row)
+{
+ int toprow;
+
+ set_top_row(curses_menu, *last_top_row);
+ toprow = top_row(curses_menu);
+ if (selected_index < toprow ||
+ selected_index >= toprow+mwin_max_lines) {
+ toprow = max(selected_index-mwin_max_lines/2, 0);
+ if (toprow >= item_count(curses_menu)-mwin_max_lines)
+ toprow = item_count(curses_menu)-mwin_max_lines;
+ set_top_row(curses_menu, toprow);
+ }
+ set_current_item(curses_menu,
+ curses_menu_items[selected_index]);
+ *last_top_row = toprow;
+ post_menu(curses_menu);
+ refresh_all_windows(main_window);
+}
+
+/* this function assumes reset_menu has been called before */
+static void show_menu(const char *prompt, const char *instructions,
+ int selected_index, int *last_top_row)
+{
+ int maxx, maxy;
+ WINDOW *menu_window;
+
+ current_instructions = instructions;
+
+ clear();
+ wattrset(main_window, attributes[NORMAL]);
+ print_in_middle(stdscr, 1, 0, COLS,
+ menu_backtitle,
+ attributes[MAIN_HEADING]);
+
+ wattrset(main_window, attributes[MAIN_MENU_BOX]);
+ box(main_window, 0, 0);
+ wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+ mvwprintw(main_window, 0, 3, " %s ", prompt);
+ wattrset(main_window, attributes[NORMAL]);
+
+ set_menu_items(curses_menu, curses_menu_items);
+
+ /* position the menu at the middle of the screen */
+ scale_menu(curses_menu, &maxy, &maxx);
+ maxx = min(maxx, mwin_max_cols-2);
+ maxy = mwin_max_lines;
+ menu_window = derwin(main_window,
+ maxy,
+ maxx,
+ 2,
+ (mwin_max_cols-maxx)/2);
+ keypad(menu_window, TRUE);
+ set_menu_win(curses_menu, menu_window);
+ set_menu_sub(curses_menu, menu_window);
+
+ /* must reassert this after changing items, otherwise returns to a
+ * default of 16
+ */
+ set_menu_format(curses_menu, maxy, 1);
+ center_item(selected_index, last_top_row);
+ set_menu_format(curses_menu, maxy, 1);
+
+ print_function_line();
+
+ /* Post the menu */
+ post_menu(curses_menu);
+ refresh_all_windows(main_window);
+}
+
+static void adj_match_dir(match_f *match_direction)
+{
+ if (*match_direction == FIND_NEXT_MATCH_DOWN)
+ *match_direction =
+ MATCH_TINKER_PATTERN_DOWN;
+ else if (*match_direction == FIND_NEXT_MATCH_UP)
+ *match_direction =
+ MATCH_TINKER_PATTERN_UP;
+ /* else, do no change.. */
+}
+
+struct match_state
+{
+ int in_search;
+ match_f match_direction;
+ char pattern[256];
+};
+
+/* Return 0 means I have handled the key. In such a case, ans should hold the
+ * item to center, or -1 otherwise.
+ * Else return -1 .
+ */
+static int do_match(int key, struct match_state *state, int *ans)
+{
+ char c = (char) key;
+ int terminate_search = 0;
+ *ans = -1;
+ if (key == '/' || (state->in_search && key == 27)) {
+ move(0, 0);
+ refresh();
+ clrtoeol();
+ state->in_search = 1-state->in_search;
+ bzero(state->pattern, sizeof(state->pattern));
+ state->match_direction = MATCH_TINKER_PATTERN_DOWN;
+ return 0;
+ } else if (!state->in_search)
+ return 1;
+
+ if (isalnum(c) || isgraph(c) || c == ' ') {
+ state->pattern[strlen(state->pattern)] = c;
+ state->pattern[strlen(state->pattern)] = '\0';
+ adj_match_dir(&state->match_direction);
+ *ans = get_mext_match(state->pattern,
+ state->match_direction);
+ } else if (key == KEY_DOWN) {
+ state->match_direction = FIND_NEXT_MATCH_DOWN;
+ *ans = get_mext_match(state->pattern,
+ state->match_direction);
+ } else if (key == KEY_UP) {
+ state->match_direction = FIND_NEXT_MATCH_UP;
+ *ans = get_mext_match(state->pattern,
+ state->match_direction);
+ } else if (key == KEY_BACKSPACE || key == 127) {
+ state->pattern[strlen(state->pattern)-1] = '\0';
+ adj_match_dir(&state->match_direction);
+ } else
+ terminate_search = 1;
+
+ if (terminate_search) {
+ state->in_search = 0;
+ bzero(state->pattern, sizeof(state->pattern));
+ move(0, 0);
+ refresh();
+ clrtoeol();
+ return -1;
+ }
+ return 0;
+}
+
+static void conf(struct menu *menu)
+{
+ struct menu *submenu = 0;
+ const char *prompt = menu_get_prompt(menu);
+ struct symbol *sym;
+ struct menu *active_menu = NULL;
+ int res;
+ int current_index = 0;
+ int last_top_row = 0;
+ struct match_state match_state = {
+ .in_search = 0,
+ .match_direction = MATCH_TINKER_PATTERN_DOWN,
+ .pattern = "",
+ };
+
+ while (!global_exit) {
+ reset_menu();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+
+ show_menu(prompt ? _(prompt) : _("Main Menu"),
+ _(menu_instructions),
+ current_index, &last_top_row);
+ keypad((menu_win(curses_menu)), TRUE);
+ while (!global_exit) {
+ if (match_state.in_search) {
+ mvprintw(0, 0,
+ "searching: %s", match_state.pattern);
+ clrtoeol();
+ }
+ refresh_all_windows(main_window);
+ res = wgetch(menu_win(curses_menu));
+ if (!res)
+ break;
+ if (do_match(res, &match_state, ¤t_index) == 0) {
+ if (current_index != -1)
+ center_item(current_index,
+ &last_top_row);
+ continue;
+ }
+ if (process_special_keys(&res,
+ (struct menu *) item_data()))
+ break;
+ switch (res) {
+ case KEY_DOWN:
+ menu_driver(curses_menu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(curses_menu, REQ_UP_ITEM);
+ break;
+ case KEY_NPAGE:
+ menu_driver(curses_menu, REQ_SCR_DPAGE);
+ break;
+ case KEY_PPAGE:
+ menu_driver(curses_menu, REQ_SCR_UPAGE);
+ break;
+ case KEY_HOME:
+ menu_driver(curses_menu, REQ_FIRST_ITEM);
+ break;
+ case KEY_END:
+ menu_driver(curses_menu, REQ_LAST_ITEM);
+ break;
+ case 'h':
+ case '?':
+ show_help((struct menu *) item_data());
+ break;
+ }
+ if (res == 10 || res == 27 ||
+ res == 32 || res == 'n' || res == 'y' ||
+ res == KEY_LEFT || res == KEY_RIGHT ||
+ res == 'm')
+ break;
+ refresh_all_windows(main_window);
+ }
+
+ refresh_all_windows(main_window);
+ /* if ESC or left*/
+ if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
+ break;
+
+ /* remember location in the menu */
+ last_top_row = top_row(curses_menu);
+ current_index = curses_item_index();
+
+ if (!item_tag())
+ continue;
+
+ submenu = (struct menu *) item_data();
+ active_menu = (struct menu *)item_data();
+ if (!submenu || !menu_is_visible(submenu))
+ continue;
+ if (submenu)
+ sym = submenu->sym;
+ else
+ sym = NULL;
+
+ switch (res) {
+ case ' ':
+ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+ else if (item_is_tag('m'))
+ conf(submenu);
+ break;
+ case KEY_RIGHT:
+ case 10: /* ENTER WAS PRESSED */
+ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data =
+ (void *) (long) !submenu->data;
+ else
+ conf(submenu);
+ break;
+ case 't':
+ if (sym_is_choice(sym) &&
+ sym_get_tristate_value(sym) == yes)
+ conf_choice(submenu);
+ else if (submenu->prompt &&
+ submenu->prompt->type == P_MENU)
+ conf(submenu);
+ else if (res == 10)
+ sym_toggle_tristate_value(sym);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ }
+ break;
+ case 'y':
+ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ btn_dialog(main_window, setmod_text, 0);
+ }
+ break;
+ case 'n':
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 'm':
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ }
+ }
+}
+
+static void conf_message_callback(const char *fmt, va_list ap)
+{
+ char buf[1024];
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ btn_dialog(main_window, buf, 1, "<OK>");
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ if (menu && menu->sym && menu_has_help(menu)) {
+ if (menu->sym->name) {
+ str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
+ str_append(&help, _(menu_get_help(menu)));
+ str_append(&help, "\n");
+ get_symbol_str(&help, menu->sym);
+ } else {
+ str_append(&help, _(menu_get_help(menu)));
+ }
+ } else {
+ str_append(&help, nohelp_text);
+ }
+ show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
+ str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+ const char *prompt = _(menu_get_prompt(menu));
+ struct menu *child = 0;
+ struct symbol *active;
+ int selected_index = 0;
+ int last_top_row = 0;
+ int res, i = 0;
+ struct match_state match_state = {
+ .in_search = 0,
+ .match_direction = MATCH_TINKER_PATTERN_DOWN,
+ .pattern = "",
+ };
+
+ active = sym_get_choice_value(menu->sym);
+ /* this is mostly duplicated from the conf() function. */
+ while (!global_exit) {
+ reset_menu();
+
+ for (i = 0, child = menu->list; child; child = child->next) {
+ if (!show_all_items && !menu_is_visible(child))
+ continue;
+
+ if (child->sym == sym_get_choice_value(menu->sym))
+ item_make(child, ':', "<X> %s",
+ _(menu_get_prompt(child)));
+ else if (child->sym)
+ item_make(child, ':', " %s",
+ _(menu_get_prompt(child)));
+ else
+ item_make(child, ':', "*** %s ***",
+ _(menu_get_prompt(child)));
+
+ if (child->sym == active){
+ last_top_row = top_row(curses_menu);
+ selected_index = i;
+ }
+ i++;
+ }
+ show_menu(prompt ? _(prompt) : _("Choice Menu"),
+ _(radiolist_instructions),
+ selected_index,
+ &last_top_row);
+ while (!global_exit) {
+ if (match_state.in_search) {
+ mvprintw(0, 0, "searching: %s",
+ match_state.pattern);
+ clrtoeol();
+ }
+ refresh_all_windows(main_window);
+ res = wgetch(menu_win(curses_menu));
+ if (!res)
+ break;
+ if (do_match(res, &match_state, &selected_index) == 0) {
+ if (selected_index != -1)
+ center_item(selected_index,
+ &last_top_row);
+ continue;
+ }
+ if (process_special_keys(
+ &res,
+ (struct menu *) item_data()))
+ break;
+ switch (res) {
+ case KEY_DOWN:
+ menu_driver(curses_menu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(curses_menu, REQ_UP_ITEM);
+ break;
+ case KEY_NPAGE:
+ menu_driver(curses_menu, REQ_SCR_DPAGE);
+ break;
+ case KEY_PPAGE:
+ menu_driver(curses_menu, REQ_SCR_UPAGE);
+ break;
+ case KEY_HOME:
+ menu_driver(curses_menu, REQ_FIRST_ITEM);
+ break;
+ case KEY_END:
+ menu_driver(curses_menu, REQ_LAST_ITEM);
+ break;
+ case 'h':
+ case '?':
+ show_help((struct menu *) item_data());
+ break;
+ }
+ if (res == 10 || res == 27 || res == ' ' ||
+ res == KEY_LEFT){
+ break;
+ }
+ refresh_all_windows(main_window);
+ }
+ /* if ESC or left */
+ if (res == 27 || res == KEY_LEFT)
+ break;
+
+ child = item_data();
+ if (!child || !menu_is_visible(child) || !child->sym)
+ continue;
+ switch (res) {
+ case ' ':
+ case 10:
+ case KEY_RIGHT:
+ sym_set_tristate_value(child->sym, yes);
+ return;
+ case 'h':
+ case '?':
+ show_help(child);
+ active = child->sym;
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_string(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+ char dialog_input_result[256];
+
+ while (1) {
+ int res;
+ const char *heading;
+
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+ heading = _(inputbox_instructions_int);
+ break;
+ case S_HEX:
+ heading = _(inputbox_instructions_hex);
+ break;
+ case S_STRING:
+ heading = _(inputbox_instructions_string);
+ break;
+ default:
+ heading = _("Internal nconf error!");
+ }
+ res = dialog_inputbox(main_window,
+ prompt ? _(prompt) : _("Main Menu"),
+ heading,
+ sym_get_string_value(menu->sym),
+ dialog_input_result,
+ sizeof(dialog_input_result));
+ switch (res) {
+ case 0:
+ if (sym_set_string_value(menu->sym,
+ dialog_input_result))
+ return;
+ btn_dialog(main_window,
+ _("You have made an invalid entry."), 0);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_load(void)
+{
+ char dialog_input_result[256];
+ while (1) {
+ int res;
+ res = dialog_inputbox(main_window,
+ NULL, load_config_text,
+ filename,
+ dialog_input_result,
+ sizeof(dialog_input_result));
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_read(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ sym_set_change_count(1);
+ return;
+ }
+ btn_dialog(main_window, _("File does not exist!"), 0);
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Load Alternate Configuration"),
+ load_config_help);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_save(void)
+{
+ char dialog_input_result[256];
+ while (1) {
+ int res;
+ res = dialog_inputbox(main_window,
+ NULL, save_config_text,
+ filename,
+ dialog_input_result,
+ sizeof(dialog_input_result));
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ res = conf_write(dialog_input_result);
+ if (!res) {
+ set_config_filename(dialog_input_result);
+ return;
+ }
+ btn_dialog(main_window, _("Can't create file! "
+ "Probably a nonexistent directory."),
+ 1, "<OK>");
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Save Alternate Configuration"),
+ save_config_help);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+void setup_windows(void)
+{
+ if (main_window != NULL)
+ delwin(main_window);
+
+ /* set up the menu and menu window */
+ main_window = newwin(LINES-2, COLS-2, 2, 1);
+ keypad(main_window, TRUE);
+ mwin_max_lines = LINES-7;
+ mwin_max_cols = COLS-6;
+
+ /* panels order is from bottom to top */
+ new_panel(main_window);
+}
+
+int main(int ac, char **av)
+{
+ char *mode;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ conf_parse(av[1]);
+ conf_read(NULL);
+
+ mode = getenv("NCONFIG_MODE");
+ if (mode) {
+ if (!strcasecmp(mode, "single_menu"))
+ single_menu_mode = 1;
+ }
+
+ /* Initialize curses */
+ initscr();
+ /* set color theme */
+ set_colors();
+
+ cbreak();
+ noecho();
+ keypad(stdscr, TRUE);
+ curs_set(0);
+
+ if (COLS < 75 || LINES < 20) {
+ endwin();
+ printf("Your terminal should have at "
+ "least 20 lines and 75 columns\n");
+ return 1;
+ }
+
+ notimeout(stdscr, FALSE);
+ ESCDELAY = 1;
+
+ /* set btns menu */
+ curses_menu = new_menu(curses_menu_items);
+ menu_opts_off(curses_menu, O_SHOWDESC);
+ menu_opts_on(curses_menu, O_SHOWMATCH);
+ menu_opts_on(curses_menu, O_ONEVALUE);
+ menu_opts_on(curses_menu, O_NONCYCLIC);
+ menu_opts_on(curses_menu, O_IGNORECASE);
+ set_menu_mark(curses_menu, " ");
+ set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
+ set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
+ set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
+
+ set_config_filename(conf_get_configname());
+ setup_windows();
+
+ /* check for KEY_FUNC(1) */
+ if (has_key(KEY_F(1)) == FALSE) {
+ show_scroll_win(main_window,
+ _("Instructions"),
+ _(menu_no_f_instructions));
+ }
+
+ conf_set_message_callback(conf_message_callback);
+ /* do the work */
+ while (!global_exit) {
+ conf(&rootmenu);
+ if (!global_exit && do_exit() == 0)
+ break;
+ }
+ /* ok, we are done */
+ unpost_menu(curses_menu);
+ free_menu(curses_menu);
+ delwin(main_window);
+ clear();
+ refresh();
+ endwin();
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#include "nconf.h"
+
+/* a list of all the different widgets we use */
+attributes_t attributes[ATTR_MAX+1] = {0};
+
+/* available colors:
+ COLOR_BLACK 0
+ COLOR_RED 1
+ COLOR_GREEN 2
+ COLOR_YELLOW 3
+ COLOR_BLUE 4
+ COLOR_MAGENTA 5
+ COLOR_CYAN 6
+ COLOR_WHITE 7
+ */
+static void set_normal_colors(void)
+{
+ init_pair(NORMAL, -1, -1);
+ init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
+
+ /* FORE is for the selected item */
+ init_pair(MAIN_MENU_FORE, -1, -1);
+ /* BACK for all the rest */
+ init_pair(MAIN_MENU_BACK, -1, -1);
+ init_pair(MAIN_MENU_GREY, -1, -1);
+ init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
+ init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
+
+ init_pair(SCROLLWIN_TEXT, -1, -1);
+ init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
+ init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
+
+ init_pair(DIALOG_TEXT, -1, -1);
+ init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
+ init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
+ init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
+
+ init_pair(INPUT_BOX, COLOR_YELLOW, -1);
+ init_pair(INPUT_HEADING, COLOR_GREEN, -1);
+ init_pair(INPUT_TEXT, -1, -1);
+ init_pair(INPUT_FIELD, -1, -1);
+
+ init_pair(FUNCTION_HIGHLIGHT, -1, -1);
+ init_pair(FUNCTION_TEXT, COLOR_BLUE, -1);
+}
+
+/* available attributes:
+ A_NORMAL Normal display (no highlight)
+ A_STANDOUT Best highlighting mode of the terminal.
+ A_UNDERLINE Underlining
+ A_REVERSE Reverse video
+ A_BLINK Blinking
+ A_DIM Half bright
+ A_BOLD Extra bright or bold
+ A_PROTECT Protected mode
+ A_INVIS Invisible or blank mode
+ A_ALTCHARSET Alternate character set
+ A_CHARTEXT Bit-mask to extract a character
+ COLOR_PAIR(n) Color-pair number n
+ */
+static void normal_color_theme(void)
+{
+ /* automatically add color... */
+#define mkattr(name, attr) do { \
+attributes[name] = attr | COLOR_PAIR(name); } while (0)
+ mkattr(NORMAL, NORMAL);
+ mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+ mkattr(MAIN_MENU_FORE, A_REVERSE);
+ mkattr(MAIN_MENU_BACK, A_NORMAL);
+ mkattr(MAIN_MENU_GREY, A_NORMAL);
+ mkattr(MAIN_MENU_HEADING, A_BOLD);
+ mkattr(MAIN_MENU_BOX, A_NORMAL);
+
+ mkattr(SCROLLWIN_TEXT, A_NORMAL);
+ mkattr(SCROLLWIN_HEADING, A_BOLD);
+ mkattr(SCROLLWIN_BOX, A_BOLD);
+
+ mkattr(DIALOG_TEXT, A_BOLD);
+ mkattr(DIALOG_BOX, A_BOLD);
+ mkattr(DIALOG_MENU_FORE, A_STANDOUT);
+ mkattr(DIALOG_MENU_BACK, A_NORMAL);
+
+ mkattr(INPUT_BOX, A_NORMAL);
+ mkattr(INPUT_HEADING, A_BOLD);
+ mkattr(INPUT_TEXT, A_NORMAL);
+ mkattr(INPUT_FIELD, A_UNDERLINE);
+
+ mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
+ mkattr(FUNCTION_TEXT, A_REVERSE);
+}
+
+static void no_colors_theme(void)
+{
+ /* automatically add highlight, no color */
+#define mkattrn(name, attr) { attributes[name] = attr; }
+
+ mkattrn(NORMAL, NORMAL);
+ mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+ mkattrn(MAIN_MENU_FORE, A_STANDOUT);
+ mkattrn(MAIN_MENU_BACK, A_NORMAL);
+ mkattrn(MAIN_MENU_GREY, A_NORMAL);
+ mkattrn(MAIN_MENU_HEADING, A_BOLD);
+ mkattrn(MAIN_MENU_BOX, A_NORMAL);
+
+ mkattrn(SCROLLWIN_TEXT, A_NORMAL);
+ mkattrn(SCROLLWIN_HEADING, A_BOLD);
+ mkattrn(SCROLLWIN_BOX, A_BOLD);
+
+ mkattrn(DIALOG_TEXT, A_NORMAL);
+ mkattrn(DIALOG_BOX, A_BOLD);
+ mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
+ mkattrn(DIALOG_MENU_BACK, A_NORMAL);
+
+ mkattrn(INPUT_BOX, A_BOLD);
+ mkattrn(INPUT_HEADING, A_BOLD);
+ mkattrn(INPUT_TEXT, A_NORMAL);
+ mkattrn(INPUT_FIELD, A_UNDERLINE);
+
+ mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
+ mkattrn(FUNCTION_TEXT, A_REVERSE);
+}
+
+void set_colors()
+{
+ start_color();
+ use_default_colors();
+ set_normal_colors();
+ if (has_colors()) {
+ normal_color_theme();
+ } else {
+ /* give defaults */
+ no_colors_theme();
+ }
+}
+
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+ int starty,
+ int startx,
+ int width,
+ const char *string,
+ chtype color)
+{ int length, x, y;
+ float temp;
+
+
+ if (win == NULL)
+ win = stdscr;
+ getyx(win, y, x);
+ if (startx != 0)
+ x = startx;
+ if (starty != 0)
+ y = starty;
+ if (width == 0)
+ width = 80;
+
+ length = strlen(string);
+ temp = (width - length) / 2;
+ x = startx + (int)temp;
+ (void) wattrset(win, color);
+ mvwprintw(win, y, x, "%s", string);
+ refresh();
+}
+
+int get_line_no(const char *text)
+{
+ int i;
+ int total = 1;
+
+ if (!text)
+ return 0;
+
+ for (i = 0; text[i] != '\0'; i++)
+ if (text[i] == '\n')
+ total++;
+ return total;
+}
+
+const char *get_line(const char *text, int line_no)
+{
+ int i;
+ int lines = 0;
+
+ if (!text)
+ return 0;
+
+ for (i = 0; text[i] != '\0' && lines < line_no; i++)
+ if (text[i] == '\n')
+ lines++;
+ return text+i;
+}
+
+int get_line_length(const char *line)
+{
+ int res = 0;
+ while (*line != '\0' && *line != '\n') {
+ line++;
+ res++;
+ }
+ return res;
+}
+
+/* print all lines to the window. */
+void fill_window(WINDOW *win, const char *text)
+{
+ int x, y;
+ int total_lines = get_line_no(text);
+ int i;
+
+ getmaxyx(win, y, x);
+ /* do not go over end of line */
+ total_lines = min(total_lines, y);
+ for (i = 0; i < total_lines; i++) {
+ char tmp[x+10];
+ const char *line = get_line(text, i);
+ int len = get_line_length(line);
+ strncpy(tmp, line, min(len, x));
+ tmp[len] = '\0';
+ mvwprintw(win, i, 0, "%s", tmp);
+ }
+}
+
+/* get the message, and buttons.
+ * each button must be a char*
+ * return the selected button
+ *
+ * this dialog is used for 2 different things:
+ * 1) show a text box, no buttons.
+ * 2) show a dialog, with horizontal buttons
+ */
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
+{
+ va_list ap;
+ char *btn;
+ int btns_width = 0;
+ int msg_lines = 0;
+ int msg_width = 0;
+ int total_width;
+ int win_rows = 0;
+ WINDOW *win;
+ WINDOW *msg_win;
+ WINDOW *menu_win;
+ MENU *menu;
+ ITEM *btns[btn_num+1];
+ int i, x, y;
+ int res = -1;
+
+
+ va_start(ap, btn_num);
+ for (i = 0; i < btn_num; i++) {
+ btn = va_arg(ap, char *);
+ btns[i] = new_item(btn, "");
+ btns_width += strlen(btn)+1;
+ }
+ va_end(ap);
+ btns[btn_num] = NULL;
+
+ /* find the widest line of msg: */
+ msg_lines = get_line_no(msg);
+ for (i = 0; i < msg_lines; i++) {
+ const char *line = get_line(msg, i);
+ int len = get_line_length(line);
+ if (msg_width < len)
+ msg_width = len;
+ }
+
+ total_width = max(msg_width, btns_width);
+ /* place dialog in middle of screen */
+ y = (LINES-(msg_lines+4))/2;
+ x = (COLS-(total_width+4))/2;
+
+
+ /* create the windows */
+ if (btn_num > 0)
+ win_rows = msg_lines+4;
+ else
+ win_rows = msg_lines+2;
+
+ win = newwin(win_rows, total_width+4, y, x);
+ keypad(win, TRUE);
+ menu_win = derwin(win, 1, btns_width, win_rows-2,
+ 1+(total_width+2-btns_width)/2);
+ menu = new_menu(btns);
+ msg_win = derwin(win, win_rows-2, msg_width, 1,
+ 1+(total_width+2-msg_width)/2);
+
+ set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
+ set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
+
+ (void) wattrset(win, attributes[DIALOG_BOX]);
+ box(win, 0, 0);
+
+ /* print message */
+ (void) wattrset(msg_win, attributes[DIALOG_TEXT]);
+ fill_window(msg_win, msg);
+
+ set_menu_win(menu, win);
+ set_menu_sub(menu, menu_win);
+ set_menu_format(menu, 1, btn_num);
+ menu_opts_off(menu, O_SHOWDESC);
+ menu_opts_off(menu, O_SHOWMATCH);
+ menu_opts_on(menu, O_ONEVALUE);
+ menu_opts_on(menu, O_NONCYCLIC);
+ set_menu_mark(menu, "");
+ post_menu(menu);
+
+
+ touchwin(win);
+ refresh_all_windows(main_window);
+ while ((res = wgetch(win))) {
+ switch (res) {
+ case KEY_LEFT:
+ menu_driver(menu, REQ_LEFT_ITEM);
+ break;
+ case KEY_RIGHT:
+ menu_driver(menu, REQ_RIGHT_ITEM);
+ break;
+ case 10: /* ENTER */
+ case 27: /* ESCAPE */
+ case ' ':
+ case KEY_F(F_BACK):
+ case KEY_F(F_EXIT):
+ break;
+ }
+ touchwin(win);
+ refresh_all_windows(main_window);
+
+ if (res == 10 || res == ' ') {
+ res = item_index(current_item(menu));
+ break;
+ } else if (res == 27 || res == KEY_F(F_BACK) ||
+ res == KEY_F(F_EXIT)) {
+ res = KEY_EXIT;
+ break;
+ }
+ }
+
+ unpost_menu(menu);
+ free_menu(menu);
+ for (i = 0; i < btn_num; i++)
+ free_item(btns[i]);
+
+ delwin(win);
+ return res;
+}
+
+int dialog_inputbox(WINDOW *main_window,
+ const char *title, const char *prompt,
+ const char *init, char *result, int result_len)
+{
+ int prompt_lines = 0;
+ int prompt_width = 0;
+ WINDOW *win;
+ WINDOW *prompt_win;
+ WINDOW *form_win;
+ PANEL *panel;
+ int i, x, y;
+ int res = -1;
+ int cursor_position = strlen(init);
+
+
+ /* find the widest line of msg: */
+ prompt_lines = get_line_no(prompt);
+ for (i = 0; i < prompt_lines; i++) {
+ const char *line = get_line(prompt, i);
+ int len = get_line_length(line);
+ prompt_width = max(prompt_width, len);
+ }
+
+ if (title)
+ prompt_width = max(prompt_width, strlen(title));
+
+ /* place dialog in middle of screen */
+ y = (LINES-(prompt_lines+4))/2;
+ x = (COLS-(prompt_width+4))/2;
+
+ strncpy(result, init, result_len);
+
+ /* create the windows */
+ win = newwin(prompt_lines+6, prompt_width+7, y, x);
+ prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
+ form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
+ keypad(form_win, TRUE);
+
+ (void) wattrset(form_win, attributes[INPUT_FIELD]);
+
+ (void) wattrset(win, attributes[INPUT_BOX]);
+ box(win, 0, 0);
+ (void) wattrset(win, attributes[INPUT_HEADING]);
+ if (title)
+ mvwprintw(win, 0, 3, "%s", title);
+
+ /* print message */
+ (void) wattrset(prompt_win, attributes[INPUT_TEXT]);
+ fill_window(prompt_win, prompt);
+
+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+ mvwprintw(form_win, 0, 0, "%s", result);
+
+ /* create panels */
+ panel = new_panel(win);
+
+ /* show the cursor */
+ curs_set(1);
+
+ touchwin(win);
+ refresh_all_windows(main_window);
+ while ((res = wgetch(form_win))) {
+ int len = strlen(result);
+ switch (res) {
+ case 10: /* ENTER */
+ case 27: /* ESCAPE */
+ case KEY_F(F_HELP):
+ case KEY_F(F_EXIT):
+ case KEY_F(F_BACK):
+ break;
+ case 127:
+ case KEY_BACKSPACE:
+ if (cursor_position > 0) {
+ memmove(&result[cursor_position-1],
+ &result[cursor_position],
+ len-cursor_position+1);
+ cursor_position--;
+ }
+ break;
+ case KEY_DC:
+ if (cursor_position >= 0 && cursor_position < len) {
+ memmove(&result[cursor_position],
+ &result[cursor_position+1],
+ len-cursor_position+1);
+ }
+ break;
+ case KEY_UP:
+ case KEY_RIGHT:
+ if (cursor_position < len &&
+ cursor_position < min(result_len, prompt_width))
+ cursor_position++;
+ break;
+ case KEY_DOWN:
+ case KEY_LEFT:
+ if (cursor_position > 0)
+ cursor_position--;
+ break;
+ default:
+ if ((isgraph(res) || isspace(res)) &&
+ len-2 < result_len) {
+ /* insert the char at the proper position */
+ memmove(&result[cursor_position+1],
+ &result[cursor_position],
+ len+1);
+ result[cursor_position] = res;
+ cursor_position++;
+ } else {
+ mvprintw(0, 0, "unknow key: %d\n", res);
+ }
+ break;
+ }
+ wmove(form_win, 0, 0);
+ wclrtoeol(form_win);
+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+ mvwprintw(form_win, 0, 0, "%s", result);
+ wmove(form_win, 0, cursor_position);
+ touchwin(win);
+ refresh_all_windows(main_window);
+
+ if (res == 10) {
+ res = 0;
+ break;
+ } else if (res == 27 || res == KEY_F(F_BACK) ||
+ res == KEY_F(F_EXIT)) {
+ res = KEY_EXIT;
+ break;
+ } else if (res == KEY_F(F_HELP)) {
+ res = 1;
+ break;
+ }
+ }
+
+ /* hide the cursor */
+ curs_set(0);
+ del_panel(panel);
+ delwin(prompt_win);
+ delwin(form_win);
+ delwin(win);
+ return res;
+}
+
+/* refresh all windows in the correct order */
+void refresh_all_windows(WINDOW *main_window)
+{
+ update_panels();
+ touchwin(main_window);
+ refresh();
+}
+
+/* layman's scrollable window... */
+void show_scroll_win(WINDOW *main_window,
+ const char *title,
+ const char *text)
+{
+ int res;
+ int total_lines = get_line_no(text);
+ int x, y;
+ int start_x = 0, start_y = 0;
+ int text_lines = 0, text_cols = 0;
+ int total_cols = 0;
+ int win_cols = 0;
+ int win_lines = 0;
+ int i = 0;
+ WINDOW *win;
+ WINDOW *pad;
+ PANEL *panel;
+
+ /* find the widest line of msg: */
+ total_lines = get_line_no(text);
+ for (i = 0; i < total_lines; i++) {
+ const char *line = get_line(text, i);
+ int len = get_line_length(line);
+ total_cols = max(total_cols, len+2);
+ }
+
+ /* create the pad */
+ pad = newpad(total_lines+10, total_cols+10);
+ (void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
+ fill_window(pad, text);
+
+ win_lines = min(total_lines+4, LINES-2);
+ win_cols = min(total_cols+2, COLS-2);
+ text_lines = max(win_lines-4, 0);
+ text_cols = max(win_cols-2, 0);
+
+ /* place window in middle of screen */
+ y = (LINES-win_lines)/2;
+ x = (COLS-win_cols)/2;
+
+ win = newwin(win_lines, win_cols, y, x);
+ keypad(win, TRUE);
+ /* show the help in the help window, and show the help panel */
+ (void) wattrset(win, attributes[SCROLLWIN_BOX]);
+ box(win, 0, 0);
+ (void) wattrset(win, attributes[SCROLLWIN_HEADING]);
+ mvwprintw(win, 0, 3, " %s ", title);
+ panel = new_panel(win);
+
+ /* handle scrolling */
+ do {
+
+ copywin(pad, win, start_y, start_x, 2, 2, text_lines,
+ text_cols, 0);
+ print_in_middle(win,
+ text_lines+2,
+ 0,
+ text_cols,
+ "<OK>",
+ attributes[DIALOG_MENU_FORE]);
+ wrefresh(win);
+
+ res = wgetch(win);
+ switch (res) {
+ case KEY_NPAGE:
+ case ' ':
+ start_y += text_lines-2;
+ break;
+ case KEY_PPAGE:
+ start_y -= text_lines+2;
+ break;
+ case KEY_HOME:
+ start_y = 0;
+ break;
+ case KEY_END:
+ start_y = total_lines-text_lines;
+ break;
+ case KEY_DOWN:
+ case 'j':
+ start_y++;
+ break;
+ case KEY_UP:
+ case 'k':
+ start_y--;
+ break;
+ case KEY_LEFT:
+ case 'h':
+ start_x--;
+ break;
+ case KEY_RIGHT:
+ case 'l':
+ start_x++;
+ break;
+ }
+ if (res == 10 || res == 27 || res == 'q'
+ || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) {
+ break;
+ }
+ if (start_y < 0)
+ start_y = 0;
+ if (start_y >= total_lines-text_lines)
+ start_y = total_lines-text_lines;
+ if (start_x < 0)
+ start_x = 0;
+ if (start_x >= total_cols-text_cols)
+ start_x = total_cols-text_cols;
+ } while (res);
+
+ del_panel(panel);
+ delwin(win);
+ refresh_all_windows(main_window);
+}
--- /dev/null
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <curses.h>
+#include <menu.h>
+#include <panel.h>
+#include <form.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "ncurses.h"
+
+#define max(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a > _b ? _a : _b; })
+
+#define min(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a < _b ? _a : _b; })
+
+typedef enum {
+ NORMAL = 1,
+ MAIN_HEADING,
+ MAIN_MENU_BOX,
+ MAIN_MENU_FORE,
+ MAIN_MENU_BACK,
+ MAIN_MENU_GREY,
+ MAIN_MENU_HEADING,
+ SCROLLWIN_TEXT,
+ SCROLLWIN_HEADING,
+ SCROLLWIN_BOX,
+ DIALOG_TEXT,
+ DIALOG_MENU_FORE,
+ DIALOG_MENU_BACK,
+ DIALOG_BOX,
+ INPUT_BOX,
+ INPUT_HEADING,
+ INPUT_TEXT,
+ INPUT_FIELD,
+ FUNCTION_TEXT,
+ FUNCTION_HIGHLIGHT,
+ ATTR_MAX
+} attributes_t;
+extern attributes_t attributes[];
+
+typedef enum {
+ F_HELP = 1,
+ F_SYMBOL = 2,
+ F_INSTS = 3,
+ F_CONF = 4,
+ F_BACK = 5,
+ F_SAVE = 6,
+ F_LOAD = 7,
+ F_SEARCH = 8,
+ F_EXIT = 9,
+} function_key;
+
+void set_colors(void);
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+ int starty,
+ int startx,
+ int width,
+ const char *string,
+ chtype color);
+int get_line_length(const char *line);
+int get_line_no(const char *text);
+const char *get_line(const char *text, int line_no);
+void fill_window(WINDOW *win, const char *text);
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
+int dialog_inputbox(WINDOW *main_window,
+ const char *title, const char *prompt,
+ const char *init, char *result, int result_len);
+void refresh_all_windows(WINDOW *main_window);
+void show_scroll_win(WINDOW *main_window,
+ const char *title,
+ const char *text);
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <qglobal.h>
+
+#if QT_VERSION < 0x040000
+#include <qmainwindow.h>
+#include <qvbox.h>
+#include <qvaluelist.h>
+#include <qtextbrowser.h>
+#include <qaction.h>
+#include <qheader.h>
+#include <qfiledialog.h>
+#include <qdragobject.h>
+#include <qpopupmenu.h>
+#else
+#include <q3mainwindow.h>
+#include <q3vbox.h>
+#include <q3valuelist.h>
+#include <q3textbrowser.h>
+#include <q3action.h>
+#include <q3header.h>
+#include <q3filedialog.h>
+#include <q3dragobject.h>
+#include <q3popupmenu.h>
+#endif
+
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qtoolbar.h>
+#include <qlayout.h>
+#include <qsplitter.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qmenubar.h>
+#include <qmessagebox.h>
+#include <qregexp.h>
+#include <qevent.h>
+
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "qconf.h"
+
+#include "qconf.moc"
+#include "images.c"
+
+#ifdef _
+# undef _
+# define _ qgettext
+#endif
+
+static QApplication *configApp;
+static ConfigSettings *configSettings;
+
+Q3Action *ConfigMainWindow::saveAction;
+
+static inline QString qgettext(const char* str)
+{
+ return QString::fromLocal8Bit(gettext(str));
+}
+
+static inline QString qgettext(const QString& str)
+{
+ return QString::fromLocal8Bit(gettext(str.latin1()));
+}
+
+/**
+ * Reads a list of integer values from the application settings.
+ */
+Q3ValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+{
+ Q3ValueList<int> result;
+ QStringList entryList = readListEntry(key, ok);
+ QStringList::Iterator it;
+
+ for (it = entryList.begin(); it != entryList.end(); ++it)
+ result.push_back((*it).toInt());
+
+ return result;
+}
+
+/**
+ * Writes a list of integer values to the application settings.
+ */
+bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList<int>& value)
+{
+ QStringList stringList;
+ Q3ValueList<int>::ConstIterator it;
+
+ for (it = value.begin(); it != value.end(); ++it)
+ stringList.push_back(QString::number(*it));
+ return writeEntry(key, stringList);
+}
+
+
+/*
+ * set the new data
+ * TODO check the value
+ */
+void ConfigItem::okRename(int col)
+{
+ Parent::okRename(col);
+ sym_set_string_value(menu->sym, text(dataColIdx).latin1());
+ listView()->updateList(this);
+}
+
+/*
+ * update the displayed of a menu entry
+ */
+void ConfigItem::updateMenu(void)
+{
+ ConfigList* list;
+ struct symbol* sym;
+ struct property *prop;
+ QString prompt;
+ int type;
+ tristate expr;
+
+ list = listView();
+ if (goParent) {
+ setPixmap(promptColIdx, list->menuBackPix);
+ prompt = "..";
+ goto set_prompt;
+ }
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ prompt = _(menu_get_prompt(menu));
+
+ if (prop) switch (prop->type) {
+ case P_MENU:
+ if (list->mode == singleMode || list->mode == symbolMode) {
+ /* a menuconfig entry is displayed differently
+ * depending whether it's at the view root or a child.
+ */
+ if (sym && list->rootEntry == menu)
+ break;
+ setPixmap(promptColIdx, list->menuPix);
+ } else {
+ if (sym)
+ break;
+ setPixmap(promptColIdx, 0);
+ }
+ goto set_prompt;
+ case P_COMMENT:
+ setPixmap(promptColIdx, 0);
+ goto set_prompt;
+ default:
+ ;
+ }
+ if (!sym)
+ goto set_prompt;
+
+ setText(nameColIdx, QString::fromLocal8Bit(sym->name));
+
+ type = sym_get_type(sym);
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ char ch;
+
+ if (!sym_is_changable(sym) && list->optMode == normalOpt) {
+ setPixmap(promptColIdx, 0);
+ setText(noColIdx, QString::null);
+ setText(modColIdx, QString::null);
+ setText(yesColIdx, QString::null);
+ break;
+ }
+ expr = sym_get_tristate_value(sym);
+ switch (expr) {
+ case yes:
+ if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+ setPixmap(promptColIdx, list->choiceYesPix);
+ else
+ setPixmap(promptColIdx, list->symbolYesPix);
+ setText(yesColIdx, "Y");
+ ch = 'Y';
+ break;
+ case mod:
+ setPixmap(promptColIdx, list->symbolModPix);
+ setText(modColIdx, "M");
+ ch = 'M';
+ break;
+ default:
+ if (sym_is_choice_value(sym) && type == S_BOOLEAN)
+ setPixmap(promptColIdx, list->choiceNoPix);
+ else
+ setPixmap(promptColIdx, list->symbolNoPix);
+ setText(noColIdx, "N");
+ ch = 'N';
+ break;
+ }
+ if (expr != no)
+ setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
+ if (expr != mod)
+ setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
+ if (expr != yes)
+ setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
+
+ setText(dataColIdx, QChar(ch));
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ const char* data;
+
+ data = sym_get_string_value(sym);
+
+ int i = list->mapIdx(dataColIdx);
+ if (i >= 0)
+ setRenameEnabled(i, TRUE);
+ setText(dataColIdx, data);
+ if (type == S_STRING)
+ prompt = QString("%1: %2").arg(prompt).arg(data);
+ else
+ prompt = QString("(%2) %1").arg(prompt).arg(data);
+ break;
+ }
+ if (!sym_has_value(sym) && visible)
+ prompt += _(" (NEW)");
+set_prompt:
+ setText(promptColIdx, prompt);
+}
+
+void ConfigItem::testUpdateMenu(bool v)
+{
+ ConfigItem* i;
+
+ visible = v;
+ if (!menu)
+ return;
+
+ sym_calc_value(menu->sym);
+ if (menu->flags & MENU_CHANGED) {
+ /* the menu entry changed, so update all list items */
+ menu->flags &= ~MENU_CHANGED;
+ for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
+ i->updateMenu();
+ } else if (listView()->updateAll)
+ updateMenu();
+}
+
+void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
+{
+ ConfigList* list = listView();
+
+ if (visible) {
+ if (isSelected() && !list->hasFocus() && list->mode == menuMode)
+ Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
+ else
+ Parent::paintCell(p, cg, column, width, align);
+ } else
+ Parent::paintCell(p, list->disabledColorGroup, column, width, align);
+}
+
+/*
+ * construct a menu entry
+ */
+void ConfigItem::init(void)
+{
+ if (menu) {
+ ConfigList* list = listView();
+ nextItem = (ConfigItem*)menu->data;
+ menu->data = this;
+
+ if (list->mode != fullMode)
+ setOpen(TRUE);
+ sym_calc_value(menu->sym);
+ }
+ updateMenu();
+}
+
+/*
+ * destruct a menu entry
+ */
+ConfigItem::~ConfigItem(void)
+{
+ if (menu) {
+ ConfigItem** ip = (ConfigItem**)&menu->data;
+ for (; *ip; ip = &(*ip)->nextItem) {
+ if (*ip == this) {
+ *ip = nextItem;
+ break;
+ }
+ }
+ }
+}
+
+ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
+ : Parent(parent)
+{
+ connect(this, SIGNAL(lostFocus()), SLOT(hide()));
+}
+
+void ConfigLineEdit::show(ConfigItem* i)
+{
+ item = i;
+ if (sym_get_string_value(item->menu->sym))
+ setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
+ else
+ setText(QString::null);
+ Parent::show();
+ setFocus();
+}
+
+void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
+{
+ switch (e->key()) {
+ case Qt::Key_Escape:
+ break;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ sym_set_string_value(item->menu->sym, text().latin1());
+ parent()->updateList(item);
+ break;
+ default:
+ Parent::keyPressEvent(e);
+ return;
+ }
+ e->accept();
+ parent()->list->setFocus();
+ hide();
+}
+
+ConfigList::ConfigList(ConfigView* p, const char *name)
+ : Parent(p, name),
+ updateAll(false),
+ symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
+ choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
+ menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
+ showName(false), showRange(false), showData(false), optMode(normalOpt),
+ rootEntry(0), headerPopup(0)
+{
+ int i;
+
+ setSorting(-1);
+ setRootIsDecorated(TRUE);
+ disabledColorGroup = palette().active();
+ disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
+ inactivedColorGroup = palette().active();
+ inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
+
+ connect(this, SIGNAL(selectionChanged(void)),
+ SLOT(updateSelection(void)));
+
+ if (name) {
+ configSettings->beginGroup(name);
+ showName = configSettings->readBoolEntry("/showName", false);
+ showRange = configSettings->readBoolEntry("/showRange", false);
+ showData = configSettings->readBoolEntry("/showData", false);
+ optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
+ configSettings->endGroup();
+ connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+ }
+
+ for (i = 0; i < colNr; i++)
+ colMap[i] = colRevMap[i] = -1;
+ addColumn(promptColIdx, _("Option"));
+
+ reinit();
+}
+
+bool ConfigList::menuSkip(struct menu *menu)
+{
+ if (optMode == normalOpt && menu_is_visible(menu))
+ return false;
+ if (optMode == promptOpt && menu_has_prompt(menu))
+ return false;
+ if (optMode == allOpt)
+ return false;
+ return true;
+}
+
+void ConfigList::reinit(void)
+{
+ removeColumn(dataColIdx);
+ removeColumn(yesColIdx);
+ removeColumn(modColIdx);
+ removeColumn(noColIdx);
+ removeColumn(nameColIdx);
+
+ if (showName)
+ addColumn(nameColIdx, _("Name"));
+ if (showRange) {
+ addColumn(noColIdx, "N");
+ addColumn(modColIdx, "M");
+ addColumn(yesColIdx, "Y");
+ }
+ if (showData)
+ addColumn(dataColIdx, _("Value"));
+
+ updateListAll();
+}
+
+void ConfigList::saveSettings(void)
+{
+ if (name()) {
+ configSettings->beginGroup(name());
+ configSettings->writeEntry("/showName", showName);
+ configSettings->writeEntry("/showRange", showRange);
+ configSettings->writeEntry("/showData", showData);
+ configSettings->writeEntry("/optionMode", (int)optMode);
+ configSettings->endGroup();
+ }
+}
+
+ConfigItem* ConfigList::findConfigItem(struct menu *menu)
+{
+ ConfigItem* item = (ConfigItem*)menu->data;
+
+ for (; item; item = item->nextItem) {
+ if (this == item->listView())
+ break;
+ }
+
+ return item;
+}
+
+void ConfigList::updateSelection(void)
+{
+ struct menu *menu;
+ enum prop_type type;
+
+ ConfigItem* item = (ConfigItem*)selectedItem();
+ if (!item)
+ return;
+
+ menu = item->menu;
+ emit menuChanged(menu);
+ if (!menu)
+ return;
+ type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (mode == menuMode && type == P_MENU)
+ emit menuSelected(menu);
+}
+
+void ConfigList::updateList(ConfigItem* item)
+{
+ ConfigItem* last = 0;
+
+ if (!rootEntry) {
+ if (mode != listMode)
+ goto update;
+ Q3ListViewItemIterator it(this);
+ ConfigItem* item;
+
+ for (; it.current(); ++it) {
+ item = (ConfigItem*)it.current();
+ if (!item->menu)
+ continue;
+ item->testUpdateMenu(menu_is_visible(item->menu));
+ }
+ return;
+ }
+
+ if (rootEntry != &rootmenu && (mode == singleMode ||
+ (mode == symbolMode && rootEntry->parent != &rootmenu))) {
+ item = firstChild();
+ if (!item)
+ item = new ConfigItem(this, 0, true);
+ last = item;
+ }
+ if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
+ rootEntry->sym && rootEntry->prompt) {
+ item = last ? last->nextSibling() : firstChild();
+ if (!item)
+ item = new ConfigItem(this, last, rootEntry, true);
+ else
+ item->testUpdateMenu(true);
+
+ updateMenuList(item, rootEntry);
+ triggerUpdate();
+ return;
+ }
+update:
+ updateMenuList(this, rootEntry);
+ triggerUpdate();
+}
+
+void ConfigList::setValue(ConfigItem* item, tristate val)
+{
+ struct symbol* sym;
+ int type;
+ tristate oldval;
+
+ sym = item->menu ? item->menu->sym : 0;
+ if (!sym)
+ return;
+
+ type = sym_get_type(sym);
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ oldval = sym_get_tristate_value(sym);
+
+ if (!sym_set_tristate_value(sym, val))
+ return;
+ if (oldval == no && item->menu->list)
+ item->setOpen(TRUE);
+ parent()->updateList(item);
+ break;
+ }
+}
+
+void ConfigList::changeValue(ConfigItem* item)
+{
+ struct symbol* sym;
+ struct menu* menu;
+ int type, oldexpr, newexpr;
+
+ menu = item->menu;
+ if (!menu)
+ return;
+ sym = menu->sym;
+ if (!sym) {
+ if (item->menu->list)
+ item->setOpen(!item->isOpen());
+ return;
+ }
+
+ type = sym_get_type(sym);
+ switch (type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ oldexpr = sym_get_tristate_value(sym);
+ newexpr = sym_toggle_tristate_value(sym);
+ if (item->menu->list) {
+ if (oldexpr == newexpr)
+ item->setOpen(!item->isOpen());
+ else if (oldexpr == no)
+ item->setOpen(TRUE);
+ }
+ if (oldexpr != newexpr)
+ parent()->updateList(item);
+ break;
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ if (colMap[dataColIdx] >= 0)
+ item->startRename(colMap[dataColIdx]);
+ else
+ parent()->lineEdit->show(item);
+ break;
+ }
+}
+
+void ConfigList::setRootMenu(struct menu *menu)
+{
+ enum prop_type type;
+
+ if (rootEntry == menu)
+ return;
+ type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (type != P_MENU)
+ return;
+ updateMenuList(this, 0);
+ rootEntry = menu;
+ updateListAll();
+ setSelected(currentItem(), hasFocus());
+ ensureItemVisible(currentItem());
+}
+
+void ConfigList::setParentMenu(void)
+{
+ ConfigItem* item;
+ struct menu *oldroot;
+
+ oldroot = rootEntry;
+ if (rootEntry == &rootmenu)
+ return;
+ setRootMenu(menu_get_parent_menu(rootEntry->parent));
+
+ Q3ListViewItemIterator it(this);
+ for (; (item = (ConfigItem*)it.current()); it++) {
+ if (item->menu == oldroot) {
+ setCurrentItem(item);
+ ensureItemVisible(item);
+ break;
+ }
+ }
+}
+
+/*
+ * update all the children of a menu entry
+ * removes/adds the entries from the parent widget as necessary
+ *
+ * parent: either the menu list widget or a menu entry widget
+ * menu: entry to be updated
+ */
+template <class P>
+void ConfigList::updateMenuList(P* parent, struct menu* menu)
+{
+ struct menu* child;
+ ConfigItem* item;
+ ConfigItem* last;
+ bool visible;
+ enum prop_type type;
+
+ if (!menu) {
+ while ((item = parent->firstChild()))
+ delete item;
+ return;
+ }
+
+ last = parent->firstChild();
+ if (last && !last->goParent)
+ last = 0;
+ for (child = menu->list; child; child = child->next) {
+ item = last ? last->nextSibling() : parent->firstChild();
+ type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+ switch (mode) {
+ case menuMode:
+ if (!(child->flags & MENU_ROOT))
+ goto hide;
+ break;
+ case symbolMode:
+ if (child->flags & MENU_ROOT)
+ goto hide;
+ break;
+ default:
+ break;
+ }
+
+ visible = menu_is_visible(child);
+ if (!menuSkip(child)) {
+ if (!child->sym && !child->list && !child->prompt)
+ continue;
+ if (!item || item->menu != child)
+ item = new ConfigItem(parent, last, child, visible);
+ else
+ item->testUpdateMenu(visible);
+
+ if (mode == fullMode || mode == menuMode || type != P_MENU)
+ updateMenuList(item, child);
+ else
+ updateMenuList(item, 0);
+ last = item;
+ continue;
+ }
+ hide:
+ if (item && item->menu == child) {
+ last = parent->firstChild();
+ if (last == item)
+ last = 0;
+ else while (last->nextSibling() != item)
+ last = last->nextSibling();
+ delete item;
+ }
+ }
+}
+
+void ConfigList::keyPressEvent(QKeyEvent* ev)
+{
+ Q3ListViewItem* i = currentItem();
+ ConfigItem* item;
+ struct menu *menu;
+ enum prop_type type;
+
+ if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
+ emit parentSelected();
+ ev->accept();
+ return;
+ }
+
+ if (!i) {
+ Parent::keyPressEvent(ev);
+ return;
+ }
+ item = (ConfigItem*)i;
+
+ switch (ev->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ if (item->goParent) {
+ emit parentSelected();
+ break;
+ }
+ menu = item->menu;
+ if (!menu)
+ break;
+ type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (type == P_MENU && rootEntry != menu &&
+ mode != fullMode && mode != menuMode) {
+ emit menuSelected(menu);
+ break;
+ }
+ case Qt::Key_Space:
+ changeValue(item);
+ break;
+ case Qt::Key_N:
+ setValue(item, no);
+ break;
+ case Qt::Key_M:
+ setValue(item, mod);
+ break;
+ case Qt::Key_Y:
+ setValue(item, yes);
+ break;
+ default:
+ Parent::keyPressEvent(ev);
+ return;
+ }
+ ev->accept();
+}
+
+void ConfigList::contentsMousePressEvent(QMouseEvent* e)
+{
+ //QPoint p(contentsToViewport(e->pos()));
+ //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMousePressEvent(e);
+}
+
+void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
+{
+ QPoint p(contentsToViewport(e->pos()));
+ ConfigItem* item = (ConfigItem*)itemAt(p);
+ struct menu *menu;
+ enum prop_type ptype;
+ const QPixmap* pm;
+ int idx, x;
+
+ if (!item)
+ goto skip;
+
+ menu = item->menu;
+ x = header()->offset() + p.x();
+ idx = colRevMap[header()->sectionAt(x)];
+ switch (idx) {
+ case promptColIdx:
+ pm = item->pixmap(promptColIdx);
+ if (pm) {
+ int off = header()->sectionPos(0) + itemMargin() +
+ treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
+ if (x >= off && x < off + pm->width()) {
+ if (item->goParent) {
+ emit parentSelected();
+ break;
+ } else if (!menu)
+ break;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (ptype == P_MENU && rootEntry != menu &&
+ mode != fullMode && mode != menuMode)
+ emit menuSelected(menu);
+ else
+ changeValue(item);
+ }
+ }
+ break;
+ case noColIdx:
+ setValue(item, no);
+ break;
+ case modColIdx:
+ setValue(item, mod);
+ break;
+ case yesColIdx:
+ setValue(item, yes);
+ break;
+ case dataColIdx:
+ changeValue(item);
+ break;
+ }
+
+skip:
+ //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMouseReleaseEvent(e);
+}
+
+void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
+{
+ //QPoint p(contentsToViewport(e->pos()));
+ //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMouseMoveEvent(e);
+}
+
+void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
+{
+ QPoint p(contentsToViewport(e->pos()));
+ ConfigItem* item = (ConfigItem*)itemAt(p);
+ struct menu *menu;
+ enum prop_type ptype;
+
+ if (!item)
+ goto skip;
+ if (item->goParent) {
+ emit parentSelected();
+ goto skip;
+ }
+ menu = item->menu;
+ if (!menu)
+ goto skip;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
+ emit menuSelected(menu);
+ else if (menu->sym)
+ changeValue(item);
+
+skip:
+ //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
+ Parent::contentsMouseDoubleClickEvent(e);
+}
+
+void ConfigList::focusInEvent(QFocusEvent *e)
+{
+ struct menu *menu = NULL;
+
+ Parent::focusInEvent(e);
+
+ ConfigItem* item = (ConfigItem *)currentItem();
+ if (item) {
+ setSelected(item, TRUE);
+ menu = item->menu;
+ }
+ emit gotFocus(menu);
+}
+
+void ConfigList::contextMenuEvent(QContextMenuEvent *e)
+{
+ if (e->y() <= header()->geometry().bottom()) {
+ if (!headerPopup) {
+ Q3Action *action;
+
+ headerPopup = new Q3PopupMenu(this);
+ action = new Q3Action(NULL, _("Show Name"), 0, this);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)),
+ parent(), SLOT(setShowName(bool)));
+ connect(parent(), SIGNAL(showNameChanged(bool)),
+ action, SLOT(setOn(bool)));
+ action->setOn(showName);
+ action->addTo(headerPopup);
+ action = new Q3Action(NULL, _("Show Range"), 0, this);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)),
+ parent(), SLOT(setShowRange(bool)));
+ connect(parent(), SIGNAL(showRangeChanged(bool)),
+ action, SLOT(setOn(bool)));
+ action->setOn(showRange);
+ action->addTo(headerPopup);
+ action = new Q3Action(NULL, _("Show Data"), 0, this);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)),
+ parent(), SLOT(setShowData(bool)));
+ connect(parent(), SIGNAL(showDataChanged(bool)),
+ action, SLOT(setOn(bool)));
+ action->setOn(showData);
+ action->addTo(headerPopup);
+ }
+ headerPopup->exec(e->globalPos());
+ e->accept();
+ } else
+ e->ignore();
+}
+
+ConfigView*ConfigView::viewList;
+QAction *ConfigView::showNormalAction;
+QAction *ConfigView::showAllAction;
+QAction *ConfigView::showPromptAction;
+
+ConfigView::ConfigView(QWidget* parent, const char *name)
+ : Parent(parent, name)
+{
+ list = new ConfigList(this, name);
+ lineEdit = new ConfigLineEdit(this);
+ lineEdit->hide();
+
+ this->nextView = viewList;
+ viewList = this;
+}
+
+ConfigView::~ConfigView(void)
+{
+ ConfigView** vp;
+
+ for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
+ if (*vp == this) {
+ *vp = nextView;
+ break;
+ }
+ }
+}
+
+void ConfigView::setOptionMode(QAction *act)
+{
+ if (act == showNormalAction)
+ list->optMode = normalOpt;
+ else if (act == showAllAction)
+ list->optMode = allOpt;
+ else
+ list->optMode = promptOpt;
+
+ list->updateListAll();
+}
+
+void ConfigView::setShowName(bool b)
+{
+ if (list->showName != b) {
+ list->showName = b;
+ list->reinit();
+ emit showNameChanged(b);
+ }
+}
+
+void ConfigView::setShowRange(bool b)
+{
+ if (list->showRange != b) {
+ list->showRange = b;
+ list->reinit();
+ emit showRangeChanged(b);
+ }
+}
+
+void ConfigView::setShowData(bool b)
+{
+ if (list->showData != b) {
+ list->showData = b;
+ list->reinit();
+ emit showDataChanged(b);
+ }
+}
+
+void ConfigList::setAllOpen(bool open)
+{
+ Q3ListViewItemIterator it(this);
+
+ for (; it.current(); it++)
+ it.current()->setOpen(open);
+}
+
+void ConfigView::updateList(ConfigItem* item)
+{
+ ConfigView* v;
+
+ for (v = viewList; v; v = v->nextView)
+ v->list->updateList(item);
+}
+
+void ConfigView::updateListAll(void)
+{
+ ConfigView* v;
+
+ for (v = viewList; v; v = v->nextView)
+ v->list->updateListAll();
+}
+
+ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
+ : Parent(parent, name), sym(0), _menu(0)
+{
+ if (name) {
+ configSettings->beginGroup(name);
+ _showDebug = configSettings->readBoolEntry("/showDebug", false);
+ configSettings->endGroup();
+ connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+ }
+}
+
+void ConfigInfoView::saveSettings(void)
+{
+ if (name()) {
+ configSettings->beginGroup(name());
+ configSettings->writeEntry("/showDebug", showDebug());
+ configSettings->endGroup();
+ }
+}
+
+void ConfigInfoView::setShowDebug(bool b)
+{
+ if (_showDebug != b) {
+ _showDebug = b;
+ if (_menu)
+ menuInfo();
+ else if (sym)
+ symbolInfo();
+ emit showDebugChanged(b);
+ }
+}
+
+void ConfigInfoView::setInfo(struct menu *m)
+{
+ if (_menu == m)
+ return;
+ _menu = m;
+ sym = NULL;
+ if (!_menu)
+ clear();
+ else
+ menuInfo();
+}
+
+void ConfigInfoView::symbolInfo(void)
+{
+ QString str;
+
+ str += "<big>Symbol: <b>";
+ str += print_filter(sym->name);
+ str += "</b></big><br><br>value: ";
+ str += print_filter(sym_get_string_value(sym));
+ str += "<br>visibility: ";
+ str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
+ str += "<br>";
+ str += debug_info(sym);
+
+ setText(str);
+}
+
+void ConfigInfoView::menuInfo(void)
+{
+ struct symbol* sym;
+ QString head, debug, help;
+
+ sym = _menu->sym;
+ if (sym) {
+ if (_menu->prompt) {
+ head += "<big><b>";
+ head += print_filter(_(_menu->prompt->text));
+ head += "</b></big>";
+ if (sym->name) {
+ head += " (";
+ if (showDebug())
+ head += QString().sprintf("<a href=\"s%p\">", sym);
+ head += print_filter(sym->name);
+ if (showDebug())
+ head += "</a>";
+ head += ")";
+ }
+ } else if (sym->name) {
+ head += "<big><b>";
+ if (showDebug())
+ head += QString().sprintf("<a href=\"s%p\">", sym);
+ head += print_filter(sym->name);
+ if (showDebug())
+ head += "</a>";
+ head += "</b></big>";
+ }
+ head += "<br><br>";
+
+ if (showDebug())
+ debug = debug_info(sym);
+
+ struct gstr help_gstr = str_new();
+ menu_get_ext_help(_menu, &help_gstr);
+ help = print_filter(str_get(&help_gstr));
+ str_free(&help_gstr);
+ } else if (_menu->prompt) {
+ head += "<big><b>";
+ head += print_filter(_(_menu->prompt->text));
+ head += "</b></big><br><br>";
+ if (showDebug()) {
+ if (_menu->prompt->visible.expr) {
+ debug += " dep: ";
+ expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+ debug += "<br><br>";
+ }
+ }
+ }
+ if (showDebug())
+ debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
+
+ setText(head + debug + help);
+}
+
+QString ConfigInfoView::debug_info(struct symbol *sym)
+{
+ QString debug;
+
+ debug += "type: ";
+ debug += print_filter(sym_type_name(sym->type));
+ if (sym_is_choice(sym))
+ debug += " (choice)";
+ debug += "<br>";
+ if (sym->rev_dep.expr) {
+ debug += "reverse dep: ";
+ expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ }
+ for (struct property *prop = sym->prop; prop; prop = prop->next) {
+ switch (prop->type) {
+ case P_PROMPT:
+ case P_MENU:
+ debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
+ debug += print_filter(_(prop->text));
+ debug += "</a><br>";
+ break;
+ case P_DEFAULT:
+ case P_SELECT:
+ case P_RANGE:
+ case P_ENV:
+ debug += prop_get_type_name(prop->type);
+ debug += ": ";
+ expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ break;
+ case P_CHOICE:
+ if (sym_is_choice(sym)) {
+ debug += "choice: ";
+ expr_print(prop->expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ }
+ break;
+ default:
+ debug += "unknown property: ";
+ debug += prop_get_type_name(prop->type);
+ debug += "<br>";
+ }
+ if (prop->visible.expr) {
+ debug += " dep: ";
+ expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
+ debug += "<br>";
+ }
+ }
+ debug += "<br>";
+
+ return debug;
+}
+
+QString ConfigInfoView::print_filter(const QString &str)
+{
+ QRegExp re("[<>&\"\\n]");
+ QString res = str;
+ for (int i = 0; (i = res.find(re, i)) >= 0;) {
+ switch (res[i].latin1()) {
+ case '<':
+ res.replace(i, 1, "<");
+ i += 4;
+ break;
+ case '>':
+ res.replace(i, 1, ">");
+ i += 4;
+ break;
+ case '&':
+ res.replace(i, 1, "&");
+ i += 5;
+ break;
+ case '"':
+ res.replace(i, 1, """);
+ i += 6;
+ break;
+ case '\n':
+ res.replace(i, 1, "<br>");
+ i += 4;
+ break;
+ }
+ }
+ return res;
+}
+
+void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
+{
+ QString* text = reinterpret_cast<QString*>(data);
+ QString str2 = print_filter(str);
+
+ if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
+ *text += QString().sprintf("<a href=\"s%p\">", sym);
+ *text += str2;
+ *text += "</a>";
+ } else
+ *text += str2;
+}
+
+Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+{
+ Q3PopupMenu* popup = Parent::createPopupMenu(pos);
+ Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup);
+ action->setToggleAction(TRUE);
+ connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
+ connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
+ action->setOn(showDebug());
+ popup->insertSeparator();
+ action->addTo(popup);
+ return popup;
+}
+
+void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
+{
+ Parent::contentsContextMenuEvent(e);
+}
+
+ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
+ : Parent(parent, name), result(NULL)
+{
+ setCaption("Search Config");
+
+ QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
+ QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
+ layout2->addWidget(new QLabel(_("Find:"), this));
+ editField = new QLineEdit(this);
+ connect(editField, SIGNAL(returnPressed()), SLOT(search()));
+ layout2->addWidget(editField);
+ searchButton = new QPushButton(_("Search"), this);
+ searchButton->setAutoDefault(FALSE);
+ connect(searchButton, SIGNAL(clicked()), SLOT(search()));
+ layout2->addWidget(searchButton);
+ layout1->addLayout(layout2);
+
+ split = new QSplitter(this);
+ split->setOrientation(Qt::Vertical);
+ list = new ConfigView(split, name);
+ list->list->mode = listMode;
+ info = new ConfigInfoView(split, name);
+ connect(list->list, SIGNAL(menuChanged(struct menu *)),
+ info, SLOT(setInfo(struct menu *)));
+ connect(list->list, SIGNAL(menuChanged(struct menu *)),
+ parent, SLOT(setMenuLink(struct menu *)));
+
+ layout1->addWidget(split);
+
+ if (name) {
+ int x, y, width, height;
+ bool ok;
+
+ configSettings->beginGroup(name);
+ width = configSettings->readNumEntry("/window width", parent->width() / 2);
+ height = configSettings->readNumEntry("/window height", parent->height() / 2);
+ resize(width, height);
+ x = configSettings->readNumEntry("/window x", 0, &ok);
+ if (ok)
+ y = configSettings->readNumEntry("/window y", 0, &ok);
+ if (ok)
+ move(x, y);
+ Q3ValueList<int> sizes = configSettings->readSizes("/split", &ok);
+ if (ok)
+ split->setSizes(sizes);
+ configSettings->endGroup();
+ connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
+ }
+}
+
+void ConfigSearchWindow::saveSettings(void)
+{
+ if (name()) {
+ configSettings->beginGroup(name());
+ configSettings->writeEntry("/window x", pos().x());
+ configSettings->writeEntry("/window y", pos().y());
+ configSettings->writeEntry("/window width", size().width());
+ configSettings->writeEntry("/window height", size().height());
+ configSettings->writeSizes("/split", split->sizes());
+ configSettings->endGroup();
+ }
+}
+
+void ConfigSearchWindow::search(void)
+{
+ struct symbol **p;
+ struct property *prop;
+ ConfigItem *lastItem = NULL;
+
+ free(result);
+ list->list->clear();
+ info->clear();
+
+ result = sym_re_search(editField->text().latin1());
+ if (!result)
+ return;
+ for (p = result; *p; p++) {
+ for_all_prompts((*p), prop)
+ lastItem = new ConfigItem(list->list, lastItem, prop->menu,
+ menu_is_visible(prop->menu));
+ }
+}
+
+/*
+ * Construct the complete config widget
+ */
+ConfigMainWindow::ConfigMainWindow(void)
+ : searchWindow(0)
+{
+ QMenuBar* menu;
+ bool ok;
+ int x, y, width, height;
+ char title[256];
+
+ QDesktopWidget *d = configApp->desktop();
+ snprintf(title, sizeof(title), "%s%s",
+ rootmenu.prompt->text,
+#if QT_VERSION < 0x040000
+ " (Qt3)"
+#else
+ ""
+#endif
+ );
+ setCaption(title);
+
+ width = configSettings->readNumEntry("/window width", d->width() - 64);
+ height = configSettings->readNumEntry("/window height", d->height() - 64);
+ resize(width, height);
+ x = configSettings->readNumEntry("/window x", 0, &ok);
+ if (ok)
+ y = configSettings->readNumEntry("/window y", 0, &ok);
+ if (ok)
+ move(x, y);
+
+ split1 = new QSplitter(this);
+ split1->setOrientation(Qt::Horizontal);
+ setCentralWidget(split1);
+
+ menuView = new ConfigView(split1, "menu");
+ menuList = menuView->list;
+
+ split2 = new QSplitter(split1);
+ split2->setOrientation(Qt::Vertical);
+
+ // create config tree
+ configView = new ConfigView(split2, "config");
+ configList = configView->list;
+
+ helpText = new ConfigInfoView(split2, "help");
+ helpText->setTextFormat(Qt::RichText);
+
+ setTabOrder(configList, helpText);
+ configList->setFocus();
+
+ menu = menuBar();
+ toolBar = new Q3ToolBar("Tools", this);
+
+ backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this);
+ connect(backAction, SIGNAL(activated()), SLOT(goBack()));
+ backAction->setEnabled(FALSE);
+ Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
+ connect(quitAction, SIGNAL(activated()), SLOT(close()));
+ Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
+ connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
+ saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
+ connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+ conf_set_changed_callback(conf_changed);
+ // Set saveAction's initial state
+ conf_changed();
+ Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this);
+ connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
+ Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
+ connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
+ Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
+ connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
+ Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
+ connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
+ Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
+ connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
+
+ Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this);
+ showNameAction->setToggleAction(TRUE);
+ connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
+ connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
+ showNameAction->setOn(configView->showName());
+ Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this);
+ showRangeAction->setToggleAction(TRUE);
+ connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
+ connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
+ showRangeAction->setOn(configList->showRange);
+ Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this);
+ showDataAction->setToggleAction(TRUE);
+ connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
+ connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
+ showDataAction->setOn(configList->showData);
+
+ QActionGroup *optGroup = new QActionGroup(this);
+ optGroup->setExclusive(TRUE);
+ connect(optGroup, SIGNAL(selected(QAction *)), configView,
+ SLOT(setOptionMode(QAction *)));
+ connect(optGroup, SIGNAL(selected(QAction *)), menuView,
+ SLOT(setOptionMode(QAction *)));
+
+#if QT_VERSION >= 0x040000
+ configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup);
+ configView->showAllAction = new QAction(_("Show All Options"), optGroup);
+ configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup);
+#else
+ configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup);
+ configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup);
+ configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup);
+#endif
+ configView->showNormalAction->setToggleAction(TRUE);
+ configView->showNormalAction->setOn(configList->optMode == normalOpt);
+ configView->showAllAction->setToggleAction(TRUE);
+ configView->showAllAction->setOn(configList->optMode == allOpt);
+ configView->showPromptAction->setToggleAction(TRUE);
+ configView->showPromptAction->setOn(configList->optMode == promptOpt);
+
+ Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this);
+ showDebugAction->setToggleAction(TRUE);
+ connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
+ connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
+ showDebugAction->setOn(helpText->showDebug());
+
+ Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this);
+ connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
+ Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this);
+ connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+
+ // init tool bar
+ backAction->addTo(toolBar);
+ toolBar->addSeparator();
+ loadAction->addTo(toolBar);
+ saveAction->addTo(toolBar);
+ toolBar->addSeparator();
+ singleViewAction->addTo(toolBar);
+ splitViewAction->addTo(toolBar);
+ fullViewAction->addTo(toolBar);
+
+ // create config menu
+ Q3PopupMenu* config = new Q3PopupMenu(this);
+ menu->insertItem(_("&File"), config);
+ loadAction->addTo(config);
+ saveAction->addTo(config);
+ saveAsAction->addTo(config);
+ config->insertSeparator();
+ quitAction->addTo(config);
+
+ // create edit menu
+ Q3PopupMenu* editMenu = new Q3PopupMenu(this);
+ menu->insertItem(_("&Edit"), editMenu);
+ searchAction->addTo(editMenu);
+
+ // create options menu
+ Q3PopupMenu* optionMenu = new Q3PopupMenu(this);
+ menu->insertItem(_("&Option"), optionMenu);
+ showNameAction->addTo(optionMenu);
+ showRangeAction->addTo(optionMenu);
+ showDataAction->addTo(optionMenu);
+ optionMenu->insertSeparator();
+ optGroup->addTo(optionMenu);
+ optionMenu->insertSeparator();
+
+ // create help menu
+ Q3PopupMenu* helpMenu = new Q3PopupMenu(this);
+ menu->insertSeparator();
+ menu->insertItem(_("&Help"), helpMenu);
+ showIntroAction->addTo(helpMenu);
+ showAboutAction->addTo(helpMenu);
+
+ connect(configList, SIGNAL(menuChanged(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(configList, SIGNAL(menuSelected(struct menu *)),
+ SLOT(changeMenu(struct menu *)));
+ connect(configList, SIGNAL(parentSelected()),
+ SLOT(goBack()));
+ connect(menuList, SIGNAL(menuChanged(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(menuList, SIGNAL(menuSelected(struct menu *)),
+ SLOT(changeMenu(struct menu *)));
+
+ connect(configList, SIGNAL(gotFocus(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(menuList, SIGNAL(gotFocus(struct menu *)),
+ helpText, SLOT(setInfo(struct menu *)));
+ connect(menuList, SIGNAL(gotFocus(struct menu *)),
+ SLOT(listFocusChanged(void)));
+ connect(helpText, SIGNAL(menuSelected(struct menu *)),
+ SLOT(setMenuLink(struct menu *)));
+
+ QString listMode = configSettings->readEntry("/listMode", "symbol");
+ if (listMode == "single")
+ showSingleView();
+ else if (listMode == "full")
+ showFullView();
+ else /*if (listMode == "split")*/
+ showSplitView();
+
+ // UI setup done, restore splitter positions
+ Q3ValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+ if (ok)
+ split1->setSizes(sizes);
+
+ sizes = configSettings->readSizes("/split2", &ok);
+ if (ok)
+ split2->setSizes(sizes);
+}
+
+void ConfigMainWindow::loadConfig(void)
+{
+ QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this);
+ if (s.isNull())
+ return;
+ if (conf_read(QFile::encodeName(s)))
+ QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
+ ConfigView::updateListAll();
+}
+
+void ConfigMainWindow::saveConfig(void)
+{
+ if (conf_write(NULL))
+ QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::saveConfigAs(void)
+{
+ QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
+ if (s.isNull())
+ return;
+ if (conf_write(QFile::encodeName(s)))
+ QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+}
+
+void ConfigMainWindow::searchConfig(void)
+{
+ if (!searchWindow)
+ searchWindow = new ConfigSearchWindow(this, "search");
+ searchWindow->show();
+}
+
+void ConfigMainWindow::changeMenu(struct menu *menu)
+{
+ configList->setRootMenu(menu);
+ if (configList->rootEntry->parent == &rootmenu)
+ backAction->setEnabled(FALSE);
+ else
+ backAction->setEnabled(TRUE);
+}
+
+void ConfigMainWindow::setMenuLink(struct menu *menu)
+{
+ struct menu *parent;
+ ConfigList* list = NULL;
+ ConfigItem* item;
+
+ if (configList->menuSkip(menu))
+ return;
+
+ switch (configList->mode) {
+ case singleMode:
+ list = configList;
+ parent = menu_get_parent_menu(menu);
+ if (!parent)
+ return;
+ list->setRootMenu(parent);
+ break;
+ case symbolMode:
+ if (menu->flags & MENU_ROOT) {
+ configList->setRootMenu(menu);
+ configList->clearSelection();
+ list = menuList;
+ } else {
+ list = configList;
+ parent = menu_get_parent_menu(menu->parent);
+ if (!parent)
+ return;
+ item = menuList->findConfigItem(parent);
+ if (item) {
+ menuList->setSelected(item, TRUE);
+ menuList->ensureItemVisible(item);
+ }
+ list->setRootMenu(parent);
+ }
+ break;
+ case fullMode:
+ list = configList;
+ break;
+ default:
+ break;
+ }
+
+ if (list) {
+ item = list->findConfigItem(menu);
+ if (item) {
+ list->setSelected(item, TRUE);
+ list->ensureItemVisible(item);
+ list->setFocus();
+ }
+ }
+}
+
+void ConfigMainWindow::listFocusChanged(void)
+{
+ if (menuList->mode == menuMode)
+ configList->clearSelection();
+}
+
+void ConfigMainWindow::goBack(void)
+{
+ ConfigItem* item;
+
+ configList->setParentMenu();
+ if (configList->rootEntry == &rootmenu)
+ backAction->setEnabled(FALSE);
+ item = (ConfigItem*)menuList->selectedItem();
+ while (item) {
+ if (item->menu == configList->rootEntry) {
+ menuList->setSelected(item, TRUE);
+ break;
+ }
+ item = (ConfigItem*)item->parent();
+ }
+}
+
+void ConfigMainWindow::showSingleView(void)
+{
+ menuView->hide();
+ menuList->setRootMenu(0);
+ configList->mode = singleMode;
+ if (configList->rootEntry == &rootmenu)
+ configList->updateListAll();
+ else
+ configList->setRootMenu(&rootmenu);
+ configList->setAllOpen(TRUE);
+ configList->setFocus();
+}
+
+void ConfigMainWindow::showSplitView(void)
+{
+ configList->mode = symbolMode;
+ if (configList->rootEntry == &rootmenu)
+ configList->updateListAll();
+ else
+ configList->setRootMenu(&rootmenu);
+ configList->setAllOpen(TRUE);
+ configApp->processEvents();
+ menuList->mode = menuMode;
+ menuList->setRootMenu(&rootmenu);
+ menuList->setAllOpen(TRUE);
+ menuView->show();
+ menuList->setFocus();
+}
+
+void ConfigMainWindow::showFullView(void)
+{
+ menuView->hide();
+ menuList->setRootMenu(0);
+ configList->mode = fullMode;
+ if (configList->rootEntry == &rootmenu)
+ configList->updateListAll();
+ else
+ configList->setRootMenu(&rootmenu);
+ configList->setAllOpen(FALSE);
+ configList->setFocus();
+}
+
+/*
+ * ask for saving configuration before quitting
+ * TODO ask only when something changed
+ */
+void ConfigMainWindow::closeEvent(QCloseEvent* e)
+{
+ if (!conf_get_changed()) {
+ e->accept();
+ return;
+ }
+ QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
+ QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
+ mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
+ mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
+ mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
+ switch (mb.exec()) {
+ case QMessageBox::Yes:
+ conf_write(NULL);
+ case QMessageBox::No:
+ e->accept();
+ break;
+ case QMessageBox::Cancel:
+ e->ignore();
+ break;
+ }
+}
+
+void ConfigMainWindow::showIntro(void)
+{
+ static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n"
+ "For each option, a blank box indicates the feature is disabled, a check\n"
+ "indicates it is enabled, and a dot indicates that it is to be compiled\n"
+ "as a module. Clicking on the box will cycle through the three states.\n\n"
+ "If you do not see an option (e.g., a device driver) that you believe\n"
+ "should be present, try turning on Show All Options under the Options menu.\n"
+ "Although there is no cross reference yet to help you figure out what other\n"
+ "options must be enabled to support the option you are interested in, you can\n"
+ "still view the help of a grayed-out option.\n\n"
+ "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
+ "which you can then match by examining other options.\n\n");
+
+ QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::showAbout(void)
+{
+ static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
+ "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
+
+ QMessageBox::information(this, "qconf", str);
+}
+
+void ConfigMainWindow::saveSettings(void)
+{
+ configSettings->writeEntry("/window x", pos().x());
+ configSettings->writeEntry("/window y", pos().y());
+ configSettings->writeEntry("/window width", size().width());
+ configSettings->writeEntry("/window height", size().height());
+
+ QString entry;
+ switch(configList->mode) {
+ case singleMode :
+ entry = "single";
+ break;
+
+ case symbolMode :
+ entry = "split";
+ break;
+
+ case fullMode :
+ entry = "full";
+ break;
+
+ default:
+ break;
+ }
+ configSettings->writeEntry("/listMode", entry);
+
+ configSettings->writeSizes("/split1", split1->sizes());
+ configSettings->writeSizes("/split2", split2->sizes());
+}
+
+void ConfigMainWindow::conf_changed(void)
+{
+ if (saveAction)
+ saveAction->setEnabled(conf_get_changed());
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+ struct menu *child;
+ static int menu_cnt = 0;
+
+ menu->flags |= MENU_ROOT;
+ for (child = menu->list; child; child = child->next) {
+ if (child->prompt && child->prompt->type == P_MENU) {
+ menu_cnt++;
+ fixup_rootmenu(child);
+ menu_cnt--;
+ } else if (!menu_cnt)
+ fixup_rootmenu(child);
+ }
+}
+
+static const char *progname;
+
+static void usage(void)
+{
+ printf(_("%s <config>\n"), progname);
+ exit(0);
+}
+
+int main(int ac, char** av)
+{
+ ConfigMainWindow* v;
+ const char *name;
+
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+#ifndef LKC_DIRECT_LINK
+ kconfig_load();
+#endif
+
+ progname = av[0];
+ configApp = new QApplication(ac, av);
+ if (ac > 1 && av[1][0] == '-') {
+ switch (av[1][1]) {
+ case 'h':
+ case '?':
+ usage();
+ }
+ name = av[2];
+ } else
+ name = av[1];
+ if (!name)
+ usage();
+
+ conf_parse(name);
+ fixup_rootmenu(&rootmenu);
+ conf_read(NULL);
+ //zconfdump(stdout);
+
+ configSettings = new ConfigSettings();
+ configSettings->beginGroup("/kconfig/qconf");
+ v = new ConfigMainWindow();
+
+ //zconfdump(stdout);
+ configApp->setMainWidget(v);
+ configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
+ configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
+ v->show();
+ configApp->exec();
+
+ configSettings->endGroup();
+ delete configSettings;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#if QT_VERSION < 0x040000
+#include <qlistview.h>
+#else
+#include <q3listview.h>
+#endif
+#include <qsettings.h>
+
+#if QT_VERSION < 0x040000
+#define Q3ValueList QValueList
+#define Q3PopupMenu QPopupMenu
+#define Q3ListView QListView
+#define Q3ListViewItem QListViewItem
+#define Q3VBox QVBox
+#define Q3TextBrowser QTextBrowser
+#define Q3MainWindow QMainWindow
+#define Q3Action QAction
+#define Q3ToolBar QToolBar
+#define Q3ListViewItemIterator QListViewItemIterator
+#define Q3FileDialog QFileDialog
+#endif
+
+class ConfigView;
+class ConfigList;
+class ConfigItem;
+class ConfigLineEdit;
+class ConfigMainWindow;
+
+class ConfigSettings : public QSettings {
+public:
+ Q3ValueList<int> readSizes(const QString& key, bool *ok);
+ bool writeSizes(const QString& key, const Q3ValueList<int>& value);
+};
+
+enum colIdx {
+ promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr
+};
+enum listMode {
+ singleMode, menuMode, symbolMode, fullMode, listMode
+};
+enum optionMode {
+ normalOpt = 0, allOpt, promptOpt
+};
+
+class ConfigList : public Q3ListView {
+ Q_OBJECT
+ typedef class Q3ListView Parent;
+public:
+ ConfigList(ConfigView* p, const char *name = 0);
+ void reinit(void);
+ ConfigView* parent(void) const
+ {
+ return (ConfigView*)Parent::parent();
+ }
+ ConfigItem* findConfigItem(struct menu *);
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+ void contentsMousePressEvent(QMouseEvent *e);
+ void contentsMouseReleaseEvent(QMouseEvent *e);
+ void contentsMouseMoveEvent(QMouseEvent *e);
+ void contentsMouseDoubleClickEvent(QMouseEvent *e);
+ void focusInEvent(QFocusEvent *e);
+ void contextMenuEvent(QContextMenuEvent *e);
+
+public slots:
+ void setRootMenu(struct menu *menu);
+
+ void updateList(ConfigItem *item);
+ void setValue(ConfigItem* item, tristate val);
+ void changeValue(ConfigItem* item);
+ void updateSelection(void);
+ void saveSettings(void);
+signals:
+ void menuChanged(struct menu *menu);
+ void menuSelected(struct menu *menu);
+ void parentSelected(void);
+ void gotFocus(struct menu *);
+
+public:
+ void updateListAll(void)
+ {
+ updateAll = true;
+ updateList(NULL);
+ updateAll = false;
+ }
+ ConfigList* listView()
+ {
+ return this;
+ }
+ ConfigItem* firstChild() const
+ {
+ return (ConfigItem *)Parent::firstChild();
+ }
+ int mapIdx(colIdx idx)
+ {
+ return colMap[idx];
+ }
+ void addColumn(colIdx idx, const QString& label)
+ {
+ colMap[idx] = Parent::addColumn(label);
+ colRevMap[colMap[idx]] = idx;
+ }
+ void removeColumn(colIdx idx)
+ {
+ int col = colMap[idx];
+ if (col >= 0) {
+ Parent::removeColumn(col);
+ colRevMap[col] = colMap[idx] = -1;
+ }
+ }
+ void setAllOpen(bool open);
+ void setParentMenu(void);
+
+ bool menuSkip(struct menu *);
+
+ template <class P>
+ void updateMenuList(P*, struct menu*);
+
+ bool updateAll;
+
+ QPixmap symbolYesPix, symbolModPix, symbolNoPix;
+ QPixmap choiceYesPix, choiceNoPix;
+ QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
+
+ bool showName, showRange, showData;
+ enum listMode mode;
+ enum optionMode optMode;
+ struct menu *rootEntry;
+ QColorGroup disabledColorGroup;
+ QColorGroup inactivedColorGroup;
+ Q3PopupMenu* headerPopup;
+
+private:
+ int colMap[colNr];
+ int colRevMap[colNr];
+};
+
+class ConfigItem : public Q3ListViewItem {
+ typedef class Q3ListViewItem Parent;
+public:
+ ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v)
+ : Parent(parent, after), menu(m), visible(v), goParent(false)
+ {
+ init();
+ }
+ ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
+ : Parent(parent, after), menu(m), visible(v), goParent(false)
+ {
+ init();
+ }
+ ConfigItem(Q3ListView *parent, ConfigItem *after, bool v)
+ : Parent(parent, after), menu(0), visible(v), goParent(true)
+ {
+ init();
+ }
+ ~ConfigItem(void);
+ void init(void);
+ void okRename(int col);
+ void updateMenu(void);
+ void testUpdateMenu(bool v);
+ ConfigList* listView() const
+ {
+ return (ConfigList*)Parent::listView();
+ }
+ ConfigItem* firstChild() const
+ {
+ return (ConfigItem *)Parent::firstChild();
+ }
+ ConfigItem* nextSibling() const
+ {
+ return (ConfigItem *)Parent::nextSibling();
+ }
+ void setText(colIdx idx, const QString& text)
+ {
+ Parent::setText(listView()->mapIdx(idx), text);
+ }
+ QString text(colIdx idx) const
+ {
+ return Parent::text(listView()->mapIdx(idx));
+ }
+ void setPixmap(colIdx idx, const QPixmap& pm)
+ {
+ Parent::setPixmap(listView()->mapIdx(idx), pm);
+ }
+ const QPixmap* pixmap(colIdx idx) const
+ {
+ return Parent::pixmap(listView()->mapIdx(idx));
+ }
+ void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+
+ ConfigItem* nextItem;
+ struct menu *menu;
+ bool visible;
+ bool goParent;
+};
+
+class ConfigLineEdit : public QLineEdit {
+ Q_OBJECT
+ typedef class QLineEdit Parent;
+public:
+ ConfigLineEdit(ConfigView* parent);
+ ConfigView* parent(void) const
+ {
+ return (ConfigView*)Parent::parent();
+ }
+ void show(ConfigItem *i);
+ void keyPressEvent(QKeyEvent *e);
+
+public:
+ ConfigItem *item;
+};
+
+class ConfigView : public Q3VBox {
+ Q_OBJECT
+ typedef class Q3VBox Parent;
+public:
+ ConfigView(QWidget* parent, const char *name = 0);
+ ~ConfigView(void);
+ static void updateList(ConfigItem* item);
+ static void updateListAll(void);
+
+ bool showName(void) const { return list->showName; }
+ bool showRange(void) const { return list->showRange; }
+ bool showData(void) const { return list->showData; }
+public slots:
+ void setShowName(bool);
+ void setShowRange(bool);
+ void setShowData(bool);
+ void setOptionMode(QAction *);
+signals:
+ void showNameChanged(bool);
+ void showRangeChanged(bool);
+ void showDataChanged(bool);
+public:
+ ConfigList* list;
+ ConfigLineEdit* lineEdit;
+
+ static ConfigView* viewList;
+ ConfigView* nextView;
+
+ static QAction *showNormalAction;
+ static QAction *showAllAction;
+ static QAction *showPromptAction;
+};
+
+class ConfigInfoView : public Q3TextBrowser {
+ Q_OBJECT
+ typedef class Q3TextBrowser Parent;
+public:
+ ConfigInfoView(QWidget* parent, const char *name = 0);
+ bool showDebug(void) const { return _showDebug; }
+
+public slots:
+ void setInfo(struct menu *menu);
+ void saveSettings(void);
+ void setShowDebug(bool);
+
+signals:
+ void showDebugChanged(bool);
+ void menuSelected(struct menu *);
+
+protected:
+ void symbolInfo(void);
+ void menuInfo(void);
+ QString debug_info(struct symbol *sym);
+ static QString print_filter(const QString &str);
+ static void expr_print_help(void *data, struct symbol *sym, const char *str);
+ Q3PopupMenu* createPopupMenu(const QPoint& pos);
+ void contentsContextMenuEvent(QContextMenuEvent *e);
+
+ struct symbol *sym;
+ struct menu *_menu;
+ bool _showDebug;
+};
+
+class ConfigSearchWindow : public QDialog {
+ Q_OBJECT
+ typedef class QDialog Parent;
+public:
+ ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
+
+public slots:
+ void saveSettings(void);
+ void search(void);
+
+protected:
+ QLineEdit* editField;
+ QPushButton* searchButton;
+ QSplitter* split;
+ ConfigView* list;
+ ConfigInfoView* info;
+
+ struct symbol **result;
+};
+
+class ConfigMainWindow : public Q3MainWindow {
+ Q_OBJECT
+
+ static Q3Action *saveAction;
+ static void conf_changed(void);
+public:
+ ConfigMainWindow(void);
+public slots:
+ void changeMenu(struct menu *);
+ void setMenuLink(struct menu *);
+ void listFocusChanged(void);
+ void goBack(void);
+ void loadConfig(void);
+ void saveConfig(void);
+ void saveConfigAs(void);
+ void searchConfig(void);
+ void showSingleView(void);
+ void showSplitView(void);
+ void showFullView(void);
+ void showIntro(void);
+ void showAbout(void);
+ void saveSettings(void);
+
+protected:
+ void closeEvent(QCloseEvent *e);
+
+ ConfigSearchWindow *searchWindow;
+ ConfigView *menuView;
+ ConfigList *menuList;
+ ConfigView *configView;
+ ConfigList *configList;
+ ConfigInfoView *helpText;
+ Q3ToolBar *toolBar;
+ Q3Action *backAction;
+ QSplitter* split1;
+ QSplitter* split2;
+};
--- /dev/null
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <sys/utsname.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+struct symbol symbol_yes = {
+ .name = "y",
+ .curr = { "y", yes },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_mod = {
+ .name = "m",
+ .curr = { "m", mod },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_no = {
+ .name = "n",
+ .curr = { "n", no },
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
+}, symbol_empty = {
+ .name = "",
+ .curr = { "", no },
+ .flags = SYMBOL_VALID,
+};
+
+struct symbol *sym_defconfig_list;
+struct symbol *modules_sym;
+tristate modules_val;
+
+struct expr *sym_env_list;
+
+static void sym_add_default(struct symbol *sym, const char *def)
+{
+ struct property *prop = prop_alloc(P_DEFAULT, sym);
+
+ prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
+}
+
+void sym_init(void)
+{
+ struct symbol *sym;
+ struct utsname uts;
+ static bool inited = false;
+
+ if (inited)
+ return;
+ inited = true;
+
+ uname(&uts);
+
+ sym = sym_lookup("UNAME_RELEASE", 0);
+ sym->type = S_STRING;
+ sym->flags |= SYMBOL_AUTO;
+ sym_add_default(sym, uts.release);
+}
+
+enum symbol_type sym_get_type(struct symbol *sym)
+{
+ enum symbol_type type = sym->type;
+
+ if (type == S_TRISTATE) {
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ type = S_BOOLEAN;
+ else if (modules_val == no)
+ type = S_BOOLEAN;
+ }
+ return type;
+}
+
+const char *sym_type_name(enum symbol_type type)
+{
+ switch (type) {
+ case S_BOOLEAN:
+ return "boolean";
+ case S_TRISTATE:
+ return "tristate";
+ case S_INT:
+ return "integer";
+ case S_HEX:
+ return "hex";
+ case S_STRING:
+ return "string";
+ case S_UNKNOWN:
+ return "unknown";
+ case S_OTHER:
+ break;
+ }
+ return "???";
+}
+
+struct property *sym_get_choice_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_choices(sym, prop)
+ return prop;
+ return NULL;
+}
+
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_ENV)
+ return prop;
+ return NULL;
+}
+
+struct property *sym_get_default_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_defaults(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+static struct property *sym_get_range_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_RANGE) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri != no)
+ return prop;
+ }
+ return NULL;
+}
+
+static int sym_get_range_val(struct symbol *sym, int base)
+{
+ sym_calc_value(sym);
+ switch (sym->type) {
+ case S_INT:
+ base = 10;
+ break;
+ case S_HEX:
+ base = 16;
+ break;
+ default:
+ break;
+ }
+ return strtol(sym->curr.val, NULL, base);
+}
+
+static void sym_validate_range(struct symbol *sym)
+{
+ struct property *prop;
+ int base, val, val2;
+ char str[64];
+
+ switch (sym->type) {
+ case S_INT:
+ base = 10;
+ break;
+ case S_HEX:
+ base = 16;
+ break;
+ default:
+ return;
+ }
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return;
+ val = strtol(sym->curr.val, NULL, base);
+ val2 = sym_get_range_val(prop->expr->left.sym, base);
+ if (val >= val2) {
+ val2 = sym_get_range_val(prop->expr->right.sym, base);
+ if (val <= val2)
+ return;
+ }
+ if (sym->type == S_INT)
+ sprintf(str, "%d", val2);
+ else
+ sprintf(str, "0x%x", val2);
+ sym->curr.val = strdup(str);
+}
+
+static void sym_calc_visibility(struct symbol *sym)
+{
+ struct property *prop;
+ tristate tri;
+
+ /* any prompt visible? */
+ tri = no;
+ for_all_prompts(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ tri = EXPR_OR(tri, prop->visible.tri);
+ }
+ if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+ tri = yes;
+ if (sym->visible != tri) {
+ sym->visible = tri;
+ sym_set_changed(sym);
+ }
+ if (sym_is_choice_value(sym))
+ return;
+ /* defaulting to "yes" if no explicit "depends on" are given */
+ tri = yes;
+ if (sym->dir_dep.expr)
+ tri = expr_calc_value(sym->dir_dep.expr);
+ if (tri == mod)
+ tri = yes;
+ if (sym->dir_dep.tri != tri) {
+ sym->dir_dep.tri = tri;
+ sym_set_changed(sym);
+ }
+ tri = no;
+ if (sym->rev_dep.expr)
+ tri = expr_calc_value(sym->rev_dep.expr);
+ if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ tri = yes;
+ if (sym->rev_dep.tri != tri) {
+ sym->rev_dep.tri = tri;
+ sym_set_changed(sym);
+ }
+}
+
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+
+ /* any of the defaults visible? */
+ for_all_defaults(sym, prop) {
+ prop->visible.tri = expr_calc_value(prop->visible.expr);
+ if (prop->visible.tri == no)
+ continue;
+ def_sym = prop_get_symbol(prop);
+ if (def_sym->visible != no)
+ return def_sym;
+ }
+
+ /* just get the first visible value */
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
+ if (def_sym->visible != no)
+ return def_sym;
+
+ /* failed to locate any defaults */
+ return NULL;
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+
+ /* first calculate all choice values' visibilities */
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
+ sym_calc_visibility(def_sym);
+
+ /* is the user choice visible? */
+ def_sym = sym->def[S_DEF_USER].val;
+ if (def_sym && def_sym->visible != no)
+ return def_sym;
+
+ def_sym = sym_choice_default(sym);
+
+ if (def_sym == NULL)
+ /* no choice? reset tristate value */
+ sym->curr.tri = no;
+
+ return def_sym;
+}
+
+void sym_calc_value(struct symbol *sym)
+{
+ struct symbol_value newval, oldval;
+ struct property *prop;
+ struct expr *e;
+
+ if (!sym)
+ return;
+
+ if (sym->flags & SYMBOL_VALID)
+ return;
+ sym->flags |= SYMBOL_VALID;
+
+ oldval = sym->curr;
+
+ switch (sym->type) {
+ case S_INT:
+ case S_HEX:
+ case S_STRING:
+ newval = symbol_empty.curr;
+ break;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ newval = symbol_no.curr;
+ break;
+ default:
+ sym->curr.val = sym->name;
+ sym->curr.tri = no;
+ return;
+ }
+ if (!sym_is_choice_value(sym))
+ sym->flags &= ~SYMBOL_WRITE;
+
+ sym_calc_visibility(sym);
+
+ /* set default if recursively called */
+ sym->curr = newval;
+
+ switch (sym_get_type(sym)) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ if (sym_is_choice_value(sym) && sym->visible == yes) {
+ prop = sym_get_choice_prop(sym);
+ newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+ } else {
+ if (sym->visible != no) {
+ /* if the symbol is visible use the user value
+ * if available, otherwise try the default value
+ */
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym)) {
+ newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+ sym->visible);
+ goto calc_newval;
+ }
+ }
+ if (sym->rev_dep.tri != no)
+ sym->flags |= SYMBOL_WRITE;
+ if (!sym_is_choice(sym)) {
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ sym->flags |= SYMBOL_WRITE;
+ newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+ prop->visible.tri);
+ }
+ }
+ calc_newval:
+ if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+ struct expr *e;
+ e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+ sym->dir_dep.expr);
+ fprintf(stderr, "warning: (");
+ expr_fprint(e, stderr);
+ fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+ sym->name);
+ expr_fprint(sym->dir_dep.expr, stderr);
+ fprintf(stderr, ")\n");
+ expr_free(e);
+ }
+ newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
+ }
+ if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+ newval.tri = yes;
+ break;
+ case S_STRING:
+ case S_HEX:
+ case S_INT:
+ if (sym->visible != no) {
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym)) {
+ newval.val = sym->def[S_DEF_USER].val;
+ break;
+ }
+ }
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ struct symbol *ds = prop_get_symbol(prop);
+ if (ds) {
+ sym->flags |= SYMBOL_WRITE;
+ sym_calc_value(ds);
+ newval.val = ds->curr.val;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+
+ sym->curr = newval;
+ if (sym_is_choice(sym) && newval.tri == yes)
+ sym->curr.val = sym_calc_choice(sym);
+ sym_validate_range(sym);
+
+ if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
+ sym_set_changed(sym);
+ if (modules_sym == sym) {
+ sym_set_all_changed();
+ modules_val = modules_sym->curr.tri;
+ }
+ }
+
+ if (sym_is_choice(sym)) {
+ struct symbol *choice_sym;
+
+ prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, choice_sym) {
+ if ((sym->flags & SYMBOL_WRITE) &&
+ choice_sym->visible != no)
+ choice_sym->flags |= SYMBOL_WRITE;
+ if (sym->flags & SYMBOL_CHANGED)
+ sym_set_changed(choice_sym);
+ }
+ }
+
+ if (sym->flags & SYMBOL_AUTO)
+ sym->flags &= ~SYMBOL_WRITE;
+}
+
+void sym_clear_all_valid(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_VALID;
+ sym_add_change_count(1);
+ if (modules_sym)
+ sym_calc_value(modules_sym);
+}
+
+void sym_set_changed(struct symbol *sym)
+{
+ struct property *prop;
+
+ sym->flags |= SYMBOL_CHANGED;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu)
+ prop->menu->flags |= MENU_CHANGED;
+ }
+}
+
+void sym_set_all_changed(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym_set_changed(sym);
+}
+
+bool sym_tristate_within_range(struct symbol *sym, tristate val)
+{
+ int type = sym_get_type(sym);
+
+ if (sym->visible == no)
+ return false;
+
+ if (type != S_BOOLEAN && type != S_TRISTATE)
+ return false;
+
+ if (type == S_BOOLEAN && val == mod)
+ return false;
+ if (sym->visible <= sym->rev_dep.tri)
+ return false;
+ if (sym_is_choice_value(sym) && sym->visible == yes)
+ return val == yes;
+ return val >= sym->rev_dep.tri && val <= sym->visible;
+}
+
+bool sym_set_tristate_value(struct symbol *sym, tristate val)
+{
+ tristate oldval = sym_get_tristate_value(sym);
+
+ if (oldval != val && !sym_tristate_within_range(sym, val))
+ return false;
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+ sym_set_changed(sym);
+ }
+ /*
+ * setting a choice value also resets the new flag of the choice
+ * symbol and all other choice values.
+ */
+ if (sym_is_choice_value(sym) && val == yes) {
+ struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+ struct property *prop;
+ struct expr *e;
+
+ cs->def[S_DEF_USER].val = sym;
+ cs->flags |= SYMBOL_DEF_USER;
+ prop = sym_get_choice_prop(cs);
+ for (e = prop->expr; e; e = e->left.expr) {
+ if (e->right.sym->visible != no)
+ e->right.sym->flags |= SYMBOL_DEF_USER;
+ }
+ }
+
+ sym->def[S_DEF_USER].tri = val;
+ if (oldval != val)
+ sym_clear_all_valid();
+
+ return true;
+}
+
+tristate sym_toggle_tristate_value(struct symbol *sym)
+{
+ tristate oldval, newval;
+
+ oldval = newval = sym_get_tristate_value(sym);
+ do {
+ switch (newval) {
+ case no:
+ newval = mod;
+ break;
+ case mod:
+ newval = yes;
+ break;
+ case yes:
+ newval = no;
+ break;
+ }
+ if (sym_set_tristate_value(sym, newval))
+ break;
+ } while (oldval != newval);
+ return newval;
+}
+
+bool sym_string_valid(struct symbol *sym, const char *str)
+{
+ signed char ch;
+
+ switch (sym->type) {
+ case S_STRING:
+ return true;
+ case S_INT:
+ ch = *str++;
+ if (ch == '-')
+ ch = *str++;
+ if (!isdigit(ch))
+ return false;
+ if (ch == '0' && *str != 0)
+ return false;
+ while ((ch = *str++)) {
+ if (!isdigit(ch))
+ return false;
+ }
+ return true;
+ case S_HEX:
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+ str += 2;
+ ch = *str++;
+ do {
+ if (!isxdigit(ch))
+ return false;
+ } while ((ch = *str++));
+ return true;
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ case 'm': case 'M':
+ case 'n': case 'N':
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_string_within_range(struct symbol *sym, const char *str)
+{
+ struct property *prop;
+ int val;
+
+ switch (sym->type) {
+ case S_STRING:
+ return sym_string_valid(sym, str);
+ case S_INT:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtol(str, NULL, 10);
+ return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
+ val <= sym_get_range_val(prop->expr->right.sym, 10);
+ case S_HEX:
+ if (!sym_string_valid(sym, str))
+ return false;
+ prop = sym_get_range_prop(sym);
+ if (!prop)
+ return true;
+ val = strtol(str, NULL, 16);
+ return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
+ val <= sym_get_range_val(prop->expr->right.sym, 16);
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (str[0]) {
+ case 'y': case 'Y':
+ return sym_tristate_within_range(sym, yes);
+ case 'm': case 'M':
+ return sym_tristate_within_range(sym, mod);
+ case 'n': case 'N':
+ return sym_tristate_within_range(sym, no);
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool sym_set_string_value(struct symbol *sym, const char *newval)
+{
+ const char *oldval;
+ char *val;
+ int size;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (newval[0]) {
+ case 'y': case 'Y':
+ return sym_set_tristate_value(sym, yes);
+ case 'm': case 'M':
+ return sym_set_tristate_value(sym, mod);
+ case 'n': case 'N':
+ return sym_set_tristate_value(sym, no);
+ }
+ return false;
+ default:
+ ;
+ }
+
+ if (!sym_string_within_range(sym, newval))
+ return false;
+
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
+ sym_set_changed(sym);
+ }
+
+ oldval = sym->def[S_DEF_USER].val;
+ size = strlen(newval) + 1;
+ if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
+ size += 2;
+ sym->def[S_DEF_USER].val = val = malloc(size);
+ *val++ = '0';
+ *val++ = 'x';
+ } else if (!oldval || strcmp(oldval, newval))
+ sym->def[S_DEF_USER].val = val = malloc(size);
+ else
+ return true;
+
+ strcpy(val, newval);
+ free((void *)oldval);
+ sym_clear_all_valid();
+
+ return true;
+}
+
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *ds;
+ const char *str;
+ tristate val;
+
+ sym_calc_visibility(sym);
+ sym_calc_value(modules_sym);
+ val = symbol_no.curr.tri;
+ str = symbol_empty.curr.val;
+
+ /* If symbol has a default value look it up */
+ prop = sym_get_default_prop(sym);
+ if (prop != NULL) {
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /* The visibility may limit the value from yes => mod */
+ val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+ break;
+ default:
+ /*
+ * The following fails to handle the situation
+ * where a default value is further limited by
+ * the valid range.
+ */
+ ds = prop_get_symbol(prop);
+ if (ds != NULL) {
+ sym_calc_value(ds);
+ str = (const char *)ds->curr.val;
+ }
+ }
+ }
+
+ /* Handle select statements */
+ val = EXPR_OR(val, sym->rev_dep.tri);
+
+ /* transpose mod to yes if modules are not enabled */
+ if (val == mod)
+ if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+ val = yes;
+
+ /* transpose mod to yes if type is bool */
+ if (sym->type == S_BOOLEAN && val == mod)
+ val = yes;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (val) {
+ case no: return "n";
+ case mod: return "m";
+ case yes: return "y";
+ }
+ case S_INT:
+ case S_HEX:
+ return str;
+ case S_STRING:
+ return str;
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ }
+ return "";
+}
+
+const char *sym_get_string_value(struct symbol *sym)
+{
+ tristate val;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ val = sym_get_tristate_value(sym);
+ switch (val) {
+ case no:
+ return "n";
+ case mod:
+ return "m";
+ case yes:
+ return "y";
+ }
+ break;
+ default:
+ ;
+ }
+ return (const char *)sym->curr.val;
+}
+
+bool sym_is_changable(struct symbol *sym)
+{
+ return sym->visible > sym->rev_dep.tri;
+}
+
+static unsigned strhash(const char *s)
+{
+ /* fnv32 hash */
+ unsigned hash = 2166136261U;
+ for (; *s; s++)
+ hash = (hash ^ *s) * 0x01000193;
+ return hash;
+}
+
+struct symbol *sym_lookup(const char *name, int flags)
+{
+ struct symbol *symbol;
+ char *new_name;
+ int hash;
+
+ if (name) {
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ hash = strhash(name) % SYMBOL_HASHSIZE;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ (flags ? symbol->flags & flags
+ : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+ return symbol;
+ }
+ new_name = strdup(name);
+ } else {
+ new_name = NULL;
+ hash = 0;
+ }
+
+ symbol = malloc(sizeof(*symbol));
+ memset(symbol, 0, sizeof(*symbol));
+ symbol->name = new_name;
+ symbol->type = S_UNKNOWN;
+ symbol->flags |= flags;
+
+ symbol->next = symbol_hash[hash];
+ symbol_hash[hash] = symbol;
+
+ return symbol;
+}
+
+struct symbol *sym_find(const char *name)
+{
+ struct symbol *symbol = NULL;
+ int hash = 0;
+
+ if (!name)
+ return NULL;
+
+ if (name[0] && !name[1]) {
+ switch (name[0]) {
+ case 'y': return &symbol_yes;
+ case 'm': return &symbol_mod;
+ case 'n': return &symbol_no;
+ }
+ }
+ hash = strhash(name) % SYMBOL_HASHSIZE;
+
+ for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ !(symbol->flags & SYMBOL_CONST))
+ break;
+ }
+
+ return symbol;
+}
+
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+ const char *src;
+ char *res;
+ size_t reslen;
+
+ reslen = strlen(in) + 1;
+ res = malloc(reslen);
+ res[0] = '\0';
+
+ while ((src = strchr(in, '$'))) {
+ char *p, name[SYMBOL_MAXLENGTH];
+ const char *symval = "";
+ struct symbol *sym;
+ size_t newlen;
+
+ strncat(res, in, src - in);
+ src++;
+
+ p = name;
+ while (isalnum(*src) || *src == '_')
+ *p++ = *src++;
+ *p = '\0';
+
+ sym = sym_find(name);
+ if (sym != NULL) {
+ sym_calc_value(sym);
+ symval = sym_get_string_value(sym);
+ }
+
+ newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+ if (newlen > reslen) {
+ reslen = newlen;
+ res = realloc(res, reslen);
+ }
+
+ strcat(res, symval);
+ in = src;
+ }
+ strcat(res, in);
+
+ return res;
+}
+
+struct symbol **sym_re_search(const char *pattern)
+{
+ struct symbol *sym, **sym_arr = NULL;
+ int i, cnt, size;
+ regex_t re;
+
+ cnt = size = 0;
+ /* Skip if empty */
+ if (strlen(pattern) == 0)
+ return NULL;
+ if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+ return NULL;
+
+ for_all_symbols(i, sym) {
+ if (sym->flags & SYMBOL_CONST || !sym->name)
+ continue;
+ if (regexec(&re, sym->name, 0, NULL, 0))
+ continue;
+ if (cnt + 1 >= size) {
+ void *tmp = sym_arr;
+ size += 16;
+ sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
+ if (!sym_arr) {
+ free(tmp);
+ return NULL;
+ }
+ }
+ sym_calc_value(sym);
+ sym_arr[cnt++] = sym;
+ }
+ if (sym_arr)
+ sym_arr[cnt] = NULL;
+ regfree(&re);
+
+ return sym_arr;
+}
+
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note inser() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+ struct dep_stack *prev, *next;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+ memset(stack, 0, sizeof(*stack));
+ if (check_top)
+ check_top->next = stack;
+ stack->prev = check_top;
+ stack->sym = sym;
+ check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+ check_top = check_top->prev;
+ if (check_top)
+ check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+ struct dep_stack *stack;
+ struct symbol *sym, *next_sym;
+ struct menu *menu = NULL;
+ struct property *prop;
+ struct dep_stack cv_stack;
+
+ if (sym_is_choice_value(last_sym)) {
+ dep_stack_insert(&cv_stack, last_sym);
+ last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+ }
+
+ for (stack = check_top; stack != NULL; stack = stack->prev)
+ if (stack->sym == last_sym)
+ break;
+ if (!stack) {
+ fprintf(stderr, "unexpected recursive dependency error\n");
+ return;
+ }
+
+ for (; stack; stack = stack->next) {
+ sym = stack->sym;
+ next_sym = stack->next ? stack->next->sym : last_sym;
+ prop = stack->prop;
+ if (prop == NULL)
+ prop = stack->sym->prop;
+
+ /* for choice values find the menu entry (used below) */
+ if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+ for (prop = sym->prop; prop; prop = prop->next) {
+ menu = prop->menu;
+ if (prop->menu)
+ break;
+ }
+ }
+ if (stack->sym == last_sym)
+ fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+ prop->file->name, prop->lineno);
+ if (stack->expr) {
+ fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ prop_get_type_name(prop->type),
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (stack->prop) {
+ fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice(sym)) {
+ fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice_value(sym)) {
+ fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else {
+ fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ }
+ }
+
+ if (check_top == &cv_stack)
+ dep_stack_remove();
+}
+
+static struct symbol *sym_check_expr_deps(struct expr *e)
+{
+ struct symbol *sym;
+
+ if (!e)
+ return NULL;
+ switch (e->type) {
+ case E_OR:
+ case E_AND:
+ sym = sym_check_expr_deps(e->left.expr);
+ if (sym)
+ return sym;
+ return sym_check_expr_deps(e->right.expr);
+ case E_NOT:
+ return sym_check_expr_deps(e->left.expr);
+ case E_EQUAL:
+ case E_UNEQUAL:
+ sym = sym_check_deps(e->left.sym);
+ if (sym)
+ return sym;
+ return sym_check_deps(e->right.sym);
+ case E_SYMBOL:
+ return sym_check_deps(e->left.sym);
+ default:
+ break;
+ }
+ printf("Oops! How to check %d?\n", e->type);
+ return NULL;
+}
+
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, sym);
+
+ sym2 = sym_check_expr_deps(sym->rev_dep.expr);
+ if (sym2)
+ goto out;
+
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_CHOICE || prop->type == P_SELECT)
+ continue;
+ stack.prop = prop;
+ sym2 = sym_check_expr_deps(prop->visible.expr);
+ if (sym2)
+ break;
+ if (prop->type != P_DEFAULT || sym_is_choice(sym))
+ continue;
+ stack.expr = prop->expr;
+ sym2 = sym_check_expr_deps(prop->expr);
+ if (sym2)
+ break;
+ stack.expr = NULL;
+ }
+
+out:
+ dep_stack_remove();
+
+ return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+ struct symbol *sym, *sym2;
+ struct property *prop;
+ struct expr *e;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, choice);
+
+ prop = sym_get_choice_prop(choice);
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+ choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(choice);
+ choice->flags &= ~SYMBOL_CHECK;
+ if (sym2)
+ goto out;
+
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ sym2 = sym_check_sym_deps(sym);
+ if (sym2)
+ break;
+ }
+out:
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags &= ~SYMBOL_CHECK;
+
+ if (sym2 && sym_is_choice_value(sym2) &&
+ prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+ sym2 = choice;
+
+ dep_stack_remove();
+
+ return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+
+ if (sym->flags & SYMBOL_CHECK) {
+ sym_check_print_recursive(sym);
+ return sym;
+ }
+ if (sym->flags & SYMBOL_CHECKED)
+ return NULL;
+
+ if (sym_is_choice_value(sym)) {
+ struct dep_stack stack;
+
+ /* for choice groups start the check with main choice symbol */
+ dep_stack_insert(&stack, sym);
+ prop = sym_get_choice_prop(sym);
+ sym2 = sym_check_deps(prop_get_symbol(prop));
+ dep_stack_remove();
+ } else if (sym_is_choice(sym)) {
+ sym2 = sym_check_choice_deps(sym);
+ } else {
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(sym);
+ sym->flags &= ~SYMBOL_CHECK;
+ }
+
+ if (sym2 && sym2 == sym)
+ sym2 = NULL;
+
+ return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+ struct property *prop;
+ struct property **propp;
+
+ prop = malloc(sizeof(*prop));
+ memset(prop, 0, sizeof(*prop));
+ prop->type = type;
+ prop->sym = sym;
+ prop->file = current_file;
+ prop->lineno = zconf_lineno();
+
+ /* append property to the prop list of symbol */
+ if (sym) {
+ for (propp = &sym->prop; *propp; propp = &(*propp)->next)
+ ;
+ *propp = prop;
+ }
+
+ return prop;
+}
+
+struct symbol *prop_get_symbol(struct property *prop)
+{
+ if (prop->expr && (prop->expr->type == E_SYMBOL ||
+ prop->expr->type == E_LIST))
+ return prop->expr->left.sym;
+ return NULL;
+}
+
+const char *prop_get_type_name(enum prop_type type)
+{
+ switch (type) {
+ case P_PROMPT:
+ return "prompt";
+ case P_ENV:
+ return "env";
+ case P_COMMENT:
+ return "comment";
+ case P_MENU:
+ return "menu";
+ case P_DEFAULT:
+ return "default";
+ case P_CHOICE:
+ return "choice";
+ case P_SELECT:
+ return "select";
+ case P_RANGE:
+ return "range";
+ case P_SYMBOL:
+ return "symbol";
+ case P_UNKNOWN:
+ break;
+ }
+ return "unknown";
+}
+
+static void prop_add_env(const char *env)
+{
+ struct symbol *sym, *sym2;
+ struct property *prop;
+ char *p;
+
+ sym = current_entry->sym;
+ sym->flags |= SYMBOL_AUTO;
+ for_all_properties(sym, prop, P_ENV) {
+ sym2 = prop_get_symbol(prop);
+ if (strcmp(sym2->name, env))
+ menu_warn(current_entry, "redefining environment symbol from %s",
+ sym2->name);
+ return;
+ }
+
+ prop = prop_alloc(P_ENV, sym);
+ prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+ sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+ sym_env_list->right.sym = sym;
+
+ p = getenv(env);
+ if (p)
+ sym_add_default(sym, p);
+ else
+ menu_warn(current_entry, "environment variable %s undefined", env);
+}
--- /dev/null
+/*
+ * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <string.h>
+#include "lkc.h"
+
+/* file already present in list? If not add it */
+struct file *file_lookup(const char *name)
+{
+ struct file *file;
+ const char *file_name = sym_expand_string_value(name);
+
+ for (file = file_list; file; file = file->next) {
+ if (!strcmp(name, file->name)) {
+ free((void *)file_name);
+ return file;
+ }
+ }
+
+ file = malloc(sizeof(*file));
+ memset(file, 0, sizeof(*file));
+ file->name = file_name;
+ file->next = file_list;
+ file_list = file;
+ return file;
+}
+
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+ struct symbol *sym, *env_sym;
+ struct expr *e;
+ struct file *file;
+ FILE *out;
+
+ if (!name)
+ name = ".kconfig.d";
+ out = fopen("..config.tmp", "w");
+ if (!out)
+ return 1;
+ fprintf(out, "deps_config := \\\n");
+ for (file = file_list; file; file = file->next) {
+ if (file->next)
+ fprintf(out, "\t%s \\\n", file->name);
+ else
+ fprintf(out, "\t%s\n", file->name);
+ }
+ fprintf(out, "\n%s: \\\n"
+ "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+ expr_list_for_each_sym(sym_env_list, e, sym) {
+ struct property *prop;
+ const char *value;
+
+ prop = sym_get_env_prop(sym);
+ env_sym = prop_get_symbol(prop);
+ if (!env_sym)
+ continue;
+ value = getenv(env_sym->name);
+ if (!value)
+ value = "";
+ fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+ fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
+ fprintf(out, "endif\n");
+ }
+
+ fprintf(out, "\n$(deps_config): ;\n");
+ fclose(out);
+ rename("..config.tmp", name);
+ return 0;
+}
+
+
+/* Allocate initial growable string */
+struct gstr str_new(void)
+{
+ struct gstr gs;
+ gs.s = malloc(sizeof(char) * 64);
+ gs.len = 64;
+ gs.max_width = 0;
+ strcpy(gs.s, "\0");
+ return gs;
+}
+
+/* Allocate and assign growable string */
+struct gstr str_assign(const char *s)
+{
+ struct gstr gs;
+ gs.s = strdup(s);
+ gs.len = strlen(s) + 1;
+ gs.max_width = 0;
+ return gs;
+}
+
+/* Free storage for growable string */
+void str_free(struct gstr *gs)
+{
+ if (gs->s)
+ free(gs->s);
+ gs->s = NULL;
+ gs->len = 0;
+}
+
+/* Append to growable string */
+void str_append(struct gstr *gs, const char *s)
+{
+ size_t l;
+ if (s) {
+ l = strlen(gs->s) + strlen(s) + 1;
+ if (l > gs->len) {
+ gs->s = realloc(gs->s, l);
+ gs->len = l;
+ }
+ strcat(gs->s, s);
+ }
+}
+
+/* Append printf formatted string to growable string */
+void str_printf(struct gstr *gs, const char *fmt, ...)
+{
+ va_list ap;
+ char s[10000]; /* big enough... */
+ va_start(ap, fmt);
+ vsnprintf(s, sizeof(s), fmt, ap);
+ str_append(gs, s);
+ va_end(ap);
+}
+
+/* Retrieve value of growable string */
+const char *str_get(struct gstr *gs)
+{
+ return gs->s;
+}
+
--- /dev/null
+%language=ANSI-C
+%define hash-function-name kconf_id_hash
+%define lookup-function-name kconf_id_lookup
+%define string-pool-name kconf_id_strings
+%compare-strncmp
+%enum
+%pic
+%struct-type
+
+struct kconf_id;
+
+static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+
+%%
+mainmenu, T_MAINMENU, TF_COMMAND
+menu, T_MENU, TF_COMMAND
+endmenu, T_ENDMENU, TF_COMMAND
+source, T_SOURCE, TF_COMMAND
+choice, T_CHOICE, TF_COMMAND
+endchoice, T_ENDCHOICE, TF_COMMAND
+comment, T_COMMENT, TF_COMMAND
+config, T_CONFIG, TF_COMMAND
+menuconfig, T_MENUCONFIG, TF_COMMAND
+help, T_HELP, TF_COMMAND
+if, T_IF, TF_COMMAND|TF_PARAM
+endif, T_ENDIF, TF_COMMAND
+depends, T_DEPENDS, TF_COMMAND
+optional, T_OPTIONAL, TF_COMMAND
+default, T_DEFAULT, TF_COMMAND, S_UNKNOWN
+prompt, T_PROMPT, TF_COMMAND
+tristate, T_TYPE, TF_COMMAND, S_TRISTATE
+def_tristate, T_DEFAULT, TF_COMMAND, S_TRISTATE
+bool, T_TYPE, TF_COMMAND, S_BOOLEAN
+boolean, T_TYPE, TF_COMMAND, S_BOOLEAN
+def_bool, T_DEFAULT, TF_COMMAND, S_BOOLEAN
+int, T_TYPE, TF_COMMAND, S_INT
+hex, T_TYPE, TF_COMMAND, S_HEX
+string, T_TYPE, TF_COMMAND, S_STRING
+select, T_SELECT, TF_COMMAND
+range, T_RANGE, TF_COMMAND
+visible, T_VISIBLE, TF_COMMAND
+option, T_OPTION, TF_COMMAND
+on, T_ON, TF_PARAM
+modules, T_OPT_MODULES, TF_OPTION
+defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION
+env, T_OPT_ENV, TF_OPTION
+%%
--- /dev/null
+/* ANSI-C code produced by gperf version 3.0.3 */
+/* Command-line: gperf */
+/* Computed positions: -k'1,3' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+struct kconf_id;
+
+static struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+/* maximum key range = 50, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+kconf_id_hash (register const char *str, register unsigned int len)
+{
+ static unsigned char asso_values[] =
+ {
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 40, 5,
+ 0, 0, 5, 52, 0, 20, 52, 52, 10, 20,
+ 5, 0, 35, 52, 0, 30, 0, 15, 0, 52,
+ 15, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval;
+}
+
+struct kconf_id_strings_t
+ {
+ char kconf_id_strings_str2[sizeof("on")];
+ char kconf_id_strings_str3[sizeof("env")];
+ char kconf_id_strings_str5[sizeof("endif")];
+ char kconf_id_strings_str6[sizeof("option")];
+ char kconf_id_strings_str7[sizeof("endmenu")];
+ char kconf_id_strings_str8[sizeof("optional")];
+ char kconf_id_strings_str9[sizeof("endchoice")];
+ char kconf_id_strings_str10[sizeof("range")];
+ char kconf_id_strings_str11[sizeof("choice")];
+ char kconf_id_strings_str12[sizeof("default")];
+ char kconf_id_strings_str13[sizeof("def_bool")];
+ char kconf_id_strings_str14[sizeof("help")];
+ char kconf_id_strings_str16[sizeof("config")];
+ char kconf_id_strings_str17[sizeof("def_tristate")];
+ char kconf_id_strings_str18[sizeof("hex")];
+ char kconf_id_strings_str19[sizeof("defconfig_list")];
+ char kconf_id_strings_str22[sizeof("if")];
+ char kconf_id_strings_str23[sizeof("int")];
+ char kconf_id_strings_str27[sizeof("modules")];
+ char kconf_id_strings_str28[sizeof("tristate")];
+ char kconf_id_strings_str29[sizeof("menu")];
+ char kconf_id_strings_str32[sizeof("comment")];
+ char kconf_id_strings_str35[sizeof("menuconfig")];
+ char kconf_id_strings_str36[sizeof("string")];
+ char kconf_id_strings_str37[sizeof("visible")];
+ char kconf_id_strings_str41[sizeof("prompt")];
+ char kconf_id_strings_str42[sizeof("depends")];
+ char kconf_id_strings_str44[sizeof("bool")];
+ char kconf_id_strings_str46[sizeof("select")];
+ char kconf_id_strings_str47[sizeof("boolean")];
+ char kconf_id_strings_str48[sizeof("mainmenu")];
+ char kconf_id_strings_str51[sizeof("source")];
+ };
+static struct kconf_id_strings_t kconf_id_strings_contents =
+ {
+ "on",
+ "env",
+ "endif",
+ "option",
+ "endmenu",
+ "optional",
+ "endchoice",
+ "range",
+ "choice",
+ "default",
+ "def_bool",
+ "help",
+ "config",
+ "def_tristate",
+ "hex",
+ "defconfig_list",
+ "if",
+ "int",
+ "modules",
+ "tristate",
+ "menu",
+ "comment",
+ "menuconfig",
+ "string",
+ "visible",
+ "prompt",
+ "depends",
+ "bool",
+ "select",
+ "boolean",
+ "mainmenu",
+ "source"
+ };
+#define kconf_id_strings ((const char *) &kconf_id_strings_contents)
+#ifdef __GNUC__
+__inline
+#ifdef __GNUC_STDC_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
+#endif
+struct kconf_id *
+kconf_id_lookup (register const char *str, register unsigned int len)
+{
+ enum
+ {
+ TOTAL_KEYWORDS = 32,
+ MIN_WORD_LENGTH = 2,
+ MAX_WORD_LENGTH = 14,
+ MIN_HASH_VALUE = 2,
+ MAX_HASH_VALUE = 51
+ };
+
+ static struct kconf_id wordlist[] =
+ {
+ {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_ON, TF_PARAM},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_OPT_ENV, TF_OPTION},
+ {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_OPTION, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_OPTIONAL, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_CHOICE, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_HELP, TF_COMMAND},
+ {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_CONFIG, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_HEX},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19, T_OPT_DEFCONFIG_LIST,TF_OPTION},
+ {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_IF, TF_COMMAND|TF_PARAM},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_INT},
+ {-1}, {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_TYPE, TF_COMMAND, S_TRISTATE},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND},
+ {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
+ {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_TYPE, TF_COMMAND, S_STRING},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_VISIBLE, TF_COMMAND},
+ {-1}, {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_PROMPT, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_DEPENDS, TF_COMMAND},
+ {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_SELECT, TF_COMMAND},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND},
+ {-1}, {-1},
+ {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_SOURCE, TF_COMMAND}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = kconf_id_hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ {
+ register int o = wordlist[key].name;
+ if (o >= 0)
+ {
+ register const char *s = o + kconf_id_strings;
+
+ if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+ return &wordlist[key];
+ }
+ }
+ }
+ return 0;
+}
+
--- /dev/null
+%option backup nostdinit noyywrap never-interactive full ecs
+%option 8bit backup nodefault perf-report perf-report
+%option noinput
+%x COMMAND HELP STRING PARAM
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define START_STRSIZE 16
+
+static struct {
+ struct file *file;
+ int lineno;
+} current_pos;
+
+static char *text;
+static int text_size, text_asize;
+
+struct buffer {
+ struct buffer *parent;
+ YY_BUFFER_STATE state;
+};
+
+struct buffer *current_buf;
+
+static int last_ts, first_ts;
+
+static void zconf_endhelp(void);
+static void zconf_endfile(void);
+
+static void new_string(void)
+{
+ text = malloc(START_STRSIZE);
+ text_asize = START_STRSIZE;
+ text_size = 0;
+ *text = 0;
+}
+
+static void append_string(const char *str, int size)
+{
+ int new_size = text_size + size + 1;
+ if (new_size > text_asize) {
+ new_size += START_STRSIZE - 1;
+ new_size &= -START_STRSIZE;
+ text = realloc(text, new_size);
+ text_asize = new_size;
+ }
+ memcpy(text + text_size, str, size);
+ text_size += size;
+ text[text_size] = 0;
+}
+
+static void alloc_string(const char *str, int size)
+{
+ text = malloc(size + 1);
+ memcpy(text, str, size);
+ text[size] = 0;
+}
+%}
+
+ws [ \n\t]
+n [A-Za-z0-9_]
+
+%%
+ int str = 0;
+ int ts, i;
+
+[ \t]*#.*\n |
+[ \t]*\n {
+ current_file->lineno++;
+ return T_EOL;
+}
+[ \t]*#.*
+
+
+[ \t]+ {
+ BEGIN(COMMAND);
+}
+
+. {
+ unput(yytext[0]);
+ BEGIN(COMMAND);
+}
+
+
+<COMMAND>{
+ {n}+ {
+ struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+ BEGIN(PARAM);
+ current_pos.file = current_file;
+ current_pos.lineno = current_file->lineno;
+ if (id && id->flags & TF_COMMAND) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ .
+ \n {
+ BEGIN(INITIAL);
+ current_file->lineno++;
+ return T_EOL;
+ }
+}
+
+<PARAM>{
+ "&&" return T_AND;
+ "||" return T_OR;
+ "(" return T_OPEN_PAREN;
+ ")" return T_CLOSE_PAREN;
+ "!" return T_NOT;
+ "=" return T_EQUAL;
+ "!=" return T_UNEQUAL;
+ \"|\' {
+ str = yytext[0];
+ new_string();
+ BEGIN(STRING);
+ }
+ \n BEGIN(INITIAL); current_file->lineno++; return T_EOL;
+ --- /* ignore */
+ ({n}|[-/.])+ {
+ struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+ if (id && id->flags & TF_PARAM) {
+ zconflval.id = id;
+ return id->token;
+ }
+ alloc_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD;
+ }
+ #.* /* comment */
+ \\\n current_file->lineno++;
+ .
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<STRING>{
+ [^'"\\\n]+/\n {
+ append_string(yytext, yyleng);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ [^'"\\\n]+ {
+ append_string(yytext, yyleng);
+ }
+ \\.?/\n {
+ append_string(yytext + 1, yyleng - 1);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ }
+ \\.? {
+ append_string(yytext + 1, yyleng - 1);
+ }
+ \'|\" {
+ if (str == yytext[0]) {
+ BEGIN(PARAM);
+ zconflval.string = text;
+ return T_WORD_QUOTE;
+ } else
+ append_string(yytext, 1);
+ }
+ \n {
+ printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+ current_file->lineno++;
+ BEGIN(INITIAL);
+ return T_EOL;
+ }
+ <<EOF>> {
+ BEGIN(INITIAL);
+ }
+}
+
+<HELP>{
+ [ \t]+ {
+ ts = 0;
+ for (i = 0; i < yyleng; i++) {
+ if (yytext[i] == '\t')
+ ts = (ts & ~7) + 8;
+ else
+ ts++;
+ }
+ last_ts = ts;
+ if (first_ts) {
+ if (ts < first_ts) {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ ts -= first_ts;
+ while (ts > 8) {
+ append_string(" ", 8);
+ ts -= 8;
+ }
+ append_string(" ", ts);
+ }
+ }
+ [ \t]*\n/[^ \t\n] {
+ current_file->lineno++;
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+ [ \t]*\n {
+ current_file->lineno++;
+ append_string("\n", 1);
+ }
+ [^ \t\n].* {
+ while (yyleng) {
+ if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+ break;
+ yyleng--;
+ }
+ append_string(yytext, yyleng);
+ if (!first_ts)
+ first_ts = last_ts;
+ }
+ <<EOF>> {
+ zconf_endhelp();
+ return T_HELPTEXT;
+ }
+}
+
+<<EOF>> {
+ if (current_file) {
+ zconf_endfile();
+ return T_EOL;
+ }
+ fclose(yyin);
+ yyterminate();
+}
+
+%%
+void zconf_starthelp(void)
+{
+ new_string();
+ last_ts = first_ts = 0;
+ BEGIN(HELP);
+}
+
+static void zconf_endhelp(void)
+{
+ zconflval.string = text;
+ BEGIN(INITIAL);
+}
+
+
+/*
+ * Try to open specified file with following names:
+ * ./name
+ * $(srctree)/name
+ * The latter is used when srctree is separate from objtree
+ * when compiling the kernel.
+ * Return NULL if file is not found.
+ */
+FILE *zconf_fopen(const char *name)
+{
+ char *env, fullname[PATH_MAX+1];
+ FILE *f;
+
+ f = fopen(name, "r");
+ if (!f && name != NULL && name[0] != '/') {
+ env = getenv(SRCTREE);
+ if (env) {
+ sprintf(fullname, "%s/%s", env, name);
+ f = fopen(fullname, "r");
+ }
+ }
+ return f;
+}
+
+void zconf_initscan(const char *name)
+{
+ yyin = zconf_fopen(name);
+ if (!yyin) {
+ printf("can't find file %s\n", name);
+ exit(1);
+ }
+
+ current_buf = malloc(sizeof(*current_buf));
+ memset(current_buf, 0, sizeof(*current_buf));
+
+ current_file = file_lookup(name);
+ current_file->lineno = 1;
+ current_file->flags = FILE_BUSY;
+}
+
+void zconf_nextfile(const char *name)
+{
+ struct file *file = file_lookup(name);
+ struct buffer *buf = malloc(sizeof(*buf));
+ memset(buf, 0, sizeof(*buf));
+
+ current_buf->state = YY_CURRENT_BUFFER;
+ yyin = zconf_fopen(file->name);
+ if (!yyin) {
+ printf("%s:%d: can't open file \"%s\"\n",
+ zconf_curname(), zconf_lineno(), file->name);
+ exit(1);
+ }
+ yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+ buf->parent = current_buf;
+ current_buf = buf;
+
+ if (file->flags & FILE_BUSY) {
+ printf("%s:%d: do not source '%s' from itself\n",
+ zconf_curname(), zconf_lineno(), name);
+ exit(1);
+ }
+ if (file->flags & FILE_SCANNED) {
+ printf("%s:%d: file '%s' is already sourced from '%s'\n",
+ zconf_curname(), zconf_lineno(), name,
+ file->parent->name);
+ exit(1);
+ }
+ file->flags |= FILE_BUSY;
+ file->lineno = 1;
+ file->parent = current_file;
+ current_file = file;
+}
+
+static void zconf_endfile(void)
+{
+ struct buffer *parent;
+
+ current_file->flags |= FILE_SCANNED;
+ current_file->flags &= ~FILE_BUSY;
+ current_file = current_file->parent;
+
+ parent = current_buf->parent;
+ if (parent) {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(parent->state);
+ }
+ free(current_buf);
+ current_buf = parent;
+}
+
+int zconf_lineno(void)
+{
+ return current_pos.lineno;
+}
+
+const char *zconf_curname(void)
+{
+ return current_pos.file ? current_pos.file->name : "<none>";
+}
--- /dev/null
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ 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/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.4.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+/* Substitute the variable and function names. */
+#define yyparse zconfparse
+#define yylex zconflex
+#define yyerror zconferror
+#define yylval zconflval
+#define yychar zconfchar
+#define yydebug zconfdebug
+#define yynerrs zconfnerrs
+
+
+/* Copy the first part of user declarations. */
+
+
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ T_MAINMENU = 258,
+ T_MENU = 259,
+ T_ENDMENU = 260,
+ T_SOURCE = 261,
+ T_CHOICE = 262,
+ T_ENDCHOICE = 263,
+ T_COMMENT = 264,
+ T_CONFIG = 265,
+ T_MENUCONFIG = 266,
+ T_HELP = 267,
+ T_HELPTEXT = 268,
+ T_IF = 269,
+ T_ENDIF = 270,
+ T_DEPENDS = 271,
+ T_OPTIONAL = 272,
+ T_PROMPT = 273,
+ T_TYPE = 274,
+ T_DEFAULT = 275,
+ T_SELECT = 276,
+ T_RANGE = 277,
+ T_VISIBLE = 278,
+ T_OPTION = 279,
+ T_ON = 280,
+ T_WORD = 281,
+ T_WORD_QUOTE = 282,
+ T_UNEQUAL = 283,
+ T_CLOSE_PAREN = 284,
+ T_OPEN_PAREN = 285,
+ T_EOL = 286,
+ T_OR = 287,
+ T_AND = 288,
+ T_EQUAL = 289,
+ T_NOT = 290
+ };
+#endif
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+
+ char *string;
+ struct file *file;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ struct kconf_id *id;
+
+
+
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 11
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 290
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 36
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 50
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 118
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 191
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 290
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 6, 8, 11, 13, 14, 17, 20,
+ 23, 26, 31, 36, 40, 42, 44, 46, 48, 50,
+ 52, 54, 56, 58, 60, 62, 64, 66, 68, 72,
+ 75, 79, 82, 86, 89, 90, 93, 96, 99, 102,
+ 105, 108, 112, 117, 122, 127, 133, 137, 138, 142,
+ 143, 146, 150, 153, 155, 159, 160, 163, 166, 169,
+ 172, 175, 180, 184, 187, 192, 193, 196, 200, 202,
+ 206, 207, 210, 213, 216, 220, 224, 228, 230, 234,
+ 235, 238, 241, 244, 248, 252, 255, 258, 261, 262,
+ 265, 268, 271, 276, 277, 280, 283, 286, 287, 290,
+ 292, 294, 297, 300, 303, 305, 308, 309, 312, 314,
+ 318, 322, 326, 329, 333, 337, 339, 341, 342
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 37, 0, -1, 81, 38, -1, 38, -1, 63, 39,
+ -1, 39, -1, -1, 39, 41, -1, 39, 55, -1,
+ 39, 67, -1, 39, 80, -1, 39, 26, 1, 31,
+ -1, 39, 40, 1, 31, -1, 39, 1, 31, -1,
+ 16, -1, 18, -1, 19, -1, 21, -1, 17, -1,
+ 22, -1, 20, -1, 23, -1, 31, -1, 61, -1,
+ 71, -1, 44, -1, 46, -1, 69, -1, 26, 1,
+ 31, -1, 1, 31, -1, 10, 26, 31, -1, 43,
+ 47, -1, 11, 26, 31, -1, 45, 47, -1, -1,
+ 47, 48, -1, 47, 49, -1, 47, 75, -1, 47,
+ 73, -1, 47, 42, -1, 47, 31, -1, 19, 78,
+ 31, -1, 18, 79, 82, 31, -1, 20, 83, 82,
+ 31, -1, 21, 26, 82, 31, -1, 22, 84, 84,
+ 82, 31, -1, 24, 50, 31, -1, -1, 50, 26,
+ 51, -1, -1, 34, 79, -1, 7, 85, 31, -1,
+ 52, 56, -1, 80, -1, 53, 58, 54, -1, -1,
+ 56, 57, -1, 56, 75, -1, 56, 73, -1, 56,
+ 31, -1, 56, 42, -1, 18, 79, 82, 31, -1,
+ 19, 78, 31, -1, 17, 31, -1, 20, 26, 82,
+ 31, -1, -1, 58, 41, -1, 14, 83, 81, -1,
+ 80, -1, 59, 62, 60, -1, -1, 62, 41, -1,
+ 62, 67, -1, 62, 55, -1, 3, 79, 81, -1,
+ 4, 79, 31, -1, 64, 76, 74, -1, 80, -1,
+ 65, 68, 66, -1, -1, 68, 41, -1, 68, 67,
+ -1, 68, 55, -1, 6, 79, 31, -1, 9, 79,
+ 31, -1, 70, 74, -1, 12, 31, -1, 72, 13,
+ -1, -1, 74, 75, -1, 74, 31, -1, 74, 42,
+ -1, 16, 25, 83, 31, -1, -1, 76, 77, -1,
+ 76, 31, -1, 23, 82, -1, -1, 79, 82, -1,
+ 26, -1, 27, -1, 5, 31, -1, 8, 31, -1,
+ 15, 31, -1, 31, -1, 81, 31, -1, -1, 14,
+ 83, -1, 84, -1, 84, 34, 84, -1, 84, 28,
+ 84, -1, 30, 83, 29, -1, 35, 83, -1, 83,
+ 32, 83, -1, 83, 33, 83, -1, 26, -1, 27,
+ -1, -1, 26, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 108, 108, 108, 110, 110, 112, 114, 115, 116,
+ 117, 118, 119, 123, 127, 127, 127, 127, 127, 127,
+ 127, 127, 131, 132, 133, 134, 135, 136, 140, 141,
+ 147, 155, 161, 169, 179, 181, 182, 183, 184, 185,
+ 186, 189, 197, 203, 213, 219, 225, 228, 230, 241,
+ 242, 247, 256, 261, 269, 272, 274, 275, 276, 277,
+ 278, 281, 287, 298, 304, 314, 316, 321, 329, 337,
+ 340, 342, 343, 344, 349, 356, 363, 368, 376, 379,
+ 381, 382, 383, 386, 394, 401, 408, 414, 421, 423,
+ 424, 425, 428, 436, 438, 439, 442, 449, 451, 456,
+ 457, 460, 461, 462, 466, 467, 470, 471, 474, 475,
+ 476, 477, 478, 479, 480, 483, 484, 487, 488
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
+ "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
+ "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
+ "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE",
+ "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL",
+ "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL",
+ "T_NOT", "$accept", "input", "start", "stmt_list", "option_name",
+ "common_stmt", "option_error", "config_entry_start", "config_stmt",
+ "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
+ "config_option", "symbol_option", "symbol_option_list",
+ "symbol_option_arg", "choice", "choice_entry", "choice_end",
+ "choice_stmt", "choice_option_list", "choice_option", "choice_block",
+ "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu",
+ "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt",
+ "comment", "comment_stmt", "help_start", "help", "depends_list",
+ "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt",
+ "end", "nl", "if_expr", "expr", "symbol", "word_opt", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 36, 37, 37, 38, 38, 39, 39, 39, 39,
+ 39, 39, 39, 39, 40, 40, 40, 40, 40, 40,
+ 40, 40, 41, 41, 41, 41, 41, 41, 42, 42,
+ 43, 44, 45, 46, 47, 47, 47, 47, 47, 47,
+ 47, 48, 48, 48, 48, 48, 49, 50, 50, 51,
+ 51, 52, 53, 54, 55, 56, 56, 56, 56, 56,
+ 56, 57, 57, 57, 57, 58, 58, 59, 60, 61,
+ 62, 62, 62, 62, 63, 64, 65, 66, 67, 68,
+ 68, 68, 68, 69, 70, 71, 72, 73, 74, 74,
+ 74, 74, 75, 76, 76, 76, 77, 78, 78, 79,
+ 79, 80, 80, 80, 81, 81, 82, 82, 83, 83,
+ 83, 83, 83, 83, 83, 84, 84, 85, 85
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 2, 1, 2, 1, 0, 2, 2, 2,
+ 2, 4, 4, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 3, 2,
+ 3, 2, 3, 2, 0, 2, 2, 2, 2, 2,
+ 2, 3, 4, 4, 4, 5, 3, 0, 3, 0,
+ 2, 3, 2, 1, 3, 0, 2, 2, 2, 2,
+ 2, 4, 3, 2, 4, 0, 2, 3, 1, 3,
+ 0, 2, 2, 2, 3, 3, 3, 1, 3, 0,
+ 2, 2, 2, 3, 3, 2, 2, 2, 0, 2,
+ 2, 2, 4, 0, 2, 2, 2, 0, 2, 1,
+ 1, 2, 2, 2, 1, 2, 0, 2, 1, 3,
+ 3, 3, 2, 3, 3, 1, 1, 0, 1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 6, 0, 104, 0, 3, 0, 6, 6, 99, 100,
+ 0, 1, 0, 0, 0, 0, 117, 0, 0, 0,
+ 0, 0, 0, 14, 18, 15, 16, 20, 17, 19,
+ 21, 0, 22, 0, 7, 34, 25, 34, 26, 55,
+ 65, 8, 70, 23, 93, 79, 9, 27, 88, 24,
+ 10, 0, 105, 2, 74, 13, 0, 101, 0, 118,
+ 0, 102, 0, 0, 0, 115, 116, 0, 0, 0,
+ 108, 103, 0, 0, 0, 0, 0, 0, 0, 88,
+ 0, 0, 75, 83, 51, 84, 30, 32, 0, 112,
+ 0, 0, 67, 0, 0, 11, 12, 0, 0, 0,
+ 0, 97, 0, 0, 0, 47, 0, 40, 39, 35,
+ 36, 0, 38, 37, 0, 0, 97, 0, 59, 60,
+ 56, 58, 57, 66, 54, 53, 71, 73, 69, 72,
+ 68, 106, 95, 0, 94, 80, 82, 78, 81, 77,
+ 90, 91, 89, 111, 113, 114, 110, 109, 29, 86,
+ 0, 106, 0, 106, 106, 106, 0, 0, 0, 87,
+ 63, 106, 0, 106, 0, 96, 0, 0, 41, 98,
+ 0, 0, 106, 49, 46, 28, 0, 62, 0, 107,
+ 92, 42, 43, 44, 0, 0, 48, 61, 64, 45,
+ 50
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 3, 4, 5, 33, 34, 108, 35, 36, 37,
+ 38, 74, 109, 110, 157, 186, 39, 40, 124, 41,
+ 76, 120, 77, 42, 128, 43, 78, 6, 44, 45,
+ 137, 46, 80, 47, 48, 49, 111, 112, 81, 113,
+ 79, 134, 152, 153, 50, 7, 165, 69, 70, 60
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -90
+static const yytype_int16 yypact[] =
+{
+ 4, 42, -90, 96, -90, 111, -90, 15, -90, -90,
+ 75, -90, 82, 42, 104, 42, 110, 107, 42, 115,
+ 125, -4, 121, -90, -90, -90, -90, -90, -90, -90,
+ -90, 162, -90, 163, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, 139, -90, -90, 138, -90, 142, -90, 143, -90,
+ 152, -90, 164, 167, 168, -90, -90, -4, -4, 77,
+ -18, -90, 177, 185, 33, 71, 195, 247, 236, -2,
+ 236, 171, -90, -90, -90, -90, -90, -90, 41, -90,
+ -4, -4, 138, 97, 97, -90, -90, 186, 187, 194,
+ 42, 42, -4, 196, 97, -90, 219, -90, -90, -90,
+ -90, 210, -90, -90, 204, 42, 42, 199, -90, -90,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, 222, -90, 223, -90, -90, -90, -90, -90, -90,
+ -90, -90, -90, -90, 215, -90, -90, -90, -90, -90,
+ -4, 222, 228, 222, -5, 222, 97, 35, 229, -90,
+ -90, 222, 232, 222, -4, -90, 135, 233, -90, -90,
+ 234, 235, 222, 240, -90, -90, 237, -90, 239, -13,
+ -90, -90, -90, -90, 244, 42, -90, -90, -90, -90,
+ -90
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -90, -90, 269, 271, -90, 23, -70, -90, -90, -90,
+ -90, 243, -90, -90, -90, -90, -90, -90, -90, -48,
+ -90, -90, -90, -90, -90, -90, -90, -90, -90, -90,
+ -90, -20, -90, -90, -90, -90, -90, 206, 205, -68,
+ -90, -90, 169, -1, 27, -7, 118, -66, -89, -90
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -86
+static const yytype_int16 yytable[] =
+{
+ 10, 88, 89, 54, 146, 147, 119, 1, 122, 164,
+ 93, 141, 56, 142, 58, 156, 94, 62, 1, 90,
+ 91, 131, 65, 66, 144, 145, 67, 90, 91, 132,
+ 127, 68, 136, -31, 97, 2, 154, -31, -31, -31,
+ -31, -31, -31, -31, -31, 98, 52, -31, -31, 99,
+ -31, 100, 101, 102, 103, 104, -31, 105, 129, 106,
+ 138, 173, 92, 141, 107, 142, 174, 172, 8, 9,
+ 143, -33, 97, 90, 91, -33, -33, -33, -33, -33,
+ -33, -33, -33, 98, 166, -33, -33, 99, -33, 100,
+ 101, 102, 103, 104, -33, 105, 11, 106, 179, 151,
+ 123, 126, 107, 135, 125, 130, 2, 139, 2, 90,
+ 91, -5, 12, 55, 161, 13, 14, 15, 16, 17,
+ 18, 19, 20, 65, 66, 21, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 57, 59, 31, 61, -4,
+ 12, 63, 32, 13, 14, 15, 16, 17, 18, 19,
+ 20, 64, 71, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 72, 73, 31, 180, 90, 91, 52,
+ 32, -85, 97, 82, 83, -85, -85, -85, -85, -85,
+ -85, -85, -85, 84, 190, -85, -85, 99, -85, -85,
+ -85, -85, -85, -85, -85, 85, 97, 106, 86, 87,
+ -52, -52, 140, -52, -52, -52, -52, 98, 95, -52,
+ -52, 99, 114, 115, 116, 117, 96, 148, 149, 150,
+ 158, 106, 155, 159, 97, 163, 118, -76, -76, -76,
+ -76, -76, -76, -76, -76, 160, 164, -76, -76, 99,
+ 13, 14, 15, 16, 17, 18, 19, 20, 91, 106,
+ 21, 22, 14, 15, 140, 17, 18, 19, 20, 168,
+ 175, 21, 22, 177, 181, 182, 183, 32, 187, 167,
+ 188, 169, 170, 171, 185, 189, 53, 51, 32, 176,
+ 75, 178, 121, 0, 133, 162, 0, 0, 0, 0,
+ 184
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 1, 67, 68, 10, 93, 94, 76, 3, 76, 14,
+ 28, 81, 13, 81, 15, 104, 34, 18, 3, 32,
+ 33, 23, 26, 27, 90, 91, 30, 32, 33, 31,
+ 78, 35, 80, 0, 1, 31, 102, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 31, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 78, 26,
+ 80, 26, 69, 133, 31, 133, 31, 156, 26, 27,
+ 29, 0, 1, 32, 33, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 150, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 0, 26, 164, 100,
+ 77, 78, 31, 80, 77, 78, 31, 80, 31, 32,
+ 33, 0, 1, 31, 115, 4, 5, 6, 7, 8,
+ 9, 10, 11, 26, 27, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 31, 26, 26, 31, 0,
+ 1, 26, 31, 4, 5, 6, 7, 8, 9, 10,
+ 11, 26, 31, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 1, 1, 26, 31, 32, 33, 31,
+ 31, 0, 1, 31, 31, 4, 5, 6, 7, 8,
+ 9, 10, 11, 31, 185, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 31, 1, 26, 31, 31,
+ 5, 6, 31, 8, 9, 10, 11, 12, 31, 14,
+ 15, 16, 17, 18, 19, 20, 31, 31, 31, 25,
+ 1, 26, 26, 13, 1, 26, 31, 4, 5, 6,
+ 7, 8, 9, 10, 11, 31, 14, 14, 15, 16,
+ 4, 5, 6, 7, 8, 9, 10, 11, 33, 26,
+ 14, 15, 5, 6, 31, 8, 9, 10, 11, 31,
+ 31, 14, 15, 31, 31, 31, 31, 31, 31, 151,
+ 31, 153, 154, 155, 34, 31, 7, 6, 31, 161,
+ 37, 163, 76, -1, 79, 116, -1, -1, -1, -1,
+ 172
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 31, 37, 38, 39, 63, 81, 26, 27,
+ 79, 0, 1, 4, 5, 6, 7, 8, 9, 10,
+ 11, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 26, 31, 40, 41, 43, 44, 45, 46, 52,
+ 53, 55, 59, 61, 64, 65, 67, 69, 70, 71,
+ 80, 39, 31, 38, 81, 31, 79, 31, 79, 26,
+ 85, 31, 79, 26, 26, 26, 27, 30, 35, 83,
+ 84, 31, 1, 1, 47, 47, 56, 58, 62, 76,
+ 68, 74, 31, 31, 31, 31, 31, 31, 83, 83,
+ 32, 33, 81, 28, 34, 31, 31, 1, 12, 16,
+ 18, 19, 20, 21, 22, 24, 26, 31, 42, 48,
+ 49, 72, 73, 75, 17, 18, 19, 20, 31, 42,
+ 57, 73, 75, 41, 54, 80, 41, 55, 60, 67,
+ 80, 23, 31, 74, 77, 41, 55, 66, 67, 80,
+ 31, 42, 75, 29, 83, 83, 84, 84, 31, 31,
+ 25, 79, 78, 79, 83, 26, 84, 50, 1, 13,
+ 31, 79, 78, 26, 14, 82, 83, 82, 31, 82,
+ 82, 82, 84, 26, 31, 31, 82, 31, 82, 83,
+ 31, 31, 31, 31, 82, 34, 51, 31, 31, 31,
+ 79
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+\f
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+\f
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+ case 53: /* "choice_entry" */
+
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+
+ break;
+ case 59: /* "if_entry" */
+
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+
+ break;
+ case 65: /* "menu_entry" */
+
+ {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno);
+ if (current_menu == (yyvaluep->menu))
+ menu_end_menu();
+};
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Prevent warnings from -Wmissing-prototypes. */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 10:
+
+ { zconf_error("unexpected end statement"); ;}
+ break;
+
+ case 11:
+
+ { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;}
+ break;
+
+ case 12:
+
+ {
+ zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
+;}
+ break;
+
+ case 13:
+
+ { zconf_error("invalid statement"); ;}
+ break;
+
+ case 28:
+
+ { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;}
+ break;
+
+ case 29:
+
+ { zconf_error("invalid option"); ;}
+ break;
+
+ case 30:
+
+ {
+ struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+ break;
+
+ case 31:
+
+ {
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 32:
+
+ {
+ struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+;}
+ break;
+
+ case 33:
+
+ {
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconfprint("warning: menuconfig statement without prompt");
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 41:
+
+ {
+ menu_set_type((yyvsp[(1) - (3)].id)->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ (yyvsp[(1) - (3)].id)->stype);
+;}
+ break;
+
+ case 42:
+
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 43:
+
+ {
+ menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr));
+ if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN)
+ menu_set_type((yyvsp[(1) - (4)].id)->stype);
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ (yyvsp[(1) - (4)].id)->stype);
+;}
+ break;
+
+ case 44:
+
+ {
+ menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 45:
+
+ {
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
+ printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 48:
+
+ {
+ struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string)));
+ if (id && id->flags & TF_OPTION)
+ menu_add_option(id->token, (yyvsp[(3) - (3)].string));
+ else
+ zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
+ free((yyvsp[(2) - (3)].string));
+;}
+ break;
+
+ case 49:
+
+ { (yyval.string) = NULL; ;}
+ break;
+
+ case 50:
+
+ { (yyval.string) = (yyvsp[(2) - (2)].string); ;}
+ break;
+
+ case 51:
+
+ {
+ struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE);
+ sym->flags |= SYMBOL_AUTO;
+ menu_add_entry(sym);
+ menu_add_expr(P_CHOICE, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 52:
+
+ {
+ (yyval.menu) = menu_add_menu();
+;}
+ break;
+
+ case 53:
+
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ }
+;}
+ break;
+
+ case 61:
+
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 62:
+
+ {
+ if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) {
+ menu_set_type((yyvsp[(1) - (3)].id)->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ (yyvsp[(1) - (3)].id)->stype);
+ } else
+ YYERROR;
+;}
+ break;
+
+ case 63:
+
+ {
+ current_entry->sym->flags |= SYMBOL_OPTIONAL;
+ printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 64:
+
+ {
+ if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) {
+ menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:default\n",
+ zconf_curname(), zconf_lineno());
+ } else
+ YYERROR;
+;}
+ break;
+
+ case 67:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ menu_add_entry(NULL);
+ menu_add_dep((yyvsp[(2) - (3)].expr));
+ (yyval.menu) = menu_add_menu();
+;}
+ break;
+
+ case 68:
+
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ }
+;}
+ break;
+
+ case 74:
+
+ {
+ menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+;}
+ break;
+
+ case 75:
+
+ {
+ menu_add_entry(NULL);
+ menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 76:
+
+ {
+ (yyval.menu) = menu_add_menu();
+;}
+ break;
+
+ case 77:
+
+ {
+ if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ }
+;}
+ break;
+
+ case 83:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
+ zconf_nextfile((yyvsp[(2) - (3)].string));
+;}
+ break;
+
+ case 84:
+
+ {
+ menu_add_entry(NULL);
+ menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 85:
+
+ {
+ menu_end_entry();
+;}
+ break;
+
+ case 86:
+
+ {
+ printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ zconf_starthelp();
+;}
+ break;
+
+ case 87:
+
+ {
+ current_entry->help = (yyvsp[(2) - (2)].string);
+;}
+ break;
+
+ case 92:
+
+ {
+ menu_add_dep((yyvsp[(3) - (4)].expr));
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+;}
+ break;
+
+ case 96:
+
+ {
+ menu_add_visibility((yyvsp[(2) - (2)].expr));
+;}
+ break;
+
+ case 98:
+
+ {
+ menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
+;}
+ break;
+
+ case 101:
+
+ { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+ break;
+
+ case 102:
+
+ { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+ break;
+
+ case 103:
+
+ { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+ break;
+
+ case 106:
+
+ { (yyval.expr) = NULL; ;}
+ break;
+
+ case 107:
+
+ { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
+ break;
+
+ case 108:
+
+ { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
+ break;
+
+ case 109:
+
+ { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 110:
+
+ { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+ break;
+
+ case 111:
+
+ { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
+ break;
+
+ case 112:
+
+ { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
+ break;
+
+ case 113:
+
+ { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+ break;
+
+ case 114:
+
+ { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+ break;
+
+ case 115:
+
+ { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
+ break;
+
+ case 116:
+
+ { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
+ break;
+
+ case 117:
+
+ { (yyval.string) = NULL; ;}
+ break;
+
+
+
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+
+
+void conf_parse(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ zconf_initscan(name);
+
+ sym_init();
+ _menu_init();
+ modules_sym = sym_lookup(NULL, 0);
+ modules_sym->type = S_BOOLEAN;
+ modules_sym->flags |= SYMBOL_AUTO;
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+ if (getenv("ZCONF_DEBUG"))
+ zconfdebug = 1;
+#endif
+ zconfparse();
+ if (zconfnerrs)
+ exit(1);
+ if (!modules_sym->prop) {
+ struct property *prop;
+
+ prop = prop_alloc(P_DEFAULT, modules_sym);
+ prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+ }
+
+ rootmenu.prompt->text = _(rootmenu.prompt->text);
+ rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+ menu_finalize(&rootmenu);
+ for_all_symbols(i, sym) {
+ if (sym_check_deps(sym))
+ zconfnerrs++;
+ }
+ if (zconfnerrs)
+ exit(1);
+ sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+ switch (token) {
+ case T_MENU: return "menu";
+ case T_ENDMENU: return "endmenu";
+ case T_CHOICE: return "choice";
+ case T_ENDCHOICE: return "endchoice";
+ case T_IF: return "if";
+ case T_ENDIF: return "endif";
+ case T_DEPENDS: return "depends";
+ case T_VISIBLE: return "visible";
+ }
+ return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+ if (id->token != endtoken) {
+ zconf_error("unexpected '%s' within %s block",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ if (current_menu->file != current_file) {
+ zconf_error("'%s' in different file than '%s'",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ fprintf(stderr, "%s:%d: location of the '%s'\n",
+ current_menu->file->name, current_menu->lineno,
+ zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+ va_list ap;
+
+ zconfnerrs++;
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+ fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "\nchoice\n");
+ else
+ fprintf(out, "\nconfig %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" boolean\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_CHOICE:
+ fputs(" #choice value\n", out);
+ break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (menu->help) {
+ int len = strlen(menu->help);
+ while (menu->help[--len] == '\n')
+ menu->help[len] = 0;
+ fprintf(out, " help\n%s\n", menu->help);
+ }
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
+
--- /dev/null
+%{
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
+
+#define PRINTD 0x0001
+#define DEBUG_PARSE 0x0002
+
+int cdebug = PRINTD;
+
+extern int zconflex(void);
+static void zconfprint(const char *err, ...);
+static void zconf_error(const char *err, ...);
+static void zconferror(const char *err);
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
+
+static struct menu *current_menu, *current_entry;
+
+#define YYDEBUG 0
+#if YYDEBUG
+#define YYERROR_VERBOSE
+#endif
+%}
+%expect 30
+
+%union
+{
+ char *string;
+ struct file *file;
+ struct symbol *symbol;
+ struct expr *expr;
+ struct menu *menu;
+ struct kconf_id *id;
+}
+
+%token <id>T_MAINMENU
+%token <id>T_MENU
+%token <id>T_ENDMENU
+%token <id>T_SOURCE
+%token <id>T_CHOICE
+%token <id>T_ENDCHOICE
+%token <id>T_COMMENT
+%token <id>T_CONFIG
+%token <id>T_MENUCONFIG
+%token <id>T_HELP
+%token <string> T_HELPTEXT
+%token <id>T_IF
+%token <id>T_ENDIF
+%token <id>T_DEPENDS
+%token <id>T_OPTIONAL
+%token <id>T_PROMPT
+%token <id>T_TYPE
+%token <id>T_DEFAULT
+%token <id>T_SELECT
+%token <id>T_RANGE
+%token <id>T_VISIBLE
+%token <id>T_OPTION
+%token <id>T_ON
+%token <string> T_WORD
+%token <string> T_WORD_QUOTE
+%token T_UNEQUAL
+%token T_CLOSE_PAREN
+%token T_OPEN_PAREN
+%token T_EOL
+
+%left T_OR
+%left T_AND
+%left T_EQUAL T_UNEQUAL
+%nonassoc T_NOT
+
+%type <string> prompt
+%type <symbol> symbol
+%type <expr> expr
+%type <expr> if_expr
+%type <id> end
+%type <id> option_name
+%type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg word_opt
+
+%destructor {
+ fprintf(stderr, "%s:%d: missing end statement for this entry\n",
+ $$->file->name, $$->lineno);
+ if (current_menu == $$)
+ menu_end_menu();
+} if_entry menu_entry choice_entry
+
+%{
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+%}
+
+%%
+input: nl start | start;
+
+start: mainmenu_stmt stmt_list | stmt_list;
+
+stmt_list:
+ /* empty */
+ | stmt_list common_stmt
+ | stmt_list choice_stmt
+ | stmt_list menu_stmt
+ | stmt_list end { zconf_error("unexpected end statement"); }
+ | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); }
+ | stmt_list option_name error T_EOL
+{
+ zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name);
+}
+ | stmt_list error T_EOL { zconf_error("invalid statement"); }
+;
+
+option_name:
+ T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
+;
+
+common_stmt:
+ T_EOL
+ | if_stmt
+ | comment_stmt
+ | config_stmt
+ | menuconfig_stmt
+ | source_stmt
+;
+
+option_error:
+ T_WORD error T_EOL { zconf_error("unknown option \"%s\"", $1); }
+ | error T_EOL { zconf_error("invalid option"); }
+;
+
+
+/* config/menuconfig entry */
+
+config_entry_start: T_CONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+config_stmt: config_entry_start config_option_list
+{
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL
+{
+ struct symbol *sym = sym_lookup($2, 0);
+ sym->flags |= SYMBOL_OPTIONAL;
+ menu_add_entry(sym);
+ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2);
+};
+
+menuconfig_stmt: menuconfig_entry_start config_option_list
+{
+ if (current_entry->prompt)
+ current_entry->prompt->type = P_MENU;
+ else
+ zconfprint("warning: menuconfig statement without prompt");
+ menu_end_entry();
+ printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
+};
+
+config_option_list:
+ /* empty */
+ | config_option_list config_option
+ | config_option_list symbol_option
+ | config_option_list depends
+ | config_option_list help
+ | config_option_list option_error
+ | config_option_list T_EOL
+;
+
+config_option: T_TYPE prompt_stmt_opt T_EOL
+{
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+};
+
+config_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_DEFAULT expr if_expr T_EOL
+{
+ menu_add_expr(P_DEFAULT, $2, $3);
+ if ($1->stype != S_UNKNOWN)
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+};
+
+config_option: T_SELECT T_WORD if_expr T_EOL
+{
+ menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_RANGE symbol symbol if_expr T_EOL
+{
+ menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
+ printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
+};
+
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+ /* empty */
+ | symbol_option_list T_WORD symbol_option_arg
+{
+ struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+ if (id && id->flags & TF_OPTION)
+ menu_add_option(id->token, $3);
+ else
+ zconfprint("warning: ignoring unknown option %s", $2);
+ free($2);
+};
+
+symbol_option_arg:
+ /* empty */ { $$ = NULL; }
+ | T_EQUAL prompt { $$ = $2; }
+;
+
+/* choice entry */
+
+choice: T_CHOICE word_opt T_EOL
+{
+ struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+ sym->flags |= SYMBOL_AUTO;
+ menu_add_entry(sym);
+ menu_add_expr(P_CHOICE, NULL, NULL);
+ printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
+};
+
+choice_entry: choice choice_option_list
+{
+ $$ = menu_add_menu();
+};
+
+choice_end: end
+{
+ if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+choice_stmt: choice_entry choice_block choice_end
+;
+
+choice_option_list:
+ /* empty */
+ | choice_option_list choice_option
+ | choice_option_list depends
+ | choice_option_list help
+ | choice_option_list T_EOL
+ | choice_option_list option_error
+;
+
+choice_option: T_PROMPT prompt if_expr T_EOL
+{
+ menu_add_prompt(P_PROMPT, $2, $3);
+ printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_TYPE prompt_stmt_opt T_EOL
+{
+ if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) {
+ menu_set_type($1->stype);
+ printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
+ zconf_curname(), zconf_lineno(),
+ $1->stype);
+ } else
+ YYERROR;
+};
+
+choice_option: T_OPTIONAL T_EOL
+{
+ current_entry->sym->flags |= SYMBOL_OPTIONAL;
+ printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
+{
+ if ($1->stype == S_UNKNOWN) {
+ menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
+ printd(DEBUG_PARSE, "%s:%d:default\n",
+ zconf_curname(), zconf_lineno());
+ } else
+ YYERROR;
+};
+
+choice_block:
+ /* empty */
+ | choice_block common_stmt
+;
+
+/* if entry */
+
+if_entry: T_IF expr nl
+{
+ printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
+ menu_add_entry(NULL);
+ menu_add_dep($2);
+ $$ = menu_add_menu();
+};
+
+if_end: end
+{
+ if (zconf_endtoken($1, T_IF, T_ENDIF)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+if_stmt: if_entry if_block if_end
+;
+
+if_block:
+ /* empty */
+ | if_block common_stmt
+ | if_block menu_stmt
+ | if_block choice_stmt
+;
+
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU prompt nl
+{
+ menu_add_prompt(P_MENU, $2, NULL);
+};
+
+/* menu entry */
+
+menu: T_MENU prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prompt(P_MENU, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
+};
+
+menu_entry: menu visibility_list depends_list
+{
+ $$ = menu_add_menu();
+};
+
+menu_end: end
+{
+ if (zconf_endtoken($1, T_MENU, T_ENDMENU)) {
+ menu_end_menu();
+ printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
+ }
+};
+
+menu_stmt: menu_entry menu_block menu_end
+;
+
+menu_block:
+ /* empty */
+ | menu_block common_stmt
+ | menu_block menu_stmt
+ | menu_block choice_stmt
+;
+
+source_stmt: T_SOURCE prompt T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
+ zconf_nextfile($2);
+};
+
+/* comment entry */
+
+comment: T_COMMENT prompt T_EOL
+{
+ menu_add_entry(NULL);
+ menu_add_prompt(P_COMMENT, $2, NULL);
+ printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
+};
+
+comment_stmt: comment depends_list
+{
+ menu_end_entry();
+};
+
+/* help option */
+
+help_start: T_HELP T_EOL
+{
+ printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
+ zconf_starthelp();
+};
+
+help: help_start T_HELPTEXT
+{
+ current_entry->help = $2;
+};
+
+/* depends option */
+
+depends_list:
+ /* empty */
+ | depends_list depends
+ | depends_list T_EOL
+ | depends_list option_error
+;
+
+depends: T_DEPENDS T_ON expr T_EOL
+{
+ menu_add_dep($3);
+ printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
+};
+
+/* visibility option */
+
+visibility_list:
+ /* empty */
+ | visibility_list visible
+ | visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
+{
+ menu_add_visibility($2);
+};
+
+/* prompt statement */
+
+prompt_stmt_opt:
+ /* empty */
+ | prompt if_expr
+{
+ menu_add_prompt(P_PROMPT, $1, $2);
+};
+
+prompt: T_WORD
+ | T_WORD_QUOTE
+;
+
+end: T_ENDMENU T_EOL { $$ = $1; }
+ | T_ENDCHOICE T_EOL { $$ = $1; }
+ | T_ENDIF T_EOL { $$ = $1; }
+;
+
+nl:
+ T_EOL
+ | nl T_EOL
+;
+
+if_expr: /* empty */ { $$ = NULL; }
+ | T_IF expr { $$ = $2; }
+;
+
+expr: symbol { $$ = expr_alloc_symbol($1); }
+ | symbol T_EQUAL symbol { $$ = expr_alloc_comp(E_EQUAL, $1, $3); }
+ | symbol T_UNEQUAL symbol { $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); }
+ | T_OPEN_PAREN expr T_CLOSE_PAREN { $$ = $2; }
+ | T_NOT expr { $$ = expr_alloc_one(E_NOT, $2); }
+ | expr T_OR expr { $$ = expr_alloc_two(E_OR, $1, $3); }
+ | expr T_AND expr { $$ = expr_alloc_two(E_AND, $1, $3); }
+;
+
+symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); }
+ | T_WORD_QUOTE { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
+;
+
+word_opt: /* empty */ { $$ = NULL; }
+ | T_WORD
+
+%%
+
+void conf_parse(const char *name)
+{
+ struct symbol *sym;
+ int i;
+
+ zconf_initscan(name);
+
+ sym_init();
+ _menu_init();
+ modules_sym = sym_lookup(NULL, 0);
+ modules_sym->type = S_BOOLEAN;
+ modules_sym->flags |= SYMBOL_AUTO;
+ rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
+
+#if YYDEBUG
+ if (getenv("ZCONF_DEBUG"))
+ zconfdebug = 1;
+#endif
+ zconfparse();
+ if (zconfnerrs)
+ exit(1);
+ if (!modules_sym->prop) {
+ struct property *prop;
+
+ prop = prop_alloc(P_DEFAULT, modules_sym);
+ prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+ }
+
+ rootmenu.prompt->text = _(rootmenu.prompt->text);
+ rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
+ menu_finalize(&rootmenu);
+ for_all_symbols(i, sym) {
+ if (sym_check_deps(sym))
+ zconfnerrs++;
+ }
+ if (zconfnerrs)
+ exit(1);
+ sym_set_change_count(1);
+}
+
+static const char *zconf_tokenname(int token)
+{
+ switch (token) {
+ case T_MENU: return "menu";
+ case T_ENDMENU: return "endmenu";
+ case T_CHOICE: return "choice";
+ case T_ENDCHOICE: return "endchoice";
+ case T_IF: return "if";
+ case T_ENDIF: return "endif";
+ case T_DEPENDS: return "depends";
+ case T_VISIBLE: return "visible";
+ }
+ return "<token>";
+}
+
+static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+{
+ if (id->token != endtoken) {
+ zconf_error("unexpected '%s' within %s block",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ if (current_menu->file != current_file) {
+ zconf_error("'%s' in different file than '%s'",
+ kconf_id_strings + id->name, zconf_tokenname(starttoken));
+ fprintf(stderr, "%s:%d: location of the '%s'\n",
+ current_menu->file->name, current_menu->lineno,
+ zconf_tokenname(starttoken));
+ zconfnerrs++;
+ return false;
+ }
+ return true;
+}
+
+static void zconfprint(const char *err, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconf_error(const char *err, ...)
+{
+ va_list ap;
+
+ zconfnerrs++;
+ fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+ va_start(ap, err);
+ vfprintf(stderr, err, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void zconferror(const char *err)
+{
+#if YYDEBUG
+ fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
+#endif
+}
+
+static void print_quoted_string(FILE *out, const char *str)
+{
+ const char *p;
+ int len;
+
+ putc('"', out);
+ while ((p = strchr(str, '"'))) {
+ len = p - str;
+ if (len)
+ fprintf(out, "%.*s", len, str);
+ fputs("\\\"", out);
+ str = p + 1;
+ }
+ fputs(str, out);
+ putc('"', out);
+}
+
+static void print_symbol(FILE *out, struct menu *menu)
+{
+ struct symbol *sym = menu->sym;
+ struct property *prop;
+
+ if (sym_is_choice(sym))
+ fprintf(out, "\nchoice\n");
+ else
+ fprintf(out, "\nconfig %s\n", sym->name);
+ switch (sym->type) {
+ case S_BOOLEAN:
+ fputs(" boolean\n", out);
+ break;
+ case S_TRISTATE:
+ fputs(" tristate\n", out);
+ break;
+ case S_STRING:
+ fputs(" string\n", out);
+ break;
+ case S_INT:
+ fputs(" integer\n", out);
+ break;
+ case S_HEX:
+ fputs(" hex\n", out);
+ break;
+ default:
+ fputs(" ???\n", out);
+ break;
+ }
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu != menu)
+ continue;
+ switch (prop->type) {
+ case P_PROMPT:
+ fputs(" prompt ", out);
+ print_quoted_string(out, prop->text);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_DEFAULT:
+ fputs( " default ", out);
+ expr_fprint(prop->expr, out);
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" if ", out);
+ expr_fprint(prop->visible.expr, out);
+ }
+ fputc('\n', out);
+ break;
+ case P_CHOICE:
+ fputs(" #choice value\n", out);
+ break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
+ default:
+ fprintf(out, " unknown prop %d!\n", prop->type);
+ break;
+ }
+ }
+ if (menu->help) {
+ int len = strlen(menu->help);
+ while (menu->help[--len] == '\n')
+ menu->help[len] = 0;
+ fprintf(out, " help\n%s\n", menu->help);
+ }
+}
+
+void zconfdump(FILE *out)
+{
+ struct property *prop;
+ struct symbol *sym;
+ struct menu *menu;
+
+ menu = rootmenu.list;
+ while (menu) {
+ if ((sym = menu->sym))
+ print_symbol(out, menu);
+ else if ((prop = menu->prompt)) {
+ switch (prop->type) {
+ case P_COMMENT:
+ fputs("\ncomment ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ case P_MENU:
+ fputs("\nmenu ", out);
+ print_quoted_string(out, prop->text);
+ fputs("\n", out);
+ break;
+ default:
+ ;
+ }
+ if (!expr_is_yes(prop->visible.expr)) {
+ fputs(" depends ", out);
+ expr_fprint(prop->visible.expr, out);
+ fputc('\n', out);
+ }
+ }
+
+ if (menu->list)
+ menu = menu->list;
+ else if (menu->next)
+ menu = menu->next;
+ else while ((menu = menu->parent)) {
+ if (menu->prompt && menu->prompt->type == P_MENU)
+ fputs("\nendmenu\n", out);
+ if (menu->next) {
+ menu = menu->next;
+ break;
+ }
+ }
+ }
+}
+
+#include "lex.zconf.c"
+#include "util.c"
+#include "confdata.c"
+#include "expr.c"
+#include "symbol.c"
+#include "menu.c"
--- /dev/null
+#!/usr/bin/env python
+# Script to analyze code and arrange ld sections.
+#
+# Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+
+# LD script headers/trailers
+COMMONHEADER = """
+/* DO NOT EDIT! This is an autogenerated file. See tools/layoutrom.py. */
+OUTPUT_FORMAT("elf32-i386")
+OUTPUT_ARCH("i386")
+SECTIONS
+{
+"""
+COMMONTRAILER = """
+
+ /* Discard regular data sections to force a link error if
+ * code attempts to access data not marked with VAR16 (or other
+ * appropriate macro)
+ */
+ /DISCARD/ : {
+ *(.text*) *(.data*) *(.bss*) *(.rodata*)
+ *(COMMON) *(.discard*) *(.eh_frame)
+ }
+}
+"""
+
+
+######################################################################
+# Determine section locations
+######################################################################
+
+# Align 'pos' to 'alignbytes' offset
+def alignpos(pos, alignbytes):
+ mask = alignbytes - 1
+ return (pos + mask) & ~mask
+
+# Determine the final addresses for a list of sections that end at an
+# address.
+def setSectionsStart(sections, endaddr, minalign=1):
+ totspace = 0
+ for section in sections:
+ if section.align > minalign:
+ minalign = section.align
+ totspace = alignpos(totspace, section.align) + section.size
+ startaddr = (endaddr - totspace) / minalign * minalign
+ curaddr = startaddr
+ # out = [(addr, sectioninfo), ...]
+ out = []
+ for section in sections:
+ curaddr = alignpos(curaddr, section.align)
+ section.finalloc = curaddr
+ curaddr += section.size
+ return startaddr
+
+# The 16bit code can't exceed 64K of space.
+BUILD_BIOS_ADDR = 0xf0000
+BUILD_BIOS_SIZE = 0x10000
+
+# Layout the 16bit code. This ensures sections with fixed offset
+# requirements are placed in the correct location. It also places the
+# 16bit code as high as possible in the f-segment.
+def fitSections(sections, fillsections):
+ # fixedsections = [(addr, section), ...]
+ fixedsections = []
+ for section in sections:
+ if section.name.startswith('.fixedaddr.'):
+ addr = int(section.name[11:], 16)
+ section.finalloc = addr
+ fixedsections.append((addr, section))
+ if section.align != 1:
+ print "Error: Fixed section %s has non-zero alignment (%d)" % (
+ section.name, section.align)
+ sys.exit(1)
+ fixedsections.sort()
+ firstfixed = fixedsections[0][0]
+
+ # Find freespace in fixed address area
+ # fixedAddr = [(freespace, section), ...]
+ fixedAddr = []
+ for i in range(len(fixedsections)):
+ fixedsectioninfo = fixedsections[i]
+ addr, section = fixedsectioninfo
+ if i == len(fixedsections) - 1:
+ nextaddr = BUILD_BIOS_SIZE
+ else:
+ nextaddr = fixedsections[i+1][0]
+ avail = nextaddr - addr - section.size
+ fixedAddr.append((avail, section))
+ fixedAddr.sort()
+
+ # Attempt to fit other sections into fixed area
+ canrelocate = [(section.size, section.align, section.name, section)
+ for section in fillsections]
+ canrelocate.sort()
+ canrelocate = [section for size, align, name, section in canrelocate]
+ totalused = 0
+ for freespace, fixedsection in fixedAddr:
+ addpos = fixedsection.finalloc + fixedsection.size
+ totalused += fixedsection.size
+ nextfixedaddr = addpos + freespace
+# print "Filling section %x uses %d, next=%x, available=%d" % (
+# fixedsection.finalloc, fixedsection.size, nextfixedaddr, freespace)
+ while 1:
+ canfit = None
+ for fitsection in canrelocate:
+ if addpos + fitsection.size > nextfixedaddr:
+ # Can't fit and nothing else will fit.
+ break
+ fitnextaddr = alignpos(addpos, fitsection.align) + fitsection.size
+# print "Test %s - %x vs %x" % (
+# fitsection.name, fitnextaddr, nextfixedaddr)
+ if fitnextaddr > nextfixedaddr:
+ # This item can't fit.
+ continue
+ canfit = (fitnextaddr, fitsection)
+ if canfit is None:
+ break
+ # Found a section that can fit.
+ fitnextaddr, fitsection = canfit
+ canrelocate.remove(fitsection)
+ fitsection.finalloc = addpos
+ addpos = fitnextaddr
+ totalused += fitsection.size
+# print " Adding %s (size %d align %d) pos=%x avail=%d" % (
+# fitsection[2], fitsection[0], fitsection[1]
+# , fitnextaddr, nextfixedaddr - fitnextaddr)
+
+ # Report stats
+ total = BUILD_BIOS_SIZE-firstfixed
+ slack = total - totalused
+ print ("Fixed space: 0x%x-0x%x total: %d slack: %d"
+ " Percent slack: %.1f%%" % (
+ firstfixed, BUILD_BIOS_SIZE, total, slack,
+ (float(slack) / total) * 100.0))
+
+ return firstfixed
+
+# Return the subset of sections with a given name prefix
+def getSectionsPrefix(sections, category, prefix):
+ return [section for section in sections
+ if section.category == category and section.name.startswith(prefix)]
+
+def doLayout(sections):
+ # Determine 16bit positions
+ textsections = getSectionsPrefix(sections, '16', '.text.')
+ rodatasections = (getSectionsPrefix(sections, '16', '.rodata.str1.1')
+ + getSectionsPrefix(sections, '16', '.rodata.__func__.'))
+ datasections = getSectionsPrefix(sections, '16', '.data16.')
+ fixedsections = getSectionsPrefix(sections, '16', '.fixedaddr.')
+
+ firstfixed = fitSections(fixedsections, textsections)
+ remsections = [s for s in textsections+rodatasections+datasections
+ if s.finalloc is None]
+ code16_start = setSectionsStart(remsections, firstfixed)
+
+ # Determine 32seg positions
+ textsections = getSectionsPrefix(sections, '32seg', '.text.')
+ rodatasections = (getSectionsPrefix(sections, '32seg', '.rodata.str1.1')
+ +getSectionsPrefix(sections, '32seg', '.rodata.__func__.'))
+ datasections = getSectionsPrefix(sections, '32seg', '.data32seg.')
+
+ code32seg_start = setSectionsStart(
+ textsections + rodatasections + datasections, code16_start)
+
+ # Determine 32flat runtime positions
+ textsections = getSectionsPrefix(sections, '32flat', '.text.')
+ rodatasections = getSectionsPrefix(sections, '32flat', '.rodata')
+ datasections = getSectionsPrefix(sections, '32flat', '.data.')
+ bsssections = getSectionsPrefix(sections, '32flat', '.bss.')
+
+ code32flat_start = setSectionsStart(
+ textsections + rodatasections + datasections + bsssections
+ , code32seg_start + BUILD_BIOS_ADDR, 16)
+
+ # Determine 32flat init positions
+ textsections = getSectionsPrefix(sections, '32init', '.text.')
+ rodatasections = getSectionsPrefix(sections, '32init', '.rodata')
+ datasections = getSectionsPrefix(sections, '32init', '.data.')
+ bsssections = getSectionsPrefix(sections, '32init', '.bss.')
+
+ code32init_start = setSectionsStart(
+ textsections + rodatasections + datasections + bsssections
+ , code32flat_start, 16)
+
+ # Print statistics
+ size16 = BUILD_BIOS_SIZE - code16_start
+ size32seg = code16_start - code32seg_start
+ size32flat = code32seg_start + BUILD_BIOS_ADDR - code32flat_start
+ size32init = code32flat_start - code32init_start
+ print "16bit size: %d" % size16
+ print "32bit segmented size: %d" % size32seg
+ print "32bit flat size: %d" % size32flat
+ print "32bit flat init size: %d" % size32init
+
+
+######################################################################
+# Linker script output
+######################################################################
+
+# Write LD script includes for the given cross references
+def outXRefs(sections):
+ xrefs = {}
+ out = ""
+ for section in sections:
+ for reloc in section.relocs:
+ symbol = reloc.symbol
+ if (symbol.section is None
+ or (symbol.section.fileid == section.fileid
+ and symbol.name == reloc.symbolname)
+ or reloc.symbolname in xrefs):
+ continue
+ xrefs[reloc.symbolname] = 1
+ addr = symbol.section.finalloc + symbol.offset
+ if (section.fileid == '32flat'
+ and symbol.section.fileid in ('16', '32seg')):
+ addr += BUILD_BIOS_ADDR
+ out += "%s = 0x%x ;\n" % (reloc.symbolname, addr)
+ return out
+
+# Write LD script includes for the given sections using relative offsets
+def outRelSections(sections, startsym):
+ out = ""
+ for section in sections:
+ out += ". = ( 0x%x - %s ) ;\n" % (section.finalloc, startsym)
+ if section.name == '.rodata.str1.1':
+ out += "_rodata = . ;\n"
+ out += "*(%s)\n" % (section.name,)
+ return out
+
+def getSectionsFile(sections, fileid, defaddr=0):
+ sections = [(section.finalloc, section)
+ for section in sections if section.fileid == fileid]
+ sections.sort()
+ sections = [section for addr, section in sections]
+ pos = defaddr
+ if sections:
+ pos = sections[0].finalloc
+ return sections, pos
+
+# Layout the 32bit segmented code. This places the code as high as possible.
+def writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat):
+ # Write 16bit linker script
+ sections16, code16_start = getSectionsFile(sections, '16')
+ output = open(out16, 'wb')
+ output.write(COMMONHEADER + outXRefs(sections16) + """
+ code16_start = 0x%x ;
+ .text16 code16_start : {
+""" % (code16_start)
+ + outRelSections(sections16, 'code16_start')
+ + """
+ }
+"""
+ + COMMONTRAILER)
+ output.close()
+
+ # Write 32seg linker script
+ sections32seg, code32seg_start = getSectionsFile(
+ sections, '32seg', code16_start)
+ output = open(out32seg, 'wb')
+ output.write(COMMONHEADER + outXRefs(sections32seg) + """
+ code32seg_start = 0x%x ;
+ .text32seg code32seg_start : {
+""" % (code32seg_start)
+ + outRelSections(sections32seg, 'code32seg_start')
+ + """
+ }
+"""
+ + COMMONTRAILER)
+ output.close()
+
+ # Write 32flat linker script
+ sections32flat, code32flat_start = getSectionsFile(
+ sections, '32flat', code32seg_start)
+ relocstr = ""
+ relocminalign = 0
+ if genreloc:
+ # Generate relocations
+ relocstr, size, relocminalign = genRelocs(sections)
+ code32flat_start -= size
+ output = open(out32flat, 'wb')
+ output.write(COMMONHEADER
+ + outXRefs(sections32flat) + """
+ %s = 0x%x ;
+ _reloc_min_align = 0x%x ;
+ code32flat_start = 0x%x ;
+ .text code32flat_start : {
+""" % (entrysym.name,
+ entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR,
+ relocminalign, code32flat_start)
+ + relocstr
+ + """
+ code32init_start = ABSOLUTE(.) ;
+"""
+ + outRelSections(getSectionsPrefix(sections32flat, '32init', '')
+ , 'code32flat_start')
+ + """
+ code32init_end = ABSOLUTE(.) ;
+"""
+ + outRelSections(getSectionsPrefix(sections32flat, '32flat', '')
+ , 'code32flat_start')
+ + """
+ . = ( 0x%x - code32flat_start ) ;
+ *(.text32seg)
+ . = ( 0x%x - code32flat_start ) ;
+ *(.text16)
+ code32flat_end = ABSOLUTE(.) ;
+ } :text
+""" % (code32seg_start + BUILD_BIOS_ADDR, code16_start + BUILD_BIOS_ADDR)
+ + COMMONTRAILER
+ + """
+ENTRY(%s)
+PHDRS
+{
+ text PT_LOAD AT ( code32flat_start ) ;
+}
+""" % (entrysym.name,))
+ output.close()
+
+
+######################################################################
+# Detection of init code
+######################################################################
+
+# Determine init section relocations
+def genRelocs(sections):
+ absrelocs = []
+ relrelocs = []
+ initrelocs = []
+ minalign = 16
+ for section in sections:
+ if section.category == '32init' and section.align > minalign:
+ minalign = section.align
+ for reloc in section.relocs:
+ symbol = reloc.symbol
+ if symbol.section is None:
+ continue
+ relocpos = section.finalloc + reloc.offset
+ if (reloc.type == 'R_386_32' and section.category == '32init'
+ and symbol.section.category == '32init'):
+ # Absolute relocation
+ absrelocs.append(relocpos)
+ elif (reloc.type == 'R_386_PC32' and section.category == '32init'
+ and symbol.section.category != '32init'):
+ # Relative relocation
+ relrelocs.append(relocpos)
+ elif (section.category != '32init'
+ and symbol.section.category == '32init'):
+ # Relocation to the init section
+ if section.fileid in ('16', '32seg'):
+ relocpos += BUILD_BIOS_ADDR
+ initrelocs.append(relocpos)
+ absrelocs.sort()
+ relrelocs.sort()
+ initrelocs.sort()
+ out = (" _reloc_abs_start = ABSOLUTE(.) ;\n"
+ + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+ for pos in absrelocs])
+ + " _reloc_abs_end = ABSOLUTE(.) ;\n"
+ + " _reloc_rel_start = ABSOLUTE(.) ;\n"
+ + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+ for pos in relrelocs])
+ + " _reloc_rel_end = ABSOLUTE(.) ;\n"
+ + " _reloc_init_start = ABSOLUTE(.) ;\n"
+ + "".join(["LONG(0x%x - code32flat_start)\n" % (pos,)
+ for pos in initrelocs])
+ + " _reloc_init_end = ABSOLUTE(.) ;\n")
+ return out, len(absrelocs + relrelocs + initrelocs) * 4, minalign
+
+def markRuntime(section, sections):
+ if (section is None or not section.keep or section.category is not None
+ or '.init.' in section.name or section.fileid != '32flat'):
+ return
+ section.category = '32flat'
+ # Recursively mark all sections this section points to
+ for reloc in section.relocs:
+ markRuntime(reloc.symbol.section, sections)
+
+def findInit(sections):
+ # Recursively find and mark all "runtime" sections.
+ for section in sections:
+ if '.runtime.' in section.name or '.export.' in section.name:
+ markRuntime(section, sections)
+ for section in sections:
+ if section.category is not None:
+ continue
+ if section.fileid == '32flat':
+ section.category = '32init'
+ else:
+ section.category = section.fileid
+
+
+######################################################################
+# Section garbage collection
+######################################################################
+
+CFUNCPREFIX = [('_cfunc16_', 0), ('_cfunc32seg_', 1), ('_cfunc32flat_', 2)]
+
+# Find and keep the section associated with a symbol (if available).
+def keepsymbol(reloc, infos, pos, isxref):
+ symbolname = reloc.symbolname
+ mustbecfunc = 0
+ for symprefix, needpos in CFUNCPREFIX:
+ if symbolname.startswith(symprefix):
+ if needpos != pos:
+ return -1
+ symbolname = symbolname[len(symprefix):]
+ mustbecfunc = 1
+ break
+ symbol = infos[pos][1].get(symbolname)
+ if (symbol is None or symbol.section is None
+ or symbol.section.name.startswith('.discard.')):
+ return -1
+ isdestcfunc = (symbol.section.name.startswith('.text.')
+ and not symbol.section.name.startswith('.text.asm.'))
+ if ((mustbecfunc and not isdestcfunc)
+ or (not mustbecfunc and isdestcfunc and isxref)):
+ return -1
+
+ reloc.symbol = symbol
+ keepsection(symbol.section, infos, pos)
+ return 0
+
+# Note required section, and recursively set all referenced sections
+# as required.
+def keepsection(section, infos, pos=0):
+ if section.keep:
+ # Already kept - nothing to do.
+ return
+ section.keep = 1
+ # Keep all sections that this section points to
+ for reloc in section.relocs:
+ ret = keepsymbol(reloc, infos, pos, 0)
+ if not ret:
+ continue
+ # Not in primary sections - it may be a cross 16/32 reference
+ ret = keepsymbol(reloc, infos, (pos+1)%3, 1)
+ if not ret:
+ continue
+ ret = keepsymbol(reloc, infos, (pos+2)%3, 1)
+ if not ret:
+ continue
+
+# Determine which sections are actually referenced and need to be
+# placed into the output file.
+def gc(info16, info32seg, info32flat):
+ # infos = ((sections16, symbols16), (sect32seg, sym32seg)
+ # , (sect32flat, sym32flat))
+ infos = (info16, info32seg, info32flat)
+ # Start by keeping sections that are globally visible.
+ for section in info16[0]:
+ if section.name.startswith('.fixedaddr.') or '.export.' in section.name:
+ keepsection(section, infos)
+ return [section for section in info16[0]+info32seg[0]+info32flat[0]
+ if section.keep]
+
+
+######################################################################
+# Startup and input parsing
+######################################################################
+
+class Section:
+ name = size = alignment = fileid = relocs = None
+ finalloc = category = keep = None
+class Reloc:
+ offset = type = symbolname = symbol = None
+class Symbol:
+ name = offset = section = None
+
+# Read in output from objdump
+def parseObjDump(file, fileid):
+ # sections = [section, ...]
+ sections = []
+ sectionmap = {}
+ # symbols[symbolname] = symbol
+ symbols = {}
+
+ state = None
+ for line in file.readlines():
+ line = line.rstrip()
+ if line == 'Sections:':
+ state = 'section'
+ continue
+ if line == 'SYMBOL TABLE:':
+ state = 'symbol'
+ continue
+ if line.startswith('RELOCATION RECORDS FOR ['):
+ sectionname = line[24:-2]
+ if sectionname.startswith('.debug_'):
+ # Skip debugging sections (to reduce parsing time)
+ state = None
+ continue
+ state = 'reloc'
+ relocsection = sectionmap[sectionname]
+ continue
+
+ if state == 'section':
+ try:
+ idx, name, size, vma, lma, fileoff, align = line.split()
+ if align[:3] != '2**':
+ continue
+ section = Section()
+ section.name = name
+ section.size = int(size, 16)
+ section.align = 2**int(align[3:])
+ section.fileid = fileid
+ section.relocs = []
+ sections.append(section)
+ sectionmap[name] = section
+ except ValueError:
+ pass
+ continue
+ if state == 'symbol':
+ try:
+ sectionname, size, name = line[17:].split()
+ symbol = Symbol()
+ symbol.size = int(size, 16)
+ symbol.offset = int(line[:8], 16)
+ symbol.name = name
+ symbol.section = sectionmap.get(sectionname)
+ symbols[name] = symbol
+ except ValueError:
+ pass
+ continue
+ if state == 'reloc':
+ try:
+ off, type, symbolname = line.split()
+ reloc = Reloc()
+ reloc.offset = int(off, 16)
+ reloc.type = type
+ reloc.symbolname = symbolname
+ reloc.symbol = symbols.get(symbolname)
+ if reloc.symbol is None:
+ # Some binutils (2.20.1) give section name instead
+ # of a symbol - create a dummy symbol.
+ reloc.symbol = symbol = Symbol()
+ symbol.size = 0
+ symbol.offset = 0
+ symbol.name = symbolname
+ symbol.section = sectionmap.get(symbolname)
+ symbols[symbolname] = symbol
+ relocsection.relocs.append(reloc)
+ except ValueError:
+ pass
+ return sections, symbols
+
+def main():
+ # Get output name
+ in16, in32seg, in32flat, out16, out32seg, out32flat = sys.argv[1:]
+
+ # Read in the objdump information
+ infile16 = open(in16, 'rb')
+ infile32seg = open(in32seg, 'rb')
+ infile32flat = open(in32flat, 'rb')
+
+ # infoX = (sections, symbols)
+ info16 = parseObjDump(infile16, '16')
+ info32seg = parseObjDump(infile32seg, '32seg')
+ info32flat = parseObjDump(infile32flat, '32flat')
+
+ # Figure out which sections to keep.
+ sections = gc(info16, info32seg, info32flat)
+
+ # Separate 32bit flat into runtime and init parts
+ findInit(sections)
+
+ # Determine the final memory locations of each kept section.
+ doLayout(sections)
+
+ # Write out linker script files.
+ entrysym = info16[1]['entry_elf']
+ genreloc = '_reloc_abs_start' in info32flat[1]
+ writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat)
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+#!/usr/bin/env python
+# Script that can read from a serial device and show timestamps.
+#
+# Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+# Usage:
+# tools/readserial.py /dev/ttyUSB0 115200
+
+import sys
+import time
+import select
+import optparse
+
+# Reset time counter after this much idle time.
+RESTARTINTERVAL = 60
+# Number of bits in a transmitted byte - 8N1 is 1 start bit + 8 data
+# bits + 1 stop bit.
+BITSPERBYTE = 10
+
+def calibrateserialwrite(outfile, byteadjust):
+ # Build 4000 bytes of dummy data.
+ data = "0123456789" * 4 + "012345678" + "\n"
+ data = data * 80
+ while 1:
+ st = time.time()
+ outfile.write(data)
+ outfile.flush()
+ et = time.time()
+ sys.stdout.write(
+ "Wrote %d - %.1fus per char (theory states %.1fus)\n" % (
+ len(data), (et-st) / len(data) * 1000000, byteadjust * 1000000))
+ sys.stdout.flush()
+ time.sleep(3)
+
+def calibrateserialread(infile, byteadjust):
+ starttime = lasttime = 0
+ totalchars = 0
+ while 1:
+ select.select([infile], [], [])
+ d = infile.read(4096)
+ curtime = time.time()
+ if curtime - lasttime > 1.0:
+ if starttime and totalchars:
+ sys.stdout.write(
+ "Calibrating on %d bytes - %.1fus per char"
+ " (theory states %.1fus)\n" % (
+ totalchars,
+ float(lasttime - starttime) * 1000000 / totalchars,
+ byteadjust * 1000000))
+ totalchars = 0
+ starttime = curtime
+ else:
+ totalchars += len(d)
+ lasttime = curtime
+
+def readserial(infile, logfile, byteadjust):
+ lasttime = 0
+ while 1:
+ # Read data
+ try:
+ res = select.select([infile, sys.stdin], [], [])
+ except KeyboardInterrupt:
+ sys.stdout.write("\n")
+ break
+ if sys.stdin in res[0]:
+ # Got keyboard input - force reset on next serial input
+ sys.stdin.read(1)
+ lasttime = 0
+ if len(res[0]) == 1:
+ continue
+ d = infile.read(4096)
+ if not d:
+ break
+ datatime = time.time()
+
+ datatime -= len(d) * byteadjust
+
+ # Reset start time if no data for some time
+ if datatime - lasttime > RESTARTINTERVAL:
+ starttime = datatime
+ charcount = 0
+ isnewline = 1
+ msg = "\n\n======= %s (adjust=%.1fus)\n" % (
+ time.asctime(time.localtime(datatime)), byteadjust * 1000000)
+ sys.stdout.write(msg)
+ logfile.write(msg)
+ lasttime = datatime
+
+ # Translate unprintable chars; add timestamps
+ out = ""
+ for c in d:
+ if isnewline:
+ delta = datatime - starttime - (charcount * byteadjust)
+ out += "%06.3f: " % delta
+ isnewline = 0
+ oc = ord(c)
+ charcount += 1
+ datatime += byteadjust
+ if oc == 0x0d:
+ continue
+ if oc == 0x00:
+ out += "<00>\n"
+ isnewline = 1
+ continue
+ if oc == 0x0a:
+ out += "\n"
+ isnewline = 1
+ continue
+ if oc < 0x20 or oc >= 0x7f and oc != 0x09:
+ out += "<%02x>" % oc
+ continue
+ out += c
+
+ sys.stdout.write(out)
+ sys.stdout.flush()
+ logfile.write(out)
+ logfile.flush()
+
+def main():
+ usage = "%prog [options] [<serialdevice> [<baud>]]"
+ opts = optparse.OptionParser(usage)
+ opts.add_option("-f", "--file",
+ action="store_false", dest="serial", default=True,
+ help="read from file instead of serialdevice")
+ opts.add_option("-n", "--no-adjust",
+ action="store_false", dest="adjustbaud", default=True,
+ help="don't adjust times by serial rate")
+ opts.add_option("-c", "--calibrate-read",
+ action="store_true", dest="calibrate_read", default=False,
+ help="read from serial port to calibrate it")
+ opts.add_option("-C", "--calibrate-write",
+ action="store_true", dest="calibrate_write", default=False,
+ help="write to serial port to calibrate it")
+ opts.add_option("-t", "--time",
+ type="float", dest="time", default=None,
+ help="time to write one byte on serial port (in us)")
+ options, args = opts.parse_args()
+ serialport = 0
+ baud = 115200
+ if len(args) > 2:
+ opts.error("Too many arguments")
+ if len(args) > 0:
+ serialport = args[0]
+ if len(args) > 1:
+ baud = int(args[1])
+ byteadjust = float(BITSPERBYTE) / baud
+ if options.time is not None:
+ byteadjust = options.time / 1000000.0
+ if not options.adjustbaud:
+ byteadjust = 0.0
+
+ if options.serial:
+ # Read from serial port
+ try:
+ import serial
+ except ImportError:
+ print """
+Unable to find pyserial package ( http://pyserial.sourceforge.net/ ).
+On Linux machines try: yum install pyserial
+Or: apt-get install python-serial
+"""
+ sys.exit(1)
+ ser = serial.Serial(serialport, baud, timeout=0)
+ else:
+ # Read from a file
+ ser = open(serialport, 'rb')
+ import fcntl
+ import os
+ fcntl.fcntl(ser, fcntl.F_SETFL
+ , fcntl.fcntl(ser, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+ if options.calibrate_read:
+ calibrateserialread(ser, byteadjust)
+ return
+ if options.calibrate_write:
+ calibrateserialwrite(ser, byteadjust)
+ return
+
+ logname = time.strftime("seriallog-%Y%m%d_%H%M%S.log")
+ f = open(logname, 'wb')
+ readserial(ser, f, byteadjust)
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+#!/bin/sh
+# Script to test if gcc "-fwhole-program" works properly.
+
+mkdir -p out
+TMPFILE1=out/tmp_testcompile1.c
+TMPFILE1o=out/tmp_testcompile1.o
+TMPFILE1_ld=out/tmp_testcompile1.lds
+TMPFILE2=out/tmp_testcompile2.c
+TMPFILE2o=out/tmp_testcompile2.o
+TMPFILE3o=out/tmp_testcompile3.o
+
+# Test if ld's alignment handling is correct. This is a known problem
+# with the linker that ships with Ubuntu 11.04.
+cat - > $TMPFILE1 <<EOF
+const char v1[] __attribute__((section(".text.v1"))) = "0123456789";
+const char v2[] __attribute__((section(".text.v2"))) = "0123456789";
+EOF
+cat - > $TMPFILE1_ld <<EOF
+SECTIONS
+{
+ .mysection 0x88f0 : {
+. = 0x10 ;
+*(.text.v1)
+. = 0x20 ;
+*(.text.v2)
+. = 0x30 ;
+ }
+}
+EOF
+$CC -O -g -c $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
+$LD -T $TMPFILE1_ld $TMPFILE1o -o $TMPFILE2o > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo "The version of LD on this system does not properly handle" > /dev/fd/2
+ echo "alignments. As a result, this project can not be built." > /dev/fd/2
+ echo "" > /dev/fd/2
+ echo "The problem may be the result of this LD bug report:" > /dev/fd/2
+ echo " http://sourceware.org/bugzilla/show_bug.cgi?id=12726" > /dev/fd/2
+ echo "" > /dev/fd/2
+ echo "Please update to a working version of binutils and retry." > /dev/fd/2
+ echo -1
+ exit 0
+fi
+
+# Test for "-fwhole-program". Older versions of gcc (pre v4.1) don't
+# support the whole-program optimization - detect that.
+$CC -fwhole-program -S -o /dev/null -xc /dev/null > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo " Working around no -fwhole-program" > /dev/fd/2
+ echo 2
+ exit 0
+fi
+
+# Test if "visible" variables and functions are marked global. On
+# OpenSuse 10.3 "visible" variables declared with "extern" first
+# aren't marked as global in the resulting assembler. On Ubuntu 7.10
+# "visible" functions aren't marked as global in the resulting
+# assembler.
+cat - > $TMPFILE1 <<EOF
+void __attribute__((externally_visible)) t1() { }
+extern unsigned char v1;
+unsigned char v1 __attribute__((section(".data16.foo.19"))) __attribute__((externally_visible));
+EOF
+$CC -Os -c -fwhole-program $TMPFILE1 -o $TMPFILE1o > /dev/null 2>&1
+cat - > $TMPFILE2 <<EOF
+void t1();
+extern unsigned char v1;
+int __attribute__((externally_visible)) main() { t1(); return v1; }
+EOF
+$CC -Os -c -fwhole-program $TMPFILE2 -o $TMPFILE2o > /dev/null 2>&1
+$CC -nostdlib -Os $TMPFILE1o $TMPFILE2o -o $TMPFILE3o > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ echo " Working around non-functional -fwhole-program" > /dev/fd/2
+ echo 2
+ exit 0
+fi
+
+# Test if "-combine" works. On Ubuntu 8.04 the compiler doesn't work
+# correctly with combine and the "struct bregs" register due to the
+# anonymous unions and structs. On Fedora Core 12 the compiler throws
+# an internal compiler error when multiple files access global
+# variables with debugging enabled.
+cat - > $TMPFILE1 <<EOF
+// Look for anonymous union/struct failure
+struct ts { union { int u1; struct { int u2; }; }; };
+void func1(struct ts *r);
+
+// Look for global variable failure.
+struct s1_s { int v; } g1;
+void __attribute__((externally_visible)) func2() {
+ struct s1_s *l1 = &g1;
+ l1->v=0;
+}
+EOF
+cat - > $TMPFILE2 <<EOF
+struct ts { union { int u1; struct { int u2; }; }; };
+void func1(struct ts *r);
+
+extern struct s1_s g1;
+void func3() {
+ &g1;
+}
+EOF
+$CC -O -g -fwhole-program -combine -c $TMPFILE1 $TMPFILE2 -o $TMPFILE1o > /dev/null 2>&1
+if [ $? -eq 0 ]; then
+ echo 0
+else
+ echo " Working around non-functional -combine" > /dev/fd/2
+ echo 1
+fi
+
+# Also, on several compilers, -combine fails if code is emitted with a
+# reference to an extern variable that is later found to be externally
+# visible - the compiler does not mark those variables as global.
+# This is being worked around by ordering the compile objects to avoid
+# this case.
+
+# Also, the Ubuntu 8.04 compiler has a bug causing corruption when the
+# "ebp" register is clobberred in an "asm" statement. The code has
+# been modified to not clobber "ebp" - no test is available yet.
+
+rm -f $TMPFILE1 $TMPFILE1o $TMPFILE1_ld $TMPFILE2 $TMPFILE2o $TMPFILE3o
--- /dev/null
+#!/usr/bin/env python
+
+# This script is useful for taking the output of memdump() and
+# converting it back into binary output. This can be useful, for
+# example, when one wants to push that data into other tools like
+# objdump or hexdump.
+#
+# (C) Copyright 2010 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+
+import sys
+import struct
+
+def unhex(str):
+ return int(str, 16)
+
+def parseMem(filehdl):
+ mem = []
+ for line in filehdl:
+ parts = line.split(':')
+ if len(parts) < 2:
+ continue
+ try:
+ vaddr = unhex(parts[0])
+ parts = parts[1].split()
+ mem.extend([unhex(v) for v in parts])
+ except ValueError:
+ continue
+ return mem
+
+def printUsage():
+ sys.stderr.write("Usage:\n %s <file | ->\n"
+ % (sys.argv[0],))
+ sys.exit(1)
+
+def main():
+ if len(sys.argv) != 2:
+ printUsage()
+ filename = sys.argv[1]
+ if filename == '-':
+ filehdl = sys.stdin
+ else:
+ filehdl = open(filename, 'r')
+ mem = parseMem(filehdl)
+ for i in mem:
+ sys.stdout.write(struct.pack("<I", i))
+
+if __name__ == '__main__':
+ main()
--- /dev/null
+// QEMU Cirrus CLGD 54xx VGABIOS Extension.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (c) 2004 Makoto Suzuki (suzu)
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "vgatables.h" // cirrus_init
+#include "biosvar.h" // GET_GLOBAL
+#include "util.h" // dprintf
+
+struct cirrus_mode_s {
+ /* + 0 */
+ u16 mode;
+ u16 width;
+ u16 height;
+ u16 depth;
+ /* + 8 */
+ u16 hidden_dac; /* 0x3c6 */
+ u16 *seq; /* 0x3c4 */
+ u16 *graph; /* 0x3ce */
+ u16 *crtc; /* 0x3d4 */
+ /* +16 */
+ u8 bitsperpixel;
+ u8 vesacolortype;
+ u8 vesaredmask;
+ u8 vesaredpos;
+ u8 vesagreenmask;
+ u8 vesagreenpos;
+ u8 vesabluemask;
+ u8 vesabluepos;
+ /* +24 */
+ u8 vesareservedmask;
+ u8 vesareservedpos;
+};
+
+/* VGA */
+static u16 cseq_vga[] VAR16 = {0x0007,0xffff};
+static u16 cgraph_vga[] VAR16 = {0x0009,0x000a,0x000b,0xffff};
+static u16 ccrtc_vga[] VAR16 = {0x001a,0x001b,0x001d,0xffff};
+
+/* extensions */
+static u16 cgraph_svgacolor[] VAR16 = {
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08,
+ 0x0009,0x000a,0x000b,
+ 0xffff
+};
+/* 640x480x8 */
+static u16 cseq_640x480x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x580b,0x580c,0x580d,0x580e,
+ 0x0412,0x0013,0x2017,
+ 0x331b,0x331c,0x331d,0x331e,
+ 0xffff
+};
+static u16 ccrtc_640x480x8[] VAR16 = {
+ 0x2c11,
+ 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+ 0x4009,0x000c,0x000d,
+ 0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 640x480x16 */
+static u16 cseq_640x480x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x580b,0x580c,0x580d,0x580e,
+ 0x0412,0x0013,0x2017,
+ 0x331b,0x331c,0x331d,0x331e,
+ 0xffff
+};
+static u16 ccrtc_640x480x16[] VAR16 = {
+ 0x2c11,
+ 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+ 0x4009,0x000c,0x000d,
+ 0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 640x480x24 */
+static u16 cseq_640x480x24[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+ 0x580b,0x580c,0x580d,0x580e,
+ 0x0412,0x0013,0x2017,
+ 0x331b,0x331c,0x331d,0x331e,
+ 0xffff
+};
+static u16 ccrtc_640x480x24[] VAR16 = {
+ 0x2c11,
+ 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
+ 0x4009,0x000c,0x000d,
+ 0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+/* 800x600x8 */
+static u16 cseq_800x600x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x230b,0x230c,0x230d,0x230e,
+ 0x0412,0x0013,0x2017,
+ 0x141b,0x141c,0x141d,0x141e,
+ 0xffff
+};
+static u16 ccrtc_800x600x8[] VAR16 = {
+ 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+ 0x6009,0x000c,0x000d,
+ 0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 800x600x16 */
+static u16 cseq_800x600x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x230b,0x230c,0x230d,0x230e,
+ 0x0412,0x0013,0x2017,
+ 0x141b,0x141c,0x141d,0x141e,
+ 0xffff
+};
+static u16 ccrtc_800x600x16[] VAR16 = {
+ 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+ 0x6009,0x000c,0x000d,
+ 0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 800x600x24 */
+static u16 cseq_800x600x24[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+ 0x230b,0x230c,0x230d,0x230e,
+ 0x0412,0x0013,0x2017,
+ 0x141b,0x141c,0x141d,0x141e,
+ 0xffff
+};
+static u16 ccrtc_800x600x24[] VAR16 = {
+ 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
+ 0x6009,0x000c,0x000d,
+ 0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+/* 1024x768x8 */
+static u16 cseq_1024x768x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1024x768x8[] VAR16 = {
+ 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 1024x768x16 */
+static u16 cseq_1024x768x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1024x768x16[] VAR16 = {
+ 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+/* 1024x768x24 */
+static u16 cseq_1024x768x24[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1024x768x24[] VAR16 = {
+ 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+/* 1280x1024x8 */
+static u16 cseq_1280x1024x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1280x1024x8[] VAR16 = {
+ 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+/* 1280x1024x16 */
+static u16 cseq_1280x1024x16[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1280x1024x16[] VAR16 = {
+ 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x321b,0x001d,
+ 0xffff
+};
+
+/* 1600x1200x8 */
+static u16 cseq_1600x1200x8[] VAR16 = {
+ 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
+ 0x760b,0x760c,0x760d,0x760e,
+ 0x0412,0x0013,0x2017,
+ 0x341b,0x341c,0x341d,0x341e,
+ 0xffff
+};
+static u16 ccrtc_1600x1200x8[] VAR16 = {
+ 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
+ 0x6009,0x000c,0x000d,
+ 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
+ 0x001a,0x221b,0x001d,
+ 0xffff
+};
+
+static struct cirrus_mode_s cirrus_modes[] VAR16 = {
+ {0x5f,640,480,8,0x00,
+ cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8,
+ 4,0,0,0,0,0,0,0,0},
+ {0x64,640,480,16,0xe1,
+ cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+ 6,5,11,6,5,5,0,0,0},
+ {0x66,640,480,15,0xf0,
+ cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
+ 6,5,10,5,5,5,0,1,15},
+ {0x71,640,480,24,0xe5,
+ cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24,
+ 6,8,16,8,8,8,0,0,0},
+
+ {0x5c,800,600,8,0x00,
+ cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8,
+ 4,0,0,0,0,0,0,0,0},
+ {0x65,800,600,16,0xe1,
+ cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+ 6,5,11,6,5,5,0,0,0},
+ {0x67,800,600,15,0xf0,
+ cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
+ 6,5,10,5,5,5,0,1,15},
+
+ {0x60,1024,768,8,0x00,
+ cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8,
+ 4,0,0,0,0,0,0,0,0},
+ {0x74,1024,768,16,0xe1,
+ cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+ 6,5,11,6,5,5,0,0,0},
+ {0x68,1024,768,15,0xf0,
+ cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
+ 6,5,10,5,5,5,0,1,15},
+
+ {0x78,800,600,24,0xe5,
+ cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24,
+ 6,8,16,8,8,8,0,0,0},
+ {0x79,1024,768,24,0xe5,
+ cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24,
+ 6,8,16,8,8,8,0,0,0},
+
+ {0x6d,1280,1024,8,0x00,
+ cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8,
+ 4,0,0,0,0,0,0,0,0},
+ {0x69,1280,1024,15,0xf0,
+ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+ 6,5,10,5,5,5,0,1,15},
+ {0x75,1280,1024,16,0xe1,
+ cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
+ 6,5,11,6,5,5,0,0,0},
+
+ {0x7b,1600,1200,8,0x00,
+ cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8,
+ 4,0,0,0,0,0,0,0,0},
+
+ {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0,
+ 0xff,0,0,0,0,0,0,0,0},
+};
+
+static struct cirrus_mode_s *
+cirrus_get_modeentry(u8 mode)
+{
+ struct cirrus_mode_s *table_g = cirrus_modes;
+ while (table_g < &cirrus_modes[ARRAY_SIZE(cirrus_modes)]) {
+ u16 tmode = GET_GLOBAL(table_g->mode);
+ if (tmode == mode)
+ return table_g;
+ table_g++;
+ }
+ return NULL;
+}
+
+static void
+cirrus_switch_mode_setregs(u16 *data, u16 port)
+{
+ for (;;) {
+ u16 val = GET_GLOBAL(*data);
+ if (val == 0xffff)
+ return;
+ outw(val, port);
+ data++;
+ }
+}
+
+static u16
+cirrus_get_crtc(void)
+{
+ if (inb(VGAREG_READ_MISC_OUTPUT) & 1)
+ return VGAREG_VGA_CRTC_ADDRESS;
+ return VGAREG_MDA_CRTC_ADDRESS;
+}
+
+static void
+cirrus_switch_mode(struct cirrus_mode_s *table)
+{
+ // Unlock cirrus special
+ outw(0x1206, VGAREG_SEQU_ADDRESS);
+ cirrus_switch_mode_setregs(GET_GLOBAL(table->seq), VGAREG_SEQU_ADDRESS);
+ cirrus_switch_mode_setregs(GET_GLOBAL(table->graph), VGAREG_GRDC_ADDRESS);
+ cirrus_switch_mode_setregs(GET_GLOBAL(table->crtc), cirrus_get_crtc());
+
+ outb(0x00, VGAREG_PEL_MASK);
+ inb(VGAREG_PEL_MASK);
+ inb(VGAREG_PEL_MASK);
+ inb(VGAREG_PEL_MASK);
+ inb(VGAREG_PEL_MASK);
+ outb(GET_GLOBAL(table->hidden_dac), VGAREG_PEL_MASK);
+ outb(0xff, VGAREG_PEL_MASK);
+
+ u8 vesacolortype = GET_GLOBAL(table->vesacolortype);
+ u8 v = vgahw_get_single_palette_reg(0x10) & 0xfe;
+ if (vesacolortype == 3)
+ v |= 0x41;
+ else if (vesacolortype)
+ v |= 0x01;
+ vgahw_set_single_palette_reg(0x10, v);
+}
+
+void
+cirrus_set_video_mode(u8 mode)
+{
+ dprintf(1, "cirrus mode %d\n", mode);
+ SET_BDA(vbe_mode, 0);
+ struct cirrus_mode_s *table_g = cirrus_get_modeentry(mode & 0x7f);
+ if (table_g) {
+ //XXX - cirrus_set_video_mode_extended(table);
+ return;
+ }
+ table_g = cirrus_get_modeentry(0xfe);
+ cirrus_switch_mode(table_g);
+ dprintf(1, "cirrus mode switch regular\n");
+}
+
+static int
+cirrus_check(void)
+{
+ outw(0x9206, VGAREG_SEQU_ADDRESS);
+ return inb(VGAREG_SEQU_DATA) == 0x12;
+}
+
+void
+cirrus_init(void)
+{
+ dprintf(1, "cirrus init\n");
+ if (! cirrus_check())
+ return;
+ dprintf(1, "cirrus init 2\n");
+
+ // memory setup
+ outb(0x0f, VGAREG_SEQU_ADDRESS);
+ u8 v = inb(VGAREG_SEQU_DATA);
+ outb(((v & 0x18) << 8) | 0x0a, VGAREG_SEQU_ADDRESS);
+ // set vga mode
+ outw(0x0007, VGAREG_SEQU_ADDRESS);
+ // reset bitblt
+ outw(0x0431, VGAREG_GRDC_ADDRESS);
+ outw(0x0031, VGAREG_GRDC_ADDRESS);
+}
--- /dev/null
+// VGA bios implementation
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+// TODO:
+// * review correctness of converted asm by comparing with RBIL
+//
+// * convert vbe/clext code
+
+#include "bregs.h" // struct bregs
+#include "biosvar.h" // GET_BDA
+#include "util.h" // memset
+#include "vgatables.h" // find_vga_entry
+
+// XXX
+#define CONFIG_VBE 0
+#define CONFIG_CIRRUS 0
+
+// XXX
+#define DEBUG_VGA_POST 1
+#define DEBUG_VGA_10 3
+
+#define SET_VGA(var, val) SET_FARVAR(get_global_seg(), (var), (val))
+
+
+/****************************************************************
+ * Helper functions
+ ****************************************************************/
+
+static inline void
+call16_vgaint(u32 eax, u32 ebx)
+{
+ asm volatile(
+ "int $0x10\n"
+ "cli\n"
+ "cld"
+ :
+ : "a"(eax), "b"(ebx)
+ : "cc", "memory");
+}
+
+static void
+perform_gray_scale_summing(u16 start, u16 count)
+{
+ vgahw_screen_disable();
+ int i;
+ for (i = start; i < start+count; i++) {
+ u8 rgb[3];
+ vgahw_get_dac_regs(GET_SEG(SS), rgb, i, 1);
+
+ // intensity = ( 0.3 * Red ) + ( 0.59 * Green ) + ( 0.11 * Blue )
+ u16 intensity = ((77 * rgb[0] + 151 * rgb[1] + 28 * rgb[2]) + 0x80) >> 8;
+ if (intensity > 0x3f)
+ intensity = 0x3f;
+
+ vgahw_set_dac_regs(GET_SEG(SS), rgb, i, 1);
+ }
+ vgahw_screen_enable();
+}
+
+static void
+set_cursor_shape(u8 start, u8 end)
+{
+ start &= 0x3f;
+ end &= 0x1f;
+
+ u16 curs = (start << 8) + end;
+ SET_BDA(cursor_type, curs);
+
+ u8 modeset_ctl = GET_BDA(modeset_ctl);
+ u16 cheight = GET_BDA(char_height);
+ if ((modeset_ctl & 0x01) && (cheight > 8) && (end < 8) && (start < 0x20)) {
+ if (end != (start + 1))
+ start = ((start + 1) * cheight / 8) - 1;
+ else
+ start = ((end + 1) * cheight / 8) - 2;
+ end = ((end + 1) * cheight / 8) - 1;
+ }
+ vgahw_set_cursor_shape(start, end);
+}
+
+static u16
+get_cursor_shape(u8 page)
+{
+ if (page > 7)
+ return 0;
+ // FIXME should handle VGA 14/16 lines
+ return GET_BDA(cursor_type);
+}
+
+static void
+set_cursor_pos(struct cursorpos cp)
+{
+ // Should not happen...
+ if (cp.page > 7)
+ return;
+
+ // Bios cursor pos
+ SET_BDA(cursor_pos[cp.page], (cp.y << 8) | cp.x);
+
+ // Set the hardware cursor
+ u8 current = GET_BDA(video_page);
+ if (cp.page != current)
+ return;
+
+ // Get the dimensions
+ u16 nbcols = GET_BDA(video_cols);
+ u16 nbrows = GET_BDA(video_rows) + 1;
+
+ // Calculate the address knowing nbcols nbrows and page num
+ u16 address = (SCREEN_IO_START(nbcols, nbrows, cp.page)
+ + cp.x + cp.y * nbcols);
+
+ vgahw_set_cursor_pos(address);
+}
+
+static struct cursorpos
+get_cursor_pos(u8 page)
+{
+ if (page == 0xff)
+ // special case - use current page
+ page = GET_BDA(video_page);
+ if (page > 7) {
+ struct cursorpos cp = { 0, 0, 0xfe };
+ return cp;
+ }
+ // FIXME should handle VGA 14/16 lines
+ u16 xy = GET_BDA(cursor_pos[page]);
+ struct cursorpos cp = {xy, xy>>8, page};
+ return cp;
+}
+
+static void
+set_active_page(u8 page)
+{
+ if (page > 7)
+ return;
+
+ // Get the mode
+ struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+ if (!vmode_g)
+ return;
+
+ // Get pos curs pos for the right page
+ struct cursorpos cp = get_cursor_pos(page);
+
+ u16 address;
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
+ // Get the dimensions
+ u16 nbcols = GET_BDA(video_cols);
+ u16 nbrows = GET_BDA(video_rows) + 1;
+
+ // Calculate the address knowing nbcols nbrows and page num
+ address = SCREEN_MEM_START(nbcols, nbrows, page);
+ SET_BDA(video_pagestart, address);
+
+ // Start address
+ address = SCREEN_IO_START(nbcols, nbrows, page);
+ } else {
+ struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+ address = page * GET_GLOBAL(vparam_g->slength);
+ }
+
+ vgahw_set_active_page(address);
+
+ // And change the BIOS page
+ SET_BDA(video_page, page);
+
+ dprintf(1, "Set active page %02x address %04x\n", page, address);
+
+ // Display the cursor, now the page is active
+ set_cursor_pos(cp);
+}
+
+static void
+set_scan_lines(u8 lines)
+{
+ vgahw_set_scan_lines(lines);
+ if (lines == 8)
+ set_cursor_shape(0x06, 0x07);
+ else
+ set_cursor_shape(lines - 4, lines - 3);
+ SET_BDA(char_height, lines);
+ u16 vde = vgahw_get_vde();
+ u8 rows = vde / lines;
+ SET_BDA(video_rows, rows - 1);
+ u16 cols = GET_BDA(video_cols);
+ SET_BDA(video_pagesize, rows * cols * 2);
+}
+
+
+/****************************************************************
+ * Character writing
+ ****************************************************************/
+
+// Scroll the screen one line. This function is designed to be called
+// tail-recursive to reduce stack usage.
+static void noinline
+scroll_one(u16 nbrows, u16 nbcols, u8 page)
+{
+ struct cursorpos ul = {0, 0, page};
+ struct cursorpos lr = {nbcols-1, nbrows-1, page};
+ vgafb_scroll(1, -1, ul, lr);
+}
+
+// Write a character to the screen at a given position. Implement
+// special characters and scroll the screen if necessary.
+static void
+write_teletype(struct cursorpos *pcp, struct carattr ca)
+{
+ struct cursorpos cp = *pcp;
+
+ // Get the dimensions
+ u16 nbrows = GET_BDA(video_rows) + 1;
+ u16 nbcols = GET_BDA(video_cols);
+
+ switch (ca.car) {
+ case 7:
+ //FIXME should beep
+ break;
+ case 8:
+ if (cp.x > 0)
+ cp.x--;
+ break;
+ case '\r':
+ cp.x = 0;
+ break;
+ case '\n':
+ cp.y++;
+ break;
+ case '\t':
+ do {
+ struct carattr dummyca = {' ', ca.attr, ca.use_attr};
+ vgafb_write_char(cp, dummyca);
+ cp.x++;
+ } while (cp.x < nbcols && cp.x % 8);
+ break;
+ default:
+ vgafb_write_char(cp, ca);
+ cp.x++;
+ }
+
+ // Do we need to wrap ?
+ if (cp.x == nbcols) {
+ cp.x = 0;
+ cp.y++;
+ }
+ // Do we need to scroll ?
+ if (cp.y < nbrows) {
+ *pcp = cp;
+ return;
+ }
+ // Scroll screen
+ cp.y--;
+ *pcp = cp;
+ scroll_one(nbrows, nbcols, cp.page);
+}
+
+// Write out a buffer of alternating characters and attributes.
+static void
+write_attr_string(struct cursorpos *pcp, u16 count, u16 seg, u8 *offset_far)
+{
+ while (count--) {
+ u8 car = GET_FARVAR(seg, *offset_far);
+ offset_far++;
+ u8 attr = GET_FARVAR(seg, *offset_far);
+ offset_far++;
+
+ struct carattr ca = {car, attr, 1};
+ write_teletype(pcp, ca);
+ }
+}
+
+// Write out a buffer of characters.
+static void
+write_string(struct cursorpos *pcp, u8 attr, u16 count, u16 seg, u8 *offset_far)
+{
+ while (count--) {
+ u8 car = GET_FARVAR(seg, *offset_far);
+ offset_far++;
+
+ struct carattr ca = {car, attr, 1};
+ write_teletype(pcp, ca);
+ }
+}
+
+
+/****************************************************************
+ * Save and restore bda state
+ ****************************************************************/
+
+static void
+save_bda_state(u16 seg, struct saveBDAstate *info)
+{
+ SET_FARVAR(seg, info->video_mode, GET_BDA(video_mode));
+ SET_FARVAR(seg, info->video_cols, GET_BDA(video_cols));
+ SET_FARVAR(seg, info->video_pagesize, GET_BDA(video_pagesize));
+ SET_FARVAR(seg, info->crtc_address, GET_BDA(crtc_address));
+ SET_FARVAR(seg, info->video_rows, GET_BDA(video_rows));
+ SET_FARVAR(seg, info->char_height, GET_BDA(char_height));
+ SET_FARVAR(seg, info->video_ctl, GET_BDA(video_ctl));
+ SET_FARVAR(seg, info->video_switches, GET_BDA(video_switches));
+ SET_FARVAR(seg, info->modeset_ctl, GET_BDA(modeset_ctl));
+ SET_FARVAR(seg, info->cursor_type, GET_BDA(cursor_type));
+ u16 i;
+ for (i=0; i<8; i++)
+ SET_FARVAR(seg, info->cursor_pos[i], GET_BDA(cursor_pos[i]));
+ SET_FARVAR(seg, info->video_pagestart, GET_BDA(video_pagestart));
+ SET_FARVAR(seg, info->video_page, GET_BDA(video_page));
+ /* current font */
+ SET_FARVAR(seg, info->font0, GET_IVT(0x1f));
+ SET_FARVAR(seg, info->font1, GET_IVT(0x43));
+}
+
+static void
+restore_bda_state(u16 seg, struct saveBDAstate *info)
+{
+ SET_BDA(video_mode, GET_FARVAR(seg, info->video_mode));
+ SET_BDA(video_cols, GET_FARVAR(seg, info->video_cols));
+ SET_BDA(video_pagesize, GET_FARVAR(seg, info->video_pagesize));
+ SET_BDA(crtc_address, GET_FARVAR(seg, info->crtc_address));
+ SET_BDA(video_rows, GET_FARVAR(seg, info->video_rows));
+ SET_BDA(char_height, GET_FARVAR(seg, info->char_height));
+ SET_BDA(video_ctl, GET_FARVAR(seg, info->video_ctl));
+ SET_BDA(video_switches, GET_FARVAR(seg, info->video_switches));
+ SET_BDA(modeset_ctl, GET_FARVAR(seg, info->modeset_ctl));
+ SET_BDA(cursor_type, GET_FARVAR(seg, info->cursor_type));
+ u16 i;
+ for (i = 0; i < 8; i++)
+ SET_BDA(cursor_pos[i], GET_FARVAR(seg, info->cursor_pos[i]));
+ SET_BDA(video_pagestart, GET_FARVAR(seg, info->video_pagestart));
+ SET_BDA(video_page, GET_FARVAR(seg, info->video_page));
+ /* current font */
+ SET_IVT(0x1f, GET_FARVAR(seg, info->font0));
+ SET_IVT(0x43, GET_FARVAR(seg, info->font1));
+}
+
+
+/****************************************************************
+ * VGA int 10 handler
+ ****************************************************************/
+
+// set video mode
+static void
+handle_1000(struct bregs *regs)
+{
+ u8 noclearmem = regs->al & 0x80;
+ u8 mode = regs->al & 0x7f;
+
+ // Set regs->al
+ if (mode > 7)
+ regs->al = 0x20;
+ else if (mode == 6)
+ regs->al = 0x3f;
+ else
+ regs->al = 0x30;
+
+ if (CONFIG_CIRRUS)
+ cirrus_set_video_mode(mode);
+
+ if (CONFIG_VBE)
+ if (vbe_has_vbe_display())
+ dispi_set_enable(VBE_DISPI_DISABLED);
+
+ // find the entry in the video modes
+ struct vgamode_s *vmode_g = find_vga_entry(mode);
+ dprintf(1, "mode search %02x found %p\n", mode, vmode_g);
+ if (!vmode_g)
+ return;
+
+ // Read the bios mode set control
+ u8 modeset_ctl = GET_BDA(modeset_ctl);
+
+ // Then we know the number of lines
+// FIXME
+
+ // if palette loading (bit 3 of modeset ctl = 0)
+ if ((modeset_ctl & 0x08) == 0) { // Set the PEL mask
+ vgahw_set_pel_mask(GET_GLOBAL(vmode_g->pelmask));
+
+ // From which palette
+ u8 *palette_g = GET_GLOBAL(vmode_g->dac);
+ u16 palsize = GET_GLOBAL(vmode_g->dacsize) / 3;
+
+ // Always 256*3 values
+ vgahw_set_dac_regs(get_global_seg(), palette_g, 0, palsize);
+ u16 i;
+ for (i = palsize; i < 0x0100; i++) {
+ static u8 rgb[3] VAR16;
+ vgahw_set_dac_regs(get_global_seg(), rgb, i, 1);
+ }
+
+ if ((modeset_ctl & 0x02) == 0x02)
+ perform_gray_scale_summing(0x00, 0x100);
+ }
+
+ struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+ vgahw_set_mode(vparam_g);
+
+ if (noclearmem == 0x00)
+ clear_screen(vmode_g);
+
+ // Set CRTC address VGA or MDA
+ u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+ if (GET_GLOBAL(vmode_g->memmodel) == MTEXT)
+ crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+ // Set the BIOS mem
+ u16 cheight = GET_GLOBAL(vparam_g->cheight);
+ SET_BDA(video_mode, mode);
+ SET_BDA(video_cols, GET_GLOBAL(vparam_g->twidth));
+ SET_BDA(video_pagesize, GET_GLOBAL(vparam_g->slength));
+ SET_BDA(crtc_address, crtc_addr);
+ SET_BDA(video_rows, GET_GLOBAL(vparam_g->theightm1));
+ SET_BDA(char_height, cheight);
+ SET_BDA(video_ctl, (0x60 | noclearmem));
+ SET_BDA(video_switches, 0xF9);
+ SET_BDA(modeset_ctl, GET_BDA(modeset_ctl) & 0x7f);
+
+ // FIXME We nearly have the good tables. to be reworked
+ SET_BDA(dcc_index, 0x08); // 8 is VGA should be ok for now
+ SET_BDA(video_savetable
+ , SEGOFF(get_global_seg(), (u32)video_save_pointer_table));
+
+ // FIXME
+ SET_BDA(video_msr, 0x00); // Unavailable on vanilla vga, but...
+ SET_BDA(video_pal, 0x00); // Unavailable on vanilla vga, but...
+
+ // Set cursor shape
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+ set_cursor_shape(0x06, 0x07);
+ // Set cursor pos for page 0..7
+ int i;
+ for (i = 0; i < 8; i++) {
+ struct cursorpos cp = {0, 0, i};
+ set_cursor_pos(cp);
+ }
+
+ // Set active page 0
+ set_active_page(0x00);
+
+ // Write the fonts in memory
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT) {
+ call16_vgaint(0x1104, 0);
+ call16_vgaint(0x1103, 0);
+ }
+ // Set the ints 0x1F and 0x43
+ SET_IVT(0x1f, SEGOFF(get_global_seg(), (u32)&vgafont8[128 * 8]));
+
+ switch (cheight) {
+ case 8:
+ SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont8));
+ break;
+ case 14:
+ SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont14));
+ break;
+ case 16:
+ SET_IVT(0x43, SEGOFF(get_global_seg(), (u32)vgafont16));
+ break;
+ }
+}
+
+static void
+handle_1001(struct bregs *regs)
+{
+ set_cursor_shape(regs->ch, regs->cl);
+}
+
+static void
+handle_1002(struct bregs *regs)
+{
+ struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+ set_cursor_pos(cp);
+}
+
+static void
+handle_1003(struct bregs *regs)
+{
+ regs->cx = get_cursor_shape(regs->bh);
+ struct cursorpos cp = get_cursor_pos(regs->bh);
+ regs->dl = cp.x;
+ regs->dh = cp.y;
+}
+
+// Read light pen pos (unimplemented)
+static void
+handle_1004(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->ax = regs->bx = regs->cx = regs->dx = 0;
+}
+
+static void
+handle_1005(struct bregs *regs)
+{
+ set_active_page(regs->al);
+}
+
+static void
+verify_scroll(struct bregs *regs, int dir)
+{
+ u8 page = GET_BDA(video_page);
+ struct cursorpos ul = {regs->cl, regs->ch, page};
+ struct cursorpos lr = {regs->dl, regs->dh, page};
+
+ u16 nbrows = GET_BDA(video_rows) + 1;
+ if (lr.y >= nbrows)
+ lr.y = nbrows - 1;
+ u16 nbcols = GET_BDA(video_cols);
+ if (lr.x >= nbcols)
+ lr.x = nbcols - 1;
+
+ if (ul.x > lr.x || ul.y > lr.y)
+ return;
+
+ u16 nblines = regs->al;
+ if (!nblines || nblines > lr.y - ul.y + 1)
+ nblines = lr.y - ul.y + 1;
+
+ vgafb_scroll(dir * nblines, regs->bh, ul, lr);
+}
+
+static void
+handle_1006(struct bregs *regs)
+{
+ verify_scroll(regs, 1);
+}
+
+static void
+handle_1007(struct bregs *regs)
+{
+ verify_scroll(regs, -1);
+}
+
+static void
+handle_1008(struct bregs *regs)
+{
+ struct carattr ca = vgafb_read_char(get_cursor_pos(regs->bh));
+ regs->al = ca.car;
+ regs->ah = ca.attr;
+}
+
+static void noinline
+write_chars(u8 page, struct carattr ca, u16 count)
+{
+ struct cursorpos cp = get_cursor_pos(page);
+ while (count--) {
+ vgafb_write_char(cp, ca);
+ cp.x++;
+ }
+}
+
+static void
+handle_1009(struct bregs *regs)
+{
+ struct carattr ca = {regs->al, regs->bl, 1};
+ write_chars(regs->bh, ca, regs->cx);
+}
+
+static void
+handle_100a(struct bregs *regs)
+{
+ struct carattr ca = {regs->al, regs->bl, 0};
+ write_chars(regs->bh, ca, regs->cx);
+}
+
+
+static void
+handle_100b00(struct bregs *regs)
+{
+ vgahw_set_border_color(regs->bl);
+}
+
+static void
+handle_100b01(struct bregs *regs)
+{
+ vgahw_set_palette(regs->bl);
+}
+
+static void
+handle_100bXX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_100b(struct bregs *regs)
+{
+ switch (regs->bh) {
+ case 0x00: handle_100b00(regs); break;
+ case 0x01: handle_100b01(regs); break;
+ default: handle_100bXX(regs); break;
+ }
+}
+
+
+static void
+handle_100c(struct bregs *regs)
+{
+ // XXX - page (regs->bh) is unused
+ vgafb_write_pixel(regs->al, regs->cx, regs->dx);
+}
+
+static void
+handle_100d(struct bregs *regs)
+{
+ // XXX - page (regs->bh) is unused
+ regs->al = vgafb_read_pixel(regs->cx, regs->dx);
+}
+
+static void noinline
+handle_100e(struct bregs *regs)
+{
+ // Ralf Brown Interrupt list is WRONG on bh(page)
+ // We do output only on the current page !
+ struct carattr ca = {regs->al, regs->bl, 0};
+ struct cursorpos cp = get_cursor_pos(0xff);
+ write_teletype(&cp, ca);
+ set_cursor_pos(cp);
+}
+
+static void
+handle_100f(struct bregs *regs)
+{
+ regs->bh = GET_BDA(video_page);
+ regs->al = GET_BDA(video_mode) | (GET_BDA(video_ctl) & 0x80);
+ regs->ah = GET_BDA(video_cols);
+}
+
+
+static void
+handle_101000(struct bregs *regs)
+{
+ if (regs->bl > 0x14)
+ return;
+ vgahw_set_single_palette_reg(regs->bl, regs->bh);
+}
+
+static void
+handle_101001(struct bregs *regs)
+{
+ vgahw_set_overscan_border_color(regs->bh);
+}
+
+static void
+handle_101002(struct bregs *regs)
+{
+ vgahw_set_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
+}
+
+static void
+handle_101003(struct bregs *regs)
+{
+ vgahw_toggle_intensity(regs->bl);
+}
+
+static void
+handle_101007(struct bregs *regs)
+{
+ if (regs->bl > 0x14)
+ return;
+ regs->bh = vgahw_get_single_palette_reg(regs->bl);
+}
+
+static void
+handle_101008(struct bregs *regs)
+{
+ regs->bh = vgahw_get_overscan_border_color();
+}
+
+static void
+handle_101009(struct bregs *regs)
+{
+ vgahw_get_all_palette_reg(regs->es, (u8*)(regs->dx + 0));
+}
+
+static void noinline
+handle_101010(struct bregs *regs)
+{
+ u8 rgb[3] = {regs->dh, regs->ch, regs->cl};
+ vgahw_set_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
+}
+
+static void
+handle_101012(struct bregs *regs)
+{
+ vgahw_set_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101013(struct bregs *regs)
+{
+ vgahw_select_video_dac_color_page(regs->bl, regs->bh);
+}
+
+static void noinline
+handle_101015(struct bregs *regs)
+{
+ u8 rgb[3];
+ vgahw_get_dac_regs(GET_SEG(SS), rgb, regs->bx, 1);
+ regs->dh = rgb[0];
+ regs->ch = rgb[1];
+ regs->cl = rgb[2];
+}
+
+static void
+handle_101017(struct bregs *regs)
+{
+ vgahw_get_dac_regs(regs->es, (u8*)(regs->dx + 0), regs->bx, regs->cx);
+}
+
+static void
+handle_101018(struct bregs *regs)
+{
+ vgahw_set_pel_mask(regs->bl);
+}
+
+static void
+handle_101019(struct bregs *regs)
+{
+ regs->bl = vgahw_get_pel_mask();
+}
+
+static void
+handle_10101a(struct bregs *regs)
+{
+ vgahw_read_video_dac_state(®s->bl, ®s->bh);
+}
+
+static void
+handle_10101b(struct bregs *regs)
+{
+ perform_gray_scale_summing(regs->bx, regs->cx);
+}
+
+static void
+handle_1010XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_1010(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_101000(regs); break;
+ case 0x01: handle_101001(regs); break;
+ case 0x02: handle_101002(regs); break;
+ case 0x03: handle_101003(regs); break;
+ case 0x07: handle_101007(regs); break;
+ case 0x08: handle_101008(regs); break;
+ case 0x09: handle_101009(regs); break;
+ case 0x10: handle_101010(regs); break;
+ case 0x12: handle_101012(regs); break;
+ case 0x13: handle_101013(regs); break;
+ case 0x15: handle_101015(regs); break;
+ case 0x17: handle_101017(regs); break;
+ case 0x18: handle_101018(regs); break;
+ case 0x19: handle_101019(regs); break;
+ case 0x1a: handle_10101a(regs); break;
+ case 0x1b: handle_10101b(regs); break;
+ default: handle_1010XX(regs); break;
+ }
+}
+
+
+static void
+handle_101100(struct bregs *regs)
+{
+ vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+ , regs->dx, regs->bl, regs->bh);
+}
+
+static void
+handle_101101(struct bregs *regs)
+{
+ vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+}
+
+static void
+handle_101102(struct bregs *regs)
+{
+ vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+}
+
+static void
+handle_101103(struct bregs *regs)
+{
+ vgahw_set_text_block_specifier(regs->bl);
+}
+
+static void
+handle_101104(struct bregs *regs)
+{
+ vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+}
+
+static void
+handle_101110(struct bregs *regs)
+{
+ vgafb_load_font(regs->es, (void*)(regs->bp+0), regs->cx
+ , regs->dx, regs->bl, regs->bh);
+ set_scan_lines(regs->bh);
+}
+
+static void
+handle_101111(struct bregs *regs)
+{
+ vgafb_load_font(get_global_seg(), vgafont14, 0x100, 0, regs->bl, 14);
+ set_scan_lines(14);
+}
+
+static void
+handle_101112(struct bregs *regs)
+{
+ vgafb_load_font(get_global_seg(), vgafont8, 0x100, 0, regs->bl, 8);
+ set_scan_lines(8);
+}
+
+static void
+handle_101114(struct bregs *regs)
+{
+ vgafb_load_font(get_global_seg(), vgafont16, 0x100, 0, regs->bl, 16);
+ set_scan_lines(16);
+}
+
+static void
+handle_101130(struct bregs *regs)
+{
+ switch (regs->bh) {
+ case 0x00: {
+ struct segoff_s so = GET_IVT(0x1f);
+ regs->es = so.seg;
+ regs->bp = so.offset;
+ break;
+ }
+ case 0x01: {
+ struct segoff_s so = GET_IVT(0x43);
+ regs->es = so.seg;
+ regs->bp = so.offset;
+ break;
+ }
+ case 0x02:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont14;
+ break;
+ case 0x03:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont8;
+ break;
+ case 0x04:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont8 + 128 * 8;
+ break;
+ case 0x05:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont14alt;
+ break;
+ case 0x06:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont16;
+ break;
+ case 0x07:
+ regs->es = get_global_seg();
+ regs->bp = (u32)vgafont16alt;
+ break;
+ default:
+ dprintf(1, "Get font info BH(%02x) was discarded\n", regs->bh);
+ return;
+ }
+ // Set byte/char of on screen font
+ regs->cx = GET_BDA(char_height) & 0xff;
+
+ // Set Highest char row
+ regs->dx = GET_BDA(video_rows);
+}
+
+static void
+handle_1011XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_1011(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_101100(regs); break;
+ case 0x01: handle_101101(regs); break;
+ case 0x02: handle_101102(regs); break;
+ case 0x03: handle_101103(regs); break;
+ case 0x04: handle_101104(regs); break;
+ case 0x10: handle_101110(regs); break;
+ case 0x11: handle_101111(regs); break;
+ case 0x12: handle_101112(regs); break;
+ case 0x14: handle_101114(regs); break;
+ case 0x30: handle_101130(regs); break;
+ default: handle_1011XX(regs); break;
+ }
+}
+
+
+static void
+handle_101210(struct bregs *regs)
+{
+ u16 crtc_addr = GET_BDA(crtc_address);
+ if (crtc_addr == VGAREG_MDA_CRTC_ADDRESS)
+ regs->bx = 0x0103;
+ else
+ regs->bx = 0x0003;
+ regs->cx = GET_BDA(video_switches) & 0x0f;
+}
+
+static void
+handle_101230(struct bregs *regs)
+{
+ u8 mctl = GET_BDA(modeset_ctl);
+ u8 vswt = GET_BDA(video_switches);
+ switch (regs->al) {
+ case 0x00:
+ // 200 lines
+ mctl = (mctl & ~0x10) | 0x80;
+ vswt = (vswt & ~0x0f) | 0x08;
+ break;
+ case 0x01:
+ // 350 lines
+ mctl &= ~0x90;
+ vswt = (vswt & ~0x0f) | 0x09;
+ break;
+ case 0x02:
+ // 400 lines
+ mctl = (mctl & ~0x80) | 0x10;
+ vswt = (vswt & ~0x0f) | 0x09;
+ break;
+ default:
+ dprintf(1, "Select vert res (%02x) was discarded\n", regs->al);
+ break;
+ }
+ SET_BDA(modeset_ctl, mctl);
+ SET_BDA(video_switches, vswt);
+ regs->al = 0x12;
+}
+
+static void
+handle_101231(struct bregs *regs)
+{
+ u8 v = (regs->al & 0x01) << 3;
+ u8 mctl = GET_BDA(video_ctl) & ~0x08;
+ SET_BDA(video_ctl, mctl | v);
+ regs->al = 0x12;
+}
+
+static void
+handle_101232(struct bregs *regs)
+{
+ vgahw_enable_video_addressing(regs->al);
+ regs->al = 0x12;
+}
+
+static void
+handle_101233(struct bregs *regs)
+{
+ u8 v = ((regs->al << 1) & 0x02) ^ 0x02;
+ u8 v2 = GET_BDA(modeset_ctl) & ~0x02;
+ SET_BDA(modeset_ctl, v | v2);
+ regs->al = 0x12;
+}
+
+static void
+handle_101234(struct bregs *regs)
+{
+ u8 v = (regs->al & 0x01) ^ 0x01;
+ u8 v2 = GET_BDA(modeset_ctl) & ~0x01;
+ SET_BDA(modeset_ctl, v | v2);
+ regs->al = 0x12;
+}
+
+static void
+handle_101235(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->al = 0x12;
+}
+
+static void
+handle_101236(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->al = 0x12;
+}
+
+static void
+handle_1012XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_1012(struct bregs *regs)
+{
+ switch (regs->bl) {
+ case 0x10: handle_101210(regs); break;
+ case 0x30: handle_101230(regs); break;
+ case 0x31: handle_101231(regs); break;
+ case 0x32: handle_101232(regs); break;
+ case 0x33: handle_101233(regs); break;
+ case 0x34: handle_101234(regs); break;
+ case 0x35: handle_101235(regs); break;
+ case 0x36: handle_101236(regs); break;
+ default: handle_1012XX(regs); break;
+ }
+
+ // XXX - cirrus has 1280, 1281, 1282, 1285, 129a, 12a0, 12a1, 12a2, 12ae
+}
+
+
+// Write string
+static void noinline
+handle_1013(struct bregs *regs)
+{
+ struct cursorpos cp = {regs->dl, regs->dh, regs->bh};
+ // if row=0xff special case : use current cursor position
+ if (cp.y == 0xff)
+ cp = get_cursor_pos(cp.page);
+ u8 flag = regs->al;
+ if (flag & 2)
+ write_attr_string(&cp, regs->cx, regs->es, (void*)(regs->bp + 0));
+ else
+ write_string(&cp, regs->bl, regs->cx, regs->es, (void*)(regs->bp + 0));
+
+ if (flag & 1)
+ set_cursor_pos(cp);
+}
+
+
+static void
+handle_101a00(struct bregs *regs)
+{
+ regs->bx = GET_BDA(dcc_index);
+ regs->al = 0x1a;
+}
+
+static void
+handle_101a01(struct bregs *regs)
+{
+ SET_BDA(dcc_index, regs->bl);
+ dprintf(1, "Alternate Display code (%02x) was discarded\n", regs->bh);
+ regs->al = 0x1a;
+}
+
+static void
+handle_101aXX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_101a(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_101a00(regs); break;
+ case 0x01: handle_101a01(regs); break;
+ default: handle_101aXX(regs); break;
+ }
+}
+
+
+struct funcInfo {
+ u16 static_functionality_off;
+ u16 static_functionality_seg;
+ u8 bda_0x49[30];
+ u8 bda_0x84[3];
+ u8 dcc_index;
+ u8 dcc_alt;
+ u16 colors;
+ u8 pages;
+ u8 scan_lines;
+ u8 primary_char;
+ u8 secondar_char;
+ u8 misc;
+ u8 non_vga_mode;
+ u8 reserved_2f[2];
+ u8 video_mem;
+ u8 save_flags;
+ u8 disp_info;
+ u8 reserved_34[12];
+};
+
+static void
+handle_101b(struct bregs *regs)
+{
+ u16 seg = regs->es;
+ struct funcInfo *info = (void*)(regs->di+0);
+ memset_far(seg, info, 0, sizeof(*info));
+ // Address of static functionality table
+ SET_FARVAR(seg, info->static_functionality_off, (u32)static_functionality);
+ SET_FARVAR(seg, info->static_functionality_seg, get_global_seg());
+
+ // Hard coded copy from BIOS area. Should it be cleaner ?
+ memcpy_far(seg, info->bda_0x49, SEG_BDA, (void*)0x49
+ , sizeof(info->bda_0x49));
+ memcpy_far(seg, info->bda_0x84, SEG_BDA, (void*)0x84
+ , sizeof(info->bda_0x84));
+
+ SET_FARVAR(seg, info->dcc_index, GET_BDA(dcc_index));
+ SET_FARVAR(seg, info->colors, 16);
+ SET_FARVAR(seg, info->pages, 8);
+ SET_FARVAR(seg, info->scan_lines, 2);
+ SET_FARVAR(seg, info->video_mem, 3);
+ regs->al = 0x1B;
+}
+
+
+static void
+handle_101c00(struct bregs *regs)
+{
+ u16 flags = regs->cx;
+ u16 size = 0;
+ if (flags & 1)
+ size += sizeof(struct saveVideoHardware);
+ if (flags & 2)
+ size += sizeof(struct saveBDAstate);
+ if (flags & 4)
+ size += sizeof(struct saveDACcolors);
+ regs->bx = size;
+ regs->al = 0x1c;
+}
+
+static void
+handle_101c01(struct bregs *regs)
+{
+ u16 flags = regs->cx;
+ u16 seg = regs->es;
+ void *data = (void*)(regs->bx+0);
+ if (flags & 1) {
+ vgahw_save_state(seg, data);
+ data += sizeof(struct saveVideoHardware);
+ }
+ if (flags & 2) {
+ save_bda_state(seg, data);
+ data += sizeof(struct saveBDAstate);
+ }
+ if (flags & 4)
+ vgahw_save_dac_state(seg, data);
+ regs->al = 0x1c;
+}
+
+static void
+handle_101c02(struct bregs *regs)
+{
+ u16 flags = regs->cx;
+ u16 seg = regs->es;
+ void *data = (void*)(regs->bx+0);
+ if (flags & 1) {
+ vgahw_restore_state(seg, data);
+ data += sizeof(struct saveVideoHardware);
+ }
+ if (flags & 2) {
+ restore_bda_state(seg, data);
+ data += sizeof(struct saveBDAstate);
+ }
+ if (flags & 4)
+ vgahw_restore_dac_state(seg, data);
+ regs->al = 0x1c;
+}
+
+static void
+handle_101cXX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+static void
+handle_101c(struct bregs *regs)
+{
+ switch (regs->al) {
+ case 0x00: handle_101c00(regs); break;
+ case 0x01: handle_101c01(regs); break;
+ case 0x02: handle_101c02(regs); break;
+ default: handle_101cXX(regs); break;
+ }
+}
+
+
+static void
+handle_104f00(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_return_controller_information(&AX,ES,DI);
+ // XXX - OR cirrus_vesa_00h
+}
+
+static void
+handle_104f01(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_return_mode_information(&AX,CX,ES,DI);
+ // XXX - OR cirrus_vesa_01h
+}
+
+static void
+handle_104f02(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_set_mode(&AX,BX,ES,DI);
+ // XXX - OR cirrus_vesa_02h
+}
+
+static void
+handle_104f03(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_return_current_mode
+ // XXX - OR cirrus_vesa_03h
+}
+
+static void
+handle_104f04(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_save_restore_state(&AX, CX, DX, ES, &BX);
+}
+
+static void
+handle_104f05(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_display_window_control
+ // XXX - OR cirrus_vesa_05h
+}
+
+static void
+handle_104f06(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_set_get_logical_scan_line_length
+ // XXX - OR cirrus_vesa_06h
+}
+
+static void
+handle_104f07(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_set_get_display_start
+ // XXX - OR cirrus_vesa_07h
+}
+
+static void
+handle_104f08(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_set_get_dac_palette_format
+}
+
+static void
+handle_104f0a(struct bregs *regs)
+{
+ // XXX - vbe_biosfn_return_protected_mode_interface
+}
+
+static void
+handle_104fXX(struct bregs *regs)
+{
+ debug_stub(regs);
+ regs->ax = 0x0100;
+}
+
+static void
+handle_104f(struct bregs *regs)
+{
+ if (! CONFIG_VBE || !vbe_has_vbe_display()) {
+ handle_104fXX(regs);
+ return;
+ }
+
+ switch (regs->al) {
+ case 0x00: handle_104f00(regs); break;
+ case 0x01: handle_104f01(regs); break;
+ case 0x02: handle_104f02(regs); break;
+ case 0x03: handle_104f03(regs); break;
+ case 0x04: handle_104f04(regs); break;
+ case 0x05: handle_104f05(regs); break;
+ case 0x06: handle_104f06(regs); break;
+ case 0x07: handle_104f07(regs); break;
+ case 0x08: handle_104f08(regs); break;
+ case 0x0a: handle_104f0a(regs); break;
+ default: handle_104fXX(regs); break;
+ }
+}
+
+
+static void
+handle_10XX(struct bregs *regs)
+{
+ debug_stub(regs);
+}
+
+// INT 10h Video Support Service Entry Point
+void VISIBLE16
+handle_10(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_VGA_10);
+ switch (regs->ah) {
+ case 0x00: handle_1000(regs); break;
+ case 0x01: handle_1001(regs); break;
+ case 0x02: handle_1002(regs); break;
+ case 0x03: handle_1003(regs); break;
+ case 0x04: handle_1004(regs); break;
+ case 0x05: handle_1005(regs); break;
+ case 0x06: handle_1006(regs); break;
+ case 0x07: handle_1007(regs); break;
+ case 0x08: handle_1008(regs); break;
+ case 0x09: handle_1009(regs); break;
+ case 0x0a: handle_100a(regs); break;
+ case 0x0b: handle_100b(regs); break;
+ case 0x0c: handle_100c(regs); break;
+ case 0x0d: handle_100d(regs); break;
+ case 0x0e: handle_100e(regs); break;
+ case 0x0f: handle_100f(regs); break;
+ case 0x10: handle_1010(regs); break;
+ case 0x11: handle_1011(regs); break;
+ case 0x12: handle_1012(regs); break;
+ case 0x13: handle_1013(regs); break;
+ case 0x1a: handle_101a(regs); break;
+ case 0x1b: handle_101b(regs); break;
+ case 0x1c: handle_101c(regs); break;
+ case 0x4f: handle_104f(regs); break;
+ default: handle_10XX(regs); break;
+ }
+}
+
+
+/****************************************************************
+ * VGA post
+ ****************************************************************/
+
+static void
+init_bios_area(void)
+{
+ // init detected hardware BIOS Area
+ // set 80x25 color (not clear from RBIL but usual)
+ u16 eqf = GET_BDA(equipment_list_flags);
+ SET_BDA(equipment_list_flags, (eqf & 0xffcf) | 0x20);
+
+ // Just for the first int10 find its children
+
+ // the default char height
+ SET_BDA(char_height, 0x10);
+
+ // Clear the screen
+ SET_BDA(video_ctl, 0x60);
+
+ // Set the basic screen we have
+ SET_BDA(video_switches, 0xf9);
+
+ // Set the basic modeset options
+ SET_BDA(modeset_ctl, 0x51);
+
+ // Set the default MSR
+ SET_BDA(video_msr, 0x09);
+}
+
+void VISIBLE16
+vga_post(struct bregs *regs)
+{
+ debug_enter(regs, DEBUG_VGA_POST);
+
+ vgahw_init();
+
+ init_bios_area();
+
+ if (CONFIG_VBE)
+ vbe_init();
+
+ extern void entry_10(void);
+ SET_IVT(0x10, SEGOFF(get_global_seg(), (u32)entry_10));
+
+ if (CONFIG_CIRRUS)
+ cirrus_init();
+
+ // XXX - clear screen and display info
+
+ // XXX: fill it
+ SET_VGA(video_save_pointer_table[0], (u32)video_param_table);
+ SET_VGA(video_save_pointer_table[1], get_global_seg());
+
+ // Fixup checksum
+ extern u8 _rom_header_size, _rom_header_checksum;
+ SET_VGA(_rom_header_checksum, 0);
+ u8 sum = -checksum_far(get_global_seg(), 0, _rom_header_size * 512);
+ SET_VGA(_rom_header_checksum, sum);
+}
--- /dev/null
+// Rom layout and bios assembler to C interface.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+
+/****************************************************************
+ * Include of 16bit C code
+ ****************************************************************/
+
+ .code16gcc
+#include "vgaccode.16.s"
+
+#include "entryfuncs.S" // ENTRY_*
+
+
+/****************************************************************
+ * Rom Header
+ ****************************************************************/
+
+ .section .rom.header
+ .global _rom_header, _rom_header_size, _rom_header_checksum
+_rom_header:
+ .word 0xaa55
+_rom_header_size:
+ .byte 0
+_rom_header_entry:
+ jmp _optionrom_entry
+_rom_header_checksum:
+ .byte 0
+_rom_header_other:
+ .space 21
+
+
+/****************************************************************
+ * Entry points
+ ****************************************************************/
+
+ DECLFUNC _optionrom_entry
+_optionrom_entry:
+ ENTRY_ARG vga_post
+ lretw
+
+ DECLFUNC entry_10
+entry_10:
+ ENTRY_ARG handle_10
+ iretw
--- /dev/null
+// Code for manipulating VGA framebuffers.
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "util.h" // memset_far
+#include "vgatables.h" // find_vga_entry
+
+
+/****************************************************************
+ * Screen scrolling
+ ****************************************************************/
+
+static inline void *
+memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines)
+{
+ for (; lines; lines--, dst+=stride, src+=stride)
+ memcpy_far(seg, dst, seg, src, copylen);
+ return dst;
+}
+
+static inline void
+memset_stride(u16 seg, void *dst, u8 val, int setlen, int stride, int lines)
+{
+ for (; lines; lines--, dst+=stride)
+ memset_far(seg, dst, val, setlen);
+}
+
+static inline void
+memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines)
+{
+ for (; lines; lines--, dst+=stride)
+ memset16_far(seg, dst, val, setlen);
+}
+
+static void
+scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr
+ , struct cursorpos ul, struct cursorpos lr)
+{
+ struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+ u8 cheight = GET_GLOBAL(vparam_g->cheight);
+ int stride = GET_BDA(video_cols);
+ void *src_far, *dest_far;
+ if (nblines >= 0) {
+ dest_far = (void*)(ul.y * cheight * stride + ul.x);
+ src_far = dest_far + nblines * cheight * stride;
+ } else {
+ // Scroll down
+ nblines = -nblines;
+ dest_far = (void*)(lr.y * cheight * stride + ul.x);
+ src_far = dest_far - nblines * cheight * stride;
+ stride = -stride;
+ }
+ int cols = lr.x - ul.x + 1;
+ int rows = lr.y - ul.y + 1;
+ if (nblines < rows) {
+ vgahw_grdc_write(0x05, 0x01);
+ dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols, stride
+ , (rows - nblines) * cheight);
+ }
+ if (attr < 0)
+ attr = 0;
+ vgahw_grdc_write(0x05, 0x02);
+ memset_stride(SEG_GRAPH, dest_far, attr, cols, stride, nblines * cheight);
+ vgahw_grdc_write(0x05, 0x00);
+}
+
+static void
+scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr
+ , struct cursorpos ul, struct cursorpos lr)
+{
+ struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+ u8 cheight = GET_GLOBAL(vparam_g->cheight);
+ u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+ int stride = GET_BDA(video_cols) * bpp;
+ void *src_far, *dest_far;
+ if (nblines >= 0) {
+ dest_far = (void*)(ul.y * cheight * stride + ul.x * bpp);
+ src_far = dest_far + nblines * cheight * stride;
+ } else {
+ // Scroll down
+ nblines = -nblines;
+ dest_far = (void*)(lr.y * cheight * stride + ul.x * bpp);
+ src_far = dest_far - nblines * cheight * stride;
+ stride = -stride;
+ }
+ int cols = (lr.x - ul.x + 1) * bpp;
+ int rows = lr.y - ul.y + 1;
+ if (nblines < rows) {
+ memcpy_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000, cols
+ , stride, (rows - nblines) * cheight / 2);
+ dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols
+ , stride, (rows - nblines) * cheight / 2);
+ }
+ if (attr < 0)
+ attr = 0;
+ memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols
+ , stride, nblines * cheight / 2);
+ memset_stride(SEG_CTEXT, dest_far, attr, cols
+ , stride, nblines * cheight / 2);
+}
+
+static void
+scroll_text(struct vgamode_s *vmode_g, int nblines, int attr
+ , struct cursorpos ul, struct cursorpos lr)
+{
+ u16 nbrows = GET_BDA(video_rows) + 1;
+ u16 nbcols = GET_BDA(video_cols);
+ void *src_far, *dest_far = (void*)SCREEN_MEM_START(nbcols, nbrows, ul.page);
+ int stride = nbcols * 2;
+ if (nblines >= 0) {
+ dest_far += ul.y * stride + ul.x * 2;
+ src_far = dest_far + nblines * stride;
+ } else {
+ // Scroll down
+ nblines = -nblines;
+ dest_far += lr.y * stride + ul.x * 2;
+ src_far = dest_far - nblines * stride;
+ stride = -stride;
+ }
+ int cols = (lr.x - ul.x + 1) * 2;
+ int rows = lr.y - ul.y + 1;
+ u16 seg = GET_GLOBAL(vmode_g->sstart);
+ if (nblines < rows)
+ dest_far = memcpy_stride(seg, dest_far, src_far, cols, stride
+ , (rows - nblines));
+ if (attr < 0)
+ attr = 0x07;
+ attr = (attr << 8) | ' ';
+ memset16_stride(seg, dest_far, attr, cols, stride, nblines);
+}
+
+void
+vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr)
+{
+ // Get the mode
+ struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+ if (!vmode_g)
+ return;
+
+ // FIXME gfx mode not complete
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case CTEXT:
+ case MTEXT:
+ scroll_text(vmode_g, nblines, attr, ul, lr);
+ break;
+ case PLANAR4:
+ case PLANAR1:
+ scroll_pl4(vmode_g, nblines, attr, ul, lr);
+ break;
+ case CGA:
+ scroll_cga(vmode_g, nblines, attr, ul, lr);
+ break;
+ default:
+ dprintf(1, "Scroll in graphics mode\n");
+ }
+}
+
+void
+clear_screen(struct vgamode_s *vmode_g)
+{
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case CTEXT:
+ case MTEXT:
+ memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0720, 32*1024);
+ break;
+ case CGA:
+ memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 32*1024);
+ break;
+ default:
+ // XXX - old code gets/sets/restores sequ register 2 to 0xf -
+ // but it should always be 0xf anyway.
+ memset16_far(GET_GLOBAL(vmode_g->sstart), 0, 0x0000, 64*1024);
+ }
+}
+
+
+/****************************************************************
+ * Read/write characters to screen
+ ****************************************************************/
+
+static void
+write_gfx_char_pl4(struct vgamode_s *vmode_g
+ , struct cursorpos cp, struct carattr ca)
+{
+ u16 nbcols = GET_BDA(video_cols);
+ if (cp.x >= nbcols)
+ return;
+
+ struct VideoParam_s *vparam_g = GET_GLOBAL(vmode_g->vparam);
+ u8 cheight = GET_GLOBAL(vparam_g->cheight);
+ u8 *fdata_g;
+ switch (cheight) {
+ case 14:
+ fdata_g = vgafont14;
+ break;
+ case 16:
+ fdata_g = vgafont16;
+ break;
+ default:
+ fdata_g = vgafont8;
+ }
+ u16 addr = cp.x + cp.y * cheight * nbcols;
+ u16 src = ca.car * cheight;
+ vgahw_sequ_write(0x02, 0x0f);
+ vgahw_grdc_write(0x05, 0x02);
+ if (ca.attr & 0x80)
+ vgahw_grdc_write(0x03, 0x18);
+ else
+ vgahw_grdc_write(0x03, 0x00);
+ u8 i;
+ for (i = 0; i < cheight; i++) {
+ u8 *dest_far = (void*)(addr + i * nbcols);
+ u8 j;
+ for (j = 0; j < 8; j++) {
+ u8 mask = 0x80 >> j;
+ vgahw_grdc_write(0x08, mask);
+ GET_FARVAR(SEG_GRAPH, *dest_far);
+ if (GET_GLOBAL(fdata_g[src + i]) & mask)
+ SET_FARVAR(SEG_GRAPH, *dest_far, ca.attr & 0x0f);
+ else
+ SET_FARVAR(SEG_GRAPH, *dest_far, 0x00);
+ }
+ }
+ vgahw_grdc_write(0x08, 0xff);
+ vgahw_grdc_write(0x05, 0x00);
+ vgahw_grdc_write(0x03, 0x00);
+}
+
+static void
+write_gfx_char_cga(struct vgamode_s *vmode_g
+ , struct cursorpos cp, struct carattr ca)
+{
+ u16 nbcols = GET_BDA(video_cols);
+ if (cp.x >= nbcols)
+ return;
+
+ u8 *fdata_g = vgafont8;
+ u8 bpp = GET_GLOBAL(vmode_g->pixbits);
+ u16 addr = (cp.x * bpp) + cp.y * 320;
+ u16 src = ca.car * 8;
+ u8 i;
+ for (i = 0; i < 8; i++) {
+ u8 *dest_far = (void*)(addr + (i >> 1) * 80);
+ if (i & 1)
+ dest_far += 0x2000;
+ u8 mask = 0x80;
+ if (bpp == 1) {
+ u8 data = 0;
+ if (ca.attr & 0x80)
+ data = GET_FARVAR(SEG_CTEXT, *dest_far);
+ u8 j;
+ for (j = 0; j < 8; j++) {
+ if (GET_GLOBAL(fdata_g[src + i]) & mask) {
+ if (ca.attr & 0x80)
+ data ^= (ca.attr & 0x01) << (7 - j);
+ else
+ data |= (ca.attr & 0x01) << (7 - j);
+ }
+ mask >>= 1;
+ }
+ SET_FARVAR(SEG_CTEXT, *dest_far, data);
+ } else {
+ while (mask > 0) {
+ u8 data = 0;
+ if (ca.attr & 0x80)
+ data = GET_FARVAR(SEG_CTEXT, *dest_far);
+ u8 j;
+ for (j = 0; j < 4; j++) {
+ if (GET_GLOBAL(fdata_g[src + i]) & mask) {
+ if (ca.attr & 0x80)
+ data ^= (ca.attr & 0x03) << ((3 - j) * 2);
+ else
+ data |= (ca.attr & 0x03) << ((3 - j) * 2);
+ }
+ mask >>= 1;
+ }
+ SET_FARVAR(SEG_CTEXT, *dest_far, data);
+ dest_far += 1;
+ }
+ }
+ }
+}
+
+static void
+write_gfx_char_lin(struct vgamode_s *vmode_g
+ , struct cursorpos cp, struct carattr ca)
+{
+ // Get the dimensions
+ u16 nbcols = GET_BDA(video_cols);
+ if (cp.x >= nbcols)
+ return;
+
+ u8 *fdata_g = vgafont8;
+ u16 addr = cp.x * 8 + cp.y * nbcols * 64;
+ u16 src = ca.car * 8;
+ u8 i;
+ for (i = 0; i < 8; i++) {
+ u8 *dest_far = (void*)(addr + i * nbcols * 8);
+ u8 mask = 0x80;
+ u8 j;
+ for (j = 0; j < 8; j++) {
+ u8 data = 0x00;
+ if (GET_GLOBAL(fdata_g[src + i]) & mask)
+ data = ca.attr;
+ SET_FARVAR(SEG_GRAPH, dest_far[j], data);
+ mask >>= 1;
+ }
+ }
+}
+
+static void
+write_text_char(struct vgamode_s *vmode_g
+ , struct cursorpos cp, struct carattr ca)
+{
+ // Get the dimensions
+ u16 nbrows = GET_BDA(video_rows) + 1;
+ u16 nbcols = GET_BDA(video_cols);
+
+ // Compute the address
+ void *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+ + (cp.x + cp.y * nbcols) * 2);
+
+ if (ca.use_attr) {
+ u16 dummy = (ca.attr << 8) | ca.car;
+ SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u16*)address_far, dummy);
+ } else {
+ SET_FARVAR(GET_GLOBAL(vmode_g->sstart), *(u8*)address_far, ca.car);
+ }
+}
+
+void
+vgafb_write_char(struct cursorpos cp, struct carattr ca)
+{
+ // Get the mode
+ struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+ if (!vmode_g)
+ return;
+
+ // FIXME gfx mode not complete
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case CTEXT:
+ case MTEXT:
+ write_text_char(vmode_g, cp, ca);
+ break;
+ case PLANAR4:
+ case PLANAR1:
+ write_gfx_char_pl4(vmode_g, cp, ca);
+ break;
+ case CGA:
+ write_gfx_char_cga(vmode_g, cp, ca);
+ break;
+ case LINEAR8:
+ write_gfx_char_lin(vmode_g, cp, ca);
+ break;
+ }
+}
+
+struct carattr
+vgafb_read_char(struct cursorpos cp)
+{
+ // Get the mode
+ struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+ if (!vmode_g)
+ goto fail;
+
+ if (!(GET_GLOBAL(vmode_g->memmodel) & TEXT)) {
+ // FIXME gfx mode
+ dprintf(1, "Read char in graphics mode\n");
+ goto fail;
+ }
+
+ // Get the dimensions
+ u16 nbrows = GET_BDA(video_rows) + 1;
+ u16 nbcols = GET_BDA(video_cols);
+
+ // Compute the address
+ u16 *address_far = (void*)(SCREEN_MEM_START(nbcols, nbrows, cp.page)
+ + (cp.x + cp.y * nbcols) * 2);
+ u16 v = GET_FARVAR(GET_GLOBAL(vmode_g->sstart), *address_far);
+ struct carattr ca = {v, v>>8, 0};
+ return ca;
+
+fail: ;
+ struct carattr ca2 = {0, 0, 0};
+ return ca2;
+}
+
+
+/****************************************************************
+ * Read/write pixels
+ ****************************************************************/
+
+void
+vgafb_write_pixel(u8 color, u16 x, u16 y)
+{
+ // Get the mode
+ struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+ if (!vmode_g)
+ return;
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+ return;
+
+ u8 *addr_far, mask, attr, data;
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case PLANAR4:
+ case PLANAR1:
+ addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+ mask = 0x80 >> (x & 0x07);
+ vgahw_grdc_write(0x08, mask);
+ vgahw_grdc_write(0x05, 0x02);
+ data = GET_FARVAR(SEG_GRAPH, *addr_far);
+ if (color & 0x80)
+ vgahw_grdc_write(0x03, 0x18);
+ SET_FARVAR(SEG_GRAPH, *addr_far, color);
+ vgahw_grdc_write(0x08, 0xff);
+ vgahw_grdc_write(0x05, 0x00);
+ vgahw_grdc_write(0x03, 0x00);
+ break;
+ case CGA:
+ if (GET_GLOBAL(vmode_g->pixbits) == 2)
+ addr_far = (void*)((x >> 2) + (y >> 1) * 80);
+ else
+ addr_far = (void*)((x >> 3) + (y >> 1) * 80);
+ if (y & 1)
+ addr_far += 0x2000;
+ data = GET_FARVAR(SEG_CTEXT, *addr_far);
+ if (GET_GLOBAL(vmode_g->pixbits) == 2) {
+ attr = (color & 0x03) << ((3 - (x & 0x03)) * 2);
+ mask = 0x03 << ((3 - (x & 0x03)) * 2);
+ } else {
+ attr = (color & 0x01) << (7 - (x & 0x07));
+ mask = 0x01 << (7 - (x & 0x07));
+ }
+ if (color & 0x80) {
+ data ^= attr;
+ } else {
+ data &= ~mask;
+ data |= attr;
+ }
+ SET_FARVAR(SEG_CTEXT, *addr_far, data);
+ break;
+ case LINEAR8:
+ addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
+ SET_FARVAR(SEG_GRAPH, *addr_far, color);
+ break;
+ }
+}
+
+u8
+vgafb_read_pixel(u16 x, u16 y)
+{
+ // Get the mode
+ struct vgamode_s *vmode_g = find_vga_entry(GET_BDA(video_mode));
+ if (!vmode_g)
+ return 0;
+ if (GET_GLOBAL(vmode_g->memmodel) & TEXT)
+ return 0;
+
+ u8 *addr_far, mask, attr=0, data, i;
+ switch (GET_GLOBAL(vmode_g->memmodel)) {
+ case PLANAR4:
+ case PLANAR1:
+ addr_far = (void*)(x / 8 + y * GET_BDA(video_cols));
+ mask = 0x80 >> (x & 0x07);
+ attr = 0x00;
+ for (i = 0; i < 4; i++) {
+ vgahw_grdc_write(0x04, i);
+ data = GET_FARVAR(SEG_GRAPH, *addr_far) & mask;
+ if (data > 0)
+ attr |= (0x01 << i);
+ }
+ break;
+ case CGA:
+ addr_far = (void*)((x >> 2) + (y >> 1) * 80);
+ if (y & 1)
+ addr_far += 0x2000;
+ data = GET_FARVAR(SEG_CTEXT, *addr_far);
+ if (GET_GLOBAL(vmode_g->pixbits) == 2)
+ attr = (data >> ((3 - (x & 0x03)) * 2)) & 0x03;
+ else
+ attr = (data >> (7 - (x & 0x07))) & 0x01;
+ break;
+ case LINEAR8:
+ addr_far = (void*)(x + y * (GET_BDA(video_cols) * 8));
+ attr = GET_FARVAR(SEG_GRAPH, *addr_far);
+ break;
+ }
+ return attr;
+}
+
+
+/****************************************************************
+ * Font loading
+ ****************************************************************/
+
+void
+vgafb_load_font(u16 seg, void *src_far, u16 count
+ , u16 start, u8 destflags, u8 fontsize)
+{
+ get_font_access();
+ u16 blockaddr = ((destflags & 0x03) << 14) + ((destflags & 0x04) << 11);
+ void *dest_far = (void*)(blockaddr + start*32);
+ u16 i;
+ for (i = 0; i < count; i++)
+ memcpy_far(SEG_GRAPH, dest_far + i*32
+ , seg, src_far + i*fontsize, fontsize);
+ release_font_access();
+}
--- /dev/null
+#include "vgatables.h" // vgafont8
+
+/*
+ * These fonts come from ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/fntcol16.zip
+ * The package is (c) by Joseph Gil
+ * The individual fonts are public domain
+ */
+u8 vgafont8[256 * 8] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e,
+ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,
+ 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,
+ 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18,
+ 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0,
+ 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,
+ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00,
+ 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,
+ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00,
+ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,
+ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,
+ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00,
+ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,
+ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,
+ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,
+ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,
+ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,
+ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,
+ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,
+ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,
+ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00,
+ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00,
+ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00,
+ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,
+ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,
+ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,
+ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,
+ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,
+ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
+ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
+ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
+ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00,
+ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00,
+ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,
+ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7,
+ 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,
+ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03,
+ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,
+ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00,
+ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
+ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00,
+ 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0,
+ 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc,
+ 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00,
+ 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00,
+ 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00,
+ 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00,
+ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,
+ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00,
+ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8 vgafont14[256 * 14] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x6c, 0x6c, 0x78, 0x6c, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0xc6, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc6, 0xcc, 0xd8, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0x40, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8 vgafont16[256 * 16] VAR16 = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+u8 vgafont14alt[1] VAR16;
+u8 vgafont16alt[1] VAR16;
--- /dev/null
+// VGA io port access
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "ioport.h" // outb
+#include "farptr.h" // SET_FARVAR
+#include "biosvar.h" // GET_BDA
+#include "vgatables.h" // VGAREG_*
+
+// TODO
+// * replace direct in/out calls with wrapper functions
+
+
+/****************************************************************
+ * Attribute control
+ ****************************************************************/
+
+void
+vgahw_screen_disable(void)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x00, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_screen_enable(void)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_border_color(u8 color)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x00, VGAREG_ACTL_ADDRESS);
+ u8 v1 = color & 0x0f;
+ if (v1 & 0x08)
+ v1 += 0x08;
+ outb(v1, VGAREG_ACTL_WRITE_DATA);
+
+ u8 v2 = color & 0x10;
+ int i;
+ for (i = 1; i < 4; i++) {
+ outb(i, VGAREG_ACTL_ADDRESS);
+
+ u8 cur = inb(VGAREG_ACTL_READ_DATA);
+ cur &= 0xef;
+ cur |= v2;
+ outb(cur, VGAREG_ACTL_WRITE_DATA);
+ }
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_overscan_border_color(u8 color)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x11, VGAREG_ACTL_ADDRESS);
+ outb(color, VGAREG_ACTL_WRITE_DATA);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+u8
+vgahw_get_overscan_border_color(void)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x11, VGAREG_ACTL_ADDRESS);
+ u8 v = inb(VGAREG_ACTL_READ_DATA);
+ inb(VGAREG_ACTL_RESET);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+ return v;
+}
+
+void
+vgahw_set_palette(u8 palid)
+{
+ inb(VGAREG_ACTL_RESET);
+ palid &= 0x01;
+ int i;
+ for (i = 1; i < 4; i++) {
+ outb(i, VGAREG_ACTL_ADDRESS);
+
+ u8 v = inb(VGAREG_ACTL_READ_DATA);
+ v &= 0xfe;
+ v |= palid;
+ outb(v, VGAREG_ACTL_WRITE_DATA);
+ }
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_set_single_palette_reg(u8 reg, u8 val)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(reg, VGAREG_ACTL_ADDRESS);
+ outb(val, VGAREG_ACTL_WRITE_DATA);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+u8
+vgahw_get_single_palette_reg(u8 reg)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(reg, VGAREG_ACTL_ADDRESS);
+ u8 v = inb(VGAREG_ACTL_READ_DATA);
+ inb(VGAREG_ACTL_RESET);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+ return v;
+}
+
+void
+vgahw_set_all_palette_reg(u16 seg, u8 *data_far)
+{
+ inb(VGAREG_ACTL_RESET);
+ int i;
+ for (i = 0; i < 0x10; i++) {
+ outb(i, VGAREG_ACTL_ADDRESS);
+ u8 val = GET_FARVAR(seg, *data_far);
+ outb(val, VGAREG_ACTL_WRITE_DATA);
+ data_far++;
+ }
+ outb(0x11, VGAREG_ACTL_ADDRESS);
+ outb(GET_FARVAR(seg, *data_far), VGAREG_ACTL_WRITE_DATA);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_get_all_palette_reg(u16 seg, u8 *data_far)
+{
+ int i;
+ for (i = 0; i < 0x10; i++) {
+ inb(VGAREG_ACTL_RESET);
+ outb(i, VGAREG_ACTL_ADDRESS);
+ SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
+ data_far++;
+ }
+ inb(VGAREG_ACTL_RESET);
+ outb(0x11, VGAREG_ACTL_ADDRESS);
+ SET_FARVAR(seg, *data_far, inb(VGAREG_ACTL_READ_DATA));
+ inb(VGAREG_ACTL_RESET);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_toggle_intensity(u8 flag)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x10, VGAREG_ACTL_ADDRESS);
+ u8 val = (inb(VGAREG_ACTL_READ_DATA) & 0xf7) | ((flag & 0x01) << 3);
+ outb(val, VGAREG_ACTL_WRITE_DATA);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_select_video_dac_color_page(u8 flag, u8 data)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x10, VGAREG_ACTL_ADDRESS);
+ u8 val = inb(VGAREG_ACTL_READ_DATA);
+ if (!(flag & 0x01)) {
+ // select paging mode
+ val = (val & 0x7f) | (data << 7);
+ outb(val, VGAREG_ACTL_WRITE_DATA);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+ return;
+ }
+ // select page
+ inb(VGAREG_ACTL_RESET);
+ outb(0x14, VGAREG_ACTL_ADDRESS);
+ if (!(val & 0x80))
+ data <<= 2;
+ data &= 0x0f;
+ outb(data, VGAREG_ACTL_WRITE_DATA);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+}
+
+void
+vgahw_read_video_dac_state(u8 *pmode, u8 *curpage)
+{
+ inb(VGAREG_ACTL_RESET);
+ outb(0x10, VGAREG_ACTL_ADDRESS);
+ u8 val1 = inb(VGAREG_ACTL_READ_DATA) >> 7;
+
+ inb(VGAREG_ACTL_RESET);
+ outb(0x14, VGAREG_ACTL_ADDRESS);
+ u8 val2 = inb(VGAREG_ACTL_READ_DATA) & 0x0f;
+ if (!(val1 & 0x01))
+ val2 >>= 2;
+
+ inb(VGAREG_ACTL_RESET);
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+
+ *pmode = val1;
+ *curpage = val2;
+}
+
+
+/****************************************************************
+ * DAC control
+ ****************************************************************/
+
+void
+vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
+{
+ outb(start, VGAREG_DAC_WRITE_ADDRESS);
+ while (count) {
+ outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+ data_far++;
+ outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+ data_far++;
+ outb(GET_FARVAR(seg, *data_far), VGAREG_DAC_DATA);
+ data_far++;
+ count--;
+ }
+}
+
+void
+vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count)
+{
+ outb(start, VGAREG_DAC_READ_ADDRESS);
+ while (count) {
+ SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+ data_far++;
+ SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+ data_far++;
+ SET_FARVAR(seg, *data_far, inb(VGAREG_DAC_DATA));
+ data_far++;
+ count--;
+ }
+}
+
+void
+vgahw_set_pel_mask(u8 val)
+{
+ outb(val, VGAREG_PEL_MASK);
+}
+
+u8
+vgahw_get_pel_mask(void)
+{
+ return inb(VGAREG_PEL_MASK);
+}
+
+void
+vgahw_save_dac_state(u16 seg, struct saveDACcolors *info)
+{
+ /* XXX: check this */
+ SET_FARVAR(seg, info->rwmode, inb(VGAREG_DAC_STATE));
+ SET_FARVAR(seg, info->peladdr, inb(VGAREG_DAC_WRITE_ADDRESS));
+ SET_FARVAR(seg, info->pelmask, inb(VGAREG_PEL_MASK));
+ vgahw_get_dac_regs(seg, info->dac, 0, 256);
+ SET_FARVAR(seg, info->color_select, 0);
+}
+
+void
+vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info)
+{
+ outb(GET_FARVAR(seg, info->pelmask), VGAREG_PEL_MASK);
+ vgahw_set_dac_regs(seg, info->dac, 0, 256);
+ outb(GET_FARVAR(seg, info->peladdr), VGAREG_DAC_WRITE_ADDRESS);
+}
+
+
+/****************************************************************
+ * Memory control
+ ****************************************************************/
+
+void
+vgahw_sequ_write(u8 index, u8 value)
+{
+ outw((value<<8) | index, VGAREG_SEQU_ADDRESS);
+}
+
+void
+vgahw_grdc_write(u8 index, u8 value)
+{
+ outw((value<<8) | index, VGAREG_GRDC_ADDRESS);
+}
+
+void
+vgahw_set_text_block_specifier(u8 spec)
+{
+ outw((spec << 8) | 0x03, VGAREG_SEQU_ADDRESS);
+}
+
+void
+get_font_access(void)
+{
+ outw(0x0100, VGAREG_SEQU_ADDRESS);
+ outw(0x0402, VGAREG_SEQU_ADDRESS);
+ outw(0x0704, VGAREG_SEQU_ADDRESS);
+ outw(0x0300, VGAREG_SEQU_ADDRESS);
+ outw(0x0204, VGAREG_GRDC_ADDRESS);
+ outw(0x0005, VGAREG_GRDC_ADDRESS);
+ outw(0x0406, VGAREG_GRDC_ADDRESS);
+}
+
+void
+release_font_access(void)
+{
+ outw(0x0100, VGAREG_SEQU_ADDRESS);
+ outw(0x0302, VGAREG_SEQU_ADDRESS);
+ outw(0x0304, VGAREG_SEQU_ADDRESS);
+ outw(0x0300, VGAREG_SEQU_ADDRESS);
+ u16 v = (inw(VGAREG_READ_MISC_OUTPUT) & 0x01) ? 0x0e : 0x0a;
+ outw((v << 8) | 0x06, VGAREG_GRDC_ADDRESS);
+ outw(0x0004, VGAREG_GRDC_ADDRESS);
+ outw(0x1005, VGAREG_GRDC_ADDRESS);
+}
+
+
+/****************************************************************
+ * CRTC registers
+ ****************************************************************/
+
+static u16
+get_crtc(void)
+{
+ return GET_BDA(crtc_address);
+}
+
+void
+vgahw_set_cursor_shape(u8 start, u8 end)
+{
+ u16 crtc_addr = get_crtc();
+ outb(0x0a, crtc_addr);
+ outb(start, crtc_addr + 1);
+ outb(0x0b, crtc_addr);
+ outb(end, crtc_addr + 1);
+}
+
+void
+vgahw_set_active_page(u16 address)
+{
+ u16 crtc_addr = get_crtc();
+ outb(0x0c, crtc_addr);
+ outb((address & 0xff00) >> 8, crtc_addr + 1);
+ outb(0x0d, crtc_addr);
+ outb(address & 0x00ff, crtc_addr + 1);
+}
+
+void
+vgahw_set_cursor_pos(u16 address)
+{
+ u16 crtc_addr = get_crtc();
+ outb(0x0e, crtc_addr);
+ outb((address & 0xff00) >> 8, crtc_addr + 1);
+ outb(0x0f, crtc_addr);
+ outb(address & 0x00ff, crtc_addr + 1);
+}
+
+void
+vgahw_set_scan_lines(u8 lines)
+{
+ u16 crtc_addr = get_crtc();
+ outb(0x09, crtc_addr);
+ u8 crtc_r9 = inb(crtc_addr + 1);
+ crtc_r9 = (crtc_r9 & 0xe0) | (lines - 1);
+ outb(crtc_r9, crtc_addr + 1);
+}
+
+// Get vertical display end
+u16
+vgahw_get_vde(void)
+{
+ u16 crtc_addr = get_crtc();
+ outb(0x12, crtc_addr);
+ u16 vde = inb(crtc_addr + 1);
+ outb(0x07, crtc_addr);
+ u8 ovl = inb(crtc_addr + 1);
+ vde += (((ovl & 0x02) << 7) + ((ovl & 0x40) << 3) + 1);
+ return vde;
+}
+
+
+/****************************************************************
+ * Save/Restore/Set state
+ ****************************************************************/
+
+void
+vgahw_save_state(u16 seg, struct saveVideoHardware *info)
+{
+ u16 crtc_addr = get_crtc();
+ SET_FARVAR(seg, info->sequ_index, inb(VGAREG_SEQU_ADDRESS));
+ SET_FARVAR(seg, info->crtc_index, inb(crtc_addr));
+ SET_FARVAR(seg, info->grdc_index, inb(VGAREG_GRDC_ADDRESS));
+ inb(VGAREG_ACTL_RESET);
+ u16 ar_index = inb(VGAREG_ACTL_ADDRESS);
+ SET_FARVAR(seg, info->actl_index, ar_index);
+ SET_FARVAR(seg, info->feature, inb(VGAREG_READ_FEATURE_CTL));
+
+ u16 i;
+ for (i=0; i<4; i++) {
+ outb(i+1, VGAREG_SEQU_ADDRESS);
+ SET_FARVAR(seg, info->sequ_regs[i], inb(VGAREG_SEQU_DATA));
+ }
+ outb(0, VGAREG_SEQU_ADDRESS);
+ SET_FARVAR(seg, info->sequ0, inb(VGAREG_SEQU_DATA));
+
+ for (i=0; i<25; i++) {
+ outb(i, crtc_addr);
+ SET_FARVAR(seg, info->crtc_regs[i], inb(crtc_addr + 1));
+ }
+
+ for (i=0; i<20; i++) {
+ inb(VGAREG_ACTL_RESET);
+ outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
+ SET_FARVAR(seg, info->actl_regs[i], inb(VGAREG_ACTL_READ_DATA));
+ }
+ inb(VGAREG_ACTL_RESET);
+
+ for (i=0; i<9; i++) {
+ outb(i, VGAREG_GRDC_ADDRESS);
+ SET_FARVAR(seg, info->grdc_regs[i], inb(VGAREG_GRDC_DATA));
+ }
+
+ SET_FARVAR(seg, info->crtc_addr, crtc_addr);
+
+ /* XXX: read plane latches */
+ for (i=0; i<4; i++)
+ SET_FARVAR(seg, info->plane_latch[i], 0);
+}
+
+void
+vgahw_restore_state(u16 seg, struct saveVideoHardware *info)
+{
+ // Reset Attribute Ctl flip-flop
+ inb(VGAREG_ACTL_RESET);
+
+ u16 crtc_addr = GET_FARVAR(seg, info->crtc_addr);
+
+ u16 i;
+ for (i=0; i<4; i++) {
+ outb(i+1, VGAREG_SEQU_ADDRESS);
+ outb(GET_FARVAR(seg, info->sequ_regs[i]), VGAREG_SEQU_DATA);
+ }
+ outb(0, VGAREG_SEQU_ADDRESS);
+ outb(GET_FARVAR(seg, info->sequ0), VGAREG_SEQU_DATA);
+
+ // Disable CRTC write protection
+ outw(0x0011, crtc_addr);
+ // Set CRTC regs
+ for (i=0; i<25; i++)
+ if (i != 0x11) {
+ outb(i, crtc_addr);
+ outb(GET_FARVAR(seg, info->crtc_regs[i]), crtc_addr + 1);
+ }
+ // select crtc base address
+ u16 v = inb(VGAREG_READ_MISC_OUTPUT) & ~0x01;
+ if (crtc_addr == VGAREG_VGA_CRTC_ADDRESS)
+ v |= 0x01;
+ outb(v, VGAREG_WRITE_MISC_OUTPUT);
+
+ // enable write protection if needed
+ outb(0x11, crtc_addr);
+ outb(GET_FARVAR(seg, info->crtc_regs[0x11]), crtc_addr + 1);
+
+ // Set Attribute Ctl
+ u16 ar_index = GET_FARVAR(seg, info->actl_index);
+ inb(VGAREG_ACTL_RESET);
+ for (i=0; i<20; i++) {
+ outb(i | (ar_index & 0x20), VGAREG_ACTL_ADDRESS);
+ outb(GET_FARVAR(seg, info->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
+ }
+ outb(ar_index, VGAREG_ACTL_ADDRESS);
+ inb(VGAREG_ACTL_RESET);
+
+ for (i=0; i<9; i++) {
+ outb(i, VGAREG_GRDC_ADDRESS);
+ outb(GET_FARVAR(seg, info->grdc_regs[i]), VGAREG_GRDC_DATA);
+ }
+
+ outb(GET_FARVAR(seg, info->sequ_index), VGAREG_SEQU_ADDRESS);
+ outb(GET_FARVAR(seg, info->crtc_index), crtc_addr);
+ outb(GET_FARVAR(seg, info->grdc_index), VGAREG_GRDC_ADDRESS);
+ outb(GET_FARVAR(seg, info->feature), crtc_addr - 0x4 + 0xa);
+}
+
+void
+vgahw_set_mode(struct VideoParam_s *vparam_g)
+{
+ // Reset Attribute Ctl flip-flop
+ inb(VGAREG_ACTL_RESET);
+
+ // Set Attribute Ctl
+ u16 i;
+ for (i = 0; i <= 0x13; i++) {
+ outb(i, VGAREG_ACTL_ADDRESS);
+ outb(GET_GLOBAL(vparam_g->actl_regs[i]), VGAREG_ACTL_WRITE_DATA);
+ }
+ outb(0x14, VGAREG_ACTL_ADDRESS);
+ outb(0x00, VGAREG_ACTL_WRITE_DATA);
+
+ // Set Sequencer Ctl
+ outb(0, VGAREG_SEQU_ADDRESS);
+ outb(0x03, VGAREG_SEQU_DATA);
+ for (i = 1; i <= 4; i++) {
+ outb(i, VGAREG_SEQU_ADDRESS);
+ outb(GET_GLOBAL(vparam_g->sequ_regs[i - 1]), VGAREG_SEQU_DATA);
+ }
+
+ // Set Grafx Ctl
+ for (i = 0; i <= 8; i++) {
+ outb(i, VGAREG_GRDC_ADDRESS);
+ outb(GET_GLOBAL(vparam_g->grdc_regs[i]), VGAREG_GRDC_DATA);
+ }
+
+ // Set CRTC address VGA or MDA
+ u8 miscreg = GET_GLOBAL(vparam_g->miscreg);
+ u16 crtc_addr = VGAREG_VGA_CRTC_ADDRESS;
+ if (!(miscreg & 1))
+ crtc_addr = VGAREG_MDA_CRTC_ADDRESS;
+
+ // Disable CRTC write protection
+ outw(0x0011, crtc_addr);
+ // Set CRTC regs
+ for (i = 0; i <= 0x18; i++) {
+ outb(i, crtc_addr);
+ outb(GET_GLOBAL(vparam_g->crtc_regs[i]), crtc_addr + 1);
+ }
+
+ // Set the misc register
+ outb(miscreg, VGAREG_WRITE_MISC_OUTPUT);
+
+ // Enable video
+ outb(0x20, VGAREG_ACTL_ADDRESS);
+ inb(VGAREG_ACTL_RESET);
+}
+
+
+/****************************************************************
+ * Misc
+ ****************************************************************/
+
+void
+vgahw_enable_video_addressing(u8 disable)
+{
+ u8 v = (disable & 1) ? 0x00 : 0x02;
+ u8 v2 = inb(VGAREG_READ_MISC_OUTPUT) & ~0x02;
+ outb(v | v2, VGAREG_WRITE_MISC_OUTPUT);
+}
+
+void
+vgahw_init(void)
+{
+ // switch to color mode and enable CPU access 480 lines
+ outb(0xc3, VGAREG_WRITE_MISC_OUTPUT);
+ // more than 64k 3C4/04
+ outb(0x04, VGAREG_SEQU_ADDRESS);
+ outb(0x02, VGAREG_SEQU_DATA);
+}
--- /dev/null
+// Linker definitions for an option rom
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH("i386")
+ENTRY(_optionrom_entry)
+SECTIONS
+{
+ .text 0 : {
+ KEEP(*(.rom.header))
+ *(.text.*)
+ _rodata = . ;
+ *(.rodata.__func__.*)
+ *(.rodata.str1.1)
+ *(.data16.*)
+ }
+
+ // Discard regular data sections to force a link error if
+ // 16bit code attempts to access data not marked with VAR16.
+ /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
+}
--- /dev/null
+// Tables used by VGA bios
+//
+// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2001-2008 the LGPL VGABios developers Team
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "vgatables.h" // struct VideoParamTableEntry_s
+#include "biosvar.h" // GET_GLOBAL
+
+
+/****************************************************************
+ * Video parameter table
+ ****************************************************************/
+
+struct VideoParam_s video_param_table[] VAR16 = {
+ // index=0x00 no mode defined
+ {},
+ // index=0x01 no mode defined
+ {},
+ // index=0x02 no mode defined
+ {},
+ // index=0x03 no mode defined
+ {},
+ // index=0x04 vga mode 0x04
+ { 40, 24, 8, 0x0800, /* tw, th-1, ch, slength */
+ { 0x09, 0x03, 0x00, 0x02 }, /* sequ_regs */
+ 0x63, /* miscreg */
+ { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x03, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x05 vga mode 0x05 */
+ { 40, 24, 8, 0x0800, /* tw, th-1, ch, slength */
+ { 0x09, 0x03, 0x00, 0x02 }, /* sequ_regs */
+ 0x63, /* miscreg */
+ { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x03, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x06 vga mode 0x06 */
+ { 80, 24, 8, 0x1000, /* tw, th-1, ch, slength */
+ { 0x01, 0x01, 0x00, 0x06 }, /* sequ_regs */
+ 0x63, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
+ 0x01, 0x00, 0x01, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x07 vga mode 0x07 */
+ { 80, 24, 16, 0x1000, /* tw, th-1, ch, slength */
+ { 0x00, 0x03, 0x00, 0x02 }, /* sequ_regs */
+ 0x66, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x0e, 0x00, 0x0f, 0x08 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x08 no mode defined */
+ {},
+ /* index=0x09 no mode defined */
+ {},
+ /* index=0x0a no mode defined */
+ {},
+ /* index=0x0b no mode defined */
+ {},
+ /* index=0x0c no mode defined */
+ {},
+ /* index=0x0d vga mode 0x0d */
+ { 40, 24, 8, 0x2000, /* tw, th-1, ch, slength */
+ { 0x09, 0x0f, 0x00, 0x06 }, /* sequ_regs */
+ 0x63, /* miscreg */
+ { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x0e vga mode 0x0e */
+ { 80, 24, 8, 0x4000, /* tw, th-1, ch, slength */
+ { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */
+ 0x63, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x0f no mode defined */
+ {},
+ /* index=0x10 no mode defined */
+ {},
+ /* index=0x11 vga mode 0x0f */
+ { 80, 24, 14, 0x8000, /* tw, th-1, ch, slength */
+ { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */
+ 0xa3, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x12 vga mode 0x10 */
+ { 80, 24, 14, 0x8000, /* tw, th-1, ch, slength */
+ { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */
+ 0xa3, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x85, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x13 no mode defined */
+ {},
+ /* index=0x14 no mode defined */
+ {},
+ /* index=0x15 no mode defined */
+ {},
+ /* index=0x16 no mode defined */
+ {},
+ /* index=0x17 vga mode 0x01 */
+ { 40, 24, 16, 0x0800, /* tw, th-1, ch, slength */
+ { 0x08, 0x03, 0x00, 0x02 }, /* sequ_regs */
+ 0x67, /* miscreg */
+ { 0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x18 vga mode 0x03 */
+ { 80, 24, 16, 0x1000, /* tw, th-1, ch, slength */
+ { 0x00, 0x03, 0x00, 0x02 }, /* sequ_regs */
+ 0x67, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x19 vga mode 0x07 */
+ { 80, 24, 16, 0x1000, /* tw, th-1, ch, slength */
+ { 0x00, 0x03, 0x00, 0x02 }, /* sequ_regs */
+ 0x66, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+ 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x0e, 0x00, 0x0f, 0x08 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x1a vga mode 0x11 */
+ { 80, 29, 16, 0x0000, /* tw, th-1, ch, slength */
+ { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */
+ 0xe3, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x1b vga mode 0x12 */
+ { 80, 29, 16, 0x0000, /* tw, th-1, ch, slength */
+ { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */
+ 0xe3, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x1c vga mode 0x13 */
+ { 40, 24, 8, 0x0000, /* tw, th-1, ch, slength */
+ { 0x01, 0x0f, 0x00, 0x0e }, /* sequ_regs */
+ 0x63, /* miscreg */
+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x41, 0x00, 0x0f, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+ /* index=0x1d vga mode 0x6a */
+ { 100, 36, 16, 0x0000, /* tw, th-1, ch, slength */
+ { 0x01, 0x0f, 0x00, 0x06 }, /* sequ_regs */
+ 0xe3, /* miscreg */
+ { 0x7f, 0x63, 0x63, 0x83, 0x6b, 0x1b, 0x72, 0xf0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x8d, 0x57, 0x32, 0x00, 0x57, 0x73, 0xe3,
+ 0xff }, /* crtc_regs */
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x01, 0x00, 0x0f, 0x00 }, /* actl_regs */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff }, /* grdc_regs */
+ },
+};
+
+
+/****************************************************************
+ * Palette definitions
+ ****************************************************************/
+
+/* Mono */
+static u8 palette0[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f,
+ 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f
+};
+
+static u8 palette1[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static u8 palette2[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,
+ 0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f,
+ 0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,
+ 0x00,0x15,0x00, 0x00,0x15,0x2a, 0x00,0x3f,0x00, 0x00,0x3f,0x2a,
+ 0x2a,0x15,0x00, 0x2a,0x15,0x2a, 0x2a,0x3f,0x00, 0x2a,0x3f,0x2a,
+ 0x00,0x15,0x15, 0x00,0x15,0x3f, 0x00,0x3f,0x15, 0x00,0x3f,0x3f,
+ 0x2a,0x15,0x15, 0x2a,0x15,0x3f, 0x2a,0x3f,0x15, 0x2a,0x3f,0x3f,
+ 0x15,0x00,0x00, 0x15,0x00,0x2a, 0x15,0x2a,0x00, 0x15,0x2a,0x2a,
+ 0x3f,0x00,0x00, 0x3f,0x00,0x2a, 0x3f,0x2a,0x00, 0x3f,0x2a,0x2a,
+ 0x15,0x00,0x15, 0x15,0x00,0x3f, 0x15,0x2a,0x15, 0x15,0x2a,0x3f,
+ 0x3f,0x00,0x15, 0x3f,0x00,0x3f, 0x3f,0x2a,0x15, 0x3f,0x2a,0x3f,
+ 0x15,0x15,0x00, 0x15,0x15,0x2a, 0x15,0x3f,0x00, 0x15,0x3f,0x2a,
+ 0x3f,0x15,0x00, 0x3f,0x15,0x2a, 0x3f,0x3f,0x00, 0x3f,0x3f,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f
+};
+
+static u8 palette3[] VAR16 = {
+ 0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,
+ 0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x15,0x00, 0x2a,0x2a,0x2a,
+ 0x15,0x15,0x15, 0x15,0x15,0x3f, 0x15,0x3f,0x15, 0x15,0x3f,0x3f,
+ 0x3f,0x15,0x15, 0x3f,0x15,0x3f, 0x3f,0x3f,0x15, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x00, 0x05,0x05,0x05, 0x08,0x08,0x08, 0x0b,0x0b,0x0b,
+ 0x0e,0x0e,0x0e, 0x11,0x11,0x11, 0x14,0x14,0x14, 0x18,0x18,0x18,
+ 0x1c,0x1c,0x1c, 0x20,0x20,0x20, 0x24,0x24,0x24, 0x28,0x28,0x28,
+ 0x2d,0x2d,0x2d, 0x32,0x32,0x32, 0x38,0x38,0x38, 0x3f,0x3f,0x3f,
+ 0x00,0x00,0x3f, 0x10,0x00,0x3f, 0x1f,0x00,0x3f, 0x2f,0x00,0x3f,
+ 0x3f,0x00,0x3f, 0x3f,0x00,0x2f, 0x3f,0x00,0x1f, 0x3f,0x00,0x10,
+ 0x3f,0x00,0x00, 0x3f,0x10,0x00, 0x3f,0x1f,0x00, 0x3f,0x2f,0x00,
+ 0x3f,0x3f,0x00, 0x2f,0x3f,0x00, 0x1f,0x3f,0x00, 0x10,0x3f,0x00,
+ 0x00,0x3f,0x00, 0x00,0x3f,0x10, 0x00,0x3f,0x1f, 0x00,0x3f,0x2f,
+ 0x00,0x3f,0x3f, 0x00,0x2f,0x3f, 0x00,0x1f,0x3f, 0x00,0x10,0x3f,
+ 0x1f,0x1f,0x3f, 0x27,0x1f,0x3f, 0x2f,0x1f,0x3f, 0x37,0x1f,0x3f,
+ 0x3f,0x1f,0x3f, 0x3f,0x1f,0x37, 0x3f,0x1f,0x2f, 0x3f,0x1f,0x27,
+
+ 0x3f,0x1f,0x1f, 0x3f,0x27,0x1f, 0x3f,0x2f,0x1f, 0x3f,0x37,0x1f,
+ 0x3f,0x3f,0x1f, 0x37,0x3f,0x1f, 0x2f,0x3f,0x1f, 0x27,0x3f,0x1f,
+ 0x1f,0x3f,0x1f, 0x1f,0x3f,0x27, 0x1f,0x3f,0x2f, 0x1f,0x3f,0x37,
+ 0x1f,0x3f,0x3f, 0x1f,0x37,0x3f, 0x1f,0x2f,0x3f, 0x1f,0x27,0x3f,
+ 0x2d,0x2d,0x3f, 0x31,0x2d,0x3f, 0x36,0x2d,0x3f, 0x3a,0x2d,0x3f,
+ 0x3f,0x2d,0x3f, 0x3f,0x2d,0x3a, 0x3f,0x2d,0x36, 0x3f,0x2d,0x31,
+ 0x3f,0x2d,0x2d, 0x3f,0x31,0x2d, 0x3f,0x36,0x2d, 0x3f,0x3a,0x2d,
+ 0x3f,0x3f,0x2d, 0x3a,0x3f,0x2d, 0x36,0x3f,0x2d, 0x31,0x3f,0x2d,
+ 0x2d,0x3f,0x2d, 0x2d,0x3f,0x31, 0x2d,0x3f,0x36, 0x2d,0x3f,0x3a,
+ 0x2d,0x3f,0x3f, 0x2d,0x3a,0x3f, 0x2d,0x36,0x3f, 0x2d,0x31,0x3f,
+ 0x00,0x00,0x1c, 0x07,0x00,0x1c, 0x0e,0x00,0x1c, 0x15,0x00,0x1c,
+ 0x1c,0x00,0x1c, 0x1c,0x00,0x15, 0x1c,0x00,0x0e, 0x1c,0x00,0x07,
+ 0x1c,0x00,0x00, 0x1c,0x07,0x00, 0x1c,0x0e,0x00, 0x1c,0x15,0x00,
+ 0x1c,0x1c,0x00, 0x15,0x1c,0x00, 0x0e,0x1c,0x00, 0x07,0x1c,0x00,
+ 0x00,0x1c,0x00, 0x00,0x1c,0x07, 0x00,0x1c,0x0e, 0x00,0x1c,0x15,
+ 0x00,0x1c,0x1c, 0x00,0x15,0x1c, 0x00,0x0e,0x1c, 0x00,0x07,0x1c,
+
+ 0x0e,0x0e,0x1c, 0x11,0x0e,0x1c, 0x15,0x0e,0x1c, 0x18,0x0e,0x1c,
+ 0x1c,0x0e,0x1c, 0x1c,0x0e,0x18, 0x1c,0x0e,0x15, 0x1c,0x0e,0x11,
+ 0x1c,0x0e,0x0e, 0x1c,0x11,0x0e, 0x1c,0x15,0x0e, 0x1c,0x18,0x0e,
+ 0x1c,0x1c,0x0e, 0x18,0x1c,0x0e, 0x15,0x1c,0x0e, 0x11,0x1c,0x0e,
+ 0x0e,0x1c,0x0e, 0x0e,0x1c,0x11, 0x0e,0x1c,0x15, 0x0e,0x1c,0x18,
+ 0x0e,0x1c,0x1c, 0x0e,0x18,0x1c, 0x0e,0x15,0x1c, 0x0e,0x11,0x1c,
+ 0x14,0x14,0x1c, 0x16,0x14,0x1c, 0x18,0x14,0x1c, 0x1a,0x14,0x1c,
+ 0x1c,0x14,0x1c, 0x1c,0x14,0x1a, 0x1c,0x14,0x18, 0x1c,0x14,0x16,
+ 0x1c,0x14,0x14, 0x1c,0x16,0x14, 0x1c,0x18,0x14, 0x1c,0x1a,0x14,
+ 0x1c,0x1c,0x14, 0x1a,0x1c,0x14, 0x18,0x1c,0x14, 0x16,0x1c,0x14,
+ 0x14,0x1c,0x14, 0x14,0x1c,0x16, 0x14,0x1c,0x18, 0x14,0x1c,0x1a,
+ 0x14,0x1c,0x1c, 0x14,0x1a,0x1c, 0x14,0x18,0x1c, 0x14,0x16,0x1c,
+ 0x00,0x00,0x10, 0x04,0x00,0x10, 0x08,0x00,0x10, 0x0c,0x00,0x10,
+ 0x10,0x00,0x10, 0x10,0x00,0x0c, 0x10,0x00,0x08, 0x10,0x00,0x04,
+ 0x10,0x00,0x00, 0x10,0x04,0x00, 0x10,0x08,0x00, 0x10,0x0c,0x00,
+ 0x10,0x10,0x00, 0x0c,0x10,0x00, 0x08,0x10,0x00, 0x04,0x10,0x00,
+
+ 0x00,0x10,0x00, 0x00,0x10,0x04, 0x00,0x10,0x08, 0x00,0x10,0x0c,
+ 0x00,0x10,0x10, 0x00,0x0c,0x10, 0x00,0x08,0x10, 0x00,0x04,0x10,
+ 0x08,0x08,0x10, 0x0a,0x08,0x10, 0x0c,0x08,0x10, 0x0e,0x08,0x10,
+ 0x10,0x08,0x10, 0x10,0x08,0x0e, 0x10,0x08,0x0c, 0x10,0x08,0x0a,
+ 0x10,0x08,0x08, 0x10,0x0a,0x08, 0x10,0x0c,0x08, 0x10,0x0e,0x08,
+ 0x10,0x10,0x08, 0x0e,0x10,0x08, 0x0c,0x10,0x08, 0x0a,0x10,0x08,
+ 0x08,0x10,0x08, 0x08,0x10,0x0a, 0x08,0x10,0x0c, 0x08,0x10,0x0e,
+ 0x08,0x10,0x10, 0x08,0x0e,0x10, 0x08,0x0c,0x10, 0x08,0x0a,0x10,
+ 0x0b,0x0b,0x10, 0x0c,0x0b,0x10, 0x0d,0x0b,0x10, 0x0f,0x0b,0x10,
+ 0x10,0x0b,0x10, 0x10,0x0b,0x0f, 0x10,0x0b,0x0d, 0x10,0x0b,0x0c,
+ 0x10,0x0b,0x0b, 0x10,0x0c,0x0b, 0x10,0x0d,0x0b, 0x10,0x0f,0x0b,
+ 0x10,0x10,0x0b, 0x0f,0x10,0x0b, 0x0d,0x10,0x0b, 0x0c,0x10,0x0b,
+ 0x0b,0x10,0x0b, 0x0b,0x10,0x0c, 0x0b,0x10,0x0d, 0x0b,0x10,0x0f,
+ 0x0b,0x10,0x10, 0x0b,0x0f,0x10, 0x0b,0x0d,0x10, 0x0b,0x0c,0x10,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
+ 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00
+};
+
+
+/****************************************************************
+ * Video mode list
+ ****************************************************************/
+
+#define PAL(x) x, sizeof(x)
+#define VPARAM(x) &video_param_table[x]
+
+static struct vgamode_s vga_modes[] VAR16 = {
+ //mode vparam model bits sstart pelm dac
+ {0x00, VPARAM(0x17), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)},
+ {0x01, VPARAM(0x17), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)},
+ {0x02, VPARAM(0x18), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)},
+ {0x03, VPARAM(0x18), CTEXT, 4, SEG_CTEXT, 0xFF, PAL(palette2)},
+ {0x04, VPARAM(0x04), CGA, 2, SEG_CTEXT, 0xFF, PAL(palette1)},
+ {0x05, VPARAM(0x05), CGA, 2, SEG_CTEXT, 0xFF, PAL(palette1)},
+ {0x06, VPARAM(0x06), CGA, 1, SEG_CTEXT, 0xFF, PAL(palette1)},
+ {0x07, VPARAM(0x07), MTEXT, 4, SEG_MTEXT, 0xFF, PAL(palette0)},
+ {0x0D, VPARAM(0x0d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)},
+ {0x0E, VPARAM(0x0e), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette1)},
+ {0x0F, VPARAM(0x11), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette0)},
+ {0x10, VPARAM(0x12), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+ {0x11, VPARAM(0x1a), PLANAR1, 1, SEG_GRAPH, 0xFF, PAL(palette2)},
+ {0x12, VPARAM(0x1b), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+ {0x13, VPARAM(0x1c), LINEAR8, 8, SEG_GRAPH, 0xFF, PAL(palette3)},
+ {0x6A, VPARAM(0x1d), PLANAR4, 4, SEG_GRAPH, 0xFF, PAL(palette2)},
+};
+
+struct vgamode_s *
+find_vga_entry(u8 mode)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(vga_modes); i++) {
+ struct vgamode_s *vmode_g = &vga_modes[i];
+ if (GET_GLOBAL(vmode_g->svgamode) == mode)
+ return vmode_g;
+ }
+ return NULL;
+}
+
+u16 video_save_pointer_table[14] VAR16;
+
+
+/****************************************************************
+ * Static functionality table
+ ****************************************************************/
+
+u8 static_functionality[0x10] VAR16 = {
+ /* 0 */ 0xff, // All modes supported #1
+ /* 1 */ 0xe0, // All modes supported #2
+ /* 2 */ 0x0f, // All modes supported #3
+ /* 3 */ 0x00, 0x00, 0x00, 0x00, // reserved
+ /* 7 */ 0x07, // 200, 350, 400 scan lines
+ /* 8 */ 0x02, // mamimum number of visible charsets in text mode
+ /* 9 */ 0x08, // total number of charset blocks in text mode
+ /* a */ 0xe7, // Change to add new functions
+ /* b */ 0x0c, // Change to add new functions
+ /* c */ 0x00, // reserved
+ /* d */ 0x00, // reserved
+ /* e */ 0x00, // Change to add new functions
+ /* f */ 0x00 // reserved
+};
--- /dev/null
+#ifndef __VGATABLES_H
+#define __VGATABLES_H
+
+#include "types.h" // u8
+#include "farptr.h" // struct segoff_s
+
+/*
+ *
+ * VGA registers
+ *
+ */
+#define VGAREG_ACTL_ADDRESS 0x3c0
+#define VGAREG_ACTL_WRITE_DATA 0x3c0
+#define VGAREG_ACTL_READ_DATA 0x3c1
+
+#define VGAREG_INPUT_STATUS 0x3c2
+#define VGAREG_WRITE_MISC_OUTPUT 0x3c2
+#define VGAREG_VIDEO_ENABLE 0x3c3
+#define VGAREG_SEQU_ADDRESS 0x3c4
+#define VGAREG_SEQU_DATA 0x3c5
+
+#define VGAREG_PEL_MASK 0x3c6
+#define VGAREG_DAC_STATE 0x3c7
+#define VGAREG_DAC_READ_ADDRESS 0x3c7
+#define VGAREG_DAC_WRITE_ADDRESS 0x3c8
+#define VGAREG_DAC_DATA 0x3c9
+
+#define VGAREG_READ_FEATURE_CTL 0x3ca
+#define VGAREG_READ_MISC_OUTPUT 0x3cc
+
+#define VGAREG_GRDC_ADDRESS 0x3ce
+#define VGAREG_GRDC_DATA 0x3cf
+
+#define VGAREG_MDA_CRTC_ADDRESS 0x3b4
+#define VGAREG_MDA_CRTC_DATA 0x3b5
+#define VGAREG_VGA_CRTC_ADDRESS 0x3d4
+#define VGAREG_VGA_CRTC_DATA 0x3d5
+
+#define VGAREG_MDA_WRITE_FEATURE_CTL 0x3ba
+#define VGAREG_VGA_WRITE_FEATURE_CTL 0x3da
+#define VGAREG_ACTL_RESET 0x3da
+
+#define VGAREG_MDA_MODECTL 0x3b8
+#define VGAREG_CGA_MODECTL 0x3d8
+#define VGAREG_CGA_PALETTE 0x3d9
+
+/* Video memory */
+#define SEG_GRAPH 0xA000
+#define SEG_CTEXT 0xB800
+#define SEG_MTEXT 0xB000
+
+/*
+ * Tables of default values for each mode
+ */
+#define TEXT 0x80
+
+#define CTEXT (0x00 | TEXT)
+#define MTEXT (0x01 | TEXT)
+#define CGA 0x02
+#define PLANAR1 0x03
+#define PLANAR4 0x04
+#define LINEAR8 0x05
+
+// for SVGA
+#define LINEAR15 0x10
+#define LINEAR16 0x11
+#define LINEAR24 0x12
+#define LINEAR32 0x13
+
+#define SCREEN_IO_START(x,y,p) (((((x)*(y)) | 0x00ff) + 1) * (p))
+#define SCREEN_MEM_START(x,y,p) SCREEN_IO_START(((x)*2),(y),(p))
+
+/* standard BIOS Video Parameter Table */
+struct VideoParam_s {
+ u8 twidth;
+ u8 theightm1;
+ u8 cheight;
+ u16 slength;
+ u8 sequ_regs[4];
+ u8 miscreg;
+ u8 crtc_regs[25];
+ u8 actl_regs[20];
+ u8 grdc_regs[9];
+} PACKED;
+
+struct vgamode_s {
+ u8 svgamode;
+ struct VideoParam_s *vparam;
+ u8 memmodel; /* CTEXT,MTEXT,CGA,PL1,PL2,PL4,P8,P15,P16,P24,P32 */
+ u8 pixbits;
+ u16 sstart;
+ u8 pelmask;
+ u8 *dac;
+ u16 dacsize;
+};
+
+struct saveVideoHardware {
+ u8 sequ_index;
+ u8 crtc_index;
+ u8 grdc_index;
+ u8 actl_index;
+ u8 feature;
+ u8 sequ_regs[4];
+ u8 sequ0;
+ u8 crtc_regs[25];
+ u8 actl_regs[20];
+ u8 grdc_regs[9];
+ u16 crtc_addr;
+ u8 plane_latch[4];
+};
+
+struct saveBDAstate {
+ u8 video_mode;
+ u16 video_cols;
+ u16 video_pagesize;
+ u16 crtc_address;
+ u8 video_rows;
+ u16 char_height;
+ u8 video_ctl;
+ u8 video_switches;
+ u8 modeset_ctl;
+ u16 cursor_type;
+ u16 cursor_pos[8];
+ u16 video_pagestart;
+ u8 video_page;
+ /* current font */
+ struct segoff_s font0;
+ struct segoff_s font1;
+};
+
+struct saveDACcolors {
+ u8 rwmode;
+ u8 peladdr;
+ u8 pelmask;
+ u8 dac[768];
+ u8 color_select;
+};
+
+// vgatables.c
+struct vgamode_s *find_vga_entry(u8 mode);
+extern u16 video_save_pointer_table[];
+extern struct VideoParam_s video_param_table[];
+extern u8 static_functionality[];
+
+// vgafonts.c
+extern u8 vgafont8[];
+extern u8 vgafont14[];
+extern u8 vgafont16[];
+extern u8 vgafont14alt[];
+extern u8 vgafont16alt[];
+
+// vga.c
+struct carattr {
+ u8 car, attr, use_attr;
+};
+struct cursorpos {
+ u8 x, y, page;
+};
+
+// vgafb.c
+void clear_screen(struct vgamode_s *vmode_g);
+void vgafb_scroll(int nblines, int attr
+ , struct cursorpos ul, struct cursorpos lr);
+void vgafb_write_char(struct cursorpos cp, struct carattr ca);
+struct carattr vgafb_read_char(struct cursorpos cp);
+void vgafb_write_pixel(u8 color, u16 x, u16 y);
+u8 vgafb_read_pixel(u16 x, u16 y);
+void vgafb_load_font(u16 seg, void *src_far, u16 count
+ , u16 start, u8 destflags, u8 fontsize);
+
+// vgaio.c
+void vgahw_screen_disable(void);
+void vgahw_screen_enable(void);
+void vgahw_set_border_color(u8 color);
+void vgahw_set_overscan_border_color(u8 color);
+u8 vgahw_get_overscan_border_color(void);
+void vgahw_set_palette(u8 palid);
+void vgahw_set_single_palette_reg(u8 reg, u8 val);
+u8 vgahw_get_single_palette_reg(u8 reg);
+void vgahw_set_all_palette_reg(u16 seg, u8 *data_far);
+void vgahw_get_all_palette_reg(u16 seg, u8 *data_far);
+void vgahw_toggle_intensity(u8 flag);
+void vgahw_select_video_dac_color_page(u8 flag, u8 data);
+void vgahw_read_video_dac_state(u8 *pmode, u8 *curpage);
+void vgahw_set_dac_regs(u16 seg, u8 *data_far, u8 start, int count);
+void vgahw_get_dac_regs(u16 seg, u8 *data_far, u8 start, int count);
+void vgahw_set_pel_mask(u8 val);
+u8 vgahw_get_pel_mask(void);
+void vgahw_save_dac_state(u16 seg, struct saveDACcolors *info);
+void vgahw_restore_dac_state(u16 seg, struct saveDACcolors *info);
+void vgahw_sequ_write(u8 index, u8 value);
+void vgahw_grdc_write(u8 index, u8 value);
+void vgahw_set_text_block_specifier(u8 spec);
+void get_font_access(void);
+void release_font_access(void);
+void vgahw_set_cursor_shape(u8 start, u8 end);
+void vgahw_set_active_page(u16 address);
+void vgahw_set_cursor_pos(u16 address);
+void vgahw_set_scan_lines(u8 lines);
+u16 vgahw_get_vde(void);
+void vgahw_save_state(u16 seg, struct saveVideoHardware *info);
+void vgahw_restore_state(u16 seg, struct saveVideoHardware *info);
+void vgahw_set_mode(struct VideoParam_s *vparam_g);
+void vgahw_enable_video_addressing(u8 disable);
+void vgahw_init(void);
+
+// clext.c
+void cirrus_set_video_mode(u8 mode);
+void cirrus_init(void);
+
+// vbe.c -- not implemented yet.
+#define VBE_DISPI_DISABLED 0x00
+void dispi_set_enable(int enable);
+void vbe_init(void);
+int vbe_has_vbe_display(void);
+
+#endif // vgatables.h