├── .gitignore ├── LICENSE ├── Makefile ├── PKGBUILD ├── .SRCINFO ├── PKGBUILD ├── Predator-Sense-systemd-git.install └── makepkg.sh ├── README.md ├── facer_rgb.py ├── functions.js ├── index.html ├── install.sh ├── install_openrc.sh ├── install_service.sh ├── keyboard.webp ├── main.js ├── package-lock.json ├── package.json ├── preload.js ├── push.sh ├── refresh.sh ├── src └── facer.c ├── styles.css ├── uninstall.sh └── uninstall_service.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | .cproject 55 | .project 56 | .settings 57 | *~ 58 | core 59 | .depend 60 | .*.cmd 61 | *.mod 62 | *.mod.c 63 | .tmp_versions 64 | .vscode 65 | .idea 66 | command.txt 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | obj-m := src/facer.o 2 | 3 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 4 | PWD := $(shell pwd) 5 | 6 | all: default 7 | 8 | default: 9 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 10 | 11 | install: 12 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 13 | 14 | clean: 15 | rm -rf src/*.o src/*~ src/.*.cmd src/*.ko src/*.mod.c \ 16 | .tmp_versions modules.order Module.symvers 17 | 18 | dkmsclean: 19 | @dkms remove facer/0.1 --all || true 20 | @dkms remove facer/0.2 --all || true 21 | 22 | dkms: dkmsclean 23 | dkms add . 24 | dkms install -m facer -v 0.2 25 | 26 | onboot: 27 | echo "facer" > /etc/modules-load.d/facer.conf 28 | 29 | noboot: 30 | rm -f /etc/modules-load.d/facer.conf -------------------------------------------------------------------------------- /PKGBUILD/.SRCINFO: -------------------------------------------------------------------------------- 1 | pkgbase = Predator-Sense-systemd-git 2 | pkgdesc = The CLI implementation of Predator Sense for Acer Predator Helios laptops to control CPU/GPU fans and keyboard RGB color 3 | pkgver = 1.0 4 | pkgrel = 1 5 | url = https://github.com/JafarAkhondali/acer-predator-turbo-and-rgb-keyboard-linux-module 6 | install = Predator-Sense-systemd-git.install 7 | arch = any 8 | license = GPL3 9 | makedepends = gcc 10 | makedepends = make 11 | depends = linux-headers 12 | source = git+https://github.com/JafarAkhondali/acer-predator-turbo-and-rgb-keyboard-linux-module 13 | md5sums = SKIP 14 | 15 | pkgname = Predator-Sense-systemd-git 16 | -------------------------------------------------------------------------------- /PKGBUILD/PKGBUILD: -------------------------------------------------------------------------------- 1 | # 2 | # Maintainer: Mahmoud Mohamed (Ozil) , 3 | # 4 | 5 | pkgname=Predator-Sense-systemd-git 6 | pkgver=1.0 7 | pkgrel=1 8 | pkgdesc="The CLI implementation of Predator Sense for Acer Predator Helios laptops to control CPU/GPU fans and keyboard RGB color" 9 | arch=('any') 10 | url="https://github.com/JafarAkhondali/acer-predator-turbo-and-rgb-keyboard-linux-module" 11 | license=('GPL3') 12 | depends=('linux-headers') 13 | makedepends=('gcc' 'make') 14 | source=("git+$url") 15 | md5sums=('SKIP') 16 | install="${pkgname}.install" 17 | 18 | package() { 19 | 20 | cp -af ${srcdir}/acer-predator-turbo-and-rgb-keyboard-linux-module/* ${pkgdir} 21 | 22 | cd ${pkgdir} 23 | 24 | service=turbo-fan # Service name 25 | local target_dir=${pkgdir}/opt/turbo-fan # Instalation folder 26 | local service_dir=${pkgdir}/etc/systemd/system # Service setup folder (where all services are stored) 27 | service_start_delay=5 # Delay in seconds before the service starts. 28 | 29 | mkdir -p $target_dir 30 | mkdir -p $service_dir 31 | 32 | rsync -av ./* $target_dir --exclude=".git/*" 33 | 34 | cat << EOF > $service_dir/turbo-fan.service 35 | [Unit] 36 | Description = Enables turbo button 37 | After=sysinit.target 38 | StartLimitIntervalSec=5 39 | 40 | [Service] 41 | Type=simple 42 | Restart=no 43 | RemainAfterExit=yes 44 | User=root 45 | WorkingDirectory=/opt/turbo-fan 46 | ExecStart=/bin/bash ./install.sh 47 | ExecStop=/bin/bash ./uninstall.sh 48 | 49 | [Install] 50 | WantedBy=multi-user.target 51 | 52 | EOF 53 | 54 | chmod +x $target_dir/*.sh 55 | 56 | } 57 | -------------------------------------------------------------------------------- /PKGBUILD/Predator-Sense-systemd-git.install: -------------------------------------------------------------------------------- 1 | post_install() { 2 | 3 | echo '' 4 | echo '************************************************' 5 | echo '* *' 6 | echo '* enable service to use RGB/Turbo mode *' 7 | echo '* *' 8 | echo '* RUN these commands To enable service *' 9 | echo '* *' 10 | echo '* systemctl daemon-reload *' 11 | echo '* *' 12 | echo '* systemctl start turbo-fan *' 13 | echo '* *' 14 | echo '* systemctl enable turbo-fan *' 15 | echo '* *' 16 | echo '************************************************' 17 | 18 | } 19 | 20 | post_remove(){ 21 | 22 | echo '' 23 | echo '************************************************' 24 | echo '* *' 25 | echo '* Remove service to use RGB/Turbo mode *' 26 | echo '* *' 27 | echo '* RUN these commands To enable service *' 28 | echo '* *' 29 | echo '* systemctl stop turbo-fan *' 30 | echo '* *' 31 | echo '* systemctl disable turbo-fan *' 32 | echo '* *' 33 | echo '* systemctl daemon-reload *' 34 | echo '* *' 35 | echo '* sudo rm -rvf /opt/turbo-fan *' 36 | echo '* *' 37 | echo '************************************************' 38 | 39 | } 40 | -------------------------------------------------------------------------------- /PKGBUILD/makepkg.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2022 Mahmoud Mohamed (Ozil) 3 | # LICENSE © GNU-GPL3 4 | # 5 | 6 | 7 | # Script Termination 8 | exit_on_signal_SIGINT () { 9 | { printf "\n\n%s\n" "Script interrupted." 2>&1; echo; } 10 | exit 0 11 | } 12 | 13 | exit_on_signal_SIGTERM () { 14 | { printf "\n\n%s\n" "Script terminated." 2>&1; echo; } 15 | exit 0 16 | } 17 | 18 | trap exit_on_signal_SIGINT SIGINT 19 | trap exit_on_signal_SIGTERM SIGTERM 20 | 21 | # Build packages (create a binary package -> pkg.pkg.tar.zst) 22 | build_pkg () { 23 | echo -e "\nBuilding Package...... \n" 24 | makepkg -s 25 | 26 | rm -rf acer-predator-turbo-and-rgb-keyboard-linux-module src pkg 27 | } 28 | 29 | # Execute 30 | build_pkg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenSense v1 2 | 3 | ## Opening Note 4 | ### If anyone likes this sotware please help me out by creating an icon for this project. I would be needing it for the next build as I will be making this into a package. I'm targetting snap and deb. 5 | ### If you are capable of making an icon, then please reach out to me here on Github or mail at zehratullayl@gmail.com 6 | 7 | ## Open Source Linux Implementation of Acer PredatorSense 8 | Here is the Kernel Module GitHub Link 9 | ### Acer Predator RGB keyboard backlight and Turbo mode linux kernel module 10 | https://github.com/JafarAkhondali/acer-helios-300-rgb-keyboard-linux-module 11 | 12 | ## Installation Instructions for New Users 13 | Make sure you have nodejs, npm, and git installed. 14 | 1. `git clone https://github.com/zehratullayl/Linux-Predator-GUI.git` 15 | 2. `cd Linux-Predator-GUI/` 16 | 3. `sudo ./install.sh` 17 | 4. `sudo npm -g install electron` 18 | > :warning: If electron fails to install then run `sudo npm -g install electron --unsafe-perm=true` 19 | 5. `npm install` 20 | 21 | ## Installation Instructions for Existing Users 22 | Navigate to `Linux-Predator-GUI` folder 23 | 1. `git pull` 24 | 2. `npm install` 25 | 3. `sudo ./install.sh` 26 | 27 | ## Launch Instructions 28 | `electron .` 29 | > NOTE: If for some reason on reboot or boot your keyboard defaults to blue or the color is not responding to your selection or previous selections, please run `sudo ./install.sh` before running launch command or have a look at [Known bugs](#known-bugs) 30 | 31 | 32 | ## What's New In Version 1.0 33 | 1. Added RGB Color Selector along with sliders for selecting color 34 | 2. Added Persistence so your previous preferences load up on starting the application 35 | 3. Removed Apply Button, all changes are now updated live without any need to click Apply button 36 | 3. Added Brightness Control and Neon Mode. 37 | 4. Added Support for Directions in Wave Mode. 38 | 5. Bug Fixes 39 | 6. Updated Core Libraries to latest commits by [Jafar Akhondali](https://github.com/JafarAkhondali/acer-predator-turbo-and-rgb-keyboard-linux-module.git) 40 | 41 | ## Limitations of Version 1.0 42 | 1. Only Zoom, Breathe, Neon and Wave Modes available for now. Version 2.0 will be releasing next week with Static and Shifting Modes 43 | 44 | ## Upcoming Releases 45 | - [ ] New Icon 46 | > Please look at [Opening Note](#opening-note) 47 | - [ ] Snap and Deb packages 48 | - [ ] Light Mode Support 49 | - [ ] Profiles 50 | - [ ] Shift and Static Modes 51 | - [ ] Auto updating 52 | 53 | ## Known bugs 54 | ### If the keyboard color is not responding 55 | #### Solution 56 | 1. close the app 57 | 2. `sudo ./uninstall.sh` 58 | 3. `sudo rm /dev/acer-gkbbl-0` 59 | 4. `sudo ./install.sh` 60 | 61 | ### If installation is failing with something like 62 | > make[1]: *** /lib/modules/5.11.0-27-generic/build: No such file or directory. Stop. 63 | #### Solution 64 | For Debian Based Systems 65 | 1. `uname -r` 66 | 2. copy output of the command 67 | 3. `sudo apt-get install linux-headers-` 68 | 4. Proceed to installation Process 69 | 70 | For RPM Based Systems 71 | 1. `sudo dnf install kernel-devel kernel-headers` 72 | -------------------------------------------------------------------------------- /facer_rgb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import argparse 3 | import json 4 | from pathlib import Path 5 | 6 | PAYLOAD_SIZE = 16 7 | CHARACTER_DEVICE = "/dev/acer-gkbbl-0" 8 | 9 | PAYLOAD_SIZE_STATIC_MODE = 4 10 | CHARACTER_DEVICE_STATIC = "/dev/acer-gkbbl-static-0" 11 | 12 | CONFIG_DIRECTORY = str(Path.home()) + "/.config/predator/saved profiles" 13 | path = Path(CONFIG_DIRECTORY) 14 | path.mkdir(parents=True, exist_ok=True) 15 | 16 | parser = argparse.ArgumentParser(description=f"""Interacts with experimental Acer-wmi kernel module. 17 | -m [mode index] 18 | Effect modes: 19 | 0 -> Static [Accepts ZoneID[1,2,3,4] + RGB Color] 20 | 1 -> Breath [Accepts RGB color] 21 | 2 -> Neon 22 | 3 -> Wave 23 | 4 -> Shifting [Accepts RGB color] 24 | 5 -> Zoom [Accepts RGB color] 25 | 26 | -z [ZoneID] 27 | Zone ID(Only in static mode): 28 | Possible values: 1,2,3,4 29 | 30 | -s [speed] 31 | Animation Speed: 32 | 33 | 0 -> No animation speed (static) 34 | 1 -> Slowest animation speed 35 | 9 -> Fastest animation speed 36 | 37 | You can use values between 1-9 to adjust the speed, or increase speed even more than 255, but keep in mind 38 | that values higher than 9 were not used in official PredatorSense application. 39 | 40 | -b [brightness] 41 | Keyboard backlight Brightness: 42 | 43 | 0 -> No backlight (turned off) 44 | 100 -> Maximum backlight brightness 45 | 46 | -d [direction] 47 | Animation direction: 48 | 49 | 1 -> Right to Left 50 | 2 -> Left to Right 51 | 52 | -cR [red value] 53 | Some modes require specific [R]GB color 54 | 55 | 0 -> Minimum red range 56 | 255 -> Maximum red range 57 | 58 | -cG [green value] 59 | Some modes require specific R[G]B color 60 | 61 | 0 -> Minimum green range 62 | 255 -> Maximum green range 63 | 64 | -cB [blue value] 65 | Some modes require specific RG[B] color 66 | 67 | 0 -> Minimum blue range 68 | 255 -> Maximum blue range 69 | 70 | -save [profile name] 71 | Add as last argument to save to a profile 72 | 73 | -load [profile name] 74 | Loads the profile if it exists 75 | 76 | -list 77 | Lists all the saved profiles in config directory 78 | config directory is '{CONFIG_DIRECTORY}' 79 | 80 | Some sample commands: 81 | 82 | Breath effect with Purple color(speed=4, brightness=100): 83 | ./facer_rgb.py -m 1 -s 4 -b 100 -cR 255 -cG 0 -cB 255 84 | 85 | Neon effect(speed=3, brightness=100): 86 | ./facer_rgb.py -m 2 -s 3 -b 100 87 | 88 | Wave effect(speed=5, brightness=100): 89 | ./facer_rgb.py -m 3 -s 5 -b 100 90 | 91 | Shifting effect with Blue color (speed=5, brightness=100): 92 | ./facer_rgb.py -m 4 -s 5 -b 100 -cR 0 -cB 255 -cG 0 93 | 94 | Zoom effect with Green color (speed=7, brightness=100): 95 | ./facer_rgb.py -m 5 -s 7 -b 100 -cR 0 -cB 0 -cG 255 -save zoom 96 | 97 | Static waving (speed=0) and save it as example: 98 | ./facer_rgb.py -m 3 -s 0 -b 100 -save example 99 | 100 | Load the previously saved profile: 101 | ./facer_rgb.py -load example 102 | """, formatter_class=argparse.RawTextHelpFormatter) 103 | 104 | parser.add_argument('-m', 105 | type=int, 106 | dest='mode', 107 | default=3) 108 | 109 | parser.add_argument('-z', 110 | type=int, 111 | dest='zone', 112 | default=1) 113 | 114 | parser.add_argument('-s', 115 | type=int, 116 | dest='speed', 117 | default=4) 118 | 119 | parser.add_argument('-b', 120 | type=int, 121 | dest='brightness', 122 | default=100) 123 | 124 | parser.add_argument('-d', 125 | type=int, 126 | dest='direction', 127 | default=1) 128 | 129 | parser.add_argument('-cR', 130 | type=int, 131 | dest='red', 132 | default=50) 133 | 134 | parser.add_argument('-cG', 135 | type=int, 136 | dest='green', 137 | default=255) 138 | 139 | parser.add_argument('-cB', 140 | type=int, 141 | dest='blue', 142 | default=50) 143 | 144 | parser.add_argument('-save') 145 | 146 | parser.add_argument('-load') 147 | 148 | parser.add_argument('-list', 149 | action='store_true') 150 | 151 | args = parser.parse_args() 152 | 153 | if args.list: 154 | print("Saved profiles:") 155 | for filepath in list(path.glob('*.*')): print(f"\t{filepath.stem}") 156 | exit() 157 | 158 | if args.load: 159 | with open(f"{CONFIG_DIRECTORY}/{args.load}.json", 'rt') as f: 160 | t_args = argparse.Namespace() 161 | t_args.__dict__.update(json.load(f)) 162 | args = parser.parse_args(namespace=t_args) 163 | 164 | if args.save: 165 | with open(f"{CONFIG_DIRECTORY}/{args.save}.json", 'wt') as f: 166 | vars(args).pop('save') 167 | vars(args).pop('load') 168 | json.dump(vars(args), f, indent=4) 169 | 170 | if args.mode == 0: 171 | # Static coloring mode 172 | payload = [0] * PAYLOAD_SIZE_STATIC_MODE 173 | if args.zone < 1 or args.zone > 8: 174 | print("Invalid Zone ID entered! Possible values are: 1, 2, 3, 4 from left to right") 175 | payload[0] = 1 << (args.zone - 1) 176 | payload[1] = args.red 177 | payload[2] = args.green 178 | payload[3] = args.blue 179 | with open(CHARACTER_DEVICE_STATIC, 'wb') as cd: 180 | cd.write(bytes(payload)) 181 | 182 | # Tell WMI To use STATIC coloring 183 | # Dynamic coloring mode 184 | payload = [0] * PAYLOAD_SIZE 185 | payload[2] = args.brightness 186 | with open(CHARACTER_DEVICE, 'wb') as cd: 187 | cd.write(bytes(payload)) 188 | 189 | 190 | 191 | else: 192 | # Dynamic coloring mode 193 | payload = [0] * PAYLOAD_SIZE 194 | payload[0] = args.mode 195 | payload[1] = args.speed 196 | payload[2] = args.brightness 197 | payload[3] = 8 if args.mode == 3 else 0 198 | payload[4] = args.direction 199 | payload[5] = args.red 200 | payload[6] = args.green 201 | payload[7] = args.blue 202 | 203 | with open(CHARACTER_DEVICE, 'wb') as cd: 204 | cd.write(bytes(payload)) 205 | -------------------------------------------------------------------------------- /functions.js: -------------------------------------------------------------------------------- 1 | var c, 2 | s, 3 | b, 4 | d = 1; 5 | 6 | function rightToLeft() { 7 | d = 2; 8 | func("apply"); 9 | document.getElementById("left").style.color = "mediumseagreen"; 10 | document.getElementById("right").style.color = "rgba(0, 0, 0, 0.19)"; 11 | } 12 | 13 | function leftToRight() { 14 | d = 1; 15 | func("apply"); 16 | document.getElementById("right").style.color = "mediumseagreen"; 17 | document.getElementById("left").style.color = "rgba(0, 0, 0, 0.19)"; 18 | } 19 | var SpeedSlider1 = document.querySelector("input[id=speed1]"); 20 | SpeedSlider1.oninput = (_) => { 21 | s = "ss1"; 22 | }; 23 | var SpeedSlider2 = document.querySelector("input[id=speed2]"); 24 | SpeedSlider2.oninput = (_) => { 25 | s = "ss2"; 26 | }; 27 | var SpeedSlider3 = document.querySelector("input[id=speed3]"); 28 | SpeedSlider3.oninput = (_) => { 29 | s = "ss3"; 30 | }; 31 | var SpeedSlider4 = document.querySelector("input[id=speed4]"); 32 | SpeedSlider4.oninput = (_) => { 33 | s = "ss4"; 34 | }; 35 | function send_command(m, s, b, r, g, bl) { 36 | var command = "python3 facer_rgb.py"; 37 | command += 38 | " -m " + 39 | m + 40 | " -s " + 41 | s + 42 | " -b " + 43 | b + 44 | // " -d " + 45 | // d + 46 | " -cR " + 47 | r + 48 | " -cG " + 49 | g + 50 | " -cB " + 51 | bl; 52 | window.api.send("toMain", command); 53 | } 54 | 55 | function select_color(val) { 56 | var hex = document.getElementById("rec" + val).value; 57 | //#123456 58 | var hex_r = hex.substring(1, 3), 59 | hex_g = hex.substring(3, 5), 60 | hex_b = hex.substring(5, 7); 61 | if (val == 1) { 62 | var slider1 = document.querySelector("input[id=red1]"); 63 | var slider2 = document.querySelector("input[id=green1]"); 64 | var slider3 = document.querySelector("input[id=blue1]"); 65 | slider1.value = parseInt(hex_r, 16); 66 | slider2.value = parseInt(hex_g, 16); 67 | slider3.value = parseInt(hex_b, 16); 68 | } else { 69 | var slider4 = document.querySelector("input[id=red2]"); 70 | var slider5 = document.querySelector("input[id=green2]"); 71 | var slider6 = document.querySelector("input[id=blue2]"); 72 | slider4.value = parseInt(hex_r, 16); 73 | slider5.value = parseInt(hex_g, 16); 74 | slider6.value = parseInt(hex_b, 16); 75 | } 76 | func("apply"); 77 | } 78 | 79 | function send_command2(m, s, b) { 80 | var command = "python3 facer_rgb.py"; 81 | command += " -m " + m + " -s " + s + " -b " + b + " -d " + d; 82 | window.api.send("toMain", command); 83 | } 84 | var Slider1 = document.querySelector("input[id=red1]"); 85 | Slider1.style.setProperty("--SliderColor1", `rgb(0, 0, 0)`); 86 | Slider1.oninput = (_) => { 87 | Slider1.style.setProperty("--SliderColor1", `rgb(${Slider1.value}, 0, 0)`); 88 | document.getElementById("rec1").value = 89 | "#" + 90 | Math.abs(parseInt(Slider1.value)).toString(16) + 91 | Math.abs(parseInt(Slider2.value)).toString(16) + 92 | Math.abs(parseInt(Slider3.value)).toString(16); 93 | // "rgb(" + Slider1.value + "," + Slider2.value + "," + Slider3.value + ")"; 94 | // var xy = document.getElementById("radio1").checked; 95 | // console.log(xy); 96 | // send_command(c,) 97 | }; 98 | 99 | var Slider2 = document.querySelector("input[id=green1]"); 100 | Slider2.style.setProperty("--SliderColor2", `rgb(0, 0, 0)`); 101 | Slider2.oninput = (_) => { 102 | Slider2.style.setProperty("--SliderColor2", `rgb(0, ${Slider2.value}, 0)`); 103 | document.getElementById("rec1").value = 104 | "#" + 105 | Math.abs(parseInt(Slider1.value)).toString(16) + 106 | Math.abs(parseInt(Slider2.value)).toString(16) + 107 | Math.abs(parseInt(Slider3.value)).toString(16); 108 | // "rgb(" + Slider1.value + "," + Slider2.value + "," + Slider3.value + ")"; 109 | }; 110 | var Slider3 = document.querySelector("input[id=blue1]"); 111 | Slider3.style.setProperty("--SliderColor3", `rgb(0, 0, 0)`); 112 | Slider3.oninput = (_) => { 113 | document.getElementById("rec1").value = 114 | "#" + 115 | Math.abs(parseInt(Slider1.value)).toString(16) + 116 | Math.abs(parseInt(Slider2.value)).toString(16) + 117 | Math.abs(parseInt(Slider3.value)).toString(16); 118 | // "rgb(" + Slider1.value + "," + Slider2.value + "," + Slider3.value + ")"; 119 | Slider2.style.setProperty("--SliderColor2", `rgb(0, ${Slider2.value}, 0)`); 120 | }; 121 | var Slider4 = document.querySelector("input[id=red2]"); 122 | Slider4.style.setProperty("--SliderColor1", `rgb(0, 0, 0)`); 123 | Slider4.oninput = (_) => { 124 | Slider4.style.setProperty("--SliderColor1", `rgb(${Slider4.value}, 0, 0)`); 125 | document.getElementById("rec2").value = 126 | "#" + 127 | Math.abs(parseInt(Slider4.value)).toString(16) + 128 | Math.abs(parseInt(Slider5.value)).toString(16) + 129 | Math.abs(parseInt(Slider6.value)).toString(16); 130 | // "rgb(" + Slider4.value + "," + Slider5.value + "," + Slider6.value + ")"; 131 | }; 132 | 133 | var Slider5 = document.querySelector("input[id=green2]"); 134 | Slider5.style.setProperty("--SliderColor2", `rgb(0, 0, 0)`); 135 | Slider5.oninput = (_) => { 136 | Slider5.style.setProperty("--SliderColor2", `rgb(0, ${Slider5.value}, 0)`); 137 | document.getElementById("rec2").value = 138 | "#" + 139 | Math.abs(parseInt(Slider4.value)).toString(16) + 140 | Math.abs(parseInt(Slider5.value)).toString(16) + 141 | Math.abs(parseInt(Slider6.value)).toString(16); 142 | // "rgb(" + Slider4.value + "," + Slider5.value + "," + Slider6.value + ")"; 143 | }; 144 | var Slider6 = document.querySelector("input[id=blue2]"); 145 | Slider6.style.setProperty("--SliderColor3", `rgb(0, 0, 0)`); 146 | Slider6.oninput = (_) => { 147 | Slider6.style.setProperty("--SliderColor3", `rgb(0, 0, ${Slider6.value})`); 148 | document.getElementById("rec2").value = 149 | "#" + 150 | Math.abs(parseInt(Slider4.value)).toString(16) + 151 | Math.abs(parseInt(Slider5.value)).toString(16) + 152 | Math.abs(parseInt(Slider6.value)).toString(16); 153 | // "rgb(" + Slider4.value + "," + Slider5.value + "," + Slider6.value + ")"; 154 | }; 155 | 156 | document.getElementById("sl1").style.display = "none"; 157 | document.getElementById("sl2").style.display = "none"; 158 | document.getElementById("sl3").style.display = "none"; 159 | document.getElementById("sl4").style.display = "none"; 160 | document.getElementById("back").style.display = "none"; 161 | var clicked = 0; 162 | function func(arg) { 163 | // func("apply"); 164 | // b = document.getElementById("brightness1").value; 165 | // window.api.send("toMain", x); 166 | var c1, c2; 167 | var slider; 168 | if (arg == "zoom") { 169 | document.getElementById("direction").style.display = "none"; 170 | c = "mediumseagreen2"; 171 | c1 = "mediumseagreen"; 172 | c2 = "mediumseagreen3"; 173 | c3 = "mediumseagreen4"; 174 | slider = "sl1"; 175 | } else if (arg == "breathe") { 176 | document.getElementById("direction").style.display = "none"; 177 | c = "mediumseagreen"; 178 | c1 = "mediumseagreen2"; 179 | c2 = "mediumseagreen3"; 180 | c3 = "mediumseagreen4"; 181 | slider = "sl2"; 182 | } else if (arg == "wave") { 183 | document.getElementById("direction").style.display = "block"; 184 | slider = "sl3"; 185 | c = "mediumseagreen3"; 186 | c1 = "mediumseagreen"; 187 | c2 = "mediumseagreen2"; 188 | c3 = "mediumseagreen4"; 189 | } else if (arg == "neon") { 190 | document.getElementById("direction").style.display = "none"; 191 | slider = "sl4"; 192 | c = "mediumseagreen4"; 193 | c1 = "mediumseagreen2"; 194 | c2 = "mediumseagreen3"; 195 | c3 = "mediumseagreen"; 196 | } else if (arg == "back") { 197 | document.getElementById("direction").style.display = "none"; 198 | var style_1 = document.querySelector("." + "mediumseagreen").style; 199 | var style1_1 = document.querySelector("." + "mediumseagreen2").style; 200 | var style2_1 = document.querySelector("." + "mediumseagreen3").style; 201 | var style3_1 = document.querySelector("." + "mediumseagreen4").style; 202 | style_1.setProperty("--background", "transparent"); 203 | style1_1.setProperty("--background", "transparent"); 204 | style2_1.setProperty("--background", "transparent"); 205 | style3_1.setProperty("--background", "transparent"); 206 | style_1.display = "block"; 207 | style1_1.display = "block"; 208 | style2_1.display = "block"; 209 | style3_1.display = "block"; 210 | clicked = 0; 211 | document.getElementById("sl1").style.display = "none"; 212 | document.getElementById("sl2").style.display = "none"; 213 | document.getElementById("sl3").style.display = "none"; 214 | document.getElementById("sl4").style.display = "none"; 215 | document.getElementById("back").style.display = "none"; 216 | } 217 | console.log(arg); 218 | if (arg != "apply" && arg != "back") { 219 | document.getElementById("back").style.display = "block"; 220 | var style = document.querySelector("." + c).style; 221 | var style1 = document.querySelector("." + c1).style; 222 | var style2 = document.querySelector("." + c2).style; 223 | var style3 = document.querySelector("." + c3).style; 224 | var button = document.getElementById(arg); 225 | if (clicked == 0) { 226 | clicked = 1; 227 | style.setProperty("--background", "rgb(30, 136, 78)"); 228 | // style.display = "block"; 229 | style1.display = "none"; 230 | style2.display = "none"; 231 | style3.display = "none"; 232 | var x = document.getElementById(slider); 233 | if (x.style.display === "none") { 234 | x.style.display = "block"; 235 | } else { 236 | x.style.display = "none"; 237 | } 238 | // style2.setProperty("--background", transparent); 239 | } 240 | // else { 241 | // clicked = 0; 242 | // style.setProperty("--background", "transparent"); 243 | // // style.display = "block"; 244 | // // document.getElementById("back").style.display = "none"; 245 | // style1.display = "block"; 246 | // style2.display = "block"; 247 | // } 248 | } else if (arg == "apply" && arg != "back") { 249 | var cR, cG, cB; 250 | var m; 251 | if (c == "mediumseagreen2") { 252 | m = 5; 253 | cR = "red1"; 254 | cG = "green1"; 255 | cB = "blue1"; 256 | b = document.getElementById("brightness1").value; 257 | } else if (c == "mediumseagreen") { 258 | m = 1; 259 | cR = "red2"; 260 | cG = "green2"; 261 | cB = "blue2"; 262 | b = document.getElementById("brightness2").value; 263 | } else if (c == "mediumseagreen3") { 264 | m = 3; 265 | b = document.getElementById("brightness3").value; 266 | } else if (c == "mediumseagreen4") { 267 | m = 2; 268 | b = document.getElementById("brightness4").value; 269 | } 270 | if (s == "ss1") { 271 | s = SpeedSlider1.value; 272 | } else if (s == "ss2") { 273 | s = SpeedSlider2.value; 274 | } else if (s == "ss3") { 275 | s = SpeedSlider3.value; 276 | } else if (s == "ss4") { 277 | s = SpeedSlider4.value; 278 | } 279 | // var d; 280 | // var r2l = document.getElementById("radio1").checked; 281 | // if (r2l == true) { 282 | // d = 1; 283 | // } else { 284 | // d = 2; 285 | // } 286 | // if() 287 | console.log(b); 288 | if (m == 3 || m == 2) { 289 | send_command2(m, s, b, 100); 290 | } else { 291 | send_command( 292 | m, 293 | s, 294 | b, 295 | // d, 296 | document.getElementById(cR).value, 297 | document.getElementById(cG).value, 298 | document.getElementById(cB).value, 299 | ); 300 | } 301 | } 302 | } 303 | 304 | window.api.receive("fromMain", (data) => { 305 | console.log(data); 306 | if (typeof data.s == "undefined") s = 9; 307 | else s = data.s; 308 | if (typeof data.b == "undefined") b = 99; 309 | else b = data.b; 310 | b = data.b; 311 | d = data.d; 312 | if (data.cB) { 313 | if (data.m == 5) { 314 | document.getElementById("red1").value = data.cR; 315 | document.getElementById("green1").value = data.cG; 316 | document.getElementById("blue1").value = data.cB; 317 | document.getElementById("brightness1").value = data.b; 318 | document.getElementById("speed1").value = data.s; 319 | } else if (data.m == 1) { 320 | document.getElementById("red2").value = data.cR; 321 | document.getElementById("green2").value = data.cG; 322 | document.getElementById("blue2").value = data.cB; 323 | document.getElementById("brightness2").value = data.b; 324 | document.getElementById("speed2").value = data.s; 325 | } 326 | } else { 327 | document.getElementById("speed3").value = data.s; 328 | document.getElementById("brightness3").value = data.b; 329 | if (data.d == 1) { 330 | document.getElementById("right").style.color = "mediumseagreen"; 331 | document.getElementById("left").style.color = "rgba(0, 0, 0, 0.19)"; 332 | } else { 333 | document.getElementById("left").style.color = "mediumseagreen"; 334 | document.getElementById("right").style.color = "rgba(0, 0, 0, 0.19)"; 335 | } 336 | } 337 | try { 338 | Slider1.style.setProperty("--SliderColor1", `rgb(${Slider1.value}, 0, 0)`); 339 | document.getElementById("rec1").value = 340 | "#" + 341 | Math.abs(parseInt(Slider1.value)).toString(16) + 342 | Math.abs(parseInt(Slider2.value)).toString(16) + 343 | Math.abs(parseInt(Slider3.value)).toString(16); 344 | // "rgb(" + Slider1.value + "," + Slider2.value + "," + Slider3.value + ")"; 345 | } catch (e) {} 346 | try { 347 | Slider2.style.setProperty("--SliderColor2", `rgb(0, ${Slider2.value}, 0)`); 348 | document.getElementById("rec1").value = 349 | "#" + 350 | Math.abs(parseInt(Slider1.value)).toString(16) + 351 | Math.abs(parseInt(Slider2.value)).toString(16) + 352 | Math.abs(parseInt(Slider3.value)).toString(16); 353 | // "rgb(" + Slider1.value + "," + Slider2.value + "," + Slider3.value + ")"; 354 | } catch (e) {} 355 | try { 356 | document.getElementById("rec1").value = 357 | "#" + 358 | Math.abs(parseInt(Slider1.value)).toString(16) + 359 | Math.abs(parseInt(Slider2.value)).toString(16) + 360 | Math.abs(parseInt(Slider3.value)).toString(16); 361 | // "rgb(" + Slider1.value + "," + Slider2.value + "," + Slider3.value + ")"; 362 | Slider2.style.setProperty("--SliderColor2", `rgb(0, ${Slider2.value}, 0)`); 363 | } catch (e) {} 364 | try { 365 | Slider4.style.setProperty("--SliderColor1", `rgb(${Slider4.value}, 0, 0)`); 366 | document.getElementById("rec2").value = 367 | "#" + 368 | Math.abs(parseInt(Slider4.value)).toString(16) + 369 | Math.abs(parseInt(Slider5.value)).toString(16) + 370 | Math.abs(parseInt(Slider6.value)).toString(16); 371 | // "rgb(" + Slider4.value + "," + Slider5.value + "," + Slider6.value + ")"; 372 | } catch (e) {} 373 | try { 374 | Slider5.style.setProperty("--SliderColor2", `rgb(0, ${Slider5.value}, 0)`); 375 | document.getElementById("rec2").value = 376 | "#" + 377 | Math.abs(parseInt(Slider4.value)).toString(16) + 378 | Math.abs(parseInt(Slider5.value)).toString(16) + 379 | Math.abs(parseInt(Slider6.value)).toString(16); 380 | // "rgb(" + Slider4.value + "," + Slider5.value + "," + Slider6.value + ")"; 381 | } catch (e) {} 382 | try { 383 | Slider6.style.setProperty("--SliderColor3", `rgb(0, 0, ${Slider6.value})`); 384 | document.getElementById("rec2").value = 385 | "#" + 386 | Math.abs(parseInt(Slider4.value)).toString(16) + 387 | Math.abs(parseInt(Slider5.value)).toString(16) + 388 | Math.abs(parseInt(Slider6.value)).toString(16); 389 | // "rgb(" + Slider4.value + "," + Slider5.value + "," + Slider6.value + ")"; 390 | } catch (e) {} 391 | }); 392 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | OpenSense v1.0 9 | 10 | 11 | 12 | Zoom 15 |
16 | 26 |
27 |
28 | 29 | 38 | 39 | 48 | 49 | 58 | 59 | 68 | 69 | 78 |

79 | 80 | 84 | 85 | 86 | 87 |
88 | Breathe 95 |
96 | 106 |
107 |
108 | 109 | 118 | 119 | 128 | 129 | 138 | 139 | 148 | 149 | 158 |

159 | 160 | 164 | 165 |
166 | Wave 169 |
170 |
171 |
172 | 173 | 182 | 183 | 192 |
193 | 208 | 209 | Neon 212 |
213 |
214 |
215 | 216 | 225 | 226 | 235 |
236 | 237 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $EUID -ne 0 ]]; then 4 | echo "[*] This script must be run as root" 5 | exit 1 6 | fi 7 | 8 | if [[ -f "/sys/bus/wmi/devices/7A4DDFE7-5B5D-40B4-8595-4408E0CC7F56/" ]]; then 9 | echo "[*] Sorry but your device doesn't have the required WMI module" 10 | exit 1 11 | fi 12 | 13 | # Remove previous chr devices if any exists 14 | rm /dev/acer-gkbbl-0 /dev/acer-gkbbl-static-0 -f 15 | 16 | # compile the kernel module 17 | make 18 | 19 | # remove previous acer_wmi module 20 | rmmod acer_wmi 21 | 22 | # install required modules 23 | modprobe wmi 24 | modprobe sparse-keymap 25 | modprobe video 26 | 27 | # install facer module 28 | insmod src/facer.ko 29 | dmesg | tail -n 10 30 | echo "[*] Done" -------------------------------------------------------------------------------- /install_openrc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script can install or uninstall acer turbo fan service. It means, that your turbo fan button still will be available even after rebooting. 3 | # To install service just run this script as the root (sudo) user. 4 | # After installation you can manage it as a usual service manually. Example: 'systemctl start/stop turbo-fan', 'systemctl enable/disable turbo-fan' 5 | # To uninstall service, run this script with 'remove' argument. Example: 'sudo bash ./install_service.sh remove'. 6 | # Note!!! Before removing, don't forget to switch off the turbo button because you will have forever turbo fan :) 7 | mode=${1:-install} # Allowed modes: "install" and "remove". Default: install. 8 | service=turbo-fan # Service name 9 | target_dir=/opt/turbo-fan # Instalation folder 10 | service_dir=/etc/init.d/ # Service setup folder (where all services are stored) 11 | 12 | make 13 | 14 | echo "[Mode: $mode]"; 15 | 16 | # Sudo check 17 | if [[ $(id -u) -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi 18 | 19 | # Check systemctl is installed 20 | if [[ -z "$(whereis rc-service | sed 's/systemctl: //')" ]]; then echo "rc-service is not installed! If you aren't using openrc or aren't sure, use install_service.sh instead!"; exit 1; fi 21 | # Check rsync is installed 22 | if [[ -z "$(whereis rsync | sed 's/rsync: //')" ]]; then echo "rsync is not installed"; exit 1; fi 23 | 24 | if [[ "$mode" == "install" || "$mode" == "remove" ]]; then 25 | # Check service is presented and remove if yes. 26 | if [[ "$(rc-update | grep $service)" ]]; then 27 | echo "['$service' service is presented. Remove it.]"; 28 | rc-service $service stop; 29 | rc-service del $service default; 30 | rm $service_dir/turbo-fan 31 | fi 32 | 33 | # Remove old files 34 | echo "[Remove old data]"; 35 | rm -rvf $target_dir; 36 | fi; 37 | 38 | if [[ "$mode" == "install" ]] 39 | then 40 | echo "[Create directories]"; 41 | mkdir -p $target_dir 42 | 43 | echo "[Copy new data]"; 44 | rsync -av ./* $target_dir --exclude=".git/*" 45 | 46 | echo "[Create turbo-fan service]" 47 | cat << EOF > $service_dir/turbo-fan 48 | #!/sbin/openrc-run 49 | depend() { 50 | after bootmisc consolefont modules netmount 51 | after quota keymaps 52 | after elogind 53 | use dbus xfs 54 | } 55 | 56 | start() { 57 | local EXE NAME PIDFILE AUTOCLEAN_CGROUP 58 | /sbin/rmmod acer_wmi 59 | /sbin/modprobe wmi 60 | /sbin/modprobe sparse-keymap 61 | /sbin/modprobe video 62 | /sbin/insmod $target_dir/src/facer.ko 63 | # You can also just make it launch $target_dir/install.sh by uncommenting the line below and removing everything starting from /sbin/rmmod acer_wmi to /sbin/insmod 64 | # /bin/bash $target_dir/src/facer.ko 65 | } 66 | 67 | stop() { 68 | /sbin/rmmod facer 69 | } 70 | 71 | # vim: set ts=4 : 72 | EOF 73 | chmod +x $service_dir/turbo-fan 74 | rc-update add $service default 75 | rc-service $service start 76 | fi 77 | -------------------------------------------------------------------------------- /install_service.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script can install or uninstall acer turbo fan service. It means, that your turbo fan button still will be available even after rebooting. 3 | # To install service just run this script as the root (sudo) user. 4 | # After installation you can manage it as a usual service manually. Example: 'systemctl start/stop turbo-fan', 'systemctl enable/disable turbo-fan' 5 | # To uninstall service, run this script with 'remove' argument. Example: 'sudo bash ./install_service.sh remove'. 6 | # Note!!! Before removing, don't forget to switch off the turbo button because you will have forever turbo fan :) 7 | mode=${1:-install} # Allowed modes: "install" and "remove". Default: install. 8 | service=turbo-fan # Service name 9 | target_dir=/opt/turbo-fan # Instalation folder 10 | service_dir=/etc/systemd/system # Service setup folder (where all services are stored) 11 | service_start_delay=5 # Delay in seconds before the service starts. 12 | 13 | echo "[Mode: $mode]"; 14 | 15 | # Sudo check 16 | if [[ $(id -u) -ne 0 ]] ; then echo "Please run as root" ; exit 1 ; fi 17 | 18 | # Check systemctl is installed 19 | if [[ -z "$(whereis systemctl | sed 's/systemctl: //')" ]]; then echo "systemctl is not installed"; exit 1; fi 20 | # Check rsync is installed 21 | if [[ -z "$(whereis rsync | sed 's/rsync: //')" ]]; then echo "rsync is not installed"; exit 1; fi 22 | 23 | if [[ "$mode" == "install" || "$mode" == "remove" ]]; then 24 | # Check service is presented and remove if yes. 25 | if [[ "$(systemctl --type=service | grep $service)" ]]; then 26 | echo "['$service' service is presented. Remove it.]"; 27 | systemctl stop $service; 28 | systemctl disable $service; 29 | rm $service_dir/turbo-fan.service 30 | systemctl daemon-reload 31 | fi 32 | 33 | # Remove old files 34 | echo "[Remove old data]"; 35 | rm -rvf $target_dir; 36 | fi; 37 | 38 | if [[ "$mode" == "install" ]] 39 | then 40 | echo "[Create directories]"; 41 | mkdir -p $target_dir 42 | 43 | echo "[Copy new data]"; 44 | rsync -av ./* $target_dir --exclude=".git/*" 45 | 46 | echo "[Create turbo-fan service]" 47 | cat << EOF > $service_dir/turbo-fan.service 48 | [Unit] 49 | Description = Enables turbo button 50 | After=sysinit.target 51 | StartLimitIntervalSec=$service_start_delay 52 | 53 | [Service] 54 | Type=simple 55 | Restart=no 56 | RemainAfterExit=yes 57 | User=root 58 | WorkingDirectory=$target_dir 59 | ExecStart=/bin/bash ./install.sh 60 | ExecStop=/bin/bash ./uninstall.sh 61 | 62 | [Install] 63 | WantedBy=multi-user.target 64 | EOF 65 | 66 | systemctl daemon-reload 67 | systemctl start $service 68 | systemctl enable $service 69 | fi -------------------------------------------------------------------------------- /keyboard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zehratullayl/Linux-Predator-GUI/f91d3d6b4bd6a39a6acf3cdcf69801460d7a943f/keyboard.webp -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow, ipcMain } = require("electron"); 2 | const path = require("path"); 3 | const fs = require("fs"); 4 | var exec = require("child_process").exec; 5 | 6 | // Keep a global reference of the window object, if you don't, the window will 7 | // be closed automatically when the JavaScript object is garbage collected. 8 | let win; 9 | 10 | async function createWindow() { 11 | // Create the browser window. 12 | win = new BrowserWindow({ 13 | autoHideMenuBar: true, 14 | resizable: false, 15 | width: 800, 16 | height: 800, 17 | webPreferences: { 18 | nodeIntegration: false, // is default value after Electron v5 19 | contextIsolation: true, // protect against prototype pollution 20 | enableRemoteModule: false, // turn off remote 21 | preload: path.join(__dirname, "preload.js"), // use a preload script 22 | }, 23 | }); 24 | 25 | // Load app 26 | win.loadFile(path.join(__dirname, "index.html")); 27 | const path2 = "./command.txt"; 28 | try { 29 | if (fs.existsSync(path2)) { 30 | const data = fs.readFileSync("./command.txt", { 31 | encoding: "utf8", 32 | flag: "r", 33 | }); 34 | dir = exec(data, function (err, stdout, stderr) { 35 | if (err) { 36 | // should have err.code here? 37 | } 38 | console.log(stdout); 39 | var m = 0, 40 | s = 0, 41 | b = 0, 42 | d = 0, 43 | cR = 0, 44 | cG = 0, 45 | cB = 0; 46 | if (data.includes("cB")) { 47 | var dashes = []; 48 | for (var i = 0; i < data.length; i++) { 49 | if (data.charAt(i) == "-") { 50 | dashes.push(i); 51 | } 52 | } 53 | m = parseInt(data.substring(data.indexOf("m") + 1, dashes[1] - 1)); 54 | s = parseInt(data.substring(data.indexOf("s") + 1, dashes[2] - 1)); 55 | b = parseInt(data.substring(data.indexOf("-b") + 3, dashes[3] - 1)); 56 | cR = parseInt(data.substring(data.indexOf("R") + 1, dashes[4] - 1)); 57 | cG = parseInt(data.substring(data.indexOf("G") + 1, dashes[5] - 1)); 58 | cB = parseInt(data.substring(data.indexOf("B") + 1, data.length)); 59 | console.log(m, s, b, cR, cG, cB); 60 | win.webContents.send("fromMain", { 61 | m: m, 62 | s: s, 63 | b: b, 64 | cR: cR, 65 | cG: cG, 66 | cB: cB, 67 | }); 68 | } else { 69 | var dashes = []; 70 | for (var i = 0; i < data.length; i++) { 71 | if (data.charAt(i) == "-") { 72 | dashes.push(i); 73 | } 74 | } 75 | m = parseInt(data.substring(data.indexOf("m") + 1, dashes[1] - 1)); 76 | s = parseInt(data.substring(data.indexOf("s") + 1, dashes[2] - 1)); 77 | b = parseInt(data.substring(data.indexOf("-b") + 3, dashes[3] - 1)); 78 | d = parseInt(data.substring(data.indexOf("d") + 1, data.length)); 79 | console.log(m, s, b, d); 80 | win.webContents.send("fromMain", { m: m, s: s, b: b, d: d }); 81 | } 82 | }); 83 | //file exists 84 | } 85 | } catch (err) { 86 | console.error(err); 87 | } 88 | 89 | // rest of code.. 90 | } 91 | 92 | app.on("ready", createWindow); 93 | 94 | ipcMain.on("toMain", (event, args) => { 95 | console.log(args); 96 | dir = exec(args, function (err, stdout, stderr) { 97 | if (err) { 98 | // should have err.code here? 99 | } 100 | console.log(stdout); 101 | fs.writeFileSync("command.txt", args); 102 | }); 103 | dir.on("exit", function (code) { 104 | // exit code is code 105 | }); 106 | fs.readFile("install.sh", (error, data) => { 107 | // Do something with file contents 108 | // Send result back to renderer process 109 | // win.webContents.send("fromMain", "Hello"); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linux-predator-gui", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "linux-predator-gui", 9 | "version": "1.0.0", 10 | "license": "ISC" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linux-predator-gui", 3 | "version": "1.0.0", 4 | "description": "Linux GUI App for https://github.com/JafarAkhondali/acer-helios-300-rgb-keyboard-linux-module", 5 | "main": "main.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/zehratullayl/Linux-Predator-GUI.git" 12 | }, 13 | "author": "Zehra Tul Layl", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/zehratullayl/Linux-Predator-GUI/issues" 17 | }, 18 | "homepage": "https://github.com/zehratullayl/Linux-Predator-GUI#readme" 19 | } 20 | -------------------------------------------------------------------------------- /preload.js: -------------------------------------------------------------------------------- 1 | const { contextBridge, ipcRenderer } = require("electron"); 2 | 3 | // Expose protected methods that allow the renderer process to use 4 | // the ipcRenderer without exposing the entire object 5 | contextBridge.exposeInMainWorld("api", { 6 | send: (channel, data) => { 7 | // whitelist channels 8 | let validChannels = ["toMain"]; 9 | if (validChannels.includes(channel)) { 10 | ipcRenderer.send(channel, data); 11 | } 12 | }, 13 | receive: (channel, func) => { 14 | let validChannels = ["fromMain"]; 15 | if (validChannels.includes(channel)) { 16 | // Deliberately strip event as it includes `sender` 17 | ipcRenderer.on(channel, (event, ...args) => func(...args)); 18 | } 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright (C) 2022 Mahmoud Mohamed (Ozil) 5 | # LICENSE © GNU-GPL3 6 | # 7 | 8 | # 9 | # you can run script with 2 arguments (your commit comment) 10 | # ./push.sh -m "yourCommit" 11 | # 12 | 13 | # a simple script to push your commits to GitHub # 14 | 15 | echo -e "\e[0;35m############################# \e[0m" 16 | echo -e "\e[0;35m# Git Push Script # \e[0m" 17 | echo -e "\e[0;35m############################# \e[0m" 18 | 19 | # get branch name (e.g master, main, etc... ) # 20 | Branch=$(git branch --show-current) 21 | 22 | # get new updates if it founded # 23 | echo "" 24 | echo "#################" 25 | echo "# Updating Repo #" 26 | echo "#################" 27 | git pull 28 | 29 | 30 | echo "" 31 | echo "##################################" 32 | echo "# Adding new changes to the repo #" 33 | echo "##################################" 34 | git add --all . 35 | 36 | if [ "$1" == "-m" ]; 37 | then 38 | # commit changes# 39 | echo "" 40 | git commit -m "$2" 41 | else 42 | # read commit comment from user # 43 | echo "" 44 | echo "##################################" 45 | echo "# Write your commit comment! :- #" 46 | read yourCommit 47 | 48 | # commit changes# 49 | echo "" 50 | git commit -m "$yourCommit" 51 | fi 52 | 53 | # push to repo # 54 | echo "" 55 | git push -u origin $Branch 56 | 57 | echo "" 58 | echo -e "\e[0;35m########################### \e[0m" 59 | echo -e "\e[0;35m# D O N E # \e[0m" 60 | echo -e "\e[0;35m########################### \e[0m" 61 | 62 | -------------------------------------------------------------------------------- /refresh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rmmod facer 3 | make 4 | insmod src/facer.ko 5 | dmesg | tail -n 30 6 | -------------------------------------------------------------------------------- /src/facer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Acer WMI Laptop Extras 4 | * 5 | * Copyright (C) 2007-2009 Carlos Corbacho 6 | * 7 | * Based on acer_acpi: 8 | * Copyright (C) 2005-2007 E.M. Smith 9 | * Copyright (C) 2007-2008 Carlos Corbacho 10 | */ 11 | 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | MODULE_AUTHOR("Carlos Corbacho"); 36 | MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 37 | MODULE_LICENSE("GPL"); 38 | 39 | 40 | /* 41 | * Magic Number 42 | * Meaning is unknown - this number is required for writing to ACPI for AMW0 43 | * (it's also used in acerhk when directly accessing the BIOS) 44 | */ 45 | #define ACER_AMW0_WRITE 0x9610 46 | 47 | /* 48 | * Bit masks for the AMW0 interface 49 | */ 50 | #define ACER_AMW0_WIRELESS_MASK 0x35 51 | #define ACER_AMW0_BLUETOOTH_MASK 0x34 52 | #define ACER_AMW0_MAILLED_MASK 0x31 53 | 54 | /* 55 | * Method IDs for WMID interface 56 | */ 57 | #define ACER_WMID_GET_WIRELESS_METHODID 1 58 | #define ACER_WMID_GET_BLUETOOTH_METHODID 2 59 | #define ACER_WMID_GET_BRIGHTNESS_METHODID 3 60 | #define ACER_WMID_SET_WIRELESS_METHODID 4 61 | #define ACER_WMID_SET_BLUETOOTH_METHODID 5 62 | #define ACER_WMID_SET_BRIGHTNESS_METHODID 6 63 | #define ACER_WMID_GET_THREEG_METHODID 10 64 | #define ACER_WMID_SET_THREEG_METHODID 11 65 | #define ACER_WMID_SET_GAMINGKBBL_METHODID 20 66 | #define ACER_WMID_GET_GAMINGKBBL_METHODID 21 67 | 68 | 69 | #define ACER_WMID_SET_GAMING_LED_METHODID 2 70 | #define ACER_WMID_GET_GAMING_LED_METHODID 4 71 | #define ACER_WMID_SET_GAMING_STATIC_LED_METHODID 6 72 | #define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14 73 | #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 74 | /* 75 | * Acer ACPI method GUIDs 76 | */ 77 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 78 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 79 | #define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" 80 | #define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A" 81 | #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" 82 | #define WMID_GUID4 "7A4DDFE7-5B5D-40B4-8595-4408E0CC7F56" 83 | 84 | /* 85 | * Acer ACPI event GUIDs 86 | */ 87 | #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" 88 | 89 | MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 90 | MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"); 91 | MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); 92 | 93 | enum acer_wmi_event_ids { 94 | WMID_HOTKEY_EVENT = 0x1, 95 | WMID_ACCEL_OR_KBD_DOCK_EVENT = 0x5, 96 | WMID_GAMING_TURBO_KEY_EVENT = 0x7, 97 | }; 98 | 99 | static const struct key_entry acer_wmi_keymap[] __initconst = { 100 | {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */ 101 | {KE_KEY, 0x03, {KEY_WLAN} }, /* WiFi */ 102 | {KE_KEY, 0x04, {KEY_WLAN} }, /* WiFi */ 103 | {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */ 104 | {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */ 105 | {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */ 106 | {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ 107 | {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ 108 | {KE_KEY, 0x29, {KEY_PROG3} }, /* P_Key for TM8372 */ 109 | {KE_IGNORE, 0x41, {KEY_MUTE} }, 110 | {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} }, 111 | {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} }, 112 | {KE_IGNORE, 0x43, {KEY_NEXTSONG} }, 113 | {KE_IGNORE, 0x4e, {KEY_NEXTSONG} }, 114 | {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} }, 115 | {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} }, 116 | {KE_IGNORE, 0x45, {KEY_STOP} }, 117 | {KE_IGNORE, 0x50, {KEY_STOP} }, 118 | {KE_IGNORE, 0x48, {KEY_VOLUMEUP} }, 119 | {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} }, 120 | {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} }, 121 | {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} }, 122 | {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} }, 123 | {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} }, 124 | {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ 125 | {KE_IGNORE, 0x81, {KEY_SLEEP} }, 126 | {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */ 127 | {KE_IGNORE, 0x84, {KEY_KBDILLUMTOGGLE} }, /* Automatic Keyboard background light toggle */ 128 | {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, 129 | {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} }, 130 | {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, 131 | {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} }, 132 | {KE_KEY, 0x86, {KEY_WLAN} }, 133 | {KE_KEY, 0x87, {KEY_POWER} }, 134 | {KE_END, 0} 135 | }; 136 | 137 | static struct input_dev *acer_wmi_input_dev; 138 | static struct input_dev *acer_wmi_accel_dev; 139 | 140 | struct event_return_value { 141 | u8 function; 142 | u8 key_num; 143 | u16 device_state; 144 | u16 reserved1; 145 | u8 kbd_dock_state; 146 | u8 reserved2; 147 | } __attribute__((packed)); 148 | 149 | /* 150 | * GUID3 Get Device Status device flags 151 | */ 152 | #define ACER_WMID3_GDS_WIRELESS (1<<0) /* WiFi */ 153 | #define ACER_WMID3_GDS_THREEG (1<<6) /* 3G */ 154 | #define ACER_WMID3_GDS_WIMAX (1<<7) /* WiMAX */ 155 | #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ 156 | #define ACER_WMID3_GDS_RFBTN (1<<14) /* RF Button */ 157 | 158 | #define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */ 159 | 160 | /* 161 | * Gaming functions user-space communication 162 | * A character drive will be exposed in /dev/acer-gkbbl as char block for keyboard dynamic backlight config 163 | * Config length is 16 bytes 164 | */ 165 | 166 | #define GAMING_KBBL_CHR "acer-gkbbl" 167 | #define GAMING_KBBL_CONFIG_LEN 16 168 | 169 | 170 | /* 171 | * Gaming functions user-space communication 172 | * A character drive will be exposed in /dev/acer-gkbbl-static as char block for keyboard static backlight config 173 | * Config length is 16 bytes 174 | */ 175 | 176 | #define GAMING_KBBL_STATIC_CHR "acer-gkbbl-static" 177 | #define GAMING_KBBL_STATIC_CONFIG_LEN 4 178 | 179 | /* Hotkey Customized Setting and Acer Application Status. 180 | * Set Device Default Value and Report Acer Application Status. 181 | * When Acer Application starts, it will run this method to inform 182 | * BIOS/EC that Acer Application is on. 183 | * App Status 184 | * Bit[0]: Launch Manager Status 185 | * Bit[1]: ePM Status 186 | * Bit[2]: Device Control Status 187 | * Bit[3]: Acer Power Button Utility Status 188 | * Bit[4]: RF Button Status 189 | * Bit[5]: ODD PM Status 190 | * Bit[6]: Device Default Value Control 191 | * Bit[7]: Hall Sensor Application Status 192 | */ 193 | struct func_input_params { 194 | u8 function_num; /* Function Number */ 195 | u16 commun_devices; /* Communication type devices default status */ 196 | u16 devices; /* Other type devices default status */ 197 | u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */ 198 | u8 app_mask; /* Bit mask to app_status */ 199 | u8 reserved; 200 | } __attribute__((packed)); 201 | 202 | struct func_return_value { 203 | u8 error_code; /* Error Code */ 204 | u8 ec_return_value; /* EC Return Value */ 205 | u16 reserved; 206 | } __attribute__((packed)); 207 | 208 | struct wmid3_gds_set_input_param { /* Set Device Status input parameter */ 209 | u8 function_num; /* Function Number */ 210 | u8 hotkey_number; /* Hotkey Number */ 211 | u16 devices; /* Set Device */ 212 | u8 volume_value; /* Volume Value */ 213 | } __attribute__((packed)); 214 | 215 | struct wmid3_gds_get_input_param { /* Get Device Status input parameter */ 216 | u8 function_num; /* Function Number */ 217 | u8 hotkey_number; /* Hotkey Number */ 218 | u16 devices; /* Get Device */ 219 | } __attribute__((packed)); 220 | 221 | struct wmid3_gds_return_value { /* Get Device Status return value*/ 222 | u8 error_code; /* Error Code */ 223 | u8 ec_return_value; /* EC Return Value */ 224 | u16 devices; /* Current Device Status */ 225 | u32 reserved; 226 | } __attribute__((packed)); 227 | 228 | struct hotkey_function_type_aa { 229 | u8 type; 230 | u8 length; 231 | u16 handle; 232 | u16 commun_func_bitmap; 233 | u16 application_func_bitmap; 234 | u16 media_func_bitmap; 235 | u16 display_func_bitmap; 236 | u16 others_func_bitmap; 237 | u8 commun_fn_key_number; 238 | } __attribute__((packed)); 239 | 240 | /* 241 | * Interface capability flags 242 | */ 243 | #define ACER_CAP_MAILLED BIT(0) 244 | #define ACER_CAP_WIRELESS BIT(1) 245 | #define ACER_CAP_BLUETOOTH BIT(2) 246 | #define ACER_CAP_BRIGHTNESS BIT(3) 247 | #define ACER_CAP_THREEG BIT(4) 248 | #define ACER_CAP_SET_FUNCTION_MODE BIT(5) 249 | #define ACER_CAP_KBD_DOCK BIT(6) 250 | 251 | #define ACER_CAP_TURBO_OC BIT(7) 252 | #define ACER_CAP_TURBO_LED BIT(8) 253 | #define ACER_CAP_TURBO_FAN BIT(9) 254 | #define ACER_CAP_GAMINGKB BIT(10) 255 | #define ACER_CAP_GAMINGKB_STATIC BIT(11) 256 | 257 | /* 258 | * Interface type flags 259 | */ 260 | enum interface_flags { 261 | ACER_AMW0, 262 | ACER_AMW0_V2, 263 | ACER_WMID, 264 | ACER_WMID_v2, 265 | ACER_WMID_GAMING, 266 | }; 267 | 268 | #define ACER_DEFAULT_WIRELESS 0 269 | #define ACER_DEFAULT_BLUETOOTH 0 270 | #define ACER_DEFAULT_MAILLED 0 271 | #define ACER_DEFAULT_THREEG 0 272 | 273 | static int max_brightness = 0xF; 274 | 275 | static int mailled = -1; 276 | static int brightness = -1; 277 | static int threeg = -1; 278 | static int force_series; 279 | static int force_caps = -1; 280 | static bool ec_raw_mode; 281 | static bool has_type_aa; 282 | static u16 commun_func_bitmap; 283 | static u8 commun_fn_key_number; 284 | 285 | module_param(mailled, int, 0444); 286 | module_param(brightness, int, 0444); 287 | module_param(threeg, int, 0444); 288 | module_param(force_series, int, 0444); 289 | module_param(force_caps, int, 0444); 290 | module_param(ec_raw_mode, bool, 0444); 291 | MODULE_PARM_DESC(mailled, "Set initial state of Mail LED"); 292 | MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness"); 293 | MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware"); 294 | MODULE_PARM_DESC(force_series, "Force a different laptop series"); 295 | MODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value"); 296 | MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode"); 297 | 298 | struct acer_data { 299 | int mailled; 300 | int threeg; 301 | int brightness; 302 | }; 303 | 304 | struct acer_debug { 305 | struct dentry *root; 306 | u32 wmid_devices; 307 | }; 308 | 309 | static struct rfkill *wireless_rfkill; 310 | static struct rfkill *bluetooth_rfkill; 311 | static struct rfkill *threeg_rfkill; 312 | static bool rfkill_inited; 313 | 314 | /* Each low-level interface must define at least some of the following */ 315 | struct wmi_interface { 316 | /* The WMI device type */ 317 | u32 type; 318 | 319 | /* The capabilities this interface provides */ 320 | u32 capability; 321 | 322 | /* Private data for the current interface */ 323 | struct acer_data data; 324 | 325 | /* debugfs entries associated with this interface */ 326 | struct acer_debug debug; 327 | }; 328 | 329 | /* The static interface pointer, points to the currently detected interface */ 330 | static struct wmi_interface *interface; 331 | 332 | /* The static gaming interface pointer, points to the currently detected gaming interface */ 333 | static struct wmi_interface *gaming_interface; 334 | 335 | /* 336 | * Character device registration 337 | * GAMING_KBBL_MINOR -> used to configure gaming rgb keyboard backlights from user-space 338 | */ 339 | 340 | #define GAMING_KBBL_MINOR 0 341 | #define GAMING_KBBL_STATIC_MINOR 0 342 | 343 | 344 | static int dev_major; // Global variable to store major number of driver 345 | 346 | 347 | /* 348 | * Embedded Controller quirks 349 | * Some laptops require us to directly access the EC to either enable or query 350 | * features that are not available through WMI. 351 | */ 352 | 353 | struct quirk_entry { 354 | u8 wireless; 355 | u8 mailled; 356 | s8 brightness; 357 | u8 bluetooth; 358 | u8 turbo; 359 | u8 cpu_fans; 360 | u8 gpu_fans; 361 | }; 362 | 363 | static struct quirk_entry *quirks; 364 | 365 | static void __init set_quirks(void) 366 | { 367 | if (quirks->mailled) 368 | interface->capability |= ACER_CAP_MAILLED; 369 | 370 | if (quirks->brightness) 371 | interface->capability |= ACER_CAP_BRIGHTNESS; 372 | 373 | if (quirks->turbo) 374 | interface->capability |= ACER_CAP_TURBO_OC | ACER_CAP_TURBO_LED 375 | | ACER_CAP_TURBO_FAN; 376 | } 377 | 378 | static int __init dmi_matched(const struct dmi_system_id *dmi) 379 | { 380 | quirks = dmi->driver_data; 381 | return 1; 382 | } 383 | 384 | static int __init set_force_caps(const struct dmi_system_id *dmi) 385 | { 386 | if (force_caps == -1) { 387 | force_caps = (uintptr_t)dmi->driver_data; 388 | pr_info("Found %s, set force_caps to 0x%x\n", dmi->ident, force_caps); 389 | } 390 | return 1; 391 | } 392 | 393 | static struct quirk_entry quirk_unknown = { 394 | }; 395 | 396 | static struct quirk_entry quirk_acer_aspire_1520 = { 397 | .brightness = -1, 398 | }; 399 | 400 | static struct quirk_entry quirk_acer_travelmate_2490 = { 401 | .mailled = 1, 402 | }; 403 | 404 | static struct quirk_entry quirk_acer_predator_ph315_52 = { 405 | .turbo = 1, 406 | .cpu_fans = 1, 407 | .gpu_fans = 1, 408 | }; 409 | 410 | static struct quirk_entry quirk_acer_predator_ph315_53 = { 411 | .turbo = 1, 412 | .cpu_fans = 1, 413 | .gpu_fans = 1, 414 | }; 415 | 416 | static struct quirk_entry quirk_acer_predator_ph315_54 = { 417 | .turbo = 1, 418 | .cpu_fans = 1, 419 | .gpu_fans = 1, 420 | }; 421 | 422 | static struct quirk_entry quirk_acer_predator_ph317_53 = { 423 | .turbo = 1, 424 | .cpu_fans = 1, 425 | .gpu_fans = 1, 426 | }; 427 | static struct quirk_entry quirk_acer_predator_ph317_54 = { 428 | .turbo = 1, 429 | .cpu_fans = 1, 430 | .gpu_fans = 1, 431 | }; 432 | static struct quirk_entry quirk_acer_predator_ph517_51 = { 433 | .turbo = 1, 434 | .cpu_fans = 1, 435 | .gpu_fans = 1, 436 | }; 437 | static struct quirk_entry quirk_acer_predator_ph517_52 = { 438 | .turbo = 1, 439 | .cpu_fans = 1, 440 | .gpu_fans = 1, 441 | }; 442 | static struct quirk_entry quirk_acer_predator_ph517_61 = { 443 | .turbo = 1, 444 | .cpu_fans = 1, 445 | .gpu_fans = 1, 446 | }; 447 | static struct quirk_entry quirk_acer_predator_ph717_71 = { 448 | .turbo = 1, 449 | .cpu_fans = 1, 450 | .gpu_fans = 1, 451 | }; 452 | static struct quirk_entry quirk_acer_predator_ph717_72 = { 453 | .turbo = 1, 454 | .cpu_fans = 1, 455 | .gpu_fans = 1, 456 | }; 457 | static struct quirk_entry quirk_acer_predator_pt315_51 = { 458 | .turbo = 1, 459 | .cpu_fans = 1, 460 | .gpu_fans = 1, 461 | }; 462 | static struct quirk_entry quirk_acer_predator_pt315_52 = { 463 | .turbo = 1, 464 | .cpu_fans = 1, 465 | .gpu_fans = 1, 466 | }; 467 | static struct quirk_entry quirk_acer_predator_pt515_51 = { 468 | .turbo = 1, 469 | .cpu_fans = 1, 470 | .gpu_fans = 2, 471 | }; 472 | static struct quirk_entry quirk_acer_predator_pt515_52 = { 473 | .turbo = 1, 474 | .cpu_fans = 1, 475 | .gpu_fans = 2, 476 | }; 477 | static struct quirk_entry quirk_acer_predator_pt917_71 = { 478 | .turbo = 1, 479 | .cpu_fans = 1, 480 | .gpu_fans = 1, 481 | }; 482 | 483 | /* This AMW0 laptop has no bluetooth */ 484 | static struct quirk_entry quirk_medion_md_98300 = { 485 | .wireless = 1, 486 | }; 487 | 488 | static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { 489 | .wireless = 2, 490 | }; 491 | 492 | static struct quirk_entry quirk_lenovo_ideapad_s205 = { 493 | .wireless = 3, 494 | }; 495 | 496 | /* The Aspire One has a dummy ACPI-WMI interface - disable it */ 497 | static const struct dmi_system_id acer_blacklist[] __initconst = { 498 | { 499 | .ident = "Acer Aspire One (SSD)", 500 | .matches = { 501 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 502 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), 503 | }, 504 | }, 505 | { 506 | .ident = "Acer Aspire One (HDD)", 507 | .matches = { 508 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 509 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA150"), 510 | }, 511 | }, 512 | {} 513 | }; 514 | 515 | static const struct dmi_system_id amw0_whitelist[] __initconst = { 516 | { 517 | .ident = "Acer", 518 | .matches = { 519 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 520 | }, 521 | }, 522 | { 523 | .ident = "Gateway", 524 | .matches = { 525 | DMI_MATCH(DMI_SYS_VENDOR, "Gateway"), 526 | }, 527 | }, 528 | { 529 | .ident = "Packard Bell", 530 | .matches = { 531 | DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"), 532 | }, 533 | }, 534 | {} 535 | }; 536 | 537 | /* 538 | * This quirk table is only for Acer/Gateway/Packard Bell family 539 | * that those machines are supported by acer-wmi driver. 540 | */ 541 | static const struct dmi_system_id acer_quirks[] __initconst = { 542 | { 543 | .callback = dmi_matched, 544 | .ident = "Acer Aspire 1360", 545 | .matches = { 546 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 547 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), 548 | }, 549 | .driver_data = &quirk_acer_aspire_1520, 550 | }, 551 | { 552 | .callback = dmi_matched, 553 | .ident = "Acer Aspire 1520", 554 | .matches = { 555 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 556 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"), 557 | }, 558 | .driver_data = &quirk_acer_aspire_1520, 559 | }, 560 | { 561 | .callback = dmi_matched, 562 | .ident = "Acer Aspire 3100", 563 | .matches = { 564 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 565 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"), 566 | }, 567 | .driver_data = &quirk_acer_travelmate_2490, 568 | }, 569 | { 570 | .callback = dmi_matched, 571 | .ident = "Acer Aspire 3610", 572 | .matches = { 573 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 574 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"), 575 | }, 576 | .driver_data = &quirk_acer_travelmate_2490, 577 | }, 578 | { 579 | .callback = dmi_matched, 580 | .ident = "Acer Aspire 5100", 581 | .matches = { 582 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 583 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), 584 | }, 585 | .driver_data = &quirk_acer_travelmate_2490, 586 | }, 587 | { 588 | .callback = dmi_matched, 589 | .ident = "Acer Aspire 5610", 590 | .matches = { 591 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 592 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), 593 | }, 594 | .driver_data = &quirk_acer_travelmate_2490, 595 | }, 596 | { 597 | .callback = dmi_matched, 598 | .ident = "Acer Aspire 5630", 599 | .matches = { 600 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 601 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"), 602 | }, 603 | .driver_data = &quirk_acer_travelmate_2490, 604 | }, 605 | { 606 | .callback = dmi_matched, 607 | .ident = "Acer Aspire 5650", 608 | .matches = { 609 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 610 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"), 611 | }, 612 | .driver_data = &quirk_acer_travelmate_2490, 613 | }, 614 | { 615 | .callback = dmi_matched, 616 | .ident = "Acer Aspire 5680", 617 | .matches = { 618 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 619 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"), 620 | }, 621 | .driver_data = &quirk_acer_travelmate_2490, 622 | }, 623 | { 624 | .callback = dmi_matched, 625 | .ident = "Acer Aspire 9110", 626 | .matches = { 627 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 628 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"), 629 | }, 630 | .driver_data = &quirk_acer_travelmate_2490, 631 | }, 632 | { 633 | .callback = dmi_matched, 634 | .ident = "Acer TravelMate 2490", 635 | .matches = { 636 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 637 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), 638 | }, 639 | .driver_data = &quirk_acer_travelmate_2490, 640 | }, 641 | { 642 | .callback = dmi_matched, 643 | .ident = "Acer TravelMate 4200", 644 | .matches = { 645 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 646 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"), 647 | }, 648 | .driver_data = &quirk_acer_travelmate_2490, 649 | }, 650 | { 651 | .callback = dmi_matched, 652 | .ident = "Acer Predator PH315-52", 653 | .matches = { 654 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 655 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH315-52"), 656 | }, 657 | .driver_data = &quirk_acer_predator_ph315_52, 658 | }, 659 | { 660 | .callback = dmi_matched, 661 | .ident = "Acer Predator PH315-53", 662 | .matches = { 663 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 664 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH315-53"), 665 | }, 666 | .driver_data = &quirk_acer_predator_ph315_53, 667 | }, 668 | { 669 | .callback = dmi_matched, 670 | .ident = "Acer Predator PH315-54", 671 | .matches = { 672 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 673 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH315-54"), 674 | }, 675 | .driver_data = &quirk_acer_predator_ph315_54, 676 | }, 677 | { 678 | .callback = dmi_matched, 679 | .ident = "Acer Predator PH317-53", 680 | .matches = { 681 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 682 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH317-53"), 683 | }, 684 | .driver_data = &quirk_acer_predator_ph317_53, 685 | }, 686 | { 687 | .callback = dmi_matched, 688 | .ident = "Acer Predator PH317-54", 689 | .matches = { 690 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 691 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH317-54"), 692 | }, 693 | .driver_data = &quirk_acer_predator_ph317_54, 694 | }, 695 | { 696 | .callback = dmi_matched, 697 | .ident = "Acer Predator PH517-51", 698 | .matches = { 699 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 700 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH517-51"), 701 | }, 702 | .driver_data = &quirk_acer_predator_ph517_51, 703 | }, 704 | { 705 | .callback = dmi_matched, 706 | .ident = "Acer Predator PH517-52", 707 | .matches = { 708 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 709 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH517-52"), 710 | }, 711 | .driver_data = &quirk_acer_predator_ph517_52, 712 | }, 713 | { 714 | .callback = dmi_matched, 715 | .ident = "Acer Predator PH517-61", 716 | .matches = { 717 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 718 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH517-61"), 719 | }, 720 | .driver_data = &quirk_acer_predator_ph517_61, 721 | }, 722 | { 723 | .callback = dmi_matched, 724 | .ident = "Acer Predator PH717-71", 725 | .matches = { 726 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 727 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH717-71"), 728 | }, 729 | .driver_data = &quirk_acer_predator_ph717_71, 730 | }, 731 | { 732 | .callback = dmi_matched, 733 | .ident = "Acer Predator PH717-72", 734 | .matches = { 735 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 736 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH717-72"), 737 | }, 738 | .driver_data = &quirk_acer_predator_ph717_72, 739 | }, 740 | { 741 | .callback = dmi_matched, 742 | .ident = "Acer Predator PT315-51", 743 | .matches = { 744 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 745 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PT315-51"), 746 | }, 747 | .driver_data = &quirk_acer_predator_pt315_51, 748 | }, 749 | { 750 | .callback = dmi_matched, 751 | .ident = "Acer Predator PT315-52", 752 | .matches = { 753 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 754 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PT315-52"), 755 | }, 756 | .driver_data = &quirk_acer_predator_pt315_52, 757 | }, 758 | { 759 | .callback = dmi_matched, 760 | .ident = "Acer Predator PT515-51", 761 | .matches = { 762 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 763 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PT515-51"), 764 | }, 765 | .driver_data = &quirk_acer_predator_pt515_51, 766 | }, 767 | { 768 | .callback = dmi_matched, 769 | .ident = "Acer Predator PT515-52", 770 | .matches = { 771 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 772 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PT515-52"), 773 | }, 774 | .driver_data = &quirk_acer_predator_pt515_52, 775 | }, 776 | { 777 | .callback = dmi_matched, 778 | .ident = "Acer Predator PT917-71", 779 | .matches = { 780 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 781 | DMI_MATCH(DMI_PRODUCT_NAME, "Predator PT917-71"), 782 | }, 783 | .driver_data = &quirk_acer_predator_pt917_71, 784 | }, 785 | 786 | 787 | 788 | { 789 | .callback = set_force_caps, 790 | .ident = "Acer Aspire Switch 10E SW3-016", 791 | .matches = { 792 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 793 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-016"), 794 | }, 795 | .driver_data = (void *)ACER_CAP_KBD_DOCK, 796 | }, 797 | { 798 | .callback = set_force_caps, 799 | .ident = "Acer Aspire Switch 10 SW5-012", 800 | .matches = { 801 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 802 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), 803 | }, 804 | .driver_data = (void *)ACER_CAP_KBD_DOCK, 805 | }, 806 | { 807 | .callback = set_force_caps, 808 | .ident = "Acer One 10 (S1003)", 809 | .matches = { 810 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer"), 811 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003"), 812 | }, 813 | .driver_data = (void *)ACER_CAP_KBD_DOCK, 814 | }, 815 | {} 816 | }; 817 | 818 | /* 819 | * This quirk list is for those non-acer machines that have AMW0_GUID1 820 | * but supported by acer-wmi in past days. Keeping this quirk list here 821 | * is only for backward compatible. Please do not add new machine to 822 | * here anymore. Those non-acer machines should be supported by 823 | * appropriate wmi drivers. 824 | */ 825 | static const struct dmi_system_id non_acer_quirks[] __initconst = { 826 | { 827 | .callback = dmi_matched, 828 | .ident = "Fujitsu Siemens Amilo Li 1718", 829 | .matches = { 830 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 831 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"), 832 | }, 833 | .driver_data = &quirk_fujitsu_amilo_li_1718, 834 | }, 835 | { 836 | .callback = dmi_matched, 837 | .ident = "Medion MD 98300", 838 | .matches = { 839 | DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 840 | DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"), 841 | }, 842 | .driver_data = &quirk_medion_md_98300, 843 | }, 844 | { 845 | .callback = dmi_matched, 846 | .ident = "Lenovo Ideapad S205", 847 | .matches = { 848 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 849 | DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"), 850 | }, 851 | .driver_data = &quirk_lenovo_ideapad_s205, 852 | }, 853 | { 854 | .callback = dmi_matched, 855 | .ident = "Lenovo Ideapad S205 (Brazos)", 856 | .matches = { 857 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 858 | DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"), 859 | }, 860 | .driver_data = &quirk_lenovo_ideapad_s205, 861 | }, 862 | { 863 | .callback = dmi_matched, 864 | .ident = "Lenovo 3000 N200", 865 | .matches = { 866 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 867 | DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"), 868 | }, 869 | .driver_data = &quirk_fujitsu_amilo_li_1718, 870 | }, 871 | { 872 | .callback = dmi_matched, 873 | .ident = "Lenovo Ideapad S205-10382JG", 874 | .matches = { 875 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 876 | DMI_MATCH(DMI_PRODUCT_NAME, "10382JG"), 877 | }, 878 | .driver_data = &quirk_lenovo_ideapad_s205, 879 | }, 880 | { 881 | .callback = dmi_matched, 882 | .ident = "Lenovo Ideapad S205-1038DPG", 883 | .matches = { 884 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 885 | DMI_MATCH(DMI_PRODUCT_NAME, "1038DPG"), 886 | }, 887 | .driver_data = &quirk_lenovo_ideapad_s205, 888 | }, 889 | {} 890 | }; 891 | 892 | static int __init 893 | video_set_backlight_video_vendor(const struct dmi_system_id *d) 894 | { 895 | interface->capability &= ~ACER_CAP_BRIGHTNESS; 896 | pr_info("Brightness must be controlled by generic video driver\n"); 897 | return 0; 898 | } 899 | 900 | static const struct dmi_system_id video_vendor_dmi_table[] __initconst = { 901 | { 902 | .callback = video_set_backlight_video_vendor, 903 | .ident = "Acer TravelMate 4750", 904 | .matches = { 905 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 906 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), 907 | }, 908 | }, 909 | { 910 | .callback = video_set_backlight_video_vendor, 911 | .ident = "Acer Extensa 5235", 912 | .matches = { 913 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 914 | DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), 915 | }, 916 | }, 917 | { 918 | .callback = video_set_backlight_video_vendor, 919 | .ident = "Acer TravelMate 5760", 920 | .matches = { 921 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 922 | DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), 923 | }, 924 | }, 925 | { 926 | .callback = video_set_backlight_video_vendor, 927 | .ident = "Acer Aspire 5750", 928 | .matches = { 929 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 930 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), 931 | }, 932 | }, 933 | { 934 | .callback = video_set_backlight_video_vendor, 935 | .ident = "Acer Aspire 5741", 936 | .matches = { 937 | DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 938 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"), 939 | }, 940 | }, 941 | { 942 | /* 943 | * Note no video_set_backlight_video_vendor, we must use the 944 | * acer interface, as there is no native backlight interface. 945 | */ 946 | .ident = "Acer KAV80", 947 | .matches = { 948 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 949 | DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"), 950 | }, 951 | }, 952 | {} 953 | }; 954 | 955 | /* Find which quirks are needed for a particular vendor/ model pair */ 956 | static void __init find_quirks(void) 957 | { 958 | if (!force_series) { 959 | dmi_check_system(acer_quirks); 960 | dmi_check_system(non_acer_quirks); 961 | } else if (force_series == 2490) { 962 | quirks = &quirk_acer_travelmate_2490; 963 | } 964 | 965 | if (quirks == NULL) 966 | quirks = &quirk_unknown; 967 | } 968 | 969 | /* 970 | * General interface convenience methods 971 | */ 972 | 973 | static bool has_cap(u32 cap) 974 | { 975 | return interface->capability & cap; 976 | } 977 | 978 | /* 979 | * AMW0 (V1) interface 980 | */ 981 | struct wmab_args { 982 | u32 eax; 983 | u32 ebx; 984 | u32 ecx; 985 | u32 edx; 986 | }; 987 | 988 | struct wmab_ret { 989 | u32 eax; 990 | u32 ebx; 991 | u32 ecx; 992 | u32 edx; 993 | u32 eex; 994 | }; 995 | 996 | static acpi_status wmab_execute(struct wmab_args *regbuf, 997 | struct acpi_buffer *result) 998 | { 999 | struct acpi_buffer input; 1000 | acpi_status status; 1001 | input.length = sizeof(struct wmab_args); 1002 | input.pointer = (u8 *)regbuf; 1003 | 1004 | status = wmi_evaluate_method(AMW0_GUID1, 0, 1, &input, result); 1005 | 1006 | return status; 1007 | } 1008 | 1009 | static acpi_status AMW0_get_u32(u32 *value, u32 cap) 1010 | { 1011 | int err; 1012 | u8 result; 1013 | 1014 | switch (cap) { 1015 | case ACER_CAP_MAILLED: 1016 | switch (quirks->mailled) { 1017 | default: 1018 | err = ec_read(0xA, &result); 1019 | if (err) 1020 | return AE_ERROR; 1021 | *value = (result >> 7) & 0x1; 1022 | return AE_OK; 1023 | } 1024 | break; 1025 | case ACER_CAP_WIRELESS: 1026 | switch (quirks->wireless) { 1027 | case 1: 1028 | err = ec_read(0x7B, &result); 1029 | if (err) 1030 | return AE_ERROR; 1031 | *value = result & 0x1; 1032 | return AE_OK; 1033 | case 2: 1034 | err = ec_read(0x71, &result); 1035 | if (err) 1036 | return AE_ERROR; 1037 | *value = result & 0x1; 1038 | return AE_OK; 1039 | case 3: 1040 | err = ec_read(0x78, &result); 1041 | if (err) 1042 | return AE_ERROR; 1043 | *value = result & 0x1; 1044 | return AE_OK; 1045 | default: 1046 | err = ec_read(0xA, &result); 1047 | if (err) 1048 | return AE_ERROR; 1049 | *value = (result >> 2) & 0x1; 1050 | return AE_OK; 1051 | } 1052 | break; 1053 | case ACER_CAP_BLUETOOTH: 1054 | switch (quirks->bluetooth) { 1055 | default: 1056 | err = ec_read(0xA, &result); 1057 | if (err) 1058 | return AE_ERROR; 1059 | *value = (result >> 4) & 0x1; 1060 | return AE_OK; 1061 | } 1062 | break; 1063 | case ACER_CAP_BRIGHTNESS: 1064 | switch (quirks->brightness) { 1065 | default: 1066 | err = ec_read(0x83, &result); 1067 | if (err) 1068 | return AE_ERROR; 1069 | *value = result; 1070 | return AE_OK; 1071 | } 1072 | break; 1073 | default: 1074 | return AE_ERROR; 1075 | } 1076 | return AE_OK; 1077 | } 1078 | 1079 | static acpi_status AMW0_set_u32(u32 value, u32 cap) 1080 | { 1081 | struct wmab_args args; 1082 | 1083 | args.eax = ACER_AMW0_WRITE; 1084 | args.ebx = value ? (1<<8) : 0; 1085 | args.ecx = args.edx = 0; 1086 | 1087 | switch (cap) { 1088 | case ACER_CAP_MAILLED: 1089 | if (value > 1) 1090 | return AE_BAD_PARAMETER; 1091 | args.ebx |= ACER_AMW0_MAILLED_MASK; 1092 | break; 1093 | case ACER_CAP_WIRELESS: 1094 | if (value > 1) 1095 | return AE_BAD_PARAMETER; 1096 | args.ebx |= ACER_AMW0_WIRELESS_MASK; 1097 | break; 1098 | case ACER_CAP_BLUETOOTH: 1099 | if (value > 1) 1100 | return AE_BAD_PARAMETER; 1101 | args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 1102 | break; 1103 | case ACER_CAP_BRIGHTNESS: 1104 | if (value > max_brightness) 1105 | return AE_BAD_PARAMETER; 1106 | switch (quirks->brightness) { 1107 | default: 1108 | return ec_write(0x83, value); 1109 | } 1110 | default: 1111 | return AE_ERROR; 1112 | } 1113 | 1114 | /* Actually do the set */ 1115 | return wmab_execute(&args, NULL); 1116 | } 1117 | 1118 | static acpi_status __init AMW0_find_mailled(void) 1119 | { 1120 | struct wmab_args args; 1121 | struct wmab_ret ret; 1122 | acpi_status status = AE_OK; 1123 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 1124 | union acpi_object *obj; 1125 | 1126 | args.eax = 0x86; 1127 | args.ebx = args.ecx = args.edx = 0; 1128 | 1129 | status = wmab_execute(&args, &out); 1130 | if (ACPI_FAILURE(status)) 1131 | return status; 1132 | 1133 | obj = (union acpi_object *) out.pointer; 1134 | if (obj && obj->type == ACPI_TYPE_BUFFER && 1135 | obj->buffer.length == sizeof(struct wmab_ret)) { 1136 | ret = *((struct wmab_ret *) obj->buffer.pointer); 1137 | } else { 1138 | kfree(out.pointer); 1139 | return AE_ERROR; 1140 | } 1141 | 1142 | if (ret.eex & 0x1) 1143 | interface->capability |= ACER_CAP_MAILLED; 1144 | 1145 | kfree(out.pointer); 1146 | 1147 | return AE_OK; 1148 | } 1149 | 1150 | static const struct acpi_device_id norfkill_ids[] __initconst = { 1151 | { "VPC2004", 0}, 1152 | { "IBM0068", 0}, 1153 | { "LEN0068", 0}, 1154 | { "SNY5001", 0}, /* sony-laptop in charge */ 1155 | { "HPQ6601", 0}, 1156 | { "", 0}, 1157 | }; 1158 | 1159 | static int __init AMW0_set_cap_acpi_check_device(void) 1160 | { 1161 | const struct acpi_device_id *id; 1162 | 1163 | for (id = norfkill_ids; id->id[0]; id++) 1164 | if (acpi_dev_found(id->id)) 1165 | return true; 1166 | 1167 | return false; 1168 | } 1169 | 1170 | static acpi_status __init AMW0_set_capabilities(void) 1171 | { 1172 | struct wmab_args args; 1173 | struct wmab_ret ret; 1174 | acpi_status status; 1175 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 1176 | union acpi_object *obj; 1177 | 1178 | /* 1179 | * On laptops with this strange GUID (non Acer), normal probing doesn't 1180 | * work. 1181 | */ 1182 | if (wmi_has_guid(AMW0_GUID2)) { 1183 | if ((quirks != &quirk_unknown) || 1184 | !AMW0_set_cap_acpi_check_device()) 1185 | interface->capability |= ACER_CAP_WIRELESS; 1186 | return AE_OK; 1187 | } 1188 | 1189 | args.eax = ACER_AMW0_WRITE; 1190 | args.ecx = args.edx = 0; 1191 | 1192 | args.ebx = 0xa2 << 8; 1193 | args.ebx |= ACER_AMW0_WIRELESS_MASK; 1194 | 1195 | status = wmab_execute(&args, &out); 1196 | if (ACPI_FAILURE(status)) 1197 | return status; 1198 | 1199 | obj = out.pointer; 1200 | if (obj && obj->type == ACPI_TYPE_BUFFER && 1201 | obj->buffer.length == sizeof(struct wmab_ret)) { 1202 | ret = *((struct wmab_ret *) obj->buffer.pointer); 1203 | } else { 1204 | status = AE_ERROR; 1205 | goto out; 1206 | } 1207 | 1208 | if (ret.eax & 0x1) 1209 | interface->capability |= ACER_CAP_WIRELESS; 1210 | 1211 | args.ebx = 2 << 8; 1212 | args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 1213 | 1214 | /* 1215 | * It's ok to use existing buffer for next wmab_execute call. 1216 | * But we need to kfree(out.pointer) if next wmab_execute fail. 1217 | */ 1218 | status = wmab_execute(&args, &out); 1219 | if (ACPI_FAILURE(status)) 1220 | goto out; 1221 | 1222 | obj = (union acpi_object *) out.pointer; 1223 | if (obj && obj->type == ACPI_TYPE_BUFFER 1224 | && obj->buffer.length == sizeof(struct wmab_ret)) { 1225 | ret = *((struct wmab_ret *) obj->buffer.pointer); 1226 | } else { 1227 | status = AE_ERROR; 1228 | goto out; 1229 | } 1230 | 1231 | if (ret.eax & 0x1) 1232 | interface->capability |= ACER_CAP_BLUETOOTH; 1233 | 1234 | /* 1235 | * This appears to be safe to enable, since all Wistron based laptops 1236 | * appear to use the same EC register for brightness, even if they 1237 | * differ for wireless, etc 1238 | */ 1239 | if (quirks->brightness >= 0) 1240 | interface->capability |= ACER_CAP_BRIGHTNESS; 1241 | 1242 | status = AE_OK; 1243 | out: 1244 | kfree(out.pointer); 1245 | return status; 1246 | } 1247 | 1248 | static struct wmi_interface AMW0_interface = { 1249 | .type = ACER_AMW0, 1250 | }; 1251 | 1252 | static struct wmi_interface AMW0_V2_interface = { 1253 | .type = ACER_AMW0_V2, 1254 | }; 1255 | 1256 | /* 1257 | * New interface (The WMID interface) 1258 | */ 1259 | static acpi_status 1260 | WMI_execute_u32(u32 method_id, u32 in, u32 *out) 1261 | { 1262 | struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) }; 1263 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; 1264 | union acpi_object *obj; 1265 | u32 tmp = 0; 1266 | acpi_status status; 1267 | 1268 | status = wmi_evaluate_method(WMID_GUID1, 0, method_id, &input, &result); 1269 | 1270 | if (ACPI_FAILURE(status)) 1271 | return status; 1272 | 1273 | obj = (union acpi_object *) result.pointer; 1274 | if (obj) { 1275 | if (obj->type == ACPI_TYPE_BUFFER && 1276 | (obj->buffer.length == sizeof(u32) || 1277 | obj->buffer.length == sizeof(u64))) { 1278 | tmp = *((u32 *) obj->buffer.pointer); 1279 | } else if (obj->type == ACPI_TYPE_INTEGER) { 1280 | tmp = (u32) obj->integer.value; 1281 | } 1282 | } 1283 | 1284 | if (out) 1285 | *out = tmp; 1286 | 1287 | kfree(result.pointer); 1288 | 1289 | return status; 1290 | } 1291 | 1292 | static acpi_status WMID_get_u32(u32 *value, u32 cap) 1293 | { 1294 | acpi_status status; 1295 | u8 tmp; 1296 | u32 result, method_id = 0; 1297 | 1298 | switch (cap) { 1299 | case ACER_CAP_WIRELESS: 1300 | method_id = ACER_WMID_GET_WIRELESS_METHODID; 1301 | break; 1302 | case ACER_CAP_BLUETOOTH: 1303 | method_id = ACER_WMID_GET_BLUETOOTH_METHODID; 1304 | break; 1305 | case ACER_CAP_BRIGHTNESS: 1306 | method_id = ACER_WMID_GET_BRIGHTNESS_METHODID; 1307 | break; 1308 | case ACER_CAP_THREEG: 1309 | method_id = ACER_WMID_GET_THREEG_METHODID; 1310 | break; 1311 | case ACER_CAP_MAILLED: 1312 | if (quirks->mailled == 1) { 1313 | ec_read(0x9f, &tmp); 1314 | *value = tmp & 0x1; 1315 | return 0; 1316 | } 1317 | fallthrough; 1318 | default: 1319 | return AE_ERROR; 1320 | } 1321 | status = WMI_execute_u32(method_id, 0, &result); 1322 | 1323 | if (ACPI_SUCCESS(status)) 1324 | *value = (u8)result; 1325 | 1326 | return status; 1327 | } 1328 | 1329 | static acpi_status WMID_set_u32(u32 value, u32 cap) 1330 | { 1331 | u32 method_id = 0; 1332 | char param; 1333 | 1334 | switch (cap) { 1335 | case ACER_CAP_BRIGHTNESS: 1336 | if (value > max_brightness) 1337 | return AE_BAD_PARAMETER; 1338 | method_id = ACER_WMID_SET_BRIGHTNESS_METHODID; 1339 | break; 1340 | case ACER_CAP_WIRELESS: 1341 | if (value > 1) 1342 | return AE_BAD_PARAMETER; 1343 | method_id = ACER_WMID_SET_WIRELESS_METHODID; 1344 | break; 1345 | case ACER_CAP_BLUETOOTH: 1346 | if (value > 1) 1347 | return AE_BAD_PARAMETER; 1348 | method_id = ACER_WMID_SET_BLUETOOTH_METHODID; 1349 | break; 1350 | case ACER_CAP_THREEG: 1351 | if (value > 1) 1352 | return AE_BAD_PARAMETER; 1353 | method_id = ACER_WMID_SET_THREEG_METHODID; 1354 | break; 1355 | case ACER_CAP_MAILLED: 1356 | if (value > 1) 1357 | return AE_BAD_PARAMETER; 1358 | if (quirks->mailled == 1) { 1359 | param = value ? 0x92 : 0x93; 1360 | i8042_lock_chip(); 1361 | i8042_command(¶m, 0x1059); 1362 | i8042_unlock_chip(); 1363 | return 0; 1364 | } 1365 | break; 1366 | default: 1367 | return AE_ERROR; 1368 | } 1369 | return WMI_execute_u32(method_id, (u32)value, NULL); 1370 | } 1371 | 1372 | static acpi_status wmid3_get_device_status(u32 *value, u16 device) 1373 | { 1374 | struct wmid3_gds_return_value return_value; 1375 | acpi_status status; 1376 | union acpi_object *obj; 1377 | struct wmid3_gds_get_input_param params = { 1378 | .function_num = 0x1, 1379 | .hotkey_number = commun_fn_key_number, 1380 | .devices = device, 1381 | }; 1382 | struct acpi_buffer input = { 1383 | sizeof(struct wmid3_gds_get_input_param), 1384 | ¶ms 1385 | }; 1386 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 1387 | 1388 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); 1389 | if (ACPI_FAILURE(status)) 1390 | return status; 1391 | 1392 | obj = output.pointer; 1393 | 1394 | if (!obj) 1395 | return AE_ERROR; 1396 | else if (obj->type != ACPI_TYPE_BUFFER) { 1397 | kfree(obj); 1398 | return AE_ERROR; 1399 | } 1400 | if (obj->buffer.length != 8) { 1401 | pr_warn("Unknown buffer length %d\n", obj->buffer.length); 1402 | kfree(obj); 1403 | return AE_ERROR; 1404 | } 1405 | 1406 | return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); 1407 | kfree(obj); 1408 | 1409 | if (return_value.error_code || return_value.ec_return_value) 1410 | pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n", 1411 | device, 1412 | return_value.error_code, 1413 | return_value.ec_return_value); 1414 | else 1415 | *value = !!(return_value.devices & device); 1416 | 1417 | return status; 1418 | } 1419 | 1420 | static acpi_status wmid_v2_get_u32(u32 *value, u32 cap) 1421 | { 1422 | u16 device; 1423 | 1424 | switch (cap) { 1425 | case ACER_CAP_WIRELESS: 1426 | device = ACER_WMID3_GDS_WIRELESS; 1427 | break; 1428 | case ACER_CAP_BLUETOOTH: 1429 | device = ACER_WMID3_GDS_BLUETOOTH; 1430 | break; 1431 | case ACER_CAP_THREEG: 1432 | device = ACER_WMID3_GDS_THREEG; 1433 | break; 1434 | default: 1435 | return AE_ERROR; 1436 | } 1437 | return wmid3_get_device_status(value, device); 1438 | } 1439 | 1440 | static acpi_status wmid3_set_device_status(u32 value, u16 device) 1441 | { 1442 | struct wmid3_gds_return_value return_value; 1443 | acpi_status status; 1444 | union acpi_object *obj; 1445 | u16 devices; 1446 | struct wmid3_gds_get_input_param get_params = { 1447 | .function_num = 0x1, 1448 | .hotkey_number = commun_fn_key_number, 1449 | .devices = commun_func_bitmap, 1450 | }; 1451 | struct acpi_buffer get_input = { 1452 | sizeof(struct wmid3_gds_get_input_param), 1453 | &get_params 1454 | }; 1455 | struct wmid3_gds_set_input_param set_params = { 1456 | .function_num = 0x2, 1457 | .hotkey_number = commun_fn_key_number, 1458 | .devices = commun_func_bitmap, 1459 | }; 1460 | struct acpi_buffer set_input = { 1461 | sizeof(struct wmid3_gds_set_input_param), 1462 | &set_params 1463 | }; 1464 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 1465 | struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL }; 1466 | 1467 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output); 1468 | if (ACPI_FAILURE(status)) 1469 | return status; 1470 | 1471 | obj = output.pointer; 1472 | 1473 | if (!obj) 1474 | return AE_ERROR; 1475 | else if (obj->type != ACPI_TYPE_BUFFER) { 1476 | kfree(obj); 1477 | return AE_ERROR; 1478 | } 1479 | if (obj->buffer.length != 8) { 1480 | pr_warn("Unknown buffer length %d\n", obj->buffer.length); 1481 | kfree(obj); 1482 | return AE_ERROR; 1483 | } 1484 | 1485 | return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); 1486 | kfree(obj); 1487 | 1488 | if (return_value.error_code || return_value.ec_return_value) { 1489 | pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n", 1490 | return_value.error_code, 1491 | return_value.ec_return_value); 1492 | return status; 1493 | } 1494 | 1495 | devices = return_value.devices; 1496 | set_params.devices = (value) ? (devices | device) : (devices & ~device); 1497 | 1498 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2); 1499 | if (ACPI_FAILURE(status)) 1500 | return status; 1501 | 1502 | obj = output2.pointer; 1503 | 1504 | if (!obj) 1505 | return AE_ERROR; 1506 | else if (obj->type != ACPI_TYPE_BUFFER) { 1507 | kfree(obj); 1508 | return AE_ERROR; 1509 | } 1510 | if (obj->buffer.length != 4) { 1511 | pr_warn("Unknown buffer length %d\n", obj->buffer.length); 1512 | kfree(obj); 1513 | return AE_ERROR; 1514 | } 1515 | 1516 | return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer); 1517 | kfree(obj); 1518 | 1519 | if (return_value.error_code || return_value.ec_return_value) 1520 | pr_warn("Set Device Status failed: 0x%x - 0x%x\n", 1521 | return_value.error_code, 1522 | return_value.ec_return_value); 1523 | 1524 | return status; 1525 | } 1526 | 1527 | static acpi_status wmid_v2_set_u32(u32 value, u32 cap) 1528 | { 1529 | u16 device; 1530 | 1531 | switch (cap) { 1532 | case ACER_CAP_WIRELESS: 1533 | device = ACER_WMID3_GDS_WIRELESS; 1534 | break; 1535 | case ACER_CAP_BLUETOOTH: 1536 | device = ACER_WMID3_GDS_BLUETOOTH; 1537 | break; 1538 | case ACER_CAP_THREEG: 1539 | device = ACER_WMID3_GDS_THREEG; 1540 | break; 1541 | default: 1542 | return AE_ERROR; 1543 | } 1544 | return wmid3_set_device_status(value, device); 1545 | } 1546 | 1547 | static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d) 1548 | { 1549 | struct hotkey_function_type_aa *type_aa; 1550 | 1551 | /* We are looking for OEM-specific Type AAh */ 1552 | if (header->type != 0xAA) 1553 | return; 1554 | 1555 | has_type_aa = true; 1556 | type_aa = (struct hotkey_function_type_aa *) header; 1557 | 1558 | pr_info("Function bitmap for Communication Button: 0x%x\n", 1559 | type_aa->commun_func_bitmap); 1560 | commun_func_bitmap = type_aa->commun_func_bitmap; 1561 | 1562 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) 1563 | interface->capability |= ACER_CAP_WIRELESS; 1564 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_THREEG) 1565 | interface->capability |= ACER_CAP_THREEG; 1566 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH) 1567 | interface->capability |= ACER_CAP_BLUETOOTH; 1568 | if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_RFBTN) 1569 | commun_func_bitmap &= ~ACER_WMID3_GDS_RFBTN; 1570 | 1571 | commun_fn_key_number = type_aa->commun_fn_key_number; 1572 | } 1573 | 1574 | static acpi_status __init WMID_set_capabilities(void) 1575 | { 1576 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 1577 | union acpi_object *obj; 1578 | acpi_status status; 1579 | u32 devices; 1580 | 1581 | status = wmi_query_block(WMID_GUID2, 0, &out); 1582 | if (ACPI_FAILURE(status)) 1583 | return status; 1584 | 1585 | obj = (union acpi_object *) out.pointer; 1586 | if (obj) { 1587 | if (obj->type == ACPI_TYPE_BUFFER && 1588 | (obj->buffer.length == sizeof(u32) || 1589 | obj->buffer.length == sizeof(u64))) { 1590 | devices = *((u32 *) obj->buffer.pointer); 1591 | } else if (obj->type == ACPI_TYPE_INTEGER) { 1592 | devices = (u32) obj->integer.value; 1593 | } else { 1594 | kfree(out.pointer); 1595 | return AE_ERROR; 1596 | } 1597 | } else { 1598 | kfree(out.pointer); 1599 | return AE_ERROR; 1600 | } 1601 | 1602 | pr_info("Function bitmap for Communication Device: 0x%x\n", devices); 1603 | if (devices & 0x07) 1604 | interface->capability |= ACER_CAP_WIRELESS; 1605 | if (devices & 0x40) 1606 | interface->capability |= ACER_CAP_THREEG; 1607 | if (devices & 0x10) 1608 | interface->capability |= ACER_CAP_BLUETOOTH; 1609 | 1610 | if (!(devices & 0x20)) 1611 | max_brightness = 0x9; 1612 | 1613 | kfree(out.pointer); 1614 | return status; 1615 | } 1616 | 1617 | static struct wmi_interface wmid_interface = { 1618 | .type = ACER_WMID, 1619 | }; 1620 | 1621 | static struct wmi_interface wmid_v2_interface = { 1622 | .type = ACER_WMID_v2, 1623 | }; 1624 | 1625 | /* 1626 | * WMID Gaming interface 1627 | */ 1628 | 1629 | static struct wmi_interface wmid_gaming_interface = { 1630 | .type = ACER_WMID_GAMING 1631 | }; 1632 | 1633 | static acpi_status 1634 | WMI_gaming_execute_u8_array(u32 method_id, u8 array[], size_t array_size, u32 *out) 1635 | { 1636 | struct acpi_buffer input = { (acpi_size) array_size, (void *)(array) }; 1637 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; 1638 | union acpi_object *obj; 1639 | u32 tmp = 0; 1640 | acpi_status status; 1641 | 1642 | status = wmi_evaluate_method(WMID_GUID4, 0, method_id, &input, &result); 1643 | 1644 | if (ACPI_FAILURE(status)) 1645 | return status; 1646 | 1647 | obj = (union acpi_object *) result.pointer; 1648 | if (obj) { 1649 | if (obj->type == ACPI_TYPE_BUFFER && 1650 | (obj->buffer.length == sizeof(u32) || 1651 | obj->buffer.length == sizeof(u64))) { 1652 | tmp = *((u32 *) obj->buffer.pointer); 1653 | } else if (obj->type == ACPI_TYPE_INTEGER) { 1654 | tmp = (u32) obj->integer.value; 1655 | } 1656 | } 1657 | 1658 | if (out) 1659 | *out = tmp; 1660 | 1661 | kfree(result.pointer); 1662 | 1663 | return status; 1664 | } 1665 | 1666 | 1667 | static acpi_status 1668 | WMI_gaming_execute_u64(u32 method_id, u64 in, u64 *out) 1669 | { 1670 | struct acpi_buffer input = { (acpi_size) sizeof(u64), (void *)(&in) }; 1671 | struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL }; 1672 | union acpi_object *obj; 1673 | u32 tmp = 0; 1674 | acpi_status status; 1675 | 1676 | status = wmi_evaluate_method(WMID_GUID4, 0, method_id, &input, &result); 1677 | 1678 | if (ACPI_FAILURE(status)) 1679 | return status; 1680 | obj = (union acpi_object *) result.pointer; 1681 | 1682 | if (obj) { 1683 | if (obj->type == ACPI_TYPE_BUFFER) { 1684 | if (obj->buffer.length == sizeof(u32)) 1685 | tmp = *((u32 *) obj->buffer.pointer); 1686 | else if (obj->buffer.length == sizeof(u64)) 1687 | tmp = *((u64 *) obj->buffer.pointer); 1688 | } else if (obj->type == ACPI_TYPE_INTEGER) { 1689 | tmp = (u64) obj->integer.value; 1690 | } 1691 | } 1692 | 1693 | if (out) 1694 | *out = tmp; 1695 | 1696 | kfree(result.pointer); 1697 | 1698 | return status; 1699 | } 1700 | 1701 | static acpi_status WMID_gaming_set_u64(u64 value, u32 cap) 1702 | { 1703 | u32 method_id = 0; 1704 | 1705 | if (!(interface->capability & cap)) 1706 | return AE_BAD_PARAMETER; 1707 | 1708 | switch (cap) { 1709 | case ACER_CAP_TURBO_LED: 1710 | method_id = ACER_WMID_SET_GAMING_LED_METHODID; 1711 | break; 1712 | case ACER_CAP_TURBO_FAN: 1713 | method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR; 1714 | break; 1715 | case ACER_CAP_TURBO_OC: 1716 | method_id = ACER_WMID_SET_GAMING_MISC_SETTING_METHODID; 1717 | break; 1718 | case ACER_CAP_GAMINGKB_STATIC: 1719 | method_id = ACER_WMID_SET_GAMING_STATIC_LED_METHODID; 1720 | return WMI_gaming_execute_u64(method_id, value, NULL); 1721 | default: 1722 | return AE_BAD_PARAMETER; 1723 | } 1724 | 1725 | return WMI_gaming_execute_u64(method_id, value, NULL); 1726 | } 1727 | 1728 | 1729 | static acpi_status WMID_gaming_set_u8_array(u8 array[], size_t array_size, u32 cap) 1730 | { 1731 | u32 method_id = 0; 1732 | 1733 | switch (cap) { 1734 | case ACER_CAP_GAMINGKB: 1735 | if (array_size != GAMING_KBBL_CONFIG_LEN) 1736 | return AE_BAD_PARAMETER; 1737 | method_id = ACER_WMID_SET_GAMINGKBBL_METHODID; 1738 | break; 1739 | default: 1740 | return AE_ERROR; 1741 | } 1742 | return WMI_gaming_execute_u8_array(method_id, array, array_size, NULL); 1743 | } 1744 | 1745 | static acpi_status WMID_gaming_get_u64(u64 *value, u32 cap) 1746 | { 1747 | acpi_status status; 1748 | u64 result; 1749 | u64 input; 1750 | u32 method_id; 1751 | 1752 | if (!(interface->capability & cap)) 1753 | return AE_BAD_PARAMETER; 1754 | 1755 | switch (cap) { 1756 | case ACER_CAP_TURBO_LED: 1757 | method_id = ACER_WMID_GET_GAMING_LED_METHODID; 1758 | input = 0x1; 1759 | break; 1760 | default: 1761 | return AE_BAD_PARAMETER; 1762 | } 1763 | status = WMI_gaming_execute_u64(method_id, input, &result); 1764 | if (ACPI_SUCCESS(status)) 1765 | *value = (u64) result; 1766 | 1767 | return status; 1768 | } 1769 | 1770 | void WMID_gaming_set_fan_mode(u8 fan_mode) 1771 | { 1772 | /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/ 1773 | u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0; 1774 | int i; 1775 | 1776 | if (quirks->cpu_fans > 0) 1777 | gpu_fan_config2 |= 1; 1778 | for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) 1779 | gpu_fan_config2 |= 1 << (i + 1); 1780 | for (i = 0; i < quirks->gpu_fans; ++i) 1781 | gpu_fan_config2 |= 1 << (i + 3); 1782 | if (quirks->cpu_fans > 0) 1783 | gpu_fan_config1 |= fan_mode; 1784 | for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) 1785 | gpu_fan_config1 |= fan_mode << (2 * i + 2); 1786 | for (i = 0; i < quirks->gpu_fans; ++i) 1787 | gpu_fan_config1 |= fan_mode << (2 * i + 6); 1788 | WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN); 1789 | } 1790 | 1791 | /* 1792 | * Generic Device (interface-independent) 1793 | */ 1794 | 1795 | static acpi_status get_u32(u32 *value, u32 cap) 1796 | { 1797 | acpi_status status = AE_ERROR; 1798 | 1799 | switch (interface->type) { 1800 | case ACER_AMW0: 1801 | status = AMW0_get_u32(value, cap); 1802 | break; 1803 | case ACER_AMW0_V2: 1804 | if (cap == ACER_CAP_MAILLED) { 1805 | status = AMW0_get_u32(value, cap); 1806 | break; 1807 | } 1808 | fallthrough; 1809 | case ACER_WMID: 1810 | status = WMID_get_u32(value, cap); 1811 | break; 1812 | case ACER_WMID_v2: 1813 | if (cap & (ACER_CAP_WIRELESS | 1814 | ACER_CAP_BLUETOOTH | 1815 | ACER_CAP_THREEG)) 1816 | status = wmid_v2_get_u32(value, cap); 1817 | else if (wmi_has_guid(WMID_GUID2)) 1818 | status = WMID_get_u32(value, cap); 1819 | break; 1820 | } 1821 | 1822 | return status; 1823 | } 1824 | 1825 | static acpi_status set_u32(u32 value, u32 cap) 1826 | { 1827 | acpi_status status; 1828 | 1829 | if (interface->capability & cap) { 1830 | switch (interface->type) { 1831 | case ACER_AMW0: 1832 | return AMW0_set_u32(value, cap); 1833 | case ACER_AMW0_V2: 1834 | if (cap == ACER_CAP_MAILLED) 1835 | return AMW0_set_u32(value, cap); 1836 | 1837 | /* 1838 | * On some models, some WMID methods don't toggle 1839 | * properly. For those cases, we want to run the AMW0 1840 | * method afterwards to be certain we've really toggled 1841 | * the device state. 1842 | */ 1843 | if (cap == ACER_CAP_WIRELESS || 1844 | cap == ACER_CAP_BLUETOOTH) { 1845 | status = WMID_set_u32(value, cap); 1846 | if (ACPI_FAILURE(status)) 1847 | return status; 1848 | 1849 | return AMW0_set_u32(value, cap); 1850 | } 1851 | fallthrough; 1852 | case ACER_WMID: 1853 | return WMID_set_u32(value, cap); 1854 | case ACER_WMID_v2: 1855 | if (cap & (ACER_CAP_WIRELESS | 1856 | ACER_CAP_BLUETOOTH | 1857 | ACER_CAP_THREEG)) 1858 | return wmid_v2_set_u32(value, cap); 1859 | else if (wmi_has_guid(WMID_GUID2)) 1860 | return WMID_set_u32(value, cap); 1861 | fallthrough; 1862 | default: 1863 | return AE_BAD_PARAMETER; 1864 | } 1865 | } 1866 | return AE_BAD_PARAMETER; 1867 | } 1868 | 1869 | static acpi_status set_u8_array(u8 array[], size_t array_size, u32 cap) 1870 | { 1871 | acpi_status status; 1872 | 1873 | if (interface->capability & cap) { 1874 | switch (interface->type) { 1875 | default: 1876 | return AE_BAD_PARAMETER; 1877 | } 1878 | } else if (gaming_interface->capability & cap) { 1879 | switch (gaming_interface->type) { 1880 | case ACER_WMID_GAMING: 1881 | status = WMID_gaming_set_u8_array(array, array_size, cap); 1882 | if (ACPI_FAILURE(status)) 1883 | return status; 1884 | fallthrough; 1885 | default: 1886 | return AE_BAD_PARAMETER; 1887 | } 1888 | } 1889 | return AE_BAD_PARAMETER; 1890 | } 1891 | 1892 | static void __init acer_commandline_init(void) 1893 | { 1894 | /* 1895 | * These will all fail silently if the value given is invalid, or the 1896 | * capability isn't available on the given interface 1897 | */ 1898 | if (mailled >= 0) 1899 | set_u32(mailled, ACER_CAP_MAILLED); 1900 | if (!has_type_aa && threeg >= 0) 1901 | set_u32(threeg, ACER_CAP_THREEG); 1902 | if (brightness >= 0) 1903 | set_u32(brightness, ACER_CAP_BRIGHTNESS); 1904 | } 1905 | 1906 | /* 1907 | * LED device (Mail LED only, no other LEDs known yet) 1908 | */ 1909 | static void mail_led_set(struct led_classdev *led_cdev, 1910 | enum led_brightness value) 1911 | { 1912 | set_u32(value, ACER_CAP_MAILLED); 1913 | } 1914 | 1915 | static struct led_classdev mail_led = { 1916 | .name = "acer-wmi::mail", 1917 | .brightness_set = mail_led_set, 1918 | }; 1919 | 1920 | static int acer_led_init(struct device *dev) 1921 | { 1922 | return led_classdev_register(dev, &mail_led); 1923 | } 1924 | 1925 | static void acer_led_exit(void) 1926 | { 1927 | set_u32(LED_OFF, ACER_CAP_MAILLED); 1928 | led_classdev_unregister(&mail_led); 1929 | } 1930 | 1931 | /* 1932 | * Keyboard RGB backlight character device handler. 1933 | * On systems supporting Acer gaming functions, a char device 1934 | * will be exposed to communicate with user space 1935 | * for keyboard RGB backlight configurations. 1936 | */ 1937 | 1938 | static ssize_t gkbbl_drv_write(struct file *file, 1939 | const char __user *buf, size_t count, loff_t *offset) 1940 | { 1941 | u8 config_buf[GAMING_KBBL_CONFIG_LEN]; 1942 | unsigned long err; 1943 | 1944 | if (count != GAMING_KBBL_CONFIG_LEN) { 1945 | pr_err("Invalid data given to gaming keyboard backlight"); 1946 | return 0; 1947 | } 1948 | err = copy_from_user(config_buf, buf, GAMING_KBBL_CONFIG_LEN); 1949 | if (err < 0) 1950 | pr_err("Copying data from userspace failed with code: %lu\n", err); 1951 | 1952 | set_u8_array(config_buf, GAMING_KBBL_CONFIG_LEN, ACER_CAP_GAMINGKB); 1953 | return count; 1954 | } 1955 | 1956 | 1957 | static const struct file_operations gkbbl_dev_fops = { 1958 | .owner = THIS_MODULE, 1959 | .write = gkbbl_drv_write 1960 | }; 1961 | 1962 | struct gkbbl_device_data { 1963 | struct cdev cdev; 1964 | }; 1965 | 1966 | static struct class *gkbbl_dev_class; 1967 | static struct gkbbl_device_data gkbbl_dev_data; 1968 | 1969 | static int gkbbl_dev_uevent(struct device *dev, struct kobj_uevent_env *env) 1970 | { 1971 | add_uevent_var(env, "DEVMODE=%#o", 0666); 1972 | return 0; 1973 | } 1974 | 1975 | static int __init gaming_kbbl_cdev_init(void) 1976 | { 1977 | dev_t dev; 1978 | int err; 1979 | 1980 | err = alloc_chrdev_region(&dev, 0, 1, GAMING_KBBL_CHR); 1981 | if (err < 0) { 1982 | pr_err("Char drive registering for gaming keyboard backlight failed: %d\n", err); 1983 | return err; 1984 | } 1985 | 1986 | dev_major = MAJOR(dev); 1987 | 1988 | gkbbl_dev_class = class_create(THIS_MODULE, GAMING_KBBL_CHR); 1989 | gkbbl_dev_class->dev_uevent = gkbbl_dev_uevent; 1990 | 1991 | cdev_init(&gkbbl_dev_data.cdev, &gkbbl_dev_fops); 1992 | gkbbl_dev_data.cdev.owner = THIS_MODULE; 1993 | 1994 | cdev_add(&gkbbl_dev_data.cdev, MKDEV(dev_major, GAMING_KBBL_MINOR), 1); 1995 | 1996 | device_create(gkbbl_dev_class, NULL, MKDEV(dev_major, GAMING_KBBL_MINOR), NULL, "%s-%d", 1997 | GAMING_KBBL_CHR, 1998 | GAMING_KBBL_MINOR); 1999 | 2000 | return 0; 2001 | } 2002 | 2003 | static void __exit gaming_kbbl_cdev_exit(void) 2004 | { 2005 | device_destroy(gkbbl_dev_class, MKDEV(dev_major, GAMING_KBBL_MINOR)); 2006 | 2007 | class_unregister(gkbbl_dev_class); 2008 | class_destroy(gkbbl_dev_class); 2009 | 2010 | unregister_chrdev_region(MKDEV(dev_major, GAMING_KBBL_MINOR), MINORMASK); 2011 | } 2012 | 2013 | 2014 | /* 2015 | * Keyboard RGB backlight character device handler. 2016 | * On systems supporting Acer gaming functions, a char device 2017 | * will be exposed to communicate with user space 2018 | * for keyboard RGB backlight configurations. 2019 | * Similar to above, but for handling static coloring 2020 | */ 2021 | 2022 | 2023 | struct led_zone_set_param { 2024 | u8 zone; 2025 | u8 red; 2026 | u8 green; 2027 | u8 blue; 2028 | } __packed; 2029 | 2030 | static ssize_t gkbbl_static_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) 2031 | { 2032 | u8 config_buf[4]={0,0,0,0}; 2033 | unsigned long err; 2034 | struct led_zone_set_param set_params; 2035 | struct acpi_buffer set_input; 2036 | err = copy_from_user(config_buf, buf, GAMING_KBBL_STATIC_CONFIG_LEN); 2037 | set_params = (struct led_zone_set_param) { 2038 | .zone = config_buf[0], 2039 | .red = config_buf[1], 2040 | .green = config_buf[2], 2041 | .blue = config_buf[3], 2042 | }; 2043 | set_input = (struct acpi_buffer) { 2044 | sizeof(set_params), 2045 | &set_params 2046 | }; 2047 | 2048 | if (count != GAMING_KBBL_STATIC_CONFIG_LEN) { 2049 | pr_err("Invalid data given to gaming keyboard static backlight"); 2050 | return 0; 2051 | } 2052 | 2053 | if (err < 0) 2054 | pr_err("Copying data from userspace failed with code: %lu\n", err); 2055 | 2056 | wmi_evaluate_method( WMID_GUID4, 0, ACER_WMID_SET_GAMING_STATIC_LED_METHODID, &set_input, NULL); 2057 | return count; 2058 | } 2059 | 2060 | 2061 | static const struct file_operations gkbbl_static_dev_fops = { 2062 | .owner = THIS_MODULE, 2063 | .write = gkbbl_static_drv_write 2064 | }; 2065 | 2066 | struct gkbbl_static_device_data { 2067 | struct cdev cdev; 2068 | }; 2069 | 2070 | static struct class *gkbbl_static_dev_class; 2071 | static struct gkbbl_device_data gkbbl_static_dev_data; 2072 | 2073 | static int gkbbl_static_dev_uevent(struct device *dev, struct kobj_uevent_env *env) 2074 | { 2075 | add_uevent_var(env, "DEVMODE=%#o", 0666); 2076 | return 0; 2077 | } 2078 | 2079 | static int __init gaming_kbbl_static_cdev_init(void) 2080 | { 2081 | dev_t dev; 2082 | int err; 2083 | 2084 | err = alloc_chrdev_region(&dev, 0, 1, GAMING_KBBL_STATIC_CHR); 2085 | if (err < 0) { 2086 | pr_err("Char drive registering for gaming keyboard static backlight failed: %d\n", err); 2087 | return err; 2088 | } 2089 | 2090 | dev_major = MAJOR(dev); 2091 | 2092 | gkbbl_static_dev_class = class_create(THIS_MODULE, GAMING_KBBL_STATIC_CHR); 2093 | gkbbl_static_dev_class->dev_uevent = gkbbl_static_dev_uevent; 2094 | 2095 | cdev_init(&gkbbl_static_dev_data.cdev, &gkbbl_static_dev_fops); 2096 | gkbbl_static_dev_data.cdev.owner = THIS_MODULE; 2097 | 2098 | cdev_add(&gkbbl_static_dev_data.cdev, MKDEV(dev_major, GAMING_KBBL_STATIC_MINOR), 1); 2099 | 2100 | device_create(gkbbl_static_dev_class, NULL, MKDEV(dev_major, GAMING_KBBL_STATIC_MINOR), NULL, "%s-%d", 2101 | GAMING_KBBL_STATIC_CHR, 2102 | GAMING_KBBL_STATIC_MINOR); 2103 | 2104 | return 0; 2105 | } 2106 | 2107 | static void __exit gaming_kbbl_static_cdev_exit(void) 2108 | { 2109 | device_destroy(gkbbl_static_dev_class, MKDEV(dev_major, GAMING_KBBL_STATIC_MINOR)); 2110 | 2111 | class_unregister(gkbbl_static_dev_class); 2112 | class_destroy(gkbbl_static_dev_class); 2113 | 2114 | unregister_chrdev_region(MKDEV(dev_major, GAMING_KBBL_STATIC_MINOR), MINORMASK); 2115 | } 2116 | 2117 | /* 2118 | * Backlight device 2119 | */ 2120 | static struct backlight_device *acer_backlight_device; 2121 | 2122 | static int read_brightness(struct backlight_device *bd) 2123 | { 2124 | u32 value; 2125 | get_u32(&value, ACER_CAP_BRIGHTNESS); 2126 | return value; 2127 | } 2128 | 2129 | static int update_bl_status(struct backlight_device *bd) 2130 | { 2131 | int intensity = bd->props.brightness; 2132 | 2133 | if (bd->props.power != FB_BLANK_UNBLANK) 2134 | intensity = 0; 2135 | if (bd->props.fb_blank != FB_BLANK_UNBLANK) 2136 | intensity = 0; 2137 | 2138 | set_u32(intensity, ACER_CAP_BRIGHTNESS); 2139 | 2140 | return 0; 2141 | } 2142 | 2143 | static const struct backlight_ops acer_bl_ops = { 2144 | .get_brightness = read_brightness, 2145 | .update_status = update_bl_status, 2146 | }; 2147 | 2148 | static int acer_backlight_init(struct device *dev) 2149 | { 2150 | struct backlight_properties props; 2151 | struct backlight_device *bd; 2152 | 2153 | memset(&props, 0, sizeof(struct backlight_properties)); 2154 | props.type = BACKLIGHT_PLATFORM; 2155 | props.max_brightness = max_brightness; 2156 | bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, 2157 | &props); 2158 | if (IS_ERR(bd)) { 2159 | pr_err("Could not register Acer backlight device\n"); 2160 | acer_backlight_device = NULL; 2161 | return PTR_ERR(bd); 2162 | } 2163 | 2164 | acer_backlight_device = bd; 2165 | 2166 | bd->props.power = FB_BLANK_UNBLANK; 2167 | bd->props.brightness = read_brightness(bd); 2168 | backlight_update_status(bd); 2169 | return 0; 2170 | } 2171 | 2172 | static void acer_backlight_exit(void) 2173 | { 2174 | backlight_device_unregister(acer_backlight_device); 2175 | } 2176 | 2177 | /* 2178 | * Accelerometer device 2179 | */ 2180 | static acpi_handle gsensor_handle; 2181 | 2182 | static int acer_gsensor_init(void) 2183 | { 2184 | acpi_status status; 2185 | struct acpi_buffer output; 2186 | union acpi_object out_obj; 2187 | 2188 | output.length = sizeof(out_obj); 2189 | output.pointer = &out_obj; 2190 | status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output); 2191 | if (ACPI_FAILURE(status)) 2192 | return -1; 2193 | 2194 | return 0; 2195 | } 2196 | 2197 | static int acer_gsensor_open(struct input_dev *input) 2198 | { 2199 | return acer_gsensor_init(); 2200 | } 2201 | 2202 | static int acer_gsensor_event(void) 2203 | { 2204 | acpi_status status; 2205 | struct acpi_buffer output; 2206 | union acpi_object out_obj[5]; 2207 | 2208 | if (!acer_wmi_accel_dev) 2209 | return -1; 2210 | 2211 | output.length = sizeof(out_obj); 2212 | output.pointer = out_obj; 2213 | 2214 | status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output); 2215 | if (ACPI_FAILURE(status)) 2216 | return -1; 2217 | 2218 | if (out_obj->package.count != 4) 2219 | return -1; 2220 | 2221 | input_report_abs(acer_wmi_accel_dev, ABS_X, 2222 | (s16)out_obj->package.elements[0].integer.value); 2223 | input_report_abs(acer_wmi_accel_dev, ABS_Y, 2224 | (s16)out_obj->package.elements[1].integer.value); 2225 | input_report_abs(acer_wmi_accel_dev, ABS_Z, 2226 | (s16)out_obj->package.elements[2].integer.value); 2227 | input_sync(acer_wmi_accel_dev); 2228 | return 0; 2229 | } 2230 | 2231 | /* 2232 | * Predator series turbo button 2233 | */ 2234 | static int acer_toggle_turbo(void) 2235 | { 2236 | u64 turbo_led_state; 2237 | 2238 | /* Get current state from turbo button */ 2239 | if (ACPI_FAILURE(WMID_gaming_get_u64(&turbo_led_state, ACER_CAP_TURBO_LED))) 2240 | return -1; 2241 | 2242 | if (turbo_led_state) { 2243 | /* Turn off turbo led */ 2244 | WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED); 2245 | 2246 | /* Set FAN mode to auto */ 2247 | WMID_gaming_set_fan_mode(0x1); 2248 | 2249 | /* Set OC to normal */ 2250 | WMID_gaming_set_u64(0x5, ACER_CAP_TURBO_OC); 2251 | WMID_gaming_set_u64(0x7, ACER_CAP_TURBO_OC); 2252 | } else { 2253 | /* Turn on turbo led */ 2254 | WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED); 2255 | 2256 | /* Set FAN mode to turbo */ 2257 | WMID_gaming_set_fan_mode(0x2); 2258 | 2259 | /* Set OC to turbo mode */ 2260 | WMID_gaming_set_u64(0x205, ACER_CAP_TURBO_OC); 2261 | WMID_gaming_set_u64(0x207, ACER_CAP_TURBO_OC); 2262 | } 2263 | return turbo_led_state; 2264 | } 2265 | 2266 | /* 2267 | * Switch series keyboard dock status 2268 | */ 2269 | static int acer_kbd_dock_state_to_sw_tablet_mode(u8 kbd_dock_state) 2270 | { 2271 | switch (kbd_dock_state) { 2272 | case 0x01: /* Docked, traditional clamshell laptop mode */ 2273 | return 0; 2274 | case 0x04: /* Stand-alone tablet */ 2275 | case 0x40: /* Docked, tent mode, keyboard not usable */ 2276 | return 1; 2277 | default: 2278 | pr_warn("Unknown kbd_dock_state 0x%02x\n", kbd_dock_state); 2279 | } 2280 | 2281 | return 0; 2282 | } 2283 | 2284 | static void acer_kbd_dock_get_initial_state(void) 2285 | { 2286 | u8 *output, input[8] = { 0x05, 0x00, }; 2287 | struct acpi_buffer input_buf = { sizeof(input), input }; 2288 | struct acpi_buffer output_buf = { ACPI_ALLOCATE_BUFFER, NULL }; 2289 | union acpi_object *obj; 2290 | acpi_status status; 2291 | int sw_tablet_mode; 2292 | 2293 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input_buf, &output_buf); 2294 | if (ACPI_FAILURE(status)) { 2295 | pr_err("Error getting keyboard-dock initial status: %s\n", 2296 | acpi_format_exception(status)); 2297 | return; 2298 | } 2299 | 2300 | obj = output_buf.pointer; 2301 | if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) { 2302 | pr_err("Unexpected output format getting keyboard-dock initial status\n"); 2303 | goto out_free_obj; 2304 | } 2305 | 2306 | output = obj->buffer.pointer; 2307 | if (output[0] != 0x00 || (output[3] != 0x05 && output[3] != 0x45)) { 2308 | pr_err("Unexpected output [0]=0x%02x [3]=0x%02x getting keyboard-dock initial status\n", 2309 | output[0], output[3]); 2310 | goto out_free_obj; 2311 | } 2312 | 2313 | sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(output[4]); 2314 | input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode); 2315 | 2316 | out_free_obj: 2317 | kfree(obj); 2318 | } 2319 | 2320 | static void acer_kbd_dock_event(const struct event_return_value *event) 2321 | { 2322 | int sw_tablet_mode; 2323 | 2324 | if (!has_cap(ACER_CAP_KBD_DOCK)) 2325 | return; 2326 | 2327 | sw_tablet_mode = acer_kbd_dock_state_to_sw_tablet_mode(event->kbd_dock_state); 2328 | input_report_switch(acer_wmi_input_dev, SW_TABLET_MODE, sw_tablet_mode); 2329 | input_sync(acer_wmi_input_dev); 2330 | } 2331 | 2332 | /* 2333 | * Rfkill devices 2334 | */ 2335 | static void acer_rfkill_update(struct work_struct *ignored); 2336 | static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update); 2337 | static void acer_rfkill_update(struct work_struct *ignored) 2338 | { 2339 | u32 state; 2340 | acpi_status status; 2341 | 2342 | if (has_cap(ACER_CAP_WIRELESS)) { 2343 | status = get_u32(&state, ACER_CAP_WIRELESS); 2344 | if (ACPI_SUCCESS(status)) { 2345 | if (quirks->wireless == 3) 2346 | rfkill_set_hw_state(wireless_rfkill, !state); 2347 | else 2348 | rfkill_set_sw_state(wireless_rfkill, !state); 2349 | } 2350 | } 2351 | 2352 | if (has_cap(ACER_CAP_BLUETOOTH)) { 2353 | status = get_u32(&state, ACER_CAP_BLUETOOTH); 2354 | if (ACPI_SUCCESS(status)) 2355 | rfkill_set_sw_state(bluetooth_rfkill, !state); 2356 | } 2357 | 2358 | if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) { 2359 | status = get_u32(&state, ACER_WMID3_GDS_THREEG); 2360 | if (ACPI_SUCCESS(status)) 2361 | rfkill_set_sw_state(threeg_rfkill, !state); 2362 | } 2363 | 2364 | schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 2365 | } 2366 | 2367 | static int acer_rfkill_set(void *data, bool blocked) 2368 | { 2369 | acpi_status status; 2370 | u32 cap = (unsigned long)data; 2371 | 2372 | if (rfkill_inited) { 2373 | status = set_u32(!blocked, cap); 2374 | if (ACPI_FAILURE(status)) 2375 | return -ENODEV; 2376 | } 2377 | 2378 | return 0; 2379 | } 2380 | 2381 | static const struct rfkill_ops acer_rfkill_ops = { 2382 | .set_block = acer_rfkill_set, 2383 | }; 2384 | 2385 | static struct rfkill *acer_rfkill_register(struct device *dev, 2386 | enum rfkill_type type, 2387 | char *name, u32 cap) 2388 | { 2389 | int err; 2390 | struct rfkill *rfkill_dev; 2391 | u32 state; 2392 | acpi_status status; 2393 | 2394 | rfkill_dev = rfkill_alloc(name, dev, type, 2395 | &acer_rfkill_ops, 2396 | (void *)(unsigned long)cap); 2397 | if (!rfkill_dev) 2398 | return ERR_PTR(-ENOMEM); 2399 | 2400 | status = get_u32(&state, cap); 2401 | 2402 | err = rfkill_register(rfkill_dev); 2403 | if (err) { 2404 | rfkill_destroy(rfkill_dev); 2405 | return ERR_PTR(err); 2406 | } 2407 | 2408 | if (ACPI_SUCCESS(status)) 2409 | rfkill_set_sw_state(rfkill_dev, !state); 2410 | 2411 | return rfkill_dev; 2412 | } 2413 | 2414 | static int acer_rfkill_init(struct device *dev) 2415 | { 2416 | int err; 2417 | 2418 | if (has_cap(ACER_CAP_WIRELESS)) { 2419 | wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN, 2420 | "acer-wireless", ACER_CAP_WIRELESS); 2421 | if (IS_ERR(wireless_rfkill)) { 2422 | err = PTR_ERR(wireless_rfkill); 2423 | goto error_wireless; 2424 | } 2425 | } 2426 | 2427 | if (has_cap(ACER_CAP_BLUETOOTH)) { 2428 | bluetooth_rfkill = acer_rfkill_register(dev, 2429 | RFKILL_TYPE_BLUETOOTH, "acer-bluetooth", 2430 | ACER_CAP_BLUETOOTH); 2431 | if (IS_ERR(bluetooth_rfkill)) { 2432 | err = PTR_ERR(bluetooth_rfkill); 2433 | goto error_bluetooth; 2434 | } 2435 | } 2436 | 2437 | if (has_cap(ACER_CAP_THREEG)) { 2438 | threeg_rfkill = acer_rfkill_register(dev, 2439 | RFKILL_TYPE_WWAN, "acer-threeg", 2440 | ACER_CAP_THREEG); 2441 | if (IS_ERR(threeg_rfkill)) { 2442 | err = PTR_ERR(threeg_rfkill); 2443 | goto error_threeg; 2444 | } 2445 | } 2446 | 2447 | rfkill_inited = true; 2448 | 2449 | if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) && 2450 | has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG)) 2451 | schedule_delayed_work(&acer_rfkill_work, 2452 | round_jiffies_relative(HZ)); 2453 | 2454 | return 0; 2455 | 2456 | error_threeg: 2457 | if (has_cap(ACER_CAP_BLUETOOTH)) { 2458 | rfkill_unregister(bluetooth_rfkill); 2459 | rfkill_destroy(bluetooth_rfkill); 2460 | } 2461 | error_bluetooth: 2462 | if (has_cap(ACER_CAP_WIRELESS)) { 2463 | rfkill_unregister(wireless_rfkill); 2464 | rfkill_destroy(wireless_rfkill); 2465 | } 2466 | error_wireless: 2467 | return err; 2468 | } 2469 | 2470 | static void acer_rfkill_exit(void) 2471 | { 2472 | if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) && 2473 | has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG)) 2474 | cancel_delayed_work_sync(&acer_rfkill_work); 2475 | 2476 | if (has_cap(ACER_CAP_WIRELESS)) { 2477 | rfkill_unregister(wireless_rfkill); 2478 | rfkill_destroy(wireless_rfkill); 2479 | } 2480 | 2481 | if (has_cap(ACER_CAP_BLUETOOTH)) { 2482 | rfkill_unregister(bluetooth_rfkill); 2483 | rfkill_destroy(bluetooth_rfkill); 2484 | } 2485 | 2486 | if (has_cap(ACER_CAP_THREEG)) { 2487 | rfkill_unregister(threeg_rfkill); 2488 | rfkill_destroy(threeg_rfkill); 2489 | } 2490 | return; 2491 | } 2492 | 2493 | static void acer_wmi_notify(u32 value, void *context) 2494 | { 2495 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 2496 | union acpi_object *obj; 2497 | struct event_return_value return_value; 2498 | acpi_status status; 2499 | u16 device_state; 2500 | const struct key_entry *key; 2501 | u32 scancode; 2502 | 2503 | status = wmi_get_event_data(value, &response); 2504 | if (status != AE_OK) { 2505 | pr_warn("bad event status 0x%x\n", status); 2506 | return; 2507 | } 2508 | 2509 | obj = (union acpi_object *)response.pointer; 2510 | 2511 | if (!obj) 2512 | return; 2513 | if (obj->type != ACPI_TYPE_BUFFER) { 2514 | pr_warn("Unknown response received %d\n", obj->type); 2515 | kfree(obj); 2516 | return; 2517 | } 2518 | if (obj->buffer.length != 8) { 2519 | pr_warn("Unknown buffer length %d\n", obj->buffer.length); 2520 | kfree(obj); 2521 | return; 2522 | } 2523 | 2524 | return_value = *((struct event_return_value *)obj->buffer.pointer); 2525 | kfree(obj); 2526 | 2527 | switch (return_value.function) { 2528 | case WMID_HOTKEY_EVENT: 2529 | device_state = return_value.device_state; 2530 | pr_debug("device state: 0x%x\n", device_state); 2531 | 2532 | key = sparse_keymap_entry_from_scancode(acer_wmi_input_dev, 2533 | return_value.key_num); 2534 | if (!key) { 2535 | pr_warn("Unknown key number - 0x%x\n", 2536 | return_value.key_num); 2537 | } else { 2538 | scancode = return_value.key_num; 2539 | switch (key->keycode) { 2540 | case KEY_WLAN: 2541 | case KEY_BLUETOOTH: 2542 | if (has_cap(ACER_CAP_WIRELESS)) 2543 | rfkill_set_sw_state(wireless_rfkill, 2544 | !(device_state & ACER_WMID3_GDS_WIRELESS)); 2545 | if (has_cap(ACER_CAP_THREEG)) 2546 | rfkill_set_sw_state(threeg_rfkill, 2547 | !(device_state & ACER_WMID3_GDS_THREEG)); 2548 | if (has_cap(ACER_CAP_BLUETOOTH)) 2549 | rfkill_set_sw_state(bluetooth_rfkill, 2550 | !(device_state & ACER_WMID3_GDS_BLUETOOTH)); 2551 | break; 2552 | case KEY_TOUCHPAD_TOGGLE: 2553 | scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ? 2554 | KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF; 2555 | } 2556 | sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true); 2557 | } 2558 | break; 2559 | case WMID_ACCEL_OR_KBD_DOCK_EVENT: 2560 | acer_gsensor_event(); 2561 | acer_kbd_dock_event(&return_value); 2562 | break; 2563 | case WMID_GAMING_TURBO_KEY_EVENT: 2564 | if (return_value.key_num == 0x4) 2565 | acer_toggle_turbo(); 2566 | break; 2567 | default: 2568 | pr_warn("Unknown function number - %d - %d\n", 2569 | return_value.function, return_value.key_num); 2570 | break; 2571 | } 2572 | } 2573 | 2574 | static acpi_status __init 2575 | wmid3_set_function_mode(struct func_input_params *params, 2576 | struct func_return_value *return_value) 2577 | { 2578 | acpi_status status; 2579 | union acpi_object *obj; 2580 | 2581 | struct acpi_buffer input = { sizeof(struct func_input_params), params }; 2582 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 2583 | 2584 | status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output); 2585 | if (ACPI_FAILURE(status)) 2586 | return status; 2587 | 2588 | obj = output.pointer; 2589 | 2590 | if (!obj) 2591 | return AE_ERROR; 2592 | else if (obj->type != ACPI_TYPE_BUFFER) { 2593 | kfree(obj); 2594 | return AE_ERROR; 2595 | } 2596 | if (obj->buffer.length != 4) { 2597 | pr_warn("Unknown buffer length %d\n", obj->buffer.length); 2598 | kfree(obj); 2599 | return AE_ERROR; 2600 | } 2601 | 2602 | *return_value = *((struct func_return_value *)obj->buffer.pointer); 2603 | kfree(obj); 2604 | 2605 | return status; 2606 | } 2607 | 2608 | static int __init acer_wmi_enable_ec_raw(void) 2609 | { 2610 | struct func_return_value return_value; 2611 | acpi_status status; 2612 | struct func_input_params params = { 2613 | .function_num = 0x1, 2614 | .commun_devices = 0xFFFF, 2615 | .devices = 0xFFFF, 2616 | .app_status = 0x00, /* Launch Manager Deactive */ 2617 | .app_mask = 0x01, 2618 | }; 2619 | 2620 | status = wmid3_set_function_mode(¶ms, &return_value); 2621 | 2622 | if (return_value.error_code || return_value.ec_return_value) 2623 | pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n", 2624 | return_value.error_code, 2625 | return_value.ec_return_value); 2626 | else 2627 | pr_info("Enabled EC raw mode\n"); 2628 | 2629 | return status; 2630 | } 2631 | 2632 | static int __init acer_wmi_enable_lm(void) 2633 | { 2634 | struct func_return_value return_value; 2635 | acpi_status status; 2636 | struct func_input_params params = { 2637 | .function_num = 0x1, 2638 | .commun_devices = 0xFFFF, 2639 | .devices = 0xFFFF, 2640 | .app_status = 0x01, /* Launch Manager Active */ 2641 | .app_mask = 0x01, 2642 | }; 2643 | 2644 | status = wmid3_set_function_mode(¶ms, &return_value); 2645 | 2646 | if (return_value.error_code || return_value.ec_return_value) 2647 | pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n", 2648 | return_value.error_code, 2649 | return_value.ec_return_value); 2650 | 2651 | return status; 2652 | } 2653 | 2654 | static int __init acer_wmi_enable_rf_button(void) 2655 | { 2656 | struct func_return_value return_value; 2657 | acpi_status status; 2658 | struct func_input_params params = { 2659 | .function_num = 0x1, 2660 | .commun_devices = 0xFFFF, 2661 | .devices = 0xFFFF, 2662 | .app_status = 0x10, /* RF Button Active */ 2663 | .app_mask = 0x10, 2664 | }; 2665 | 2666 | status = wmid3_set_function_mode(¶ms, &return_value); 2667 | 2668 | if (return_value.error_code || return_value.ec_return_value) 2669 | pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n", 2670 | return_value.error_code, 2671 | return_value.ec_return_value); 2672 | 2673 | return status; 2674 | } 2675 | 2676 | static int __init acer_wmi_accel_setup(void) 2677 | { 2678 | struct acpi_device *adev; 2679 | int err; 2680 | 2681 | adev = acpi_dev_get_first_match_dev("BST0001", NULL, -1); 2682 | if (!adev) 2683 | return -ENODEV; 2684 | 2685 | gsensor_handle = acpi_device_handle(adev); 2686 | acpi_dev_put(adev); 2687 | 2688 | acer_wmi_accel_dev = input_allocate_device(); 2689 | if (!acer_wmi_accel_dev) 2690 | return -ENOMEM; 2691 | 2692 | acer_wmi_accel_dev->open = acer_gsensor_open; 2693 | 2694 | acer_wmi_accel_dev->name = "Acer BMA150 accelerometer"; 2695 | acer_wmi_accel_dev->phys = "wmi/input1"; 2696 | acer_wmi_accel_dev->id.bustype = BUS_HOST; 2697 | acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS); 2698 | input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0); 2699 | input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0); 2700 | input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0); 2701 | 2702 | err = input_register_device(acer_wmi_accel_dev); 2703 | if (err) 2704 | goto err_free_dev; 2705 | 2706 | return 0; 2707 | 2708 | err_free_dev: 2709 | input_free_device(acer_wmi_accel_dev); 2710 | return err; 2711 | } 2712 | 2713 | static int __init acer_wmi_input_setup(void) 2714 | { 2715 | acpi_status status; 2716 | int err; 2717 | 2718 | acer_wmi_input_dev = input_allocate_device(); 2719 | if (!acer_wmi_input_dev) 2720 | return -ENOMEM; 2721 | 2722 | acer_wmi_input_dev->name = "Acer WMI hotkeys"; 2723 | acer_wmi_input_dev->phys = "wmi/input0"; 2724 | acer_wmi_input_dev->id.bustype = BUS_HOST; 2725 | 2726 | err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL); 2727 | if (err) 2728 | goto err_free_dev; 2729 | 2730 | if (has_cap(ACER_CAP_KBD_DOCK)) 2731 | input_set_capability(acer_wmi_input_dev, EV_SW, SW_TABLET_MODE); 2732 | 2733 | status = wmi_install_notify_handler(ACERWMID_EVENT_GUID, 2734 | acer_wmi_notify, NULL); 2735 | if (ACPI_FAILURE(status)) { 2736 | err = -EIO; 2737 | goto err_free_dev; 2738 | } 2739 | 2740 | if (has_cap(ACER_CAP_KBD_DOCK)) 2741 | acer_kbd_dock_get_initial_state(); 2742 | 2743 | err = input_register_device(acer_wmi_input_dev); 2744 | if (err) 2745 | goto err_uninstall_notifier; 2746 | 2747 | return 0; 2748 | 2749 | err_uninstall_notifier: 2750 | wmi_remove_notify_handler(ACERWMID_EVENT_GUID); 2751 | err_free_dev: 2752 | input_free_device(acer_wmi_input_dev); 2753 | return err; 2754 | } 2755 | 2756 | static void acer_wmi_input_destroy(void) 2757 | { 2758 | wmi_remove_notify_handler(ACERWMID_EVENT_GUID); 2759 | input_unregister_device(acer_wmi_input_dev); 2760 | } 2761 | 2762 | /* 2763 | * debugfs functions 2764 | */ 2765 | static u32 get_wmid_devices(void) 2766 | { 2767 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 2768 | union acpi_object *obj; 2769 | acpi_status status; 2770 | u32 devices = 0; 2771 | 2772 | status = wmi_query_block(WMID_GUID2, 0, &out); 2773 | if (ACPI_FAILURE(status)) 2774 | return 0; 2775 | 2776 | obj = (union acpi_object *) out.pointer; 2777 | if (obj) { 2778 | if (obj->type == ACPI_TYPE_BUFFER && 2779 | (obj->buffer.length == sizeof(u32) || 2780 | obj->buffer.length == sizeof(u64))) { 2781 | devices = *((u32 *) obj->buffer.pointer); 2782 | } else if (obj->type == ACPI_TYPE_INTEGER) { 2783 | devices = (u32) obj->integer.value; 2784 | } 2785 | } 2786 | 2787 | kfree(out.pointer); 2788 | return devices; 2789 | } 2790 | 2791 | /* 2792 | * Platform device 2793 | */ 2794 | static int acer_platform_probe(struct platform_device *device) 2795 | { 2796 | int err; 2797 | 2798 | if (has_cap(ACER_CAP_MAILLED)) { 2799 | err = acer_led_init(&device->dev); 2800 | if (err) 2801 | goto error_mailled; 2802 | } 2803 | 2804 | if (has_cap(ACER_CAP_BRIGHTNESS)) { 2805 | err = acer_backlight_init(&device->dev); 2806 | if (err) 2807 | goto error_brightness; 2808 | } 2809 | 2810 | err = acer_rfkill_init(&device->dev); 2811 | if (err) 2812 | goto error_rfkill; 2813 | 2814 | return err; 2815 | 2816 | error_rfkill: 2817 | if (has_cap(ACER_CAP_BRIGHTNESS)) 2818 | acer_backlight_exit(); 2819 | error_brightness: 2820 | if (has_cap(ACER_CAP_MAILLED)) 2821 | acer_led_exit(); 2822 | error_mailled: 2823 | return err; 2824 | } 2825 | 2826 | static int acer_platform_remove(struct platform_device *device) 2827 | { 2828 | if (has_cap(ACER_CAP_MAILLED)) 2829 | acer_led_exit(); 2830 | if (has_cap(ACER_CAP_BRIGHTNESS)) 2831 | acer_backlight_exit(); 2832 | 2833 | acer_rfkill_exit(); 2834 | return 0; 2835 | } 2836 | 2837 | #ifdef CONFIG_PM_SLEEP 2838 | static int acer_suspend(struct device *dev) 2839 | { 2840 | u32 value; 2841 | struct acer_data *data = &interface->data; 2842 | 2843 | if (!data) 2844 | return -ENOMEM; 2845 | 2846 | if (has_cap(ACER_CAP_MAILLED)) { 2847 | get_u32(&value, ACER_CAP_MAILLED); 2848 | set_u32(LED_OFF, ACER_CAP_MAILLED); 2849 | data->mailled = value; 2850 | } 2851 | 2852 | if (has_cap(ACER_CAP_BRIGHTNESS)) { 2853 | get_u32(&value, ACER_CAP_BRIGHTNESS); 2854 | data->brightness = value; 2855 | } 2856 | 2857 | return 0; 2858 | } 2859 | 2860 | static int acer_resume(struct device *dev) 2861 | { 2862 | struct acer_data *data = &interface->data; 2863 | 2864 | if (!data) 2865 | return -ENOMEM; 2866 | 2867 | if (has_cap(ACER_CAP_MAILLED)) 2868 | set_u32(data->mailled, ACER_CAP_MAILLED); 2869 | 2870 | if (has_cap(ACER_CAP_BRIGHTNESS)) 2871 | set_u32(data->brightness, ACER_CAP_BRIGHTNESS); 2872 | 2873 | if (acer_wmi_accel_dev) 2874 | acer_gsensor_init(); 2875 | 2876 | return 0; 2877 | } 2878 | #else 2879 | #define acer_suspend NULL 2880 | #define acer_resume NULL 2881 | #endif 2882 | 2883 | static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume); 2884 | 2885 | static void acer_platform_shutdown(struct platform_device *device) 2886 | { 2887 | struct acer_data *data = &interface->data; 2888 | 2889 | if (!data) 2890 | return; 2891 | 2892 | if (has_cap(ACER_CAP_MAILLED)) 2893 | set_u32(LED_OFF, ACER_CAP_MAILLED); 2894 | } 2895 | 2896 | static struct platform_driver acer_platform_driver = { 2897 | .driver = { 2898 | .name = "acer-wmi", 2899 | .pm = &acer_pm, 2900 | }, 2901 | .probe = acer_platform_probe, 2902 | .remove = acer_platform_remove, 2903 | .shutdown = acer_platform_shutdown, 2904 | }; 2905 | 2906 | static struct platform_device *acer_platform_device; 2907 | 2908 | static void remove_debugfs(void) 2909 | { 2910 | debugfs_remove_recursive(interface->debug.root); 2911 | } 2912 | 2913 | static void __init create_debugfs(void) 2914 | { 2915 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 2916 | 2917 | debugfs_create_u32("devices", S_IRUGO, interface->debug.root, 2918 | &interface->debug.wmid_devices); 2919 | } 2920 | 2921 | static int __init acer_wmi_init(void) 2922 | { 2923 | int err; 2924 | 2925 | pr_info("Acer Laptop ACPI-WMI Extras\n"); 2926 | 2927 | if (dmi_check_system(acer_blacklist)) { 2928 | pr_info("Blacklisted hardware detected - not loading\n"); 2929 | return -ENODEV; 2930 | } 2931 | 2932 | find_quirks(); 2933 | 2934 | /* 2935 | * The AMW0_GUID1 wmi is not only found on Acer family but also other 2936 | * machines like Lenovo, Fujitsu and Medion. In the past days, 2937 | * acer-wmi driver handled those non-Acer machines by quirks list. 2938 | * But actually acer-wmi driver was loaded on any machines that have 2939 | * AMW0_GUID1. This behavior is strange because those machines should 2940 | * be supported by appropriate wmi drivers. e.g. fujitsu-laptop, 2941 | * ideapad-laptop. So, here checks the machine that has AMW0_GUID1 2942 | * should be in Acer/Gateway/Packard Bell white list, or it's already 2943 | * in the past quirk list. 2944 | */ 2945 | if (wmi_has_guid(AMW0_GUID1) && 2946 | !dmi_check_system(amw0_whitelist) && 2947 | quirks == &quirk_unknown) { 2948 | pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n"); 2949 | return -ENODEV; 2950 | } 2951 | 2952 | /* 2953 | * Detect which ACPI-WMI interface we're using. 2954 | */ 2955 | if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 2956 | interface = &AMW0_V2_interface; 2957 | 2958 | if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 2959 | interface = &wmid_interface; 2960 | 2961 | if (wmi_has_guid(WMID_GUID3)) { 2962 | interface = &wmid_v2_interface; 2963 | if (wmi_has_guid(WMID_GUID4)) 2964 | gaming_interface = &wmid_gaming_interface; 2965 | } 2966 | 2967 | if (interface) 2968 | dmi_walk(type_aa_dmi_decode, NULL); 2969 | 2970 | if (wmi_has_guid(WMID_GUID2) && interface) { 2971 | if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) { 2972 | pr_err("Unable to detect available WMID devices\n"); 2973 | return -ENODEV; 2974 | } 2975 | /* WMID always provides brightness methods */ 2976 | interface->capability |= ACER_CAP_BRIGHTNESS; 2977 | } else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa && force_caps == -1) { 2978 | pr_err("No WMID device detection method found\n"); 2979 | return -ENODEV; 2980 | } 2981 | 2982 | if (wmi_has_guid(AMW0_GUID1) && !wmi_has_guid(WMID_GUID1)) { 2983 | interface = &AMW0_interface; 2984 | 2985 | if (ACPI_FAILURE(AMW0_set_capabilities())) { 2986 | pr_err("Unable to detect available AMW0 devices\n"); 2987 | return -ENODEV; 2988 | } 2989 | } 2990 | 2991 | if (wmi_has_guid(AMW0_GUID1)) 2992 | AMW0_find_mailled(); 2993 | 2994 | if (!interface) { 2995 | pr_err("No or unsupported WMI interface, unable to load\n"); 2996 | return -ENODEV; 2997 | } 2998 | 2999 | set_quirks(); 3000 | 3001 | if (dmi_check_system(video_vendor_dmi_table)) 3002 | acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); 3003 | 3004 | if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 3005 | interface->capability &= ~ACER_CAP_BRIGHTNESS; 3006 | 3007 | if (wmi_has_guid(WMID_GUID3)) { 3008 | interface->capability |= ACER_CAP_SET_FUNCTION_MODE; 3009 | if (wmi_has_guid(WMID_GUID4)) { 3010 | gaming_interface->capability |= ACER_CAP_GAMINGKB | ACER_CAP_GAMINGKB_STATIC; 3011 | gaming_kbbl_cdev_init(); 3012 | gaming_kbbl_static_cdev_init(); 3013 | } 3014 | } 3015 | 3016 | if (force_caps != -1) 3017 | interface->capability = force_caps; 3018 | 3019 | if (wmi_has_guid(WMID_GUID3) && 3020 | (interface->capability & ACER_CAP_SET_FUNCTION_MODE)) { 3021 | if (ACPI_FAILURE(acer_wmi_enable_rf_button())) 3022 | pr_warn("Cannot enable RF Button Driver\n"); 3023 | 3024 | if (ec_raw_mode) { 3025 | if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { 3026 | pr_err("Cannot enable EC raw mode\n"); 3027 | return -ENODEV; 3028 | } 3029 | } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { 3030 | pr_err("Cannot enable Launch Manager mode\n"); 3031 | return -ENODEV; 3032 | } 3033 | } else if (ec_raw_mode) { 3034 | pr_info("No WMID EC raw mode enable method\n"); 3035 | } 3036 | 3037 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) { 3038 | err = acer_wmi_input_setup(); 3039 | if (err) 3040 | return err; 3041 | err = acer_wmi_accel_setup(); 3042 | if (err && err != -ENODEV) 3043 | pr_warn("Cannot enable accelerometer\n"); 3044 | } 3045 | 3046 | err = platform_driver_register(&acer_platform_driver); 3047 | if (err) { 3048 | pr_err("Unable to register platform driver\n"); 3049 | goto error_platform_register; 3050 | } 3051 | 3052 | acer_platform_device = platform_device_alloc("acer-wmi", -1); 3053 | if (!acer_platform_device) { 3054 | err = -ENOMEM; 3055 | goto error_device_alloc; 3056 | } 3057 | 3058 | err = platform_device_add(acer_platform_device); 3059 | if (err) 3060 | goto error_device_add; 3061 | 3062 | if (wmi_has_guid(WMID_GUID2)) { 3063 | interface->debug.wmid_devices = get_wmid_devices(); 3064 | create_debugfs(); 3065 | } 3066 | 3067 | /* Override any initial settings with values from the commandline */ 3068 | acer_commandline_init(); 3069 | 3070 | return 0; 3071 | 3072 | error_device_add: 3073 | platform_device_put(acer_platform_device); 3074 | error_device_alloc: 3075 | platform_driver_unregister(&acer_platform_driver); 3076 | error_platform_register: 3077 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) 3078 | acer_wmi_input_destroy(); 3079 | if (acer_wmi_accel_dev) 3080 | input_unregister_device(acer_wmi_accel_dev); 3081 | 3082 | return err; 3083 | } 3084 | 3085 | static void __exit acer_wmi_exit(void) 3086 | { 3087 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) 3088 | acer_wmi_input_destroy(); 3089 | 3090 | if (acer_wmi_accel_dev) 3091 | input_unregister_device(acer_wmi_accel_dev); 3092 | 3093 | if (wmi_has_guid(WMID_GUID4)) { 3094 | gaming_kbbl_cdev_exit(); 3095 | gaming_kbbl_static_cdev_exit(); 3096 | } 3097 | 3098 | remove_debugfs(); 3099 | platform_device_unregister(acer_platform_device); 3100 | platform_driver_unregister(&acer_platform_driver); 3101 | 3102 | pr_info("Acer Laptop WMI Extras unloaded\n"); 3103 | return; 3104 | } 3105 | 3106 | module_init(acer_wmi_init); 3107 | module_exit(acer_wmi_exit); 3108 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | ::-webkit-scrollbar { 2 | display: none; 3 | } 4 | /* General Button Style */ 5 | .button { 6 | position: relative; 7 | display: block; 8 | background: transparent; 9 | width: 200px; 10 | height: 60px; 11 | line-height: 60px; 12 | text-align: center; 13 | font-size: 15px; 14 | font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", 15 | "Helvetica"; 16 | text-decoration: none; 17 | text-transform: uppercase; 18 | margin: 40px auto; 19 | } 20 | .button:before, 21 | .button:after { 22 | width: 200px; 23 | left: 0px; 24 | height: 27px; 25 | z-index: -1; 26 | } 27 | .mediumseagreen { 28 | color: rgb(212, 212, 212); 29 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 30 | } 31 | .mediumseagreen:before, 32 | .mediumseagreen:after { 33 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 34 | border: 4px solid rgb(30, 136, 78); 35 | background: var(--background); 36 | } 37 | .mediumseagreen2 { 38 | color: rgb(212, 212, 212); 39 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 40 | } 41 | .mediumseagreen2:before, 42 | .mediumseagreen2:after { 43 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 44 | border: 4px solid rgb(30, 136, 78); 45 | background: var(--background); 46 | } 47 | 48 | .mediumseagreen3 { 49 | color: rgb(212, 212, 212); 50 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 51 | } 52 | .mediumseagreen3:before, 53 | .mediumseagreen3:after { 54 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 55 | border: 4px solid rgb(30, 136, 78); 56 | background: var(--background); 57 | } 58 | 59 | .mediumseagreen4 { 60 | color: rgb(212, 212, 212); 61 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 62 | } 63 | .mediumseagreen4:before, 64 | .mediumseagreen4:after { 65 | box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 66 | border: 4px solid rgb(30, 136, 78); 67 | background: var(--background); 68 | } 69 | 70 | .button:before { 71 | position: absolute; 72 | content: ""; 73 | border-bottom: none; 74 | -webkit-transform: perspective(15px) rotateX(5deg); 75 | -moz-transform: perspective(15px) rotateX(5deg); 76 | transform: perspective(15px) rotateX(5deg); 77 | } 78 | .button:after { 79 | position: absolute; 80 | top: 32px; 81 | content: ""; 82 | border-top: none; 83 | -webkit-transform: perspective(15px) rotateX(-5deg); 84 | -moz-transform: perspective(15px) rotateX(-5deg); 85 | transform: perspective(15px) rotateX(-5deg); 86 | } 87 | 88 | /* Button Hover Style */ 89 | .mediumseagreen:hover:before, 90 | .mediumseagreen:hover:after { 91 | color: #fff; 92 | text-shadow: 93 | /* White glow */ 0 0 7px #fff, 0 0 10px #fff, 0 0 21px #fff, 94 | /* Green glow */ 0 0 42px #0fa, 0 0 82px #0fa, 0 0 92px #0fa, 0 0 102px #0fa, 95 | 0 0 151px #0fa; 96 | background: rgb(30, 136, 78); 97 | transition: all 0.5s; 98 | } 99 | .mediumseagreen2:hover:before, 100 | .mediumseagreen2:hover:after { 101 | color: #fff; 102 | text-shadow: 103 | /* White glow */ 0 0 7px #fff, 0 0 10px #fff, 0 0 21px #fff, 104 | /* Green glow */ 0 0 42px #0fa, 0 0 82px #0fa, 0 0 92px #0fa, 0 0 102px #0fa, 105 | 0 0 151px #0fa; 106 | background: rgb(30, 136, 78); 107 | transition: all 0.5s; 108 | } 109 | .mediumseagreen3:hover:before, 110 | .mediumseagreen3:hover:after { 111 | color: #fff; 112 | text-shadow: 113 | /* White glow */ 0 0 7px #fff, 0 0 10px #fff, 0 0 21px #fff, 114 | /* Green glow */ 0 0 42px #0fa, 0 0 82px #0fa, 0 0 92px #0fa, 0 0 102px #0fa, 115 | 0 0 151px #0fa; 116 | background: rgb(30, 136, 78); 117 | transition: all 0.5s; 118 | } 119 | .mediumseagreen4:hover:before, 120 | .mediumseagreen4:hover:after { 121 | color: #fff; 122 | text-shadow: 123 | /* White glow */ 0 0 7px #fff, 0 0 10px #fff, 0 0 21px #fff, 124 | /* Green glow */ 0 0 42px #0fa, 0 0 82px #0fa, 0 0 92px #0fa, 0 0 102px #0fa, 125 | 0 0 151px #0fa; 126 | background: rgb(30, 136, 78); 127 | transition: all 0.5s; 128 | } 129 | 130 | .button:hover { 131 | color: #fff; 132 | color: #fff; 133 | transition: all 0.5s; 134 | text-shadow: 135 | /* White glow */ 0 0 5px #fff, 0 0 10px #fff, 0 0 21px #fff, 136 | /* Green glow */ 0 0 42px #0fa, 0 0 82px #0fa, 0 0 92px #0fa, 0 0 102px #0fa, 137 | 0 0 151px #0fa; 138 | } 139 | 140 | /* Just for presentation */ 141 | body { 142 | position: absolute; 143 | height: 100%; 144 | width: 100%; 145 | background: rgb(54, 54, 54); 146 | } 147 | .slidecontainer { 148 | margin: auto; 149 | width: 50%; 150 | /* margin: auto; 151 | width: 50%; 152 | border: 3px solid green; */ 153 | padding: 10px; 154 | } 155 | 156 | .slider { 157 | -webkit-appearance: none; 158 | width: 100%; 159 | height: 15px; 160 | border-radius: 5px; 161 | background: #2c2c2c; 162 | outline: none; 163 | opacity: 0.6; 164 | -webkit-transition: 0.2s; 165 | transition: opacity 0.2s; 166 | } 167 | 168 | .slider:hover { 169 | opacity: 1; 170 | } 171 | 172 | #speed1::-webkit-slider-thumb { 173 | -webkit-appearance: none; 174 | appearance: none; 175 | width: 17px; 176 | height: 17px; 177 | border-radius: 50%; 178 | background: rgb(30, 136, 78); 179 | cursor: pointer; 180 | } 181 | 182 | #brightness1::-webkit-slider-thumb { 183 | -webkit-appearance: none; 184 | appearance: none; 185 | width: 17px; 186 | height: 17px; 187 | border-radius: 50%; 188 | background: rgb(30, 136, 78); 189 | cursor: pointer; 190 | } 191 | 192 | #brightness2::-webkit-slider-thumb { 193 | -webkit-appearance: none; 194 | appearance: none; 195 | width: 17px; 196 | height: 17px; 197 | border-radius: 50%; 198 | background: rgb(30, 136, 78); 199 | cursor: pointer; 200 | } 201 | 202 | #brightness3::-webkit-slider-thumb { 203 | -webkit-appearance: none; 204 | appearance: none; 205 | width: 17px; 206 | height: 17px; 207 | border-radius: 50%; 208 | background: rgb(30, 136, 78); 209 | cursor: pointer; 210 | } 211 | 212 | #brightness4::-webkit-slider-thumb { 213 | -webkit-appearance: none; 214 | appearance: none; 215 | width: 17px; 216 | height: 17px; 217 | border-radius: 50%; 218 | background: rgb(30, 136, 78); 219 | cursor: pointer; 220 | } 221 | 222 | #speed2::-webkit-slider-thumb { 223 | -webkit-appearance: none; 224 | appearance: none; 225 | width: 17px; 226 | height: 17px; 227 | border-radius: 50%; 228 | background: rgb(30, 136, 78); 229 | cursor: pointer; 230 | } 231 | 232 | #speed3::-webkit-slider-thumb { 233 | -webkit-appearance: none; 234 | appearance: none; 235 | width: 17px; 236 | height: 17px; 237 | border-radius: 50%; 238 | background: rgb(30, 136, 78); 239 | cursor: pointer; 240 | } 241 | 242 | #speed4::-webkit-slider-thumb { 243 | -webkit-appearance: none; 244 | appearance: none; 245 | width: 17px; 246 | height: 17px; 247 | border-radius: 50%; 248 | background: rgb(30, 136, 78); 249 | cursor: pointer; 250 | } 251 | 252 | #red1::-webkit-slider-thumb { 253 | -webkit-appearance: none; 254 | appearance: none; 255 | width: 17px; 256 | height: 17px; 257 | border-radius: 50%; 258 | background: var(--SliderColor1); 259 | cursor: pointer; 260 | } 261 | #green1::-webkit-slider-thumb { 262 | -webkit-appearance: none; 263 | appearance: none; 264 | width: 17px; 265 | height: 17px; 266 | border-radius: 50%; 267 | background: var(--SliderColor2); 268 | cursor: pointer; 269 | } 270 | #blue1::-webkit-slider-thumb { 271 | -webkit-appearance: none; 272 | appearance: none; 273 | width: 17px; 274 | height: 17px; 275 | border-radius: 50%; 276 | background: var(--SliderColor3); 277 | cursor: pointer; 278 | } 279 | 280 | #red2::-webkit-slider-thumb { 281 | -webkit-appearance: none; 282 | appearance: none; 283 | width: 17px; 284 | height: 17px; 285 | border-radius: 50%; 286 | background: var(--SliderColor1); 287 | cursor: pointer; 288 | } 289 | #green2::-webkit-slider-thumb { 290 | -webkit-appearance: none; 291 | appearance: none; 292 | width: 17px; 293 | height: 17px; 294 | border-radius: 50%; 295 | background: var(--SliderColor2); 296 | cursor: pointer; 297 | } 298 | #blue2::-webkit-slider-thumb { 299 | -webkit-appearance: none; 300 | appearance: none; 301 | width: 17px; 302 | height: 17px; 303 | border-radius: 50%; 304 | background: var(--SliderColor3); 305 | cursor: pointer; 306 | } 307 | 308 | /* .slider::-moz-range-thumb { 309 | width: 17px; 310 | height: 17px; 311 | border-radius: 50%; 312 | background: rgb(30, 136, 78); 313 | cursor: pointer; 314 | } */ 315 | Label { 316 | font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", 317 | "Helvetica"; 318 | color: #9b9999; 319 | } 320 | /* #rec1 { 321 | height: 10px; 322 | width: 100%; 323 | margin-top: 5px; 324 | } 325 | #rec2 { 326 | height: 10px; 327 | width: 100%; 328 | margin-top: 5px; 329 | } */ 330 | .container { 331 | position: relative; 332 | padding-left: 30px; 333 | cursor: pointer; 334 | font-size: 18px; 335 | -webkit-user-select: none; 336 | -moz-user-select: none; 337 | -ms-user-select: none; 338 | user-select: none; 339 | margin-left: 5%; 340 | } 341 | 342 | /* Hide the browser's default radio button */ 343 | .container input { 344 | position: relative; 345 | opacity: 0; 346 | cursor: pointer; 347 | } 348 | 349 | /* Create a custom radio button */ 350 | .checkmark { 351 | position: absolute; 352 | top: 0; 353 | left: 0; 354 | height: 20px; 355 | width: 20px; 356 | background-color: rgb(77, 77, 77); 357 | border-radius: 50%; 358 | } 359 | 360 | /* On mouse-over, add a grey background color */ 361 | .container:hover input ~ .checkmark { 362 | background-color: #ccc; 363 | } 364 | 365 | /* When the radio button is checked, add a blue background */ 366 | .container input:checked ~ .checkmark { 367 | background-color: rgb(30, 136, 78); 368 | } 369 | 370 | /* Create the indicator (the dot/circle - hidden when not checked) */ 371 | .checkmark:after { 372 | content: ""; 373 | position: absolute; 374 | display: none; 375 | } 376 | 377 | /* Show the indicator (dot/circle) when checked */ 378 | .container input:checked ~ .checkmark:after { 379 | display: block; 380 | } 381 | 382 | /* Style the indicator (dot/circle) */ 383 | .container .checkmark:after { 384 | top: 7px; 385 | left: 7px; 386 | width: 5px; 387 | height: 5px; 388 | border-radius: 50%; 389 | background: rgb(30, 136, 78); 390 | } 391 | 392 | #back { 393 | border-radius: 50%; 394 | font-size: 100px; 395 | color: rgba(0, 0, 0, 0.19); 396 | text-decoration: none; 397 | } 398 | #back:hover { 399 | /* color: mediumseagreen; */ 400 | transition: all 0.5s; 401 | color: #fff; 402 | text-shadow: 403 | /* White glow */ 0 0 2px #fff, 0 0 10px #fff, 0 0 21px #fff, 404 | /* Green glow */ 0 0 42px #0fa, 0 0 82px #0fa, 0 0 92px #0fa, 0 0 102px #0fa, 405 | 0 0 151px #0fa; 406 | } 407 | 408 | #left { 409 | border-radius: 50%; 410 | position: absolute; 411 | font-size: 79px; 412 | color: rgba(0, 0, 0, 0.19); 413 | text-decoration: none; 414 | left: 39%; 415 | width: 63px; 416 | /* right: 20%; */ 417 | bottom: 5%; 418 | cursor: pointer; 419 | } 420 | 421 | #left:hover { 422 | transition: all 0.5s; 423 | color: mediumseagreen; 424 | } 425 | 426 | #right { 427 | border-radius: 50%; 428 | position: absolute; 429 | font-size: 79px; 430 | color: rgba(0, 0, 0, 0.19); 431 | text-decoration: none; 432 | left: 59%; 433 | width: 63px; 434 | /* right: 20%; */ 435 | bottom: 5%; 436 | cursor: pointer; 437 | } 438 | 439 | #right:hover { 440 | transition: all 0.5s; 441 | color: mediumseagreen; 442 | } 443 | -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ $EUID -ne 0 ]]; then 3 | echo "[*] This script must be run as root" 4 | exit 1 5 | fi 6 | 7 | rmmod facer 8 | modprobe acer_wmi -------------------------------------------------------------------------------- /uninstall_service.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script can uninstall acer turbo fan service. 3 | /bin/bash ./install_service.sh remove 4 | --------------------------------------------------------------------------------