`
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 |
194 |
205 |
‹
206 |
›
207 |
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 |
--------------------------------------------------------------------------------