diff options
Diffstat (limited to '')
-rw-r--r-- | .gitignore | 14 | ||||
-rw-r--r-- | COPYING | 15 | ||||
-rw-r--r-- | DEPENDENCIES | 1 | ||||
-rw-r--r-- | LICENSE | 683 | ||||
-rw-r--r-- | Makefile | 190 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | calibrator.c | 655 | ||||
-rw-r--r-- | common.h | 393 | ||||
-rw-r--r-- | config.mk | 6 | ||||
-rw-r--r-- | crt-calibrator.1 (renamed from doc/man/crt-calibrator.1) | 0 | ||||
-rw-r--r-- | dist/archlinux/stable/.gitignore | 9 | ||||
-rw-r--r-- | dist/archlinux/stable/PKGBUILD | 25 | ||||
-rw-r--r-- | dist/archlinux/stable/crt-calibrator.install | 20 | ||||
-rw-r--r-- | doc/info/crt-calibrator.texinfo | 90 | ||||
-rw-r--r-- | doc/info/fdl.texinfo | 505 | ||||
-rw-r--r-- | drmgamma.c | 262 | ||||
-rw-r--r-- | framebuffer.c | 183 | ||||
-rw-r--r-- | gamma.c | 57 | ||||
-rw-r--r-- | src/calibrator.c | 733 | ||||
-rw-r--r-- | src/calibrator.h | 108 | ||||
-rw-r--r-- | src/drmgamma.c | 283 | ||||
-rw-r--r-- | src/drmgamma.h | 182 | ||||
-rw-r--r-- | src/framebuffer.c | 215 | ||||
-rw-r--r-- | src/framebuffer.h | 154 | ||||
-rw-r--r-- | src/gamma.c | 79 | ||||
-rw-r--r-- | src/gamma.h | 52 | ||||
-rw-r--r-- | src/state.c | 172 | ||||
-rw-r--r-- | src/state.h | 89 | ||||
-rw-r--r-- | state.c | 144 |
29 files changed, 1742 insertions, 3578 deletions
@@ -1,15 +1,5 @@ -_/ -bin/ -obj/ -.* -!.git* +*\#* *~ -\#*\# -*.bak -*.swp -*.swo *.o *.su -*.out -*.gch - +/crt-calibrator diff --git a/COPYING b/COPYING deleted file mode 100644 index a8fc716..0000000 --- a/COPYING +++ /dev/null @@ -1,15 +0,0 @@ -crt-calibrator – Calibration utility for CRT monitors -Copyright © 2014, 2015 Mattias Andrée (maandree@member.fsf.org) - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. diff --git a/DEPENDENCIES b/DEPENDENCIES index 294d82d..07f8c1c 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -12,7 +12,6 @@ BUILD DEPENDENCIES: linux gcc make - texinfo (opt-put: for info, pdf, dvi and ps manuals) INSTALL DEPENDENCIES: @@ -1,674 +1,15 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 +ISC License - 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. +© 2014, 2015, 2021 Mattias Andrée <maandree@kth.se> - Preamble +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. - 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>. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. @@ -1,174 +1,40 @@ -PREFIX = /usr -BIN = /bin -DATA = /share -BINDIR = $(PREFIX)$(BIN) -DATADIR = $(PREFIX)$(DATA) -DOCDIR = $(DATADIR)/doc -INFODIR = $(DATADIR)/info -MANDIR = $(DATADIR)/man -MAN1DIR = $(MANDIR)/man1 -LICENSES = $(DATADIR)/licenses +.POSIX: -COMMAND = crt-calibrator -PKGNAME = crt-calibrator +CONFIGFILE = config.mk +include $(CONFIGFILE) +OBJ =\ + calibrator.o\ + drmgamma.o\ + framebuffer.o\ + gamma.o\ + state.o -LIBS = libdrm +HDR = common.h -FLAGS = -std=gnu99 -Og -g -Wall -Wextra -pedantic -Wdouble-promotion -Wformat=2 \ - -Winit-self -Wmissing-include-dirs -Wtrampolines -Wfloat-equal -Wshadow \ - -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls \ - -Wnested-externs -Winline -Wno-variadic-macros -Wswitch-default \ - -Wsync-nand -Wunsafe-loop-optimizations -Wcast-align -Wstrict-overflow \ - -Wdeclaration-after-statement -Wundef -Wbad-function-cast -Wcast-qual \ - -Wwrite-strings -Wlogical-op -Waggregate-return -Wstrict-prototypes \ - -Wold-style-definition -Wpacked -Wvector-operation-performance \ - -Wunsuffixed-float-constants -Wsuggest-attribute=const \ - -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \ - -Wsuggest-attribute=format -Wnormalized=nfkc -Wconversion \ - -fstrict-aliasing -fstrict-overflow -fipa-pure-const -ftree-vrp \ - -fstack-usage -funsafe-loop-optimizations -Wtraditional-conversion +all: crt-calibrator +$(OBJ): $(@:.o=.c) $(HDR) -LD_FLAGS = -lm $(shell pkg-config --libs $(LIBS)) $(FLAGS) $(LDFLAGS) -C_FLAGS = $(shell pkg-config --cflags $(LIBS)) $(FLAGS) $(CFLAGS) $(CPPFLAGS) +crt-calibrator: $(OBJ) + $(CC) -o $@ $(OBJ) $(LDFLAGS) -OBJS = calibrator drmgamma framebuffer gamma state +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) +install: crt-calibrator + mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1" + cp -- crt-calibrator "$(DESTDIR)$(PREFIX)/bin/" + cp -- crt-calibrator.1 "$(DESTDIR)$(MANPREFIX)/man1/" - -.PHONY: default -default: base info - -.PHONY: all -all: base doc - -.PHONY: base -base: cmd - - -.PHONY: cmd -cmd: bin/crt-calibrator - -bin/crt-calibrator: $(foreach O,$(OBJS),obj/$(O).o) - @mkdir -p bin - $(CC) $(LD_FLAGS) -o $@ $^ - -obj/%.o: src/%.c src/*.h - @mkdir -p obj - $(CC) $(C_FLAGS) -c -o $@ $< - - -.PHONY: doc -doc: info pdf dvi ps - -.PHONY: info -info: bin/crt-calibrator.info -bin/%.info: doc/info/%.texinfo - @mkdir -p bin - $(MAKEINFO) $< - mv $*.info $@ - -.PHONY: pdf -pdf: bin/crt-calibrator.pdf -bin/%.pdf: doc/info/%.texinfo - @! test -d obj/pdf || rm -rf obj/pdf - @mkdir -p bin obj/pdf - cd obj/pdf && texi2pdf ../../"$<" < /dev/null - mv obj/pdf/$*.pdf $@ - -.PHONY: dvi -dvi: bin/crt-calibrator.dvi -bin/%.dvi: doc/info/%.texinfo - @! test -d obj/dvi || rm -rf obj/dvi - @mkdir -p bin obj/dvi - cd obj/dvi && $(TEXI2DVI) ../../"$<" < /dev/null - mv obj/dvi/$*.dvi $@ - -.PHONY: ps -ps: bin/crt-calibrator.ps -bin/%.ps: doc/info/%.texinfo - @! test -d obj/ps || rm -rf obj/ps - @mkdir -p bin obj/ps - cd obj/ps && texi2pdf --ps ../../"$<" < /dev/null - mv obj/ps/$*.ps $@ - - - -.PHONY: install -install: install-base install-info install-man - -.PHONY: install-all -install-all: install-base install-doc - -.PHONY: install-base -install-base: install-cmd install-copyright - - -.PHONY: install-cmd -install-cmd: bin/crt-calibrator - install -dm755 -- "$(DESTDIR)$(BINDIR)" - install -m755 $< -- "$(DESTDIR)$(BINDIR)/$(COMMAND)" - - -.PHONY: install-copyright -install-copyright: install-copying install-license - -.PHONY: install-copying -install-copying: - install -dm755 -- "$(DESTDIR)$(LICENSES)/$(PKGNAME)" - install -m644 COPYING -- "$(DESTDIR)$(LICENSES)/$(PKGNAME)" - -.PHONY: install-license -install-license: - install -dm755 -- "$(DESTDIR)$(LICENSES)/$(PKGNAME)" - install -m644 LICENSE -- "$(DESTDIR)$(LICENSES)/$(PKGNAME)" - - -.PHONY: install-doc -install-doc: install-info install-pdf install-dvi install-ps install-man - -.PHONY: install-info -install-info: bin/crt-calibrator.info - install -dm755 -- "$(DESTDIR)$(INFODIR)" - install -m644 $< -- "$(DESTDIR)$(INFODIR)/$(PKGNAME).info" - -.PHONY: install-pdf -install-pdf: bin/crt-calibrator.pdf - install -dm755 -- "$(DESTDIR)$(DOCDIR)" - install -m644 $< -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME).pdf" - -.PHONY: install-dvi -install-dvi: bin/crt-calibrator.dvi - install -dm755 -- "$(DESTDIR)$(DOCDIR)" - install -m644 $< -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME).dvi" - -.PHONY: install-ps -install-ps: bin/crt-calibrator.ps - install -dm755 -- "$(DESTDIR)$(DOCDIR)" - install -m644 $< -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME).ps" - -.PHONY: install-man -install-man: doc/man/crt-calibrator.1 - install -dm755 -- "$(DESTDIR)$(MAN1DIR)" - install -m644 $< -- "$(DESTDIR)$(MAN1DIR)/$(COMMAND).1" - - - -.PHONY: uninstall uninstall: - -rm -- "$(DESTDIR)$(BINDIR)/$(COMMAND)" - -rm -- "$(DESTDIR)$(LICENSES)/$(PKGNAME)/COPYING" - -rm -- "$(DESTDIR)$(LICENSES)/$(PKGNAME)/LICENSE" - -rmdir -- "$(DESTDIR)$(LICENSES)/$(PKGNAME)" - -rm -- "$(DESTDIR)$(INFODIR)/$(PKGNAME).info" - -rm -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME).pdf" - -rm -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME).dvi" - -rm -- "$(DESTDIR)$(DOCDIR)/$(PKGNAME).ps" - -rm -- "$(DESTDIR)$(MAN1DIR)/$(COMMAND).1" - + -rm -- "$(DESTDIR)$(BINDIR)/crt-calibrator" + -rm -- "$(DESTDIR)$(MAN1DIR)/crt-calibrator.1" - -.PHONY: clean clean: - -rm -r bin obj + -rm -rf -- crt-calibrator *.o + +.SUFFIXES: +.SUFFIXES: .o .c +.PHONY: all install uninstall clean @@ -37,4 +37,3 @@ RATIONALE SEE ALSO analyse-gamma(1), blueshift(1) - diff --git a/calibrator.c b/calibrator.c new file mode 100644 index 0000000..9456f96 --- /dev/null +++ b/calibrator.c @@ -0,0 +1,655 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Draw bars in different shades of grey, red, green and blue + * used for calibrating the contrast and brightness + */ +static void +draw_contrast_brightness(void) +{ + const int CONTRAST_BRIGHTNESS_LEVELS[21] = { + 0, 17, 27, 38, 48, 59, 70, 82, 94, 106, 119, 131, + 144, 158, 171, 185, 198, 212, 226, 241, 255 + }; + size_t f; + uint32_t y, x, colour; + framebuffer_t *restrict fb; + int v; + + for (f = 0; f < framebuffer_count; f++) { + fb = &framebuffers[f]; + for (y = 0; y < 4; y++) { + for (x = 0; x < 21; x++) { + v = CONTRAST_BRIGHTNESS_LEVELS[x]; + colour = fb_colour(v * ((y == 1) | (y == 0)), + v * ((y == 2) | (y == 0)), + v * ((y == 3) | (y == 0))); + fb_fill_rectangle(fb, colour, x * fb->width / 21, y * fb->height / 4, + (x + 1) * fb->width / 21 - x * fb->width / 21, + (y + 1) * fb->height / 4 - y * fb->height / 4); + } + } + } +} + + +/** + * Draw a seven segment display + * + * @param fb The framebuffer to draw on + * @param colour The intensity of the least intense colour to use + * @param x The X component of the top left corner of the seven segment display + * @param y The Y component of the top left corner of the seven segment display + */ +static void +draw_digit(framebuffer_t *restrict fb, int colour, uint32_t x, uint32_t y) +{ + uint32_t c; + + c = fb_colour(colour + 0, colour + 0, colour + 0); + fb_fill_rectangle(fb, c, x + 20, y, 80, 20); + + c = fb_colour(colour + 1, colour + 1, colour + 1); + fb_fill_rectangle(fb, c, x, y + 20, 20, 80); + + c = fb_colour(colour + 2, colour + 2, colour + 2); + fb_fill_rectangle(fb, c, x + 100, y + 20, 20, 80); + + c = fb_colour(colour + 3, colour + 3, colour + 3); + fb_fill_rectangle(fb, c, x + 20, y + 100, 80, 20); + + c = fb_colour(colour + 4, colour + 4, colour + 4); + fb_fill_rectangle(fb, c, x, y + 120, 20, 80); + + c = fb_colour(colour + 5, colour + 5, colour + 5); + fb_fill_rectangle(fb, c, x + 100, y + 120, 20, 80); + + c = fb_colour(colour + 6, colour + 6, colour + 6); + fb_fill_rectangle(fb, c, x + 20, y + 200, 80, 20); +} + + +/** + * Manipulate a CRT controllers gamma ramps to display a specific digit + * for one of the seven segment display on only that CRT controller's + * monitors + * + * @param crtc The CRT controller information + * @param colour The intensity of the least intense colour in the seven segment display + * @param value The valud of the digit to display + */ +static void +gamma_digit(drm_crtc_t *restrict crtc, int colour, size_t value) +{ +#define __ 0 + const int DIGITS[11] = { 1 | 2 | 4 | __ | 16 | 32 | 64, /* (0) */ + __ | __ | 4 | __ | __ | 32 | __, /* (1) */ + 1 | __ | 4 | 8 | 16 | __ | 64, /* (2) */ + 1 | __ | 4 | 8 | __ | 32 | 64, /* (3) */ + __ | 2 | 4 | 8 | __ | 32 | __, /* (4) */ + 1 | 2 | __ | 8 | __ | 32 | 64, /* (5) */ + 1 | 2 | __ | 8 | 16 | 32 | 64, /* (6) */ + 1 | __ | 4 | __ | __ | 32 | __, /* (7) */ + 1 | 2 | 4 | 8 | 16 | 32 | 64, /* (8) */ + 1 | 2 | 4 | 8 | __ | 32 | 64, /* (9) */ + __ | __ | __ | __ | __ | __ | __}; /* not visible */ +#undef __ + int i, j, digit = DIGITS[value]; + uint16_t c; + + for (i = 0; i < 7; i++) { + c = (digit & (1 << i)) ? 0xFFFF : 0; + j = i + colour; + crtc->red[j] = crtc->green[j] = crtc->blue[j] = c; + } +} + + +/** + * Draw an unique index on each monitor + * + * @return Zero on success, -1 on error + */ +static int +draw_id(void) +{ + size_t f, c, id = 0; + framebuffer_t *restrict fb; + drm_crtc_t *restrict crtc; + for (f = 0; f < framebuffer_count; f++) { + fb = &framebuffers[f]; + fb_fill_rectangle(fb, fb_colour(0, 0, 0), 0, 0, fb->width, fb->height); + draw_digit(fb, 1, 40, 40); + draw_digit(fb, 8, 180, 40); + } + for (c = 0; c < crtc_count; c++) { + crtc = &crtcs[c]; + if (drm_get_gamma(crtc) < 0) + return -1; + gamma_digit(crtc, 1, id < 10 ? 10 : (id / 10) % 10); + gamma_digit(crtc, 8, (id / 1) % 10); + id++; + if (drm_set_gamma(crtc) < 0) + return -1; + } + return 0; +} + + +/** + * Draw squares used as reference when tweeking the gamma correction + */ +static void +draw_gamma(void) +{ + size_t f; + uint32_t x, y, background, average, high, low, xoff; + framebuffer_t *restrict fb; + int r, g, b; + for (f = 0; f < framebuffer_count; f++) { + fb = framebuffers + f; + for (x = 0; x < 4; x++) { + r = (x == 1) || (x == 0); + g = (x == 2) || (x == 0); + b = (x == 3) || (x == 0); + background = fb_colour(128 * r, 128 * g, 128 * b); + average = fb_colour(188 * r, 188 * g, 188 * b); + high = fb_colour(255 * r, 255 * g, 255 * b); + low = fb_colour(0, 0, 0); + xoff = x * fb->width / 4; + fb_fill_rectangle(fb, background, xoff, 0, fb->width / 4, fb->height); + xoff += (fb->width / 4 - 200) / 2; + fb_fill_rectangle(fb, high, xoff, 40, 200, 200); + fb_fill_rectangle(fb, average, xoff + 50, 40, 100, 200); + fb_fill_rectangle(fb, average, xoff, 280, 200, 200); + for (y = 0; y < 200; y += 2) { + fb_draw_horizontal_line(fb, high, xoff + 50, 280 + y + 0, 100); + fb_draw_horizontal_line(fb, low , xoff + 50, 280 + y + 1, 100); + } + fb_fill_rectangle(fb, average, xoff, 520, 200, 200); + fb_fill_rectangle(fb, high, xoff + 50, 520, 100, 200); + } + } +} + + +/** + * Print a pattern on the screen that can be used when + * calibrating the convergence + */ +static void +draw_convergence(void) +{ + uint32_t black = fb_colour(0, 0, 0); + uint32_t white = fb_colour(255, 255, 255); + uint32_t x, y; + size_t f; + framebuffer_t *restrict fb; + for (f = 0; f < framebuffer_count; f++) { + fb = framebuffers + f; + fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); + for (y = 0; y <= fb->height; y += 16) { + if (y == fb->height) + y = fb->height - 1; + for (x = 0; x <= fb->width; x += 16) { + if (x == fb->height) + x = fb->height - 1; + fb_draw_pixel(fb, white, x, y); + } + } + } +} + + +/** + * Print a pattern on the screen that can be used when + * calibrating the moiré cancellation + * + * @param gap The horizontal and vertical gap, in pixels, between the dots + * @param diagonal Whether to draw dots in a diagonal pattern + */ +static void +draw_moire(uint32_t gap, int diagonal) +{ + uint32_t black = fb_colour(0, 0, 0); + uint32_t white = fb_colour(255, 255, 255); + uint32_t x, y, gap2 = gap << 1; + size_t f; + framebuffer_t *restrict fb; + gap += (uint32_t)!diagonal; + if (diagonal) { + for (f = 0; f < framebuffer_count; f++) { + fb = framebuffers + f; + fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); + for (y = 0; y < fb->height; y += gap) + for (x = (y % gap2); x < fb->width; x += gap2) + fb_draw_pixel(fb, white, x, y); + } + } else { + for (f = 0; f < framebuffer_count; f++) { + fb = framebuffers + f; + fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); + for (y = 0; y < fb->height; y += gap) + for (x = 0; x < fb->width; x += gap) + fb_draw_pixel(fb, white, x, y); + } + } +} + + +/** + * Analyse the monitors calibrations + * + * @return Zero on success, -1 on error + */ +static int +read_calibs(void) +{ + size_t c; + for (c = 0; c < crtc_count; c++) { + if (drm_get_gamma(&crtcs[c]) < 0) + return -1; + gamma_analyse(crtcs[c].gamma_stops, crtcs[c].red, &gammas[0][c], &contrasts[0][c], &brightnesses[0][c]); + gamma_analyse(crtcs[c].gamma_stops, crtcs[c].green, &gammas[1][c], &contrasts[1][c], &brightnesses[1][c]); + gamma_analyse(crtcs[c].gamma_stops, crtcs[c].blue, &gammas[2][c], &contrasts[2][c], &brightnesses[2][c]); + } + return 0; +} + + +/** + * Apply the selected calibrations to the monitors + * + * @return Zero on success, -1 on error + */ +static int +apply_calibs(void) +{ + size_t c; + for (c = 0; c < crtc_count; c++) { + gamma_generate(crtcs[c].gamma_stops, crtcs[c].red, gammas[0][c], contrasts[0][c], brightnesses[0][c]); + gamma_generate(crtcs[c].gamma_stops, crtcs[c].green, gammas[1][c], contrasts[1][c], brightnesses[1][c]); + gamma_generate(crtcs[c].gamma_stops, crtcs[c].blue, gammas[2][c], contrasts[2][c], brightnesses[2][c]); + if (drm_set_gamma(&crtcs[c]) < 0) + return -1; + } + return 0; +} + + +/** + * Print calibrations into a file + * + * @param fp The file + * @return Zero on success, -1 on error + */ +static int +save_calibs(FILE *fp) +{ + size_t c; + for (c = 0; c < crtc_count; c++) { + if (fprintf(fp, "# index = %lu\n", c) < 0) + return -1; + if (fprintf(fp, "edid = %s\n", crtcs[c].edid) < 0) + return -1; + if (fprintf(fp, "brightness = %f:%f:%f\n", brightnesses[0][c], brightnesses[1][c], brightnesses[2][c]) < 0) + return -1; + if (fprintf(fp, "contrast = %f:%f:%f\n", contrasts[0][c], contrasts[1][c], contrasts[2][c]) < 0) + return -1; + if (fprintf(fp, "gamma = %f:%f:%f\n\n", gammas[0][c], gammas[1][c], gammas[2][c]) < 0) + return -1; + } + return 0; +} + + +int +main(int argc, char *argv[]) +{ + FILE *output_file = stdout; + int tty_configured = 0, rc = 0, in_fork = 0, status; + int c, b, d, at_contrast, red, green, blue; + struct termios stty, saved_stty; + uint32_t gap; + size_t mon; + pid_t pid; + + if (argc > 1 && argv[1][0] == '-') { + if (argv[1][1] == '-' && !argv[1][2]) { + argv[1] = argv[2]; + argc -= 1; + } else { + printf("usage: %s [output-file]\n", *argv); + return 1; + } + } + if (argc > 2) { + printf("usage: %s [output-file]\n", *argv); + return 0; + } + + if ((acquire_video() < 0) || + (tcgetattr(STDIN_FILENO, &saved_stty) < 0) || + (tcgetattr(STDIN_FILENO, &stty) < 0)) + goto fail; + + stty.c_lflag &= (tcflag_t)~(ICANON | ECHO); + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty) < 0) + goto fail; + tty_configured = 1; + + printf("\033[?25l"); + fflush(stdout); + + pid = fork(); + if (pid > 0) { + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + perror(*argv); + rc = !!status; + goto done; + } else if (!pid) { + in_fork = 1; + } + + printf("\033[H\033[2J"); + printf("Please deactivate any program that dynamically\n"); + printf("applies filters to your monitors' colours\n"); + printf("and remove any existing filters.\n"); + printf("In doubt, you probably do not have any.\n"); + printf("Do not try to calibrate CRT monitors will\n"); + printf("they are cold.\n"); + printf("\n"); + printf("You will be presented with an image on each\n"); + printf("monitor. Please use the control panel on your\n"); + printf("to calibrate the contrast and brightness of\n"); + printf("each monitor. The contrasts adjusts the\n"); + printf("brightness of bright colours, and the\n"); + printf("brightness adjusts the brightness of dim\n"); + printf("colours. All rectangles are of equals size\n"); + printf("and they should be distrint from eachother.\n"); + printf("There should only be a slight difference\n"); + printf("between the two darkest colours for each\n"); + printf("colour. The grey colour does not need to\n"); + printf("be perfectly grey but should be close.\n"); + printf("The brightness should be as high as\n"); + printf("possible without the first square being\n"); + printf("any other colour than black or the two first\n"); + printf("square being too distinct from eachother. The\n"); + printf("contrast should be as high as possible without\n"); + printf("causing distortion.\n"); + printf("\n"); + printf("Press ENTER to continue, and ENTER again when\n"); + printf("your are done.\n"); + fflush(stdout); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + fflush(stdout); + draw_contrast_brightness(); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + printf("An index will be displayed on each monitor.\n"); + printf("It behoves you to memorise them. They will\n"); + printf("be used in the output when descibing the\n"); + printf("calibrations, and is the index of the monitors\n"); + printf("that are used when changing monitor to\n"); + printf("calibrate.\n"); + printf("\n"); + printf("Press ENTER to continue, and ENTER again when\n"); + printf("your are done.\n"); + fflush(stdout); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + fflush(stdout); + if (read_calibs() || draw_id()) + goto fail; + + while (getchar() != '\n'); + + if (apply_calibs()) + goto fail; + + printf("\033[H\033[2J"); + printf("You will not be given the opportunity to.\n"); + printf("calibrate your monitors' brightness and\n"); + printf("contrast using software incase your monitors\n"); + printf("could not be sufficiently calibrated using\n"); + printf("hardware.\n"); + printf("\n"); + printf("<Left> and <right> is used to change which\n"); + printf("monitor to calibrate. <Left> switches to the\n"); + printf("previous monitor (one lower in index) and\n"); + printf("<right> switches to the next monitor (one\n"); + printf("higher in index.)\n"); + printf("<Up> and <down> is used to increase and\n"); + printf("descrease the settings. respectively.\n"); + printf("<Shift+b> is used to switch to changing the.\n"); + printf("monitor's brightness and <shift+c> switches\n"); + printf("to contrast.\n"); + printf("<r> is used to switch to changing the red.\n"); + printf("channel, <g> switches to the green channel,\n"); + printf("<b> switches to the blue channel, and <a>\n"); + printf("is used to switch to change all channels.\n"); + printf("\n"); + printf("Press ENTER to continue, and ENTER again when\n"); + printf("your are done.\n"); + fflush(stdout); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + fflush(stdout); + draw_contrast_brightness(); + + b = at_contrast = 0; + red = green = blue = 1; + mon = 0; + while ((c = getchar()) != '\n') { + if (b) { + b = 0; + if (c == 'A' && at_contrast) { + contrasts[0][mon] += (double)red / 100; + contrasts[1][mon] += (double)green / 100; + contrasts[2][mon] += (double)blue / 100; + } else if (c == 'A') { + brightnesses[0][mon] += (double)red / 100; + brightnesses[1][mon] += (double)green / 100; + brightnesses[2][mon] += (double)blue / 100; + } else if (c == 'B' && at_contrast) { + contrasts[0][mon] -= (double)red / 100; + contrasts[1][mon] -= (double)green / 100; + contrasts[2][mon] -= (double)blue / 100; + } else if (c == 'B') { + brightnesses[0][mon] -= (double)red / 100; + brightnesses[1][mon] -= (double)green / 100; + brightnesses[2][mon] -= (double)blue / 100; + } else if (c == 'C') { + mon = (mon + 1) % crtc_count; + } else if (c == 'D') { + mon = (mon == 0 ? crtc_count : mon) - 1; + } + + if (c == 'A' || c == 'B') + apply_calibs(); + } + else if (c == '[') b = 1; + else if (c == 'B') at_contrast = 0; + else if (c == 'C') at_contrast = 1; + else if (c == 'r') red = 1, green = 0, blue = 0; + else if (c == 'g') red = 0, green = 1, blue = 0; + else if (c == 'b') red = 0, green = 0, blue = 1; + else if (c == 'a') red = 1, green = 1, blue = 1; + } + + printf("\033[H\033[2J"); + printf("You will now be presented with squares used\n"); + printf("to calibrate the gamma correction. There will\n"); + printf("be four stacks: grey, red, green and blue.\n"); + printf("Each stack has three squares: the upper square\n"); + printf("shows the characterics of how the middle square\n"); + printf("will look if the gamma is too high, and the\n"); + printf("lower shows how the middile will look if the\n"); + printf("gamma is too low. The middle square should\n"); + printf("look like it is one single colour if the gamma\n"); + printf("correction is configured correctly. You may\n"); + printf("have to look from a distance or not focus\n"); + printf("your eyes on the squares to compensate for\n"); + printf("the fact that there actually multiple colours\n"); + printf("is the square.\n"); + printf("The grey should look perfectly grey when you\n"); + printf("are done.\n"); + printf("\n"); + printf("<Left> and <right> is used to change which\n"); + printf("monitor to calibrate. <Left> switches to the\n"); + printf("previous monitor (one lower in index) and\n"); + printf("<right> switches to the next monitor (one\n"); + printf("higher in index.)\n"); + printf("<Up> and <down> is used to increase and\n"); + printf("descrease the gamma. respectively.\n"); + printf("<r> is used to switch to changing the red.\n"); + printf("channel, <g> switches to the green channel,\n"); + printf("<b> switches to the blue channel, and <a>\n"); + printf("is used to switch to change all channels.\n"); + printf("\n"); + printf("Press ENTER to continue, and ENTER again when\n"); + printf("your are done.\n"); + fflush(stdout); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + fflush(stdout); + draw_gamma(); + + b = 0; + red = green = blue = 1; + mon = 0; + while ((c = getchar()) != '\n') { + if (b) { + b = 0; + if (c == 'A') { + gammas[0][mon] += (double)red / 100; + gammas[1][mon] += (double)green / 100; + gammas[2][mon] += (double)blue / 100; + } else if (c == 'B') { + gammas[0][mon] -= (double)red / 100; + gammas[1][mon] -= (double)green / 100; + gammas[2][mon] -= (double)blue / 100; + if (gammas[0][mon] < 0) gammas[0][mon] = 0; + if (gammas[1][mon] < 0) gammas[1][mon] = 0; + if (gammas[2][mon] < 0) gammas[2][mon] = 0; + } else if (c == 'C') { + mon = (mon + 1) % crtc_count; + } else if (c == 'D') { + mon = (mon == 0 ? crtc_count : mon) - 1; + } + + if (c == 'A' || c == 'B') + apply_calibs(); + } + else if (c == '[') b = 1; + else if (c == 'r') red = 1, green = 0, blue = 0; + else if (c == 'g') red = 0, green = 1, blue = 0; + else if (c == 'b') red = 0, green = 0, blue = 1; + else if (c == 'a') red = 1, green = 1, blue = 1; + } + + printf("\033[H\033[2J"); + printf("The next step is to calibrate the monitors'\n"); + printf("convergence settings using the monitors'\n"); + printf("control panel. White dots will be printed on the\n"); + printf("screens, you should try to get as many as\n"); + printf("possible of them to appear as pure white dots\n"); + printf("rather than dots splitted in the red, green and\n"); + printf("blue dots. On most CRT monitors this is not\n"); + printf("possible to get all corners perfect.\n"); + printf("\n"); + printf("Press ENTER to continue, and ENTER again when\n"); + printf("your are done.\n"); + fflush(stdout); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + fflush(stdout); + draw_convergence(); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + printf("The final step is to calbirate the monitors' moiré\n"); + printf("cancellation. This too is done on the using the\n"); + printf("monitors' control panel.\n"); + printf("\n"); + printf("You can use <d> and the arrow keys to change the\n"); + printf("dot-pattern on the screens.\n"); + printf("\n"); + printf("Press ENTER to continue, and ENTER again when\n"); + printf("your are done.\n"); + fflush(stdout); + + while (getchar() != '\n'); + + printf("\033[H\033[2J"); + fflush(stdout); + draw_moire(1, 1); + + b = 0; + d = 1; + gap = 1; + while ((c = getchar()) != '\n') { + if (b) { + b = 0; + if (c == 'A' || c == 'C') { + draw_moire(++gap, d); + } else if (c == 'B' || c == 'D') { + if (--gap == 0) + gap = 1; + draw_moire(gap, d); + } + } else if (c == '[') { + b = 1; + } else if (c == 'd') { + draw_moire(gap, d ^= 1); + } + } + + printf("\033[H\033[2J"); + fflush(stdout); + + if (argc == 2) { + output_file = fopen(argv[1], "w"); + if (!output_file) + goto fail; + } + + if (save_calibs(output_file)) + goto fail; + fflush(output_file); + + if (argc == 2) + if (fclose(output_file)) + goto fail; + +done: + if (!in_fork) { + release_video(); + if (tty_configured) + tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty); + printf("\033[?25h"); + fflush(stdout); + } + return rc; +fail: + perror(*argv); + rc = 1; + goto done; +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..2daa994 --- /dev/null +++ b/common.h @@ -0,0 +1,393 @@ +/* See LICENSE file for copyright and license details. */ +#include <sys/ioctl.h> +#include <linux/fb.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> +#include <math.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include <xf86drm.h> +#include <xf86drmMode.h> + + +/** + * Framebuffer information + */ +typedef struct framebuffer +{ + /** + * The file descriptor used to access the framebuffer, -1 if not opened + */ + int fd; + + /** + * The width of the display in pixels + */ + uint32_t width; + + /** + * The height of the display in pixels + */ + uint32_t height; + + /** + * Increment for `mem` to move to next pixel on the line + */ + uint32_t bytes_per_pixel; + + /** + * Increment for `mem` to move down one line but stay in the same column + */ + uint32_t line_length; + + /** + * Framebuffer pointer, `MAP_FAILED` (from <sys/mman.h>) if not mapped + */ + int8_t *mem; + +} framebuffer_t; + + +/** + * Graphics card information + */ +typedef struct drm_card +{ + /** + * File descriptor for the connection to the graphics card, + * -1 if not opened + */ + int fd; + + /** + * The graphics card's mode resources, `NULL` if not acquired + */ + drmModeRes *restrict res; + + /** + * The number of CRTC:s available on the graphics card + */ + size_t crtc_count; + + /** + * The available connectors + */ + drmModeConnector **restrict connectors; + + /** + * The available encoders + */ + drmModeEncoder **restrict encoders; + + /** + * The number of connectors and encoders + */ + size_t connector_count; + +} drm_card_t; + + +/** + * CRT controller information + */ +typedef struct drm_crtc +{ + /** + * CRT controller identifier + */ + uint32_t id; + + /** + * The graphics card + */ + drm_card_t *restrict card; + + /** + * The CRT controller's connector + */ + drmModeConnector *restrict connector; + + /** + * The CRT controller's encoder + */ + drmModeEncoder *restrict encoder; + + /** + * Whether the connector is connected + */ + int connected; + + /** + * The CRT's EDID, hexadecimally encoded + */ + char *restrict edid; + + /** + * The number of stops on the gamma ramps + */ + size_t gamma_stops; + + /** + * The gamma ramp for the red channel + */ + uint16_t *restrict red; + + /** + * The gamma ramp for the green channel + */ + uint16_t *restrict green; + + /** + * The gamma ramp for the blue channel + */ + uint16_t *restrict blue; + +} drm_crtc_t; + + + +/***** gamma.c *****/ + +/** + * Analyse a gamma ramp + * + * @param stops The number of stops in the gamma ramp + * @param ramp The gamma ramp + * @param gamma Output parameter for the gamma + * @param contrast Output parameter for the contrast + * @param brightness Output parameter for the brightness + */ +void gamma_analyse(size_t stops, const uint16_t* restrict ramp, double *restrict gamma, + double *restrict contrast, double* restrict brightness); + +/** + * Generate a gamma ramp + * + * @param stops The number of stops in the gamma ramp + * @param ramp Memory area to where to write the gamma ramp + * @param gamma The gamma + * @param contrast The contrast + * @param brightness The brightness + */ +void gamma_generate(size_t stops, uint16_t *restrict ramp, double gamma, double contrast, double brightness); + + + +/***** framebuffer.c *****/ + +/** + * Figure out how many framebuffers there are on the system + * + * @return The number of framebuffers on the system + */ +size_t fb_count(void); + +/** + * Open a framebuffer + * + * @param index The index of the framebuffer to open + * @param fb Framebuffer information to fill in + * @return Zero on success, -1 on error + */ +int fb_open(size_t index, framebuffer_t *restrict fb); + +/** + * Close a framebuffer + * + * @param fb The framebuffer information + */ +void fb_close(framebuffer_t *restrict fb); + +/** + * Construct an sRGB colour in 32-bit XRGB encoding to + * use when specifying colours + * + * @param red The red component from [0, 255] sRGB + * @param green The green component from [0, 255] sRGB + * @param blue The blue component from [0, 255] sRGB + * @return The colour as one 32-bit integer + */ +#ifdef __GNUC__ +__attribute__((__const__)) +#endif +uint32_t fb_colour(int red, int green, int blue); + +/** + * Print a filled in rectangle to a framebuffer + * + * @param fb The framebuffer + * @param colour The colour to use when drawing the rectangle + * @param x The starting pixel on the X axis for the rectangle + * @param y The starting pixel on the Y axis for the rectangle + * @param width The width of the rectangle, in pixels + * @param height The height of the rectangle, in pixels + */ +void fb_fill_rectangle(framebuffer_t *restrict fb, uint32_t colour, uint32_t x, uint32_t y, uint32_t width, uint32_t height); + +/** + * Draw a horizontal line segment on a framebuffer + * + * @param fb The framebuffer + * @param colour The colour to use when drawing the rectangle + * @param x The starting pixel on the X axis for the line segment + * @param y The starting pixel on the Y axis for the line segment + * @param length The length of the line segment, in pixels + */ +void fb_draw_horizontal_line(framebuffer_t *restrict fb, uint32_t colour, uint32_t x, uint32_t y, uint32_t length); + +/** + * Draw a vertical line segment on a framebuffer + * + * @param fb The framebuffer + * @param colour The colour to use when drawing the rectangle + * @param x The starting pixel on the X axis for the line segment + * @param y The starting pixel on the Y axis for the line segment + * @param length The length of the line segment, in pixels + */ +void fb_draw_vertical_line(framebuffer_t *restrict fb, uint32_t colour, uint32_t x, uint32_t y, uint32_t length); + +/** + * Draw a single on a framebuffer + * + * @param fb The framebuffer + * @param colour The colour to use when drawing the rectangle + * @param x The pixel's position on the X axis + * @param y The pixel's position on the Y axis + */ +static inline void +fb_draw_pixel(framebuffer_t *restrict fb, uint32_t colour, uint32_t x, uint32_t y) +{ + int8_t *mem = fb->mem + y * fb->line_length + x * fb->bytes_per_pixel; + *(uint32_t *)mem = colour; +} + + + +/***** state.c ******/ + +/** + * The framebuffers on the system + */ +extern framebuffer_t *restrict framebuffers; + +/** + * The number of elements in `framebuffers` + */ +extern size_t framebuffer_count; + +/** + * The graphics cards on the system + */ +extern drm_card_t *restrict cards; + +/** + * The number of elements in `cards` + */ +extern size_t card_count; + +/** + * The connected CRT controllers on the system + */ +extern drm_crtc_t *restrict crtcs; + +/** + * The software brightness setting on each connected CRT controller, on each channel + */ +extern double *restrict brightnesses[3]; + +/** + * The software contrast setting on each connected CRT controller, on each channel + */ +extern double *restrict contrasts[3]; + +/** + * The gamma correction on each connected CRT controller, on each channel + */ +extern double *restrict gammas[3]; + +/** + * The number of elements in `crtcs`, `brightnesses[]`, `contrasts[]` and `gammas[]` + */ +extern size_t crtc_count; + +/** + * Acquire video control + * + * @return Zero on success, -1 on error + */ +int acquire_video(void); + +/** + * Release video control + */ +void release_video(void); + + + +/***** drmgamma.c ******/ + +/** + * Figure out how many graphics cards there are on the system + * + * @return The number of graphics cards on the system + */ +size_t drm_card_count(void); + +/** + * Acquire access to a graphics card + * + * @param index The index of the graphics card + * @param card Graphics card information to fill in + * @return Zero on success, -1 on error + */ +int drm_card_open(size_t index, drm_card_t *restrict card); + +/** + * Release access to a graphics card + * + * @param card The graphics card information + */ +void drm_card_close(drm_card_t *restrict card); + +/** + * Acquire access to a CRT controller + * + * @param index The index of the CRT controller + * @param card The graphics card information + * @param crtc CRT controller information to fill in + * @return Zero on success, -1 on error + */ +int drm_crtc_open(size_t index, drm_card_t *restrict card, drm_crtc_t *restrict crtc); + +/** + * Release access to a CRT controller + * + * @param crtc The CRT controller information to fill in + */ +void drm_crtc_close(drm_crtc_t *restrict crtc); + +/** + * Read the gamma ramps for a CRT controller + * + * @param crtc CRT controller information + * @return Zero on success, -1 on error + */ +int drm_get_gamma(drm_crtc_t *restrict crtc); + +/** + * Apply gamma ramps for a CRT controller + * + * @param crtc CRT controller information + * @return Zero on success, -1 on error + */ +int drm_set_gamma(drm_crtc_t *restrict crtc); diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..1288e57 --- /dev/null +++ b/config.mk @@ -0,0 +1,6 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 +CFLAGS = -std=c99 -Wall $$(pkg-config --cflags libdrm) +LDFLAGS = -lm $$(pkg-config --libs libdrm) diff --git a/doc/man/crt-calibrator.1 b/crt-calibrator.1 index f2d3ba2..f2d3ba2 100644 --- a/doc/man/crt-calibrator.1 +++ b/crt-calibrator.1 diff --git a/dist/archlinux/stable/.gitignore b/dist/archlinux/stable/.gitignore deleted file mode 100644 index b070320..0000000 --- a/dist/archlinux/stable/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -* -!/.git* -!/PKGBUILD -!/crt-calibrator.install -*~ -*.swo -*.swp -*.bak - diff --git a/dist/archlinux/stable/PKGBUILD b/dist/archlinux/stable/PKGBUILD deleted file mode 100644 index da46d3d..0000000 --- a/dist/archlinux/stable/PKGBUILD +++ /dev/null @@ -1,25 +0,0 @@ -# Maintainer: Mattias Andrée <`base64 -d`(bWFhbmRyZWUK)@member.fsf.org> - -pkgname=crt-calibrator -pkgver=1.3.1 -pkgrel=1 -pkgdesc="CRT monitor calibrator utility for Linux VT" -url="https://github.com/maandree/crt-calibrator" -arch=(i686 x86_64) -license=(GPL3) -depends=(glibc libdrm linux) -makedepends=(make coreutils gcc glibc libdrm linux texinfo) -install=crt-calibrator.install -source=("${url}/archive/${pkgver}.tar.gz") -sha256sums=(23ec9913dcfb2e4a0a7879a1665a1026648367a88411e7c50621e06d0ce781e5) - -build() { - cd "${srcdir}/crt-calibrator-${pkgver}" - make DESTDIR="${pkgdir}" -} - -package() { - cd "${srcdir}/crt-calibrator-${pkgver}" - make DESTDIR="${pkgdir}" install -} - diff --git a/dist/archlinux/stable/crt-calibrator.install b/dist/archlinux/stable/crt-calibrator.install deleted file mode 100644 index 00682af..0000000 --- a/dist/archlinux/stable/crt-calibrator.install +++ /dev/null @@ -1,20 +0,0 @@ -_file="crt-calibrator" - -infodir="usr/share/info" -file="${_file}.info" - - -post_install() { - [[ -x "usr/bin/install-info" ]] || return 0 - install-info -- "${infodir}/${file}" "${infodir}/dir" 2> /dev/null -} - -post_upgrade() { - post_install "$1" -} - -pre_remove() { - [[ -x "usr/bin/install-info" ]] || return 0 - install-info --delete -- "${infodir}/${file}" "${infodir}/dir" 2> /dev/null -} - diff --git a/doc/info/crt-calibrator.texinfo b/doc/info/crt-calibrator.texinfo deleted file mode 100644 index 602191f..0000000 --- a/doc/info/crt-calibrator.texinfo +++ /dev/null @@ -1,90 +0,0 @@ -\input texinfo @c -*-texinfo-*- - -@c %**start of header -@setfilename crt-calibrator.info -@settitle crt-calibrator -@afourpaper -@documentencoding UTF-8 -@documentlanguage en -@finalout -@c %**end of header - - -@dircategory Miscellaneous -@direntry -* crt-calibrator: (crt-calibrator). CRT monitor calibrator utility for Linux VT -@end direntry - - -@copying -Copyright @copyright{} 2015 Mattias Andrée - -@quotation -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.3 or -any later version published by the Free Software Foundation; with no -Invariant Sections, with no Front-Cover Texts, and with no Back-Cover -Texts. A copy of the license is included in the section entitled -``GNU Free Documentation License''. -@end quotation -@end copying - -@ifnottex -@node Top -@top crt-calibrator -- CRT monitor calibrator utility for Linux VT -@insertcopying -@end ifnottex - -@titlepage -@title crt-calibrator -@subtitle Passphrase strength evaluator -@author by Mattias Andrée (maandree) - -@page -@vskip 0pt plus 1filll -@insertcopying -@page -@end titlepage - -@contents - - - -@menu -* Overview:: Brief overview of @command{crt-calibrator}. -* Invoking:: Executing @command{crt-calibrator}. -* GNU Free Documentation License:: Copying and sharing this manual. -@end menu - - - -@node Overview -@chapter Overview - -@command{crt-calibrator} is an interactive tool that guides -you through calibrating your CRT monitors. - -The program cannot be run from inside X, it is required that -it is run from the Linux VT, otherwise known as the TTY. - - - -@node Invoking -@chapter Invoking - -@command{crt-calibrator} takes atmost one argument, -which must not start with a dash. - -When done, the program will print gamma-ramp information -that is useful when setting the calibrations automatically. -If a file has been specified via the command line, this -information is stored to that that file. - - - -@node GNU Free Documentation License -@appendix GNU Free Documentation License -@include fdl.texinfo - -@bye - diff --git a/doc/info/fdl.texinfo b/doc/info/fdl.texinfo deleted file mode 100644 index cb71f05..0000000 --- a/doc/info/fdl.texinfo +++ /dev/null @@ -1,505 +0,0 @@ -@c The GNU Free Documentation License. -@center Version 1.3, 3 November 2008 - -@c This file is intended to be included within another document, -@c hence no sectioning command or @node. - -@display -Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. -@uref{http://fsf.org/} - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. -@end display - -@enumerate 0 -@item -PREAMBLE - -The purpose of this License is to make a manual, textbook, or other -functional and useful document @dfn{free} in the sense of freedom: to -assure everyone the effective freedom to copy and redistribute it, -with or without modifying it, either commercially or noncommercially. -Secondarily, this License preserves for the author and publisher a way -to get credit for their work, while not being considered responsible -for modifications made by others. - -This License is a kind of ``copyleft'', which means that derivative -works of the document must themselves be free in the same sense. It -complements the GNU General Public License, which is a copyleft -license designed for free software. - -We have designed this License in order to use it for manuals for free -software, because free software needs free documentation: a free -program should come with manuals providing the same freedoms that the -software does. But this License is not limited to software manuals; -it can be used for any textual work, regardless of subject matter or -whether it is published as a printed book. We recommend this License -principally for works whose purpose is instruction or reference. - -@item -APPLICABILITY AND DEFINITIONS - -This License applies to any manual or other work, in any medium, that -contains a notice placed by the copyright holder saying it can be -distributed under the terms of this License. Such a notice grants a -world-wide, royalty-free license, unlimited in duration, to use that -work under the conditions stated herein. The ``Document'', below, -refers to any such manual or work. Any member of the public is a -licensee, and is addressed as ``you''. You accept the license if you -copy, modify or distribute the work in a way requiring permission -under copyright law. - -A ``Modified Version'' of the Document means any work containing the -Document or a portion of it, either copied verbatim, or with -modifications and/or translated into another language. - -A ``Secondary Section'' is a named appendix or a front-matter section -of the Document that deals exclusively with the relationship of the -publishers or authors of the Document to the Document's overall -subject (or to related matters) and contains nothing that could fall -directly within that overall subject. (Thus, if the Document is in -part a textbook of mathematics, a Secondary Section may not explain -any mathematics.) The relationship could be a matter of historical -connection with the subject or with related matters, or of legal, -commercial, philosophical, ethical or political position regarding -them. - -The ``Invariant Sections'' are certain Secondary Sections whose titles -are designated, as being those of Invariant Sections, in the notice -that says that the Document is released under this License. If a -section does not fit the above definition of Secondary then it is not -allowed to be designated as Invariant. The Document may contain zero -Invariant Sections. If the Document does not identify any Invariant -Sections then there are none. - -The ``Cover Texts'' are certain short passages of text that are listed, -as Front-Cover Texts or Back-Cover Texts, in the notice that says that -the Document is released under this License. A Front-Cover Text may -be at most 5 words, and a Back-Cover Text may be at most 25 words. - -A ``Transparent'' copy of the Document means a machine-readable copy, -represented in a format whose specification is available to the -general public, that is suitable for revising the document -straightforwardly with generic text editors or (for images composed of -pixels) generic paint programs or (for drawings) some widely available -drawing editor, and that is suitable for input to text formatters or -for automatic translation to a variety of formats suitable for input -to text formatters. A copy made in an otherwise Transparent file -format whose markup, or absence of markup, has been arranged to thwart -or discourage subsequent modification by readers is not Transparent. -An image format is not Transparent if used for any substantial amount -of text. A copy that is not ``Transparent'' is called ``Opaque''. - -Examples of suitable formats for Transparent copies include plain -ASCII without markup, Texinfo input format, La@TeX{} input -format, SGML or XML using a publicly available -DTD, and standard-conforming simple HTML, -PostScript or PDF designed for human modification. Examples -of transparent image formats include PNG, XCF and -JPG. Opaque formats include proprietary formats that can be -read and edited only by proprietary word processors, SGML or -XML for which the DTD and/or processing tools are -not generally available, and the machine-generated HTML, -PostScript or PDF produced by some word processors for -output purposes only. - -The ``Title Page'' means, for a printed book, the title page itself, -plus such following pages as are needed to hold, legibly, the material -this License requires to appear in the title page. For works in -formats which do not have any title page as such, ``Title Page'' means -the text near the most prominent appearance of the work's title, -preceding the beginning of the body of the text. - -The ``publisher'' means any person or entity that distributes copies -of the Document to the public. - -A section ``Entitled XYZ'' means a named subunit of the Document whose -title either is precisely XYZ or contains XYZ in parentheses following -text that translates XYZ in another language. (Here XYZ stands for a -specific section name mentioned below, such as ``Acknowledgements'', -``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' -of such a section when you modify the Document means that it remains a -section ``Entitled XYZ'' according to this definition. - -The Document may include Warranty Disclaimers next to the notice which -states that this License applies to the Document. These Warranty -Disclaimers are considered to be included by reference in this -License, but only as regards disclaiming warranties: any other -implication that these Warranty Disclaimers may have is void and has -no effect on the meaning of this License. - -@item -VERBATIM COPYING - -You may copy and distribute the Document in any medium, either -commercially or noncommercially, provided that this License, the -copyright notices, and the license notice saying this License applies -to the Document are reproduced in all copies, and that you add no other -conditions whatsoever to those of this License. You may not use -technical measures to obstruct or control the reading or further -copying of the copies you make or distribute. However, you may accept -compensation in exchange for copies. If you distribute a large enough -number of copies you must also follow the conditions in section 3. - -You may also lend copies, under the same conditions stated above, and -you may publicly display copies. - -@item -COPYING IN QUANTITY - -If you publish printed copies (or copies in media that commonly have -printed covers) of the Document, numbering more than 100, and the -Document's license notice requires Cover Texts, you must enclose the -copies in covers that carry, clearly and legibly, all these Cover -Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on -the back cover. Both covers must also clearly and legibly identify -you as the publisher of these copies. The front cover must present -the full title with all words of the title equally prominent and -visible. You may add other material on the covers in addition. -Copying with changes limited to the covers, as long as they preserve -the title of the Document and satisfy these conditions, can be treated -as verbatim copying in other respects. - -If the required texts for either cover are too voluminous to fit -legibly, you should put the first ones listed (as many as fit -reasonably) on the actual cover, and continue the rest onto adjacent -pages. - -If you publish or distribute Opaque copies of the Document numbering -more than 100, you must either include a machine-readable Transparent -copy along with each Opaque copy, or state in or with each Opaque copy -a computer-network location from which the general network-using -public has access to download using public-standard network protocols -a complete Transparent copy of the Document, free of added material. -If you use the latter option, you must take reasonably prudent steps, -when you begin distribution of Opaque copies in quantity, to ensure -that this Transparent copy will remain thus accessible at the stated -location until at least one year after the last time you distribute an -Opaque copy (directly or through your agents or retailers) of that -edition to the public. - -It is requested, but not required, that you contact the authors of the -Document well before redistributing any large number of copies, to give -them a chance to provide you with an updated version of the Document. - -@item -MODIFICATIONS - -You may copy and distribute a Modified Version of the Document under -the conditions of sections 2 and 3 above, provided that you release -the Modified Version under precisely this License, with the Modified -Version filling the role of the Document, thus licensing distribution -and modification of the Modified Version to whoever possesses a copy -of it. In addition, you must do these things in the Modified Version: - -@enumerate A -@item -Use in the Title Page (and on the covers, if any) a title distinct -from that of the Document, and from those of previous versions -(which should, if there were any, be listed in the History section -of the Document). You may use the same title as a previous version -if the original publisher of that version gives permission. - -@item -List on the Title Page, as authors, one or more persons or entities -responsible for authorship of the modifications in the Modified -Version, together with at least five of the principal authors of the -Document (all of its principal authors, if it has fewer than five), -unless they release you from this requirement. - -@item -State on the Title page the name of the publisher of the -Modified Version, as the publisher. - -@item -Preserve all the copyright notices of the Document. - -@item -Add an appropriate copyright notice for your modifications -adjacent to the other copyright notices. - -@item -Include, immediately after the copyright notices, a license notice -giving the public permission to use the Modified Version under the -terms of this License, in the form shown in the Addendum below. - -@item -Preserve in that license notice the full lists of Invariant Sections -and required Cover Texts given in the Document's license notice. - -@item -Include an unaltered copy of this License. - -@item -Preserve the section Entitled ``History'', Preserve its Title, and add -to it an item stating at least the title, year, new authors, and -publisher of the Modified Version as given on the Title Page. If -there is no section Entitled ``History'' in the Document, create one -stating the title, year, authors, and publisher of the Document as -given on its Title Page, then add an item describing the Modified -Version as stated in the previous sentence. - -@item -Preserve the network location, if any, given in the Document for -public access to a Transparent copy of the Document, and likewise -the network locations given in the Document for previous versions -it was based on. These may be placed in the ``History'' section. -You may omit a network location for a work that was published at -least four years before the Document itself, or if the original -publisher of the version it refers to gives permission. - -@item -For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve -the Title of the section, and preserve in the section all the -substance and tone of each of the contributor acknowledgements and/or -dedications given therein. - -@item -Preserve all the Invariant Sections of the Document, -unaltered in their text and in their titles. Section numbers -or the equivalent are not considered part of the section titles. - -@item -Delete any section Entitled ``Endorsements''. Such a section -may not be included in the Modified Version. - -@item -Do not retitle any existing section to be Entitled ``Endorsements'' or -to conflict in title with any Invariant Section. - -@item -Preserve any Warranty Disclaimers. -@end enumerate - -If the Modified Version includes new front-matter sections or -appendices that qualify as Secondary Sections and contain no material -copied from the Document, you may at your option designate some or all -of these sections as invariant. To do this, add their titles to the -list of Invariant Sections in the Modified Version's license notice. -These titles must be distinct from any other section titles. - -You may add a section Entitled ``Endorsements'', provided it contains -nothing but endorsements of your Modified Version by various -parties---for example, statements of peer review or that the text has -been approved by an organization as the authoritative definition of a -standard. - -You may add a passage of up to five words as a Front-Cover Text, and a -passage of up to 25 words as a Back-Cover Text, to the end of the list -of Cover Texts in the Modified Version. Only one passage of -Front-Cover Text and one of Back-Cover Text may be added by (or -through arrangements made by) any one entity. If the Document already -includes a cover text for the same cover, previously added by you or -by arrangement made by the same entity you are acting on behalf of, -you may not add another; but you may replace the old one, on explicit -permission from the previous publisher that added the old one. - -The author(s) and publisher(s) of the Document do not by this License -give permission to use their names for publicity for or to assert or -imply endorsement of any Modified Version. - -@item -COMBINING DOCUMENTS - -You may combine the Document with other documents released under this -License, under the terms defined in section 4 above for modified -versions, provided that you include in the combination all of the -Invariant Sections of all of the original documents, unmodified, and -list them all as Invariant Sections of your combined work in its -license notice, and that you preserve all their Warranty Disclaimers. - -The combined work need only contain one copy of this License, and -multiple identical Invariant Sections may be replaced with a single -copy. If there are multiple Invariant Sections with the same name but -different contents, make the title of each such section unique by -adding at the end of it, in parentheses, the name of the original -author or publisher of that section if known, or else a unique number. -Make the same adjustment to the section titles in the list of -Invariant Sections in the license notice of the combined work. - -In the combination, you must combine any sections Entitled ``History'' -in the various original documents, forming one section Entitled -``History''; likewise combine any sections Entitled ``Acknowledgements'', -and any sections Entitled ``Dedications''. You must delete all -sections Entitled ``Endorsements.'' - -@item -COLLECTIONS OF DOCUMENTS - -You may make a collection consisting of the Document and other documents -released under this License, and replace the individual copies of this -License in the various documents with a single copy that is included in -the collection, provided that you follow the rules of this License for -verbatim copying of each of the documents in all other respects. - -You may extract a single document from such a collection, and distribute -it individually under this License, provided you insert a copy of this -License into the extracted document, and follow this License in all -other respects regarding verbatim copying of that document. - -@item -AGGREGATION WITH INDEPENDENT WORKS - -A compilation of the Document or its derivatives with other separate -and independent documents or works, in or on a volume of a storage or -distribution medium, is called an ``aggregate'' if the copyright -resulting from the compilation is not used to limit the legal rights -of the compilation's users beyond what the individual works permit. -When the Document is included in an aggregate, this License does not -apply to the other works in the aggregate which are not themselves -derivative works of the Document. - -If the Cover Text requirement of section 3 is applicable to these -copies of the Document, then if the Document is less than one half of -the entire aggregate, the Document's Cover Texts may be placed on -covers that bracket the Document within the aggregate, or the -electronic equivalent of covers if the Document is in electronic form. -Otherwise they must appear on printed covers that bracket the whole -aggregate. - -@item -TRANSLATION - -Translation is considered a kind of modification, so you may -distribute translations of the Document under the terms of section 4. -Replacing Invariant Sections with translations requires special -permission from their copyright holders, but you may include -translations of some or all Invariant Sections in addition to the -original versions of these Invariant Sections. You may include a -translation of this License, and all the license notices in the -Document, and any Warranty Disclaimers, provided that you also include -the original English version of this License and the original versions -of those notices and disclaimers. In case of a disagreement between -the translation and the original version of this License or a notice -or disclaimer, the original version will prevail. - -If a section in the Document is Entitled ``Acknowledgements'', -``Dedications'', or ``History'', the requirement (section 4) to Preserve -its Title (section 1) will typically require changing the actual -title. - -@item -TERMINATION - -You may not copy, modify, sublicense, or distribute the Document -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense, or distribute it is void, and -will automatically terminate your rights under this License. - -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, receipt of a copy of some or all of the same material does -not give you any rights to use it. - -@item -FUTURE REVISIONS OF THIS LICENSE - -The Free Software Foundation may publish new, revised versions -of the GNU Free Documentation 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. See -@uref{http://www.gnu.org/copyleft/}. - -Each version of the License is given a distinguishing version number. -If the Document specifies that a particular numbered version of this -License ``or any later version'' applies to it, you have the option of -following the terms and conditions either of that specified version or -of any later version that has been published (not as a draft) by the -Free Software Foundation. If the Document does not specify a version -number of this License, you may choose any version ever published (not -as a draft) by the Free Software Foundation. If the Document -specifies that a proxy can decide which future versions of this -License can be used, that proxy's public statement of acceptance of a -version permanently authorizes you to choose that version for the -Document. - -@item -RELICENSING - -``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any -World Wide Web server that publishes copyrightable works and also -provides prominent facilities for anybody to edit those works. A -public wiki that anybody can edit is an example of such a server. A -``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the -site means any set of copyrightable works thus published on the MMC -site. - -``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0 -license published by Creative Commons Corporation, a not-for-profit -corporation with a principal place of business in San Francisco, -California, as well as future copyleft versions of that license -published by that same organization. - -``Incorporate'' means to publish or republish a Document, in whole or -in part, as part of another Document. - -An MMC is ``eligible for relicensing'' if it is licensed under this -License, and if all works that were first published under this License -somewhere other than this MMC, and subsequently incorporated in whole -or in part into the MMC, (1) had no cover texts or invariant sections, -and (2) were thus incorporated prior to November 1, 2008. - -The operator of an MMC Site may republish an MMC contained in the site -under CC-BY-SA on the same site at any time before August 1, 2009, -provided the MMC is eligible for relicensing. - -@end enumerate - -@page -@heading ADDENDUM: How to use this License for your documents - -To use this License in a document you have written, include a copy of -the License in the document and put the following copyright and -license notices just after the title page: - -@smallexample -@group - Copyright (C) @var{year} @var{your name}. - Permission is granted to copy, distribute and/or modify this document - under the terms of the GNU Free Documentation License, Version 1.3 - or any later version published by the Free Software Foundation; - with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - Texts. A copy of the license is included in the section entitled ``GNU - Free Documentation License''. -@end group -@end smallexample - -If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, -replace the ``with@dots{}Texts.''@: line with this: - -@smallexample -@group - with the Invariant Sections being @var{list their titles}, with - the Front-Cover Texts being @var{list}, and with the Back-Cover Texts - being @var{list}. -@end group -@end smallexample - -If you have Invariant Sections without Cover Texts, or some other -combination of the three, merge those two alternatives to suit the -situation. - -If your document contains nontrivial examples of program code, we -recommend releasing these examples in parallel under your choice of -free software license, such as the GNU General Public License, -to permit their use in free software. - -@c Local Variables: -@c ispell-local-pdict: "ispell-dict" -@c End: diff --git a/drmgamma.c b/drmgamma.c new file mode 100644 index 0000000..43adb2e --- /dev/null +++ b/drmgamma.c @@ -0,0 +1,262 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * The number of elements to allocates to a buffer for a DRM device pathname + */ +#define DRM_DEV_NAME_MAX_LEN\ + ((sizeof(DRM_DEV_NAME) + sizeof(DRM_DIR_NAME)) / sizeof(char) + 3 * sizeof(int)) + + + +/** + * Figure out how many graphics cards there are on the system + * + * @return The number of graphics cards on the system + */ +size_t +drm_card_count(void) +{ + char buf[DRM_DEV_NAME_MAX_LEN]; + size_t count = 0; + for (;; count++) { + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, (int)count); + if (access(buf, F_OK) < 0) + return count; + } +} + +/** + * Acquire access to a graphics card + * + * @param index The index of the graphics card + * @param card Graphics card information to fill in + * @return Zero on success, -1 on error + */ +int +drm_card_open(size_t index, drm_card_t *restrict card) +{ + char buf[DRM_DEV_NAME_MAX_LEN]; + int old_errno; + size_t i, n; + + card->fd = -1; + card->res = NULL; + card->connectors = NULL; + card->encoders = NULL; + card->connector_count = 0; + + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, (int)index); + card->fd = open(buf, O_RDWR); + if (card->fd < 0) + goto fail; + + card->res = drmModeGetResources(card->fd); + if (!card->res) + goto fail; + + card->crtc_count = (size_t)(card->res->count_crtcs); + card->connector_count = (size_t)(card->res->count_connectors); + n = card->connector_count; + + card->connectors = calloc(n, sizeof(drmModeConnector*)); + if (!card->connectors) + goto fail; + card->encoders = calloc(n, sizeof(drmModeEncoder*)); + if (!card->encoders) + goto fail; + + for (i = 0; i < n; i++) { + card->connectors[i] = drmModeGetConnector(card->fd, card->res->connectors[i]); + if (!card->connectors[i]) + goto fail; + + if (card->connectors[i]->encoder_id) { + card->encoders[i] = drmModeGetEncoder(card->fd, card->connectors[i]->encoder_id); + if (!card->encoders[i]) + goto fail; + } + } + + return 0; +fail: + old_errno = errno; + drm_card_close(card); + errno = old_errno; + return -1; +} + + +/** + * Release access to a graphics card + * + * @param card The graphics card information + */ +void +drm_card_close(drm_card_t *restrict card) +{ + size_t i, n = card->connector_count; + + if (card->encoders) { + for (i = 0; i < n; i++) + if (card->encoders[i]) + drmModeFreeEncoder(card->encoders[i]); + free(card->encoders); + card->encoders = NULL; + } + + if (card->connectors) { + for (i = 0; i < n; i++) + if (card->connectors[i]) + drmModeFreeConnector(card->connectors[i]); + free(card->connectors); + card->connectors = NULL; + } + + if (card->res) { + drmModeFreeResources(card->res); + card->res = NULL; + } + if (card->fd >= 0) { + close(card->fd); + card->fd = -1; + } +} + + +/** + * Acquire access to a CRT controller + * + * @param index The index of the CRT controller + * @param card The graphics card information + * @param crtc CRT controller information to fill in + * @return Zero on success, -1 on error + */ +int +drm_crtc_open(size_t index, drm_card_t *restrict card, drm_crtc_t *restrict crtc) +{ + drmModePropertyRes *restrict prop; + drmModePropertyBlobRes *restrict blob; + drmModeCrtc *restrict info; + size_t i, j; + int old_errno; + unsigned char c; + + crtc->edid = NULL; + crtc->red = NULL; + crtc->green = NULL; + crtc->blue = NULL; + + crtc->id = card->res->crtcs[index]; + crtc->card = card; + + crtc->connector = NULL; + crtc->encoder = NULL; + for (i = 0; i < card->connector_count; i++) { + if (card->encoders[i]) { + if (card->encoders[i]->crtc_id == crtc->id) { + crtc->connector = card->connectors[i]; + crtc->encoder = card->encoders[i]; + } + } + } + + crtc->connected = crtc->connector && crtc->connector->connection == DRM_MODE_CONNECTED; + + info = drmModeGetCrtc(card->fd, crtc->id); + if (!info) + return -1; + crtc->gamma_stops = (size_t)info->gamma_size; + drmModeFreeCrtc(info); + + /* `calloc` is for some reason required when reading the gamma ramps. */ + crtc->red = calloc(3 * crtc->gamma_stops, sizeof(uint16_t)); + if (!crtc->red) + return -1; + crtc->green = crtc->red + crtc->gamma_stops; + crtc->blue = crtc->green + crtc->gamma_stops; + + if (!crtc->connector) + return 0; + for (i = 0; i < (size_t)crtc->connector->count_props; i++) { + prop = drmModeGetProperty(card->fd, crtc->connector->props[i]); + if (!prop) + continue; + + if (strcmp(prop->name, "EDID")) + goto free_prop; + + blob = drmModeGetPropertyBlob(card->fd, (uint32_t)crtc->connector->prop_values[i]); + i = (size_t)crtc->connector->count_props; + if (!blob || !blob->data) + goto free_blob; + + crtc->edid = malloc((blob->length * 2 + 1) * sizeof(char)); + if (!crtc->edid) { + old_errno = errno; + drmModeFreePropertyBlob(blob); + drmModeFreeProperty(prop); + free(crtc->red); + crtc->red = NULL; + errno = old_errno; + return -1; + } + for (j = 0; j < blob->length; j++) { + c = ((unsigned char *)blob->data)[j]; + crtc->edid[j * 2 + 0] = "0123456789ABCDEF"[(c >> 4) & 15]; + crtc->edid[j * 2 + 1] = "0123456789ABCDEF"[(c >> 0) & 15]; + } + crtc->edid[blob->length * 2] = '\0'; + + free_blob: + if (blob) + drmModeFreePropertyBlob(blob); + + free_prop: + drmModeFreeProperty(prop); + } + + return 0; +} + + +/** + * Release access to a CRT controller + * + * @param crtc The CRT controller information to fill in + */ +void +drm_crtc_close(drm_crtc_t *restrict crtc) +{ + free(crtc->edid); + free(crtc->red); + crtc->edid = NULL; + crtc->red = NULL; +} + + +/** + * Read the gamma ramps for a CRT controller + * + * @param crtc CRT controller information + * @return Zero on success, -1 on error + */ +int +drm_get_gamma(drm_crtc_t *restrict crtc) +{ + return -!!drmModeCrtcGetGamma(crtc->card->fd, crtc->id, (uint32_t)crtc->gamma_stops, crtc->red, crtc->green, crtc->blue); +} + + +/** + * Apply gamma ramps for a CRT controller + * + * @param crtc CRT controller information + * @return Zero on success, -1 on error + */ +int +drm_set_gamma(drm_crtc_t *restrict crtc) +{ + return -!!drmModeCrtcSetGamma(crtc->card->fd, crtc->id, (uint32_t)crtc->gamma_stops, crtc->red, crtc->green, crtc->blue); +} diff --git a/framebuffer.c b/framebuffer.c new file mode 100644 index 0000000..29459ac --- /dev/null +++ b/framebuffer.c @@ -0,0 +1,183 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * The psuedodevice pathname pattern used to access a framebuffer + */ +#ifndef FB_DEVICE_PATTERN +# define FB_DEVICE_PATTERN "/dev/fb%lu" +#endif + + +/** + * The number of elements to allocates to a buffer for a framebuffer device pathname + */ +#define FB_DEVICE_MAX_LEN (sizeof(FB_DEVICE_PATTERN) / sizeof(char) + 3 * sizeof(size_t)) + + + +/** + * Figure out how many framebuffers there are on the system + * + * @return The number of framebuffers on the system + */ +size_t +fb_count(void) +{ + char buf[FB_DEVICE_MAX_LEN]; + size_t count = 0; + + for (;; count++) { + sprintf(buf, FB_DEVICE_PATTERN, count); + if (access(buf, F_OK) < 0) + return count; + } +} + + +/** + * Open a framebuffer + * + * @param index The index of the framebuffer to open + * @param fb Framebuffer information to fill in + * @return Zero on success, -1 on error + */ +int +fb_open(size_t index, framebuffer_t *restrict fb) +{ + char buf[FB_DEVICE_MAX_LEN]; + struct fb_fix_screeninfo fix_info; + struct fb_var_screeninfo var_info; + int old_errno; + + fb->fd = -1; + fb->mem = MAP_FAILED; + + sprintf(buf, FB_DEVICE_PATTERN, index); + fb->fd = open(buf, O_RDWR); + if (fb->fd < 0) + goto fail; + + if (ioctl(fb->fd, (unsigned long int)FBIOGET_FSCREENINFO, &fix_info) || + ioctl(fb->fd, (unsigned long int)FBIOGET_VSCREENINFO, &var_info)) + goto fail; + + fb->mem = mmap(NULL, (size_t)(fix_info.smem_len), PROT_WRITE, MAP_SHARED, fb->fd, (off_t)0); + if (fb->mem == MAP_FAILED) + goto fail; + + fb->mem += var_info.xoffset * (var_info.bits_per_pixel / 8); + fb->mem += var_info.yoffset * fix_info.line_length; + + fb->width = var_info.xres; + fb->height = var_info.yres; + fb->bytes_per_pixel = var_info.bits_per_pixel / 8; + fb->line_length = fix_info.line_length; + + return 0; +fail: + old_errno = errno; + fb_close(fb); + errno = old_errno; + return -1; +} + + +/** + * Close a framebuffer + * + * @param fb The framebuffer information + */ +void +fb_close(framebuffer_t *restrict fb) +{ + if (fb->fd >= 0) { + close(fb->fd); + fb->fd = -1; + } +} + + +/** + * Construct an sRGB colour in 32-bit XRGB encoding to + * use when specifying colours + * + * @param red The red component from [0, 255] sRGB + * @param green The green component from [0, 255] sRGB + * @param blue The blue component from [0, 255] sRGB + * @return The colour as one 32-bit integer + */ +uint32_t +fb_colour(int red, int green, int blue) +{ + uint32_t rc = 0; + rc |= (uint32_t)red, rc <<= 8; + rc |= (uint32_t)green, rc <<= 8; + rc |= (uint32_t)blue; + return rc; +} + + +/** + * Print a filled in rectangle to a framebuffer + * + * @param fb The framebuffer + * @param colour The colour to use when drawing the rectangle + * @param x The starting pixel on the X axis for the rectangle + * @param y The starting pixel on the Y axis for the rectangle + * @param width The width of the rectangle, in pixels + * @param height The height of the rectangle, in pixels + */ +void +fb_fill_rectangle(framebuffer_t *restrict fb, uint32_t colour, uint32_t x, uint32_t y, uint32_t width, uint32_t height) +{ + int8_t *mem = fb->mem + y * fb->line_length; + size_t x1 = x * fb->bytes_per_pixel; + size_t x2 = (x + width) * fb->bytes_per_pixel; + size_t y2 = y + height; + size_t x_, y_; + for (y_ = y; y_ != y2; y_++, mem += fb->line_length) + for (x_ = x1; x_ != x2; x_ += fb->bytes_per_pixel) + *(uint32_t *)&mem[x_] = colour; +} + + +/** + * Draw a horizontal line segment on a framebuffer + * + * @param fb The framebuffer + * @param colour The colour to use when drawing the rectangle + * @param x The starting pixel on the X axis for the line segment + * @param y The starting pixel on the Y axis for the line segment + * @param length The length of the line segment, in pixels + */ +void fb_draw_horizontal_line(framebuffer_t *restrict fb, uint32_t colour, uint32_t x, uint32_t y, uint32_t length) +{ + int8_t *mem = fb->mem + y * fb->line_length; + size_t x1 = x * fb->bytes_per_pixel; + size_t x2 = (x + length) * fb->bytes_per_pixel; + size_t x_; + for (x_ = x1; x_ != x2; x_ += fb->bytes_per_pixel) + *(uint32_t *)&mem[x_] = colour; +} + + +/** + * Draw a vertical line segment on a framebuffer + * + * @param fb The framebuffer + * @param colour The colour to use when drawing the rectangle + * @param x The starting pixel on the X axis for the line segment + * @param y The starting pixel on the Y axis for the line segment + * @param length The length of the line segment, in pixels + */ +void fb_draw_vertical_line(framebuffer_t *restrict fb, uint32_t colour, uint32_t x, uint32_t y, uint32_t length) +{ + int8_t *mem = fb->mem + y * fb->line_length + x * fb->bytes_per_pixel; + size_t y2 = y + length; + size_t y_; + + for (y_ = y; y_ != y2; y_++, mem += fb->line_length) + *(uint32_t *)mem = colour; +} @@ -0,0 +1,57 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Analyse a gamma ramp + * + * @param stops The number of stops in the gamma ramp + * @param ramp The gamma ramp + * @param gamma Output parameter for the gamma + * @param contrast Output parameter for the contrast + * @param brightness Output parameter for the brightness + */ +void gamma_analyse(size_t stops, const uint16_t *restrict ramp, double *restrict gamma, + double *restrict contrast, double *restrict brightness) +{ + double min, middle, max; + *brightness = min = (double)(ramp[0]) / (double)0xFFFF; + *contrast = max = (double)(ramp[stops - 1]) / (double)0xFFFF; + middle = (double)(ramp[stops / 2]) / (double)0xFFFF; + + if (!(stops % 2)) { + middle += (double)(ramp[stops / 2 - 1]) / (double)0xFFFF; + middle /= (double)2; + } + + middle = (middle - min) / (max - min); + *gamma = -log((double)2) / log(middle); +} + + +/** + * Generate a gamma ramp + * + * @param stops The number of stops in the gamma ramp + * @param ramp Memory area to where to write the gamma ramp + * @param gamma The gamma + * @param contrast The contrast + * @param brightness The brightness + */ +void gamma_generate(size_t stops, uint16_t *restrict ramp, double gamma, double contrast, double brightness) +{ + double diff = contrast - brightness; + double gamma_ = (double)1 / gamma; + size_t i; + int32_t y; + double y_; + + for (i = 0; i < stops; i++) { + y_ = (double)i / (double)stops; + y_ = pow(y_, gamma_) * diff + brightness; + y = (int32_t)(y_ * 0xFFFF); + if (y < 0x0000) y = 0x0000; + if (y > 0xFFFF) y = 0xFFFF; + ramp[i] = (uint16_t)y; + } +} diff --git a/src/calibrator.c b/src/calibrator.c deleted file mode 100644 index a22feb4..0000000 --- a/src/calibrator.c +++ /dev/null @@ -1,733 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "calibrator.h" - -#include "gamma.h" -#include "state.h" - -#include <unistd.h> -#include <termios.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <errno.h> - - - -/** - * Draw bars in different shades of grey, red, green and blue - * used for calibrating the contrast and brightness - */ -void draw_contrast_brightness(void) -{ - const int CONTRAST_BRIGHTNESS_LEVELS[21] = - { - 0, 17, 27, 38, 48, 59, 70, 82, 94, 106, 119, 131, - 144, 158, 171, 185, 198, 212, 226, 241, 255 - }; - size_t f; - uint32_t y, x; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - for (y = 0; y < 4; y++) - for (x = 0; x < 21; x++) - { - int v = CONTRAST_BRIGHTNESS_LEVELS[x]; - uint32_t colour = fb_colour(v * ((y == 1) | (y == 0)), - v * ((y == 2) | (y == 0)), - v * ((y == 3) | (y == 0))); - fb_fill_rectangle(fb, colour, - x * fb->width / 21, - y * fb->height / 4, - (x + 1) * fb->width / 21 - x * fb->width / 21, - (y + 1) * fb->height / 4 - y * fb->height / 4); - } - } -} - - -/** - * Draw a seven segment display - * - * @param fb The framebuffer to draw on - * @param colour The intensity of the least intense colour to use - * @param x The X component of the top left corner of the seven segment display - * @param y The Y component of the top left corner of the seven segment display - */ -void draw_digit(framebuffer_t* restrict fb, int colour, uint32_t x, uint32_t y) -{ - uint32_t c; - - c = fb_colour(colour + 0, colour + 0, colour + 0); - fb_fill_rectangle(fb, c, x + 20, y, 80, 20); - - c = fb_colour(colour + 1, colour + 1, colour + 1); - fb_fill_rectangle(fb, c, x, y + 20, 20, 80); - - c = fb_colour(colour + 2, colour + 2, colour + 2); - fb_fill_rectangle(fb, c, x + 100, y + 20, 20, 80); - - c = fb_colour(colour + 3, colour + 3, colour + 3); - fb_fill_rectangle(fb, c, x + 20, y + 100, 80, 20); - - c = fb_colour(colour + 4, colour + 4, colour + 4); - fb_fill_rectangle(fb, c, x, y + 120, 20, 80); - - c = fb_colour(colour + 5, colour + 5, colour + 5); - fb_fill_rectangle(fb, c, x + 100, y + 120, 20, 80); - - c = fb_colour(colour + 6, colour + 6, colour + 6); - fb_fill_rectangle(fb, c, x + 20, y + 200, 80, 20); -} - - -/** - * Manipulate a CRT controllers gamma ramps to display a specific digit - * for one of the seven segment display on only that CRT controller's - * monitors - * - * @param crtc The CRT controller information - * @param colour The intensity of the least intense colour in the seven segment display - * @param value The valud of the digit to display - */ -void gamma_digit(drm_crtc_t* restrict crtc, int colour, size_t value) -{ -#define __ 0 - const int DIGITS[11] = { 1 | 2 | 4 | __ | 16 | 32 | 64, /* (0) */ - __ | __ | 4 | __ | __ | 32 | __, /* (1) */ - 1 | __ | 4 | 8 | 16 | __ | 64, /* (2) */ - 1 | __ | 4 | 8 | __ | 32 | 64, /* (3) */ - __ | 2 | 4 | 8 | __ | 32 | __, /* (4) */ - 1 | 2 | __ | 8 | __ | 32 | 64, /* (5) */ - 1 | 2 | __ | 8 | 16 | 32 | 64, /* (6) */ - 1 | __ | 4 | __ | __ | 32 | __, /* (7) */ - 1 | 2 | 4 | 8 | 16 | 32 | 64, /* (8) */ - 1 | 2 | 4 | 8 | __ | 32 | 64, /* (9) */ - __ | __ | __ | __ | __ | __ | __}; /* not visible */ - int i, digit = DIGITS[value]; - - for (i = 0; i < 7; i++) - { - uint16_t c = (digit & (1 << i)) ? 0xFFFF : 0; - int j = i + colour; - crtc->red[j] = crtc->green[j] = crtc->blue[j] = c; - } -#undef __ -} - - -/** - * Draw an unique index on each monitor - * - * @return Zero on success, -1 on error - */ -int draw_id(void) -{ - size_t f, c, id = 0; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, fb_colour(0, 0, 0), 0, 0, fb->width, fb->height); - draw_digit(fb, 1, 40, 40); - draw_digit(fb, 8, 180, 40); - } - for (c = 0; c < crtc_count; c++) - { - drm_crtc_t* restrict crtc = crtcs + c; - if (drm_get_gamma(crtc) < 0) - return -1; - gamma_digit(crtc, 1, id < 10 ? 10 : (id / 10) % 10); - gamma_digit(crtc, 8, (id / 1) % 10); - id++; - if (drm_set_gamma(crtc) < 0) - return -1; - } - return 0; -} - - -/** - * Draw squares used as reference when tweeking the gamma correction - */ -void draw_gamma(void) -{ - size_t f; - uint32_t x, y; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - for (x = 0; x < 4; x++) - { - int r = (x == 1) || (x == 0); - int g = (x == 2) || (x == 0); - int b = (x == 3) || (x == 0); - uint32_t background = fb_colour(128 * r, 128 * g, 128 * b); - uint32_t average = fb_colour(188 * r, 188 * g, 188 * b); - uint32_t high = fb_colour(255 * r, 255 * g, 255 * b); - uint32_t low = fb_colour(0, 0, 0); - uint32_t xoff = x * fb->width / 4; - fb_fill_rectangle(fb, background, xoff, 0, fb->width / 4, fb->height); - xoff += (fb->width / 4 - 200) / 2; - fb_fill_rectangle(fb, high, xoff, 40, 200, 200); - fb_fill_rectangle(fb, average, xoff + 50, 40, 100, 200); - fb_fill_rectangle(fb, average, xoff, 280, 200, 200); - for (y = 0; y < 200; y += 2) - { - fb_draw_horizontal_line(fb, high, xoff + 50, 280 + y + 0, 100); - fb_draw_horizontal_line(fb, low , xoff + 50, 280 + y + 1, 100); - } - fb_fill_rectangle(fb, average, xoff, 520, 200, 200); - fb_fill_rectangle(fb, high, xoff + 50, 520, 100, 200); - } - } -} - - -/** - * Print a pattern on the screen that can be used when - * calibrating the convergence - */ -void draw_convergence(void) -{ - uint32_t black = fb_colour(0, 0, 0); - uint32_t white = fb_colour(255, 255, 255); - uint32_t x, y; - size_t f; - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); - for (y = 0; y <= fb->height; y += 16) - { - if (y == fb->height) - y = fb->height - 1; - for (x = 0; x <= fb->width; x += 16) - { - if (x == fb->height) - x = fb->height - 1; - fb_draw_pixel(fb, white, x, y); - } - } - } -} - - -/** - * Print a pattern on the screen that can be used when - * calibrating the moiré cancellation - * - * @param gap The horizontal and vertical gap, in pixels, between the dots - * @param diagonal Whether to draw dots in a diagonal pattern - */ -void draw_moire(uint32_t gap, int diagonal) -{ - uint32_t black = fb_colour(0, 0, 0); - uint32_t white = fb_colour(255, 255, 255); - uint32_t x, y, gap2 = gap << 1; - size_t f; - gap += (uint32_t)(!diagonal); - if (diagonal) - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); - for (y = 0; y < fb->height; y += gap) - for (x = (y % gap2); x < fb->width; x += gap2) - fb_draw_pixel(fb, white, x, y); - } - else - for (f = 0; f < framebuffer_count; f++) - { - framebuffer_t* restrict fb = framebuffers + f; - fb_fill_rectangle(fb, black, 0, 0, fb->width, fb->height); - for (y = 0; y < fb->height; y += gap) - for (x = 0; x < fb->width; x += gap) - fb_draw_pixel(fb, white, x, y); - } -} - - -/** - * Analyse the monitors calibrations - * - * @return Zero on success, -1 on error - */ -int read_calibs(void) -{ - size_t c; - for (c = 0; c < crtc_count; c++) - { - if (drm_get_gamma(crtcs + c) < 0) - return -1; - - gamma_analyse(crtcs[c].gamma_stops, crtcs[c].red, gammas[0] + c, - contrasts[0] + c, brightnesses[0] + c); - gamma_analyse(crtcs[c].gamma_stops, crtcs[c].green, gammas[1] + c, - contrasts[1] + c, brightnesses[1] + c); - gamma_analyse(crtcs[c].gamma_stops, crtcs[c].blue, gammas[2] + c, - contrasts[2] + c, brightnesses[2] + c); - } - return 0; -} - - -/** - * Apply the selected calibrations to the monitors - * - * @return Zero on success, -1 on error - */ -int apply_calibs(void) -{ - size_t c; - for (c = 0; c < crtc_count; c++) - { - gamma_generate(crtcs[c].gamma_stops, crtcs[c].red, gammas[0][c], - contrasts[0][c], brightnesses[0][c]); - gamma_generate(crtcs[c].gamma_stops, crtcs[c].green, gammas[1][c], - contrasts[1][c], brightnesses[1][c]); - gamma_generate(crtcs[c].gamma_stops, crtcs[c].blue, gammas[2][c], - contrasts[2][c], brightnesses[2][c]); - - if (drm_set_gamma(crtcs + c) < 0) - return -1; - } - return 0; -} - - -/** - * Print calibrations into a file - * - * @param f The file - * @return Zero on success, -1 on error - */ -int save_calibs(FILE* f) -{ - size_t c; - for (c = 0; c < crtc_count; c++) - { - if (fprintf(f, "# index = %lu\n", - c) < 0) - return -1; - - if (fprintf(f, "edid = %s\n", - crtcs[c].edid) < 0) - return -1; - - if (fprintf(f, "brightness = %f:%f:%f\n", - brightnesses[0][c], - brightnesses[1][c], - brightnesses[2][c]) < 0) - return -1; - - if (fprintf(f, "contrast = %f:%f:%f\n", - contrasts[0][c], - contrasts[1][c], - contrasts[2][c]) < 0) - return -1; - - if (fprintf(f, "gamma = %f:%f:%f\n\n", - gammas[0][c], - gammas[1][c], - gammas[2][c]) < 0) - return -1; - } - return 0; -} - - -int main(int argc, char* argv[]) -{ - FILE* output_file = stdout; - int tty_configured = 0, rc = 0, in_fork = 0; - struct termios saved_stty; - struct termios stty; - pid_t pid; - - if ((argc > 2) || ((argc == 2) && (argv[1][0] == '-'))) - { - printf("USAGE: %s [output-file]\n", *argv); - return 0; - } - - if ((acquire_video() < 0) || - (tcgetattr(STDIN_FILENO, &saved_stty) < 0) || - (tcgetattr(STDIN_FILENO, &stty) < 0)) - goto fail; - - stty.c_lflag &= (tcflag_t)~(ICANON | ECHO); - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty) < 0) - goto fail; - tty_configured = 1; - - printf("\033[?25l"); - fflush(stdout); - - pid = fork(); - if ((pid != (pid_t)-1) && (pid != 0)) - { - int status; - retry: - if (waitpid(pid, &status, 0) != (pid_t)-1) - rc = !!status; - else - { - if (errno != EINTR) - perror(*argv); - goto retry; - } - goto done; - } - else if (pid == 0) - in_fork = 1; - - printf("\033[H\033[2J"); - printf("Please deactivate any program that dynamically\n"); - printf("applies filters to your monitors' colours\n"); - printf("and remove any existing filters.\n"); - printf("In doubt, you probably do not have any.\n"); - printf("Do not try to calibrate CRT monitors will\n"); - printf("they are cold.\n"); - printf("\n"); - printf("You will be presented with an image on each\n"); - printf("monitor. Please use the control panel on your\n"); - printf("to calibrate the contrast and brightness of\n"); - printf("each monitor. The contrasts adjusts the\n"); - printf("brightness of bright colours, and the\n"); - printf("brightness adjusts the brightness of dim\n"); - printf("colours. All rectangles are of equals size\n"); - printf("and they should be distrint from eachother.\n"); - printf("There should only be a slight difference\n"); - printf("between the two darkest colours for each\n"); - printf("colour. The grey colour does not need to\n"); - printf("be perfectly grey but should be close.\n"); - printf("The brightness should be as high as\n"); - printf("possible without the first square being\n"); - printf("any other colour than black or the two first\n"); - printf("square being too distinct from eachother. The\n"); - printf("contrast should be as high as possible without\n"); - printf("causing distortion.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_contrast_brightness(); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - printf("An index will be displayed on each monitor.\n"); - printf("It behoves you to memorise them. They will\n"); - printf("be used in the output when descibing the\n"); - printf("calibrations, and is the index of the monitors\n"); - printf("that are used when changing monitor to\n"); - printf("calibrate.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - if ((read_calibs() < 0) || (draw_id() < 0)) - goto fail; - - while (getchar() != 10) - ; - - if (apply_calibs() < 0) - goto fail; - - printf("\033[H\033[2J"); - printf("You will not be given the opportunity to.\n"); - printf("calibrate your monitors' brightness and\n"); - printf("contrast using software incase your monitors\n"); - printf("could not be sufficiently calibrated using\n"); - printf("hardware.\n"); - printf("\n"); - printf("<Left> and <right> is used to change which\n"); - printf("monitor to calibrate. <Left> switches to the\n"); - printf("previous monitor (one lower in index) and\n"); - printf("<right> switches to the next monitor (one\n"); - printf("higher in index.)\n"); - printf("<Up> and <down> is used to increase and\n"); - printf("descrease the settings. respectively.\n"); - printf("<Shift+b> is used to switch to changing the.\n"); - printf("monitor's brightness and <shift+c> switches\n"); - printf("to contrast.\n"); - printf("<r> is used to switch to changing the red.\n"); - printf("channel, <g> switches to the green channel,\n"); - printf("<b> switches to the blue channel, and <a>\n"); - printf("is used to switch to change all channels.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_contrast_brightness(); - - { - int c, b = 0, at_contrast = 0; - int red = 1, green = 1, blue = 1; - size_t mon = 0; - while ((c = getchar()) != 10) - { - if (b) - { - b = 0; - if ((c == 'A') && at_contrast) - { - contrasts[0][mon] += (double)red / 100; - contrasts[1][mon] += (double)green / 100; - contrasts[2][mon] += (double)blue / 100; - } - else if (c == 'A') - { - brightnesses[0][mon] += (double)red / 100; - brightnesses[1][mon] += (double)green / 100; - brightnesses[2][mon] += (double)blue / 100; - } - else if ((c == 'B') && at_contrast) - { - contrasts[0][mon] -= (double)red / 100; - contrasts[1][mon] -= (double)green / 100; - contrasts[2][mon] -= (double)blue / 100; - } - else if (c == 'B') - { - brightnesses[0][mon] -= (double)red / 100; - brightnesses[1][mon] -= (double)green / 100; - brightnesses[2][mon] -= (double)blue / 100; - } - else if (c == 'C') - mon = (mon + 1) % crtc_count; - else if (c == 'D') - mon = (mon == 0 ? crtc_count : mon) - 1; - - if ((c == 'A') || (c == 'B')) - apply_calibs(); - } - else if (c == '[') b = 1; - else if (c == 'B') at_contrast = 0; - else if (c == 'C') at_contrast = 1; - else if (c == 'r') red = 1, green = 0, blue = 0; - else if (c == 'g') red = 0, green = 1, blue = 0; - else if (c == 'b') red = 0, green = 0, blue = 1; - else if (c == 'a') red = 1, green = 1, blue = 1; - } - } - - printf("\033[H\033[2J"); - printf("You will now be presented with squares used\n"); - printf("to calibrate the gamma correction. There will\n"); - printf("be four stacks: grey, red, green and blue.\n"); - printf("Each stack has three squares: the upper square\n"); - printf("shows the characterics of how the middle square\n"); - printf("will look if the gamma is too high, and the\n"); - printf("lower shows how the middile will look if the\n"); - printf("gamma is too low. The middle square should\n"); - printf("look like it is one single colour if the gamma\n"); - printf("correction is configured correctly. You may\n"); - printf("have to look from a distance or not focus\n"); - printf("your eyes on the squares to compensate for\n"); - printf("the fact that there actually multiple colours\n"); - printf("is the square.\n"); - printf("The grey should look perfectly grey when you\n"); - printf("are done.\n"); - printf("\n"); - printf("<Left> and <right> is used to change which\n"); - printf("monitor to calibrate. <Left> switches to the\n"); - printf("previous monitor (one lower in index) and\n"); - printf("<right> switches to the next monitor (one\n"); - printf("higher in index.)\n"); - printf("<Up> and <down> is used to increase and\n"); - printf("descrease the gamma. respectively.\n"); - printf("<r> is used to switch to changing the red.\n"); - printf("channel, <g> switches to the green channel,\n"); - printf("<b> switches to the blue channel, and <a>\n"); - printf("is used to switch to change all channels.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_gamma(); - - { - int c, b = 0; - int red = 1, green = 1, blue = 1; - size_t mon = 0; - while ((c = getchar()) != 10) - { - if (b) - { - b = 0; - if (c == 'A') - { - gammas[0][mon] += (double)red / 100; - gammas[1][mon] += (double)green / 100; - gammas[2][mon] += (double)blue / 100; - } - else if (c == 'B') - { - gammas[0][mon] -= (double)red / 100; - gammas[1][mon] -= (double)green / 100; - gammas[2][mon] -= (double)blue / 100; - if (gammas[0][mon] < 0) gammas[0][mon] = 0; - if (gammas[1][mon] < 0) gammas[1][mon] = 0; - if (gammas[2][mon] < 0) gammas[2][mon] = 0; - } - else if (c == 'C') - mon = (mon + 1) % crtc_count; - else if (c == 'D') - mon = (mon == 0 ? crtc_count : mon) - 1; - - if ((c == 'A') || (c == 'B')) - apply_calibs(); - } - else if (c == '[') b = 1; - else if (c == 'r') red = 1, green = 0, blue = 0; - else if (c == 'g') red = 0, green = 1, blue = 0; - else if (c == 'b') red = 0, green = 0, blue = 1; - else if (c == 'a') red = 1, green = 1, blue = 1; - } - } - - printf("\033[H\033[2J"); - printf("The next step is to calibrate the monitors'\n"); - printf("convergence settings using the monitors'\n"); - printf("control panel. White dots will be printed on the\n"); - printf("screens, you should try to get as many as\n"); - printf("possible of them to appear as pure white dots\n"); - printf("rather than dots splitted in the red, green and\n"); - printf("blue dots. On most CRT monitors this is not\n"); - printf("possible to get all corners perfect.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_convergence(); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - printf("The final step is to calbirate the monitors' moiré\n"); - printf("cancellation. This too is done on the using the\n"); - printf("monitors' control panel.\n"); - printf("\n"); - printf("You can use <d> and the arrow keys to change the\n"); - printf("dot-pattern on the screens.\n"); - printf("\n"); - printf("Press ENTER to continue, and ENTER again when\n"); - printf("your are done.\n"); - fflush(stdout); - - while (getchar() != 10) - ; - - printf("\033[H\033[2J"); - fflush(stdout); - draw_moire(1, 1); - - { - int c, b = 0, d = 1; - uint32_t gap = 1; - while ((c = getchar()) != 10) - { - if (b) - { - b = 0; - if ((c == 'A') || (c == 'C')) - draw_moire(++gap, d); - else if ((c == 'B') || (c == 'D')) - { - if (--gap == 0) - gap = 1; - draw_moire(gap, d); - } - } - else if (c == '[') - b = 1; - else if (c == 'd') - draw_moire(gap, d ^= 1); - } - } - - printf("\033[H\033[2J"); - fflush(stdout); - - if (argc == 2) - { - output_file = fopen(argv[1], "w"); - if (output_file == NULL) - goto fail; - } - - if (save_calibs(output_file) < 0) - goto fail; - fflush(output_file); - - if (argc == 2) - { - if (fclose(output_file)) - goto fail; - } - - done: - if (in_fork == 0) - { - release_video(); - if (tty_configured) - tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty); - printf("\033[?25h"); - fflush(stdout); - } - return rc; - fail: - perror(*argv); - rc = 1; - goto done; -} - diff --git a/src/calibrator.h b/src/calibrator.h deleted file mode 100644 index 7b823db..0000000 --- a/src/calibrator.h +++ /dev/null @@ -1,108 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef CRT_CALIBRATOR_CALIBRATOR_H -#define CRT_CALIBRATOR_CALIBRATOR_H - - -#include "framebuffer.h" -#include "drmgamma.h" - -#include <stdint.h> -#include <stddef.h> -#include <stdio.h> - - -/** - * Draw bars in different shades of grey, red, green and blue - * used for calibrating the contrast and brightness - */ -void draw_contrast_brightness(void); - -/** - * Draw a seven segment display - * - * @param fb The framebuffer to draw on - * @param colour The intensity of the least intense colour to use - * @param x The X component of the top left corner of the seven segment display - * @param y The Y component of the top left corner of the seven segment display - */ -void draw_digit(framebuffer_t* restrict fb, int colour, uint32_t x, uint32_t y); - -/** - * Manipulate a CRT controllers gamma ramps to display a specific digit - * for one of the seven segment display on only that CRT controller's - * monitors - * - * @param crtc The CRT controller information - * @param colour The intensity of the least intense colour in the seven segment display - * @param value The valud of the digit to display - */ -void gamma_digit(drm_crtc_t* restrict crtc, int colour, size_t value); - -/** - * Draw an unique index on each monitor - * - * @return Zero on success, -1 on error - */ -int draw_id(void); - -/** - * Draw squares used as reference when tweeking the gamma correction - */ -void draw_gamma(void); - -/** - * Print a pattern on the screen that can be used when - * calibrating the convergence - */ -void draw_convergence(void); - -/** - * Print a pattern on the screen that can be used when - * calibrating the moiré cancellation - * - * @param gap The horizontal and vertical gap, in pixels, between the dots - * @param diagonal Whether to draw dots in a diagonal pattern - */ -void draw_moire(uint32_t gap, int diagonal); - -/** - * Analyse the monitors calibrations - * - * @return Zero on success, -1 on error - */ -int read_calibs(void); - -/** - * Apply the selected calibrations to the monitors - * - * @return Zero on success, -1 on error - */ -int apply_calibs(void); - -/** - * Print calibrations into a file - * - * @param f The file - * @return Zero on success, -1 on error - */ -int save_calibs(FILE* f); - - -#endif - diff --git a/src/drmgamma.c b/src/drmgamma.c deleted file mode 100644 index 8f3dd97..0000000 --- a/src/drmgamma.c +++ /dev/null @@ -1,283 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "drmgamma.h" - -#include <unistd.h> -#include <errno.h> -#include <stdio.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * The number of elements to allocates to a buffer for a DRM device pathname - */ -#define DRM_DEV_NAME_MAX_LEN \ - ((sizeof(DRM_DEV_NAME) + sizeof(DRM_DIR_NAME)) / sizeof(char) + 3 * sizeof(int)) - - - -/** - * Figure out how many graphics cards there are on the system - * - * @return The number of graphics cards on the system - */ -size_t drm_card_count(void) -{ - char buf[DRM_DEV_NAME_MAX_LEN]; - size_t count = 0; - - for (;; count++) - { - sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, (int)count); - if (access(buf, F_OK) < 0) - return count; - } -} - -/** - * Acquire access to a graphics card - * - * @param index The index of the graphics card - * @param card Graphics card information to fill in - * @return Zero on success, -1 on error - */ -int drm_card_open(size_t index, drm_card_t* restrict card) -{ - char buf[DRM_DEV_NAME_MAX_LEN]; - int old_errno; - size_t i, n; - - card->fd = -1; - card->res = NULL; - card->connectors = NULL; - card->encoders = NULL; - card->connector_count = 0; - - sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, (int)index); - card->fd = open(buf, O_RDWR); - if (card->fd == -1) - goto fail; - - card->res = drmModeGetResources(card->fd); - if (card->res == NULL) - goto fail; - - card->crtc_count = (size_t)(card->res->count_crtcs); - card->connector_count = (size_t)(card->res->count_connectors); - n = card->connector_count; - - card->connectors = calloc(n, sizeof(drmModeConnector*)); - if (card->connectors == NULL) - goto fail; - card->encoders = calloc(n, sizeof(drmModeEncoder*)); - if (card->encoders == NULL) - goto fail; - - for (i = 0; i < n; i++) - { - card->connectors[i] = drmModeGetConnector(card->fd, card->res->connectors[i]); - if (card->connectors[i] == NULL) - goto fail; - - if (card->connectors[i]->encoder_id != 0) - { - card->encoders[i] = drmModeGetEncoder(card->fd, card->connectors[i]->encoder_id); - if (card->encoders[i] == NULL) - goto fail; - } - } - - return 0; - fail: - old_errno = errno; - drm_card_close(card); - errno = old_errno; - return -1; -} - - -/** - * Release access to a graphics card - * - * @param card The graphics card information - */ -void drm_card_close(drm_card_t* restrict card) -{ - size_t i, n = card->connector_count; - - if (card->encoders != NULL) - for (i = 0; i < n; i++) - if (card->encoders[i] != NULL) - drmModeFreeEncoder(card->encoders[i]); - free(card->encoders), card->encoders = NULL; - - if (card->connectors != NULL) - for (i = 0; i < n; i++) - if (card->connectors[i] != NULL) - drmModeFreeConnector(card->connectors[i]); - free(card->connectors), card->connectors = NULL; - - if (card->res != NULL) - drmModeFreeResources(card->res), card->res = NULL; - if (card->fd != -1) - close(card->fd), card->fd = -1; -} - - -/** - * Acquire access to a CRT controller - * - * @param index The index of the CRT controller - * @param card The graphics card information - * @param crtc CRT controller information to fill in - * @return Zero on success, -1 on error - */ -int drm_crtc_open(size_t index, drm_card_t* restrict card, drm_crtc_t* restrict crtc) -{ - drmModePropertyRes* restrict prop; - drmModePropertyBlobRes* restrict blob; - drmModeCrtc* restrict info; - size_t i; - int old_errno; - - crtc->edid = NULL; - crtc->red = NULL; - crtc->green = NULL; - crtc->blue = NULL; - - crtc->id = card->res->crtcs[index]; - crtc->card = card; - - crtc->connector = NULL; - crtc->encoder = NULL; - for (i = 0; i < card->connector_count; i++) - if (card->encoders[i] != NULL) - if (card->encoders[i]->crtc_id == crtc->id) - { - crtc->connector = card->connectors[i]; - crtc->encoder = card->encoders[i]; - } - - crtc->connected = (crtc->connector != NULL) && (crtc->connector->connection == DRM_MODE_CONNECTED); - - info = drmModeGetCrtc(card->fd, crtc->id); - if (info == NULL) - return -1; - crtc->gamma_stops = (size_t)(info->gamma_size); - drmModeFreeCrtc(info); - - /* `calloc` is for some reason required when reading the gamma ramps. */ - crtc->red = calloc(3 * crtc->gamma_stops, sizeof(uint16_t)); - if (crtc->red == NULL) - return -1; - crtc->green = crtc->red + crtc->gamma_stops; - crtc->blue = crtc->green + crtc->gamma_stops; - - if (crtc->connector == NULL) - return 0; - for (i = 0; i < (size_t)(crtc->connector->count_props); i++) - { - size_t j; - - prop = drmModeGetProperty(card->fd, crtc->connector->props[i]); - if (prop == NULL) - continue; - - if (strcmp(prop->name, "EDID")) - goto free_prop; - - - blob = drmModeGetPropertyBlob(card->fd, (uint32_t)(crtc->connector->prop_values[i])); - i = (size_t)(crtc->connector->count_props); - if ((blob == NULL) || (blob->data == NULL)) - goto free_blob; - - crtc->edid = malloc((blob->length * 2 + 1) * sizeof(char)); - if (crtc->edid == NULL) - { - old_errno = errno; - drmModeFreePropertyBlob(blob); - drmModeFreeProperty(prop); - free(crtc->red), crtc->red = NULL; - errno = old_errno; - return -1; - } - for (j = 0; j < blob->length; j++) - { - unsigned char c = ((unsigned char*)(blob->data))[j]; - crtc->edid[j * 2 + 0] = "0123456789ABCDEF"[(c >> 4) & 15]; - crtc->edid[j * 2 + 1] = "0123456789ABCDEF"[(c >> 0) & 15]; - } - crtc->edid[blob->length * 2] = '\0'; - - free_blob: - if (blob != NULL) - drmModeFreePropertyBlob(blob); - - free_prop: - drmModeFreeProperty(prop); - } - - return 0; -} - - -/** - * Release access to a CRT controller - * - * @param crtc The CRT controller information to fill in - */ -void drm_crtc_close(drm_crtc_t* restrict crtc) -{ - free(crtc->edid), crtc->edid = NULL; - free(crtc->red), crtc->red = NULL; -} - - -/** - * Read the gamma ramps for a CRT controller - * - * @param crtc CRT controller information - * @return Zero on success, -1 on error - */ -int drm_get_gamma(drm_crtc_t* restrict crtc) -{ - int r; - r = drmModeCrtcGetGamma(crtc->card->fd, crtc->id, (uint32_t)(crtc->gamma_stops), - crtc->red, crtc->green, crtc->blue); - return -!!r; -} - - -/** - * Apply gamma ramps for a CRT controller - * - * @param crtc CRT controller information - * @return Zero on success, -1 on error - */ -int drm_set_gamma(drm_crtc_t* restrict crtc) -{ - int r; - r = drmModeCrtcSetGamma(crtc->card->fd, crtc->id, (uint32_t)(crtc->gamma_stops), - crtc->red, crtc->green, crtc->blue); - return -!!r; -} - diff --git a/src/drmgamma.h b/src/drmgamma.h deleted file mode 100644 index e82159d..0000000 --- a/src/drmgamma.h +++ /dev/null @@ -1,182 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef CRT_CALIBRATOR_DRMGAMMA_H -#define CRT_CALIBRATOR_DRMGAMMA_H - - -#include <xf86drm.h> -#include <xf86drmMode.h> - - -/** - * Graphics card information - */ -typedef struct drm_card -{ - /** - * File descriptor for the connection to the graphics card, - * -1 if not opened - */ - int fd; - - /** - * The graphics card's mode resources, `NULL` if not acquired - */ - drmModeRes* restrict res; - - /** - * The number of CRTC:s available on the graphics card - */ - size_t crtc_count; - - /** - * The available connectors - */ - drmModeConnector** restrict connectors; - - /** - * The available encoders - */ - drmModeEncoder** restrict encoders; - - /** - * The number of connectors and encoders - */ - size_t connector_count; - -} drm_card_t; - - -/** - * CRT controller information - */ -typedef struct drm_crtc -{ - /** - * CRT controller identifier - */ - uint32_t id; - - /** - * The graphics card - */ - drm_card_t* restrict card; - - /** - * The CRT controller's connector - */ - drmModeConnector* restrict connector; - - /** - * The CRT controller's encoder - */ - drmModeEncoder* restrict encoder; - - /** - * Whether the connector is connected - */ - int connected; - - /** - * The CRT's EDID, hexadecimally encoded - */ - char* restrict edid; - - /** - * The number of stops on the gamma ramps - */ - size_t gamma_stops; - - /** - * The gamma ramp for the red channel - */ - uint16_t* restrict red; - - /** - * The gamma ramp for the green channel - */ - uint16_t* restrict green; - - /** - * The gamma ramp for the blue channel - */ - uint16_t* restrict blue; - -} drm_crtc_t; - - - -/** - * Figure out how many graphics cards there are on the system - * - * @return The number of graphics cards on the system - */ -size_t drm_card_count(void); - -/** - * Acquire access to a graphics card - * - * @param index The index of the graphics card - * @param card Graphics card information to fill in - * @return Zero on success, -1 on error - */ -int drm_card_open(size_t index, drm_card_t* restrict card); - -/** - * Release access to a graphics card - * - * @param card The graphics card information - */ -void drm_card_close(drm_card_t* restrict card); - -/** - * Acquire access to a CRT controller - * - * @param index The index of the CRT controller - * @param card The graphics card information - * @param crtc CRT controller information to fill in - * @return Zero on success, -1 on error - */ -int drm_crtc_open(size_t index, drm_card_t* restrict card, drm_crtc_t* restrict crtc); - -/** - * Release access to a CRT controller - * - * @param crtc The CRT controller information to fill in - */ -void drm_crtc_close(drm_crtc_t* restrict crtc); - -/** - * Read the gamma ramps for a CRT controller - * - * @param crtc CRT controller information - * @return Zero on success, -1 on error - */ -int drm_get_gamma(drm_crtc_t* restrict crtc); - -/** - * Apply gamma ramps for a CRT controller - * - * @param crtc CRT controller information - * @return Zero on success, -1 on error - */ -int drm_set_gamma(drm_crtc_t* restrict crtc); - - -#endif - diff --git a/src/framebuffer.c b/src/framebuffer.c deleted file mode 100644 index 55964d2..0000000 --- a/src/framebuffer.c +++ /dev/null @@ -1,215 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "framebuffer.h" - -#include <unistd.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <stropts.h> -#include <linux/fb.h> -#include <errno.h> - - -/** - * The psuedodevice pathname pattern used to access a framebuffer - */ -#ifndef FB_DEVICE_PATTERN -# define FB_DEVICE_PATTERN "/dev/fb%lu" -#endif - - -/** - * The number of elements to allocates to a buffer for a framebuffer device pathname - */ -#define FB_DEVICE_MAX_LEN (sizeof(FB_DEVICE_PATTERN) / sizeof(char) + 3 * sizeof(size_t)) - - - -/** - * Figure out how many framebuffers there are on the system - * - * @return The number of framebuffers on the system - */ -size_t fb_count(void) -{ - char buf[FB_DEVICE_MAX_LEN]; - size_t count = 0; - - for (;; count++) - { - sprintf(buf, FB_DEVICE_PATTERN, count); - if (access(buf, F_OK) < 0) - return count; - } -} - - -/** - * Open a framebuffer - * - * @param index The index of the framebuffer to open - * @param fb Framebuffer information to fill in - * @return Zero on success, -1 on error - */ -int fb_open(size_t index, framebuffer_t* restrict fb) -{ - char buf[FB_DEVICE_MAX_LEN]; - struct fb_fix_screeninfo fix_info; - struct fb_var_screeninfo var_info; - int old_errno; - - fb->fd = -1; - fb->mem = MAP_FAILED; - - sprintf(buf, FB_DEVICE_PATTERN, index); - fb->fd = open(buf, O_RDWR); - if (fb->fd == -1) - goto fail; - - if (ioctl(fb->fd, (unsigned long int)FBIOGET_FSCREENINFO, &fix_info) || - ioctl(fb->fd, (unsigned long int)FBIOGET_VSCREENINFO, &var_info)) - goto fail; - - fb->mem = mmap(NULL, (size_t)(fix_info.smem_len), PROT_WRITE, MAP_SHARED, fb->fd, (off_t)0); - if (fb->mem == MAP_FAILED) - goto fail; - - fb->mem += var_info.xoffset * (var_info.bits_per_pixel / 8); - fb->mem += var_info.yoffset * fix_info.line_length; - - fb->width = var_info.xres; - fb->height = var_info.yres; - fb->bytes_per_pixel = var_info.bits_per_pixel / 8; - fb->line_length = fix_info.line_length; - - return 0; - fail: - old_errno = errno; - fb_close(fb); - errno = old_errno; - return -1; -} - - -/** - * Close a framebuffer - * - * @param fb The framebuffer information - */ -void fb_close(framebuffer_t* restrict fb) -{ - if (fb->fd != -1) - close(fb->fd), fb->fd = -1; -} - - -/** - * Construct an sRGB colour in 32-bit XRGB encoding to - * use when specifying colours - * - * @param red The red component from [0, 255] sRGB - * @param green The green component from [0, 255] sRGB - * @param blue The blue component from [0, 255] sRGB - * @return The colour as one 32-bit integer - */ -uint32_t fb_colour(int red, int green, int blue) -{ - uint32_t rc = 0; - rc |= (uint32_t)red, rc <<= 8; - rc |= (uint32_t)green, rc <<= 8; - rc |= (uint32_t)blue; - return rc; -} - - -/** - * Print a filled in rectangle to a framebuffer - * - * @param fb The framebuffer - * @param colour The colour to use when drawing the rectangle - * @param x The starting pixel on the X axis for the rectangle - * @param y The starting pixel on the Y axis for the rectangle - * @param width The width of the rectangle, in pixels - * @param height The height of the rectangle, in pixels - */ -void fb_fill_rectangle(framebuffer_t* restrict fb, uint32_t colour, - uint32_t x, uint32_t y, uint32_t width, uint32_t height) -{ - int8_t* mem = fb->mem + y * fb->line_length; - size_t x1 = x * fb->bytes_per_pixel; - size_t x2 = (x + width) * fb->bytes_per_pixel; - size_t y2 = y + height; - size_t x_, y_; - - for (y_ = y; y_ != y2; y_++, mem += fb->line_length) - for (x_ = x1; x_ != x2; x_ += fb->bytes_per_pixel) - { - int8_t* pixel = mem + x_; - *(uint32_t*)pixel = colour; - } -} - - -/** - * Draw a horizontal line segment on a framebuffer - * - * @param fb The framebuffer - * @param colour The colour to use when drawing the rectangle - * @param x The starting pixel on the X axis for the line segment - * @param y The starting pixel on the Y axis for the line segment - * @param length The length of the line segment, in pixels - */ -void fb_draw_horizontal_line(framebuffer_t* restrict fb, uint32_t colour, - uint32_t x, uint32_t y, uint32_t length) -{ - int8_t* mem = fb->mem + y * fb->line_length; - size_t x1 = x * fb->bytes_per_pixel; - size_t x2 = (x + length) * fb->bytes_per_pixel; - size_t x_; - - for (x_ = x1; x_ != x2; x_ += fb->bytes_per_pixel) - { - int8_t* pixel = mem + x_; - *(uint32_t*)pixel = colour; - } -} - - -/** - * Draw a vertical line segment on a framebuffer - * - * @param fb The framebuffer - * @param colour The colour to use when drawing the rectangle - * @param x The starting pixel on the X axis for the line segment - * @param y The starting pixel on the Y axis for the line segment - * @param length The length of the line segment, in pixels - */ -void fb_draw_vertical_line(framebuffer_t* restrict fb, uint32_t colour, - uint32_t x, uint32_t y, uint32_t length) -{ - int8_t* mem = fb->mem + y * fb->line_length + x * fb->bytes_per_pixel; - size_t y2 = y + length; - size_t y_; - - for (y_ = y; y_ != y2; y_++, mem += fb->line_length) - *(uint32_t*)mem = colour; -} - diff --git a/src/framebuffer.h b/src/framebuffer.h deleted file mode 100644 index 11102ff..0000000 --- a/src/framebuffer.h +++ /dev/null @@ -1,154 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef CRT_CALIBRATOR_FRAMEBUFFER_H -#define CRT_CALIBRATOR_FRAMEBUFFER_H - - -#include <stddef.h> -#include <stdint.h> - - -/** - * Framebuffer information - */ -typedef struct framebuffer -{ - /** - * The file descriptor used to access the framebuffer, -1 if not opened - */ - int fd; - - /** - * The width of the display in pixels - */ - uint32_t width; - - /** - * The height of the display in pixels - */ - uint32_t height; - - /** - * Increment for `mem` to move to next pixel on the line - */ - uint32_t bytes_per_pixel; - - /** - * Increment for `mem` to move down one line but stay in the same column - */ - uint32_t line_length; - - /** - * Framebuffer pointer, `MAP_FAILED` (from <sys/mman.h>) if not mapped - */ - int8_t* mem; - -} framebuffer_t; - - -/** - * Figure out how many framebuffers there are on the system - * - * @return The number of framebuffers on the system - */ -size_t fb_count(void); - -/** - * Open a framebuffer - * - * @param index The index of the framebuffer to open - * @param fb Framebuffer information to fill in - * @return Zero on success, -1 on error - */ -int fb_open(size_t index, framebuffer_t* restrict fb); - -/** - * Close a framebuffer - * - * @param fb The framebuffer information - */ -void fb_close(framebuffer_t* restrict fb); - -/** - * Construct an sRGB colour in 32-bit XRGB encoding to - * use when specifying colours - * - * @param red The red component from [0, 255] sRGB - * @param green The green component from [0, 255] sRGB - * @param blue The blue component from [0, 255] sRGB - * @return The colour as one 32-bit integer - */ -uint32_t fb_colour(int red, int green, int blue) __attribute__((const)); - -/** - * Print a filled in rectangle to a framebuffer - * - * @param fb The framebuffer - * @param colour The colour to use when drawing the rectangle - * @param x The starting pixel on the X axis for the rectangle - * @param y The starting pixel on the Y axis for the rectangle - * @param width The width of the rectangle, in pixels - * @param height The height of the rectangle, in pixels - */ -void fb_fill_rectangle(framebuffer_t* restrict fb, uint32_t colour, - uint32_t x, uint32_t y, uint32_t width, uint32_t height); - -/** - * Draw a horizontal line segment on a framebuffer - * - * @param fb The framebuffer - * @param colour The colour to use when drawing the rectangle - * @param x The starting pixel on the X axis for the line segment - * @param y The starting pixel on the Y axis for the line segment - * @param length The length of the line segment, in pixels - */ -void fb_draw_horizontal_line(framebuffer_t* restrict fb, uint32_t colour, - uint32_t x, uint32_t y, uint32_t length); - -/** - * Draw a vertical line segment on a framebuffer - * - * @param fb The framebuffer - * @param colour The colour to use when drawing the rectangle - * @param x The starting pixel on the X axis for the line segment - * @param y The starting pixel on the Y axis for the line segment - * @param length The length of the line segment, in pixels - */ -void fb_draw_vertical_line(framebuffer_t* restrict fb, uint32_t colour, - uint32_t x, uint32_t y, uint32_t length); - - -/** - * Draw a single on a framebuffer - * - * @param fb The framebuffer - * @param colour The colour to use when drawing the rectangle - * @param x The pixel's position on the X axis - * @param y The pixel's position on the Y axis - */ -static inline void fb_draw_pixel(framebuffer_t* restrict fb, uint32_t colour, - uint32_t x, uint32_t y) -{ - int8_t* mem = fb->mem + y * fb->line_length + x * fb->bytes_per_pixel; - *(uint32_t*)mem = colour; -} - - - -#endif - diff --git a/src/gamma.c b/src/gamma.c deleted file mode 100644 index 79a50f7..0000000 --- a/src/gamma.c +++ /dev/null @@ -1,79 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "gamma.h" - -#include <math.h> - - -/** - * Analyse a gamma ramp - * - * @param stops The number of stops in the gamma ramp - * @param ramp The gamma ramp - * @param gamma Output parameter for the gamma - * @param contrast Output parameter for the contrast - * @param brightness Output parameter for the brightness - */ -void gamma_analyse(size_t stops, const uint16_t* restrict ramp, double* restrict gamma, - double* restrict contrast, double* restrict brightness) -{ - double min, middle, max; - *brightness = min = (double)(ramp[0]) / (double)0xFFFF; - *contrast = max = (double)(ramp[stops - 1]) / (double)0xFFFF; - middle = (double)(ramp[stops / 2]) / (double)0xFFFF; - - if (stops % 2 == 0) - { - middle += (double)(ramp[stops / 2 - 1]) / (double)0xFFFF; - middle /= (double)2; - } - - middle = (middle - min) / (max - min); - *gamma = -log((double)2) / log(middle); -} - - -/** - * Generate a gamma ramp - * - * @param stops The number of stops in the gamma ramp - * @param ramp Memory area to where to write the gamma ramp - * @param gamma The gamma - * @param contrast The contrast - * @param brightness The brightness - */ -void gamma_generate(size_t stops, uint16_t* restrict ramp, double gamma, - double contrast, double brightness) -{ - double diff = contrast - brightness; - double gamma_ = (double)1 / gamma; - size_t i; - int32_t y; - double y_; - - for (i = 0; i < stops; i++) - { - y_ = (double)i / (double)stops; - y_ = pow(y_, gamma_) * diff + brightness; - y = (int32_t)(y_ * 0xFFFF); - if (y < 0x0000) y = 0x0000; - if (y > 0xFFFF) y = 0xFFFF; - ramp[i] = (uint16_t)y; - } -} - diff --git a/src/gamma.h b/src/gamma.h deleted file mode 100644 index 9652598..0000000 --- a/src/gamma.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef CRT_CALIBRATOR_GAMMA_H -#define CRT_CALIBRATOR_GAMMA_H - - -#include <stddef.h> -#include <stdint.h> - - -/** - * Analyse a gamma ramp - * - * @param stops The number of stops in the gamma ramp - * @param ramp The gamma ramp - * @param gamma Output parameter for the gamma - * @param contrast Output parameter for the contrast - * @param brightness Output parameter for the brightness - */ -void gamma_analyse(size_t stops, const uint16_t* restrict ramp, double* restrict gamma, - double* restrict contrast, double* restrict brightness); - -/** - * Generate a gamma ramp - * - * @param stops The number of stops in the gamma ramp - * @param ramp Memory area to where to write the gamma ramp - * @param gamma The gamma - * @param contrast The contrast - * @param brightness The brightness - */ -void gamma_generate(size_t stops, uint16_t* restrict ramp, double gamma, - double contrast, double brightness); - - -#endif - diff --git a/src/state.c b/src/state.c deleted file mode 100644 index b4ec11a..0000000 --- a/src/state.c +++ /dev/null @@ -1,172 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "state.h" - -#include <stdlib.h> - - -/** - * The framebuffers on the system - */ -framebuffer_t* restrict framebuffers = NULL; - -/** - * The number of elements in `framebuffers` - */ -size_t framebuffer_count = 0; - -/** - * The graphics cards on the system - */ -drm_card_t* restrict cards = NULL; - -/** - * The number of elements in `cards` - */ -size_t card_count = 0; - -/** - * The connected CRT controllers on the system - */ -drm_crtc_t* restrict crtcs = NULL; - -/** - * The software brightness setting on each connected CRT controller, on each channel - */ -double* restrict brightnesses[3]; - -/** - * The software contrast setting on each connected CRT controller, on each channel - */ -double* restrict contrasts[3]; - -/** - * The gamma correction on each connected CRT controller, on each channel - */ -double* restrict gammas[3]; - -/** - * The number of elements in `crtcs`, `brightnesses[]`, `contrasts[]` and `gammas[]` - */ -size_t crtc_count = 0; - - - -/** - * Acquire video control - * - * @return Zero on success, -1 on error - */ -int acquire_video(void) -{ - size_t f, c, i, fn = fb_count(), cn = drm_card_count(); - drm_crtc_t* restrict old_crtcs; - - framebuffers = malloc(fn * sizeof(framebuffer_t)); - if (framebuffers == NULL) - return -1; - - for (f = 0; f < fn; f++) - { - framebuffer_t fb; - if (fb_open(f, &fb) < 0) - return -1; - framebuffers[framebuffer_count++] = fb; - } - - cards = malloc(cn * sizeof(drm_card_t)); - if (cards == NULL) - return -1; - - for (c = 0; c < cn; c++) - { - drm_card_t card; - if (drm_card_open(c, &card) < 0) - return -1; - cards[card_count++] = card; - - old_crtcs = crtcs; - crtcs = realloc(crtcs, (crtc_count + card.crtc_count) * sizeof(drm_crtc_t)); - if (crtcs == NULL) - { - crtcs = old_crtcs; - return -1; - } - - for (i = 0; i < card.crtc_count; i++) - { - drm_crtc_t crtc; - if (drm_crtc_open(i, cards + c, &crtc) < 0) - return -1; - if (crtc.connected) - crtcs[crtc_count++] = crtc; - else - drm_crtc_close(&crtc); - } - } - - for (c = 0; c < 3; c++) - { - brightnesses[c] = malloc(crtc_count * sizeof(double)); - if (brightnesses[c] == NULL) - return -1; - - contrasts[c] = malloc(crtc_count * sizeof(double)); - if (contrasts[c] == NULL) - return -1; - - gammas[c] = malloc(crtc_count * sizeof(double)); - if (gammas[c] == NULL) - return -1; - } - - return 0; -} - - -/** - * Release video control - */ -void release_video(void) -{ - size_t i; - - for (i = 0; i < crtc_count; i++) - drm_crtc_close(crtcs + i); - crtc_count = 0; - - for (i = 0; i < card_count; i++) - drm_card_close(cards + i); - card_count = 0; - - for (i = 0; i < framebuffer_count; i++) - fb_close(framebuffers + i); - framebuffer_count = 0; - - for (i = 0; i < 3; i++) - { - free(brightnesses[i]), brightnesses[i] = NULL; - free(contrasts[i]), contrasts[i] = NULL; - free(gammas[i]), gammas[i] = NULL; - } - - free(crtcs), crtcs = NULL; - free(cards), cards = NULL; - free(framebuffers), framebuffers = NULL; -} - diff --git a/src/state.h b/src/state.h deleted file mode 100644 index da4a580..0000000 --- a/src/state.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * crt-calibrator – Calibration utility for CRT monitors - * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef CRT_CALIBRATOR_STATE_H -#define CRT_CALIBRATOR_STATE_H - - -#include "framebuffer.h" -#include "drmgamma.h" - -#include <stddef.h> - - -/** - * The framebuffers on the system - */ -extern framebuffer_t* restrict framebuffers; - -/** - * The number of elements in `framebuffers` - */ -extern size_t framebuffer_count; - -/** - * The graphics cards on the system - */ -extern drm_card_t* restrict cards; - -/** - * The number of elements in `cards` - */ -extern size_t card_count; - -/** - * The connected CRT controllers on the system - */ -extern drm_crtc_t* restrict crtcs; - -/** - * The software brightness setting on each connected CRT controller, on each channel - */ -extern double* restrict brightnesses[3]; - -/** - * The software contrast setting on each connected CRT controller, on each channel - */ -extern double* restrict contrasts[3]; - -/** - * The gamma correction on each connected CRT controller, on each channel - */ -extern double* restrict gammas[3]; - -/** - * The number of elements in `crtcs`, `brightnesses[]`, `contrasts[]` and `gammas[]` - */ -extern size_t crtc_count; - - - -/** - * Acquire video control - * - * @return Zero on success, -1 on error - */ -int acquire_video(void); - -/** - * Release video control - */ -void release_video(void); - - -#endif - @@ -0,0 +1,144 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * The framebuffers on the system + */ +framebuffer_t *restrict framebuffers = NULL; + +/** + * The number of elements in `framebuffers` + */ +size_t framebuffer_count = 0; + +/** + * The graphics cards on the system + */ +drm_card_t *restrict cards = NULL; + +/** + * The number of elements in `cards` + */ +size_t card_count = 0; + +/** + * The connected CRT controllers on the system + */ +drm_crtc_t *restrict crtcs = NULL; + +/** + * The software brightness setting on each connected CRT controller, on each channel + */ +double *restrict brightnesses[3]; + +/** + * The software contrast setting on each connected CRT controller, on each channel + */ +double *restrict contrasts[3]; + +/** + * The gamma correction on each connected CRT controller, on each channel + */ +double *restrict gammas[3]; + +/** + * The number of elements in `crtcs`, `brightnesses[]`, `contrasts[]` and `gammas[]` + */ +size_t crtc_count = 0; + + + +/** + * Acquire video control + * + * @return Zero on success, -1 on error + */ +int +acquire_video(void) +{ + size_t f, c, i, fn = fb_count(), cn = drm_card_count(); + drm_crtc_t *restrict old_crtcs, crtc; + drm_card_t card; + framebuffer_t fb; + + framebuffers = malloc(fn * sizeof(framebuffer_t)); + if (!framebuffers) + return -1; + + for (f = 0; f < fn; f++) { + if (fb_open(f, &fb) < 0) + return -1; + framebuffers[framebuffer_count++] = fb; + } + + cards = malloc(cn * sizeof(drm_card_t)); + if (!cards) + return -1; + + for (c = 0; c < cn; c++) { + if (drm_card_open(c, &card) < 0) + return -1; + cards[card_count++] = card; + + old_crtcs = crtcs; + crtcs = realloc(crtcs, (crtc_count + card.crtc_count) * sizeof(drm_crtc_t)); + if (!crtcs) { + crtcs = old_crtcs; + return -1; + } + + for (i = 0; i < card.crtc_count; i++) { + if (drm_crtc_open(i, cards + c, &crtc) < 0) + return -1; + if (crtc.connected) + crtcs[crtc_count++] = crtc; + else + drm_crtc_close(&crtc); + } + } + + for (c = 0; c < 3; c++) { + brightnesses[c] = malloc(crtc_count * sizeof(double)); + if (!brightnesses[c]) + return -1; + contrasts[c] = malloc(crtc_count * sizeof(double)); + if (!contrasts[c]) + return -1; + gammas[c] = malloc(crtc_count * sizeof(double)); + if (!gammas[c]) + return -1; + } + + return 0; +} + + +/** + * Release video control + */ +void +release_video(void) +{ + size_t i; + while (crtc_count) + drm_crtc_close(&crtcs[--crtc_count]); + while (card_count) + drm_card_close(&cards[--card_count]); + while (framebuffer_count) + fb_close(&framebuffers[--framebuffer_count]); + for (i = 0; i < 3; i++) { + free(brightnesses[i]); + free(contrasts[i]); + free(gammas[i]); + brightnesses[i] = NULL; + contrasts[i] = NULL; + gammas[i] = NULL; + } + free(crtcs); + free(cards); + free(framebuffers); + crtcs = NULL; + cards = NULL; + framebuffers = NULL; +} |