]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/platform/x86/fujitsu-laptop.c
platform/x86: fujitsu-laptop: remove keycode fields from struct fujitsu_bl
[mirror_ubuntu-bionic-kernel.git] / drivers / platform / x86 / fujitsu-laptop.c
1 /*-*-linux-c-*-*/
2
3 /*
4 Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
5 Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
6 Copyright (C) 2008 Tony Vroon <tony@linx.net>
7 Based on earlier work:
8 Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
9 Adrian Yee <brewt-fujitsu@brewt.org>
10
11 Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
12 by its respective authors.
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.
28 */
29
30 /*
31 * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
32 * features made available on a range of Fujitsu laptops including the
33 * P2xxx/P5xxx/S6xxx/S7xxx series.
34 *
35 * This driver implements a vendor-specific backlight control interface for
36 * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu
37 * laptops.
38 *
39 * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
40 * P8010. It should work on most P-series and S-series Lifebooks, but
41 * YMMV.
42 *
43 * The module parameter use_alt_lcd_levels switches between different ACPI
44 * brightness controls which are used by different Fujitsu laptops. In most
45 * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
46 * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
47 *
48 */
49
50 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
51
52 #include <linux/module.h>
53 #include <linux/kernel.h>
54 #include <linux/init.h>
55 #include <linux/acpi.h>
56 #include <linux/dmi.h>
57 #include <linux/backlight.h>
58 #include <linux/fb.h>
59 #include <linux/input.h>
60 #include <linux/input/sparse-keymap.h>
61 #include <linux/kfifo.h>
62 #include <linux/platform_device.h>
63 #include <linux/slab.h>
64 #if IS_ENABLED(CONFIG_LEDS_CLASS)
65 #include <linux/leds.h>
66 #endif
67 #include <acpi/video.h>
68
69 #define FUJITSU_DRIVER_VERSION "0.6.0"
70
71 #define FUJITSU_LCD_N_LEVELS 8
72
73 #define ACPI_FUJITSU_CLASS "fujitsu"
74 #define ACPI_FUJITSU_BL_HID "FUJ02B1"
75 #define ACPI_FUJITSU_BL_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
76 #define ACPI_FUJITSU_BL_DEVICE_NAME "Fujitsu FUJ02B1"
77 #define ACPI_FUJITSU_LAPTOP_HID "FUJ02E3"
78 #define ACPI_FUJITSU_LAPTOP_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
79 #define ACPI_FUJITSU_LAPTOP_DEVICE_NAME "Fujitsu FUJ02E3"
80
81 #define ACPI_FUJITSU_NOTIFY_CODE1 0x80
82
83 /* FUNC interface - command values */
84 #define FUNC_FLAGS 0x1000
85 #define FUNC_LEDS 0x1001
86 #define FUNC_BUTTONS 0x1002
87 #define FUNC_BACKLIGHT 0x1004
88
89 /* FUNC interface - responses */
90 #define UNSUPPORTED_CMD 0x80000000
91
92 /* FUNC interface - status flags */
93 #define FLAG_RFKILL 0x020
94 #define FLAG_LID 0x100
95 #define FLAG_DOCK 0x200
96
97 #if IS_ENABLED(CONFIG_LEDS_CLASS)
98 /* FUNC interface - LED control */
99 #define FUNC_LED_OFF 0x1
100 #define FUNC_LED_ON 0x30001
101 #define KEYBOARD_LAMPS 0x100
102 #define LOGOLAMP_POWERON 0x2000
103 #define LOGOLAMP_ALWAYS 0x4000
104 #define RADIO_LED_ON 0x20
105 #define ECO_LED 0x10000
106 #define ECO_LED_ON 0x80000
107 #endif
108
109 /* Hotkey details */
110 #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */
111 #define KEY2_CODE 0x411
112 #define KEY3_CODE 0x412
113 #define KEY4_CODE 0x413
114 #define KEY5_CODE 0x420
115
116 #define MAX_HOTKEY_RINGBUFFER_SIZE 100
117 #define RINGBUFFERSIZE 40
118
119 /* Debugging */
120 #define FUJLAPTOP_DBG_ERROR 0x0001
121 #define FUJLAPTOP_DBG_WARN 0x0002
122 #define FUJLAPTOP_DBG_INFO 0x0004
123 #define FUJLAPTOP_DBG_TRACE 0x0008
124
125 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
126 #define vdbg_printk(a_dbg_level, format, arg...) \
127 do { if (dbg_level & a_dbg_level) \
128 printk(KERN_DEBUG pr_fmt("%s: " format), __func__, ## arg); \
129 } while (0)
130 #else
131 #define vdbg_printk(a_dbg_level, format, arg...) \
132 do { } while (0)
133 #endif
134
135 /* Device controlling the backlight and associated keys */
136 struct fujitsu_bl {
137 acpi_handle acpi_handle;
138 struct acpi_device *dev;
139 struct input_dev *input;
140 char phys[32];
141 struct backlight_device *bl_device;
142
143 unsigned int max_brightness;
144 unsigned int brightness_changed;
145 unsigned int brightness_level;
146 };
147
148 static struct fujitsu_bl *fujitsu_bl;
149 static int use_alt_lcd_levels = -1;
150 static int disable_brightness_adjust = -1;
151
152 /* Device used to access hotkeys and other features on the laptop */
153 struct fujitsu_laptop {
154 acpi_handle acpi_handle;
155 struct acpi_device *dev;
156 struct input_dev *input;
157 char phys[32];
158 struct platform_device *pf_device;
159 struct kfifo fifo;
160 spinlock_t fifo_lock;
161 int flags_supported;
162 int flags_state;
163 int logolamp_registered;
164 int kblamps_registered;
165 int radio_led_registered;
166 int eco_led_registered;
167 };
168
169 static struct fujitsu_laptop *fujitsu_laptop;
170
171 #if IS_ENABLED(CONFIG_LEDS_CLASS)
172 static enum led_brightness logolamp_get(struct led_classdev *cdev);
173 static int logolamp_set(struct led_classdev *cdev,
174 enum led_brightness brightness);
175
176 static struct led_classdev logolamp_led = {
177 .name = "fujitsu::logolamp",
178 .brightness_get = logolamp_get,
179 .brightness_set_blocking = logolamp_set
180 };
181
182 static enum led_brightness kblamps_get(struct led_classdev *cdev);
183 static int kblamps_set(struct led_classdev *cdev,
184 enum led_brightness brightness);
185
186 static struct led_classdev kblamps_led = {
187 .name = "fujitsu::kblamps",
188 .brightness_get = kblamps_get,
189 .brightness_set_blocking = kblamps_set
190 };
191
192 static enum led_brightness radio_led_get(struct led_classdev *cdev);
193 static int radio_led_set(struct led_classdev *cdev,
194 enum led_brightness brightness);
195
196 static struct led_classdev radio_led = {
197 .name = "fujitsu::radio_led",
198 .default_trigger = "rfkill-any",
199 .brightness_get = radio_led_get,
200 .brightness_set_blocking = radio_led_set
201 };
202
203 static enum led_brightness eco_led_get(struct led_classdev *cdev);
204 static int eco_led_set(struct led_classdev *cdev,
205 enum led_brightness brightness);
206
207 static struct led_classdev eco_led = {
208 .name = "fujitsu::eco_led",
209 .brightness_get = eco_led_get,
210 .brightness_set_blocking = eco_led_set
211 };
212 #endif
213
214 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
215 static u32 dbg_level = 0x03;
216 #endif
217
218 /* Fujitsu ACPI interface function */
219
220 static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
221 {
222 acpi_status status = AE_OK;
223 union acpi_object params[4] = {
224 { .type = ACPI_TYPE_INTEGER },
225 { .type = ACPI_TYPE_INTEGER },
226 { .type = ACPI_TYPE_INTEGER },
227 { .type = ACPI_TYPE_INTEGER }
228 };
229 struct acpi_object_list arg_list = { 4, &params[0] };
230 unsigned long long value;
231 acpi_handle handle = NULL;
232
233 status = acpi_get_handle(fujitsu_laptop->acpi_handle, "FUNC", &handle);
234 if (ACPI_FAILURE(status)) {
235 vdbg_printk(FUJLAPTOP_DBG_ERROR,
236 "FUNC interface is not present\n");
237 return -ENODEV;
238 }
239
240 params[0].integer.value = cmd;
241 params[1].integer.value = arg0;
242 params[2].integer.value = arg1;
243 params[3].integer.value = arg2;
244
245 status = acpi_evaluate_integer(handle, NULL, &arg_list, &value);
246 if (ACPI_FAILURE(status)) {
247 vdbg_printk(FUJLAPTOP_DBG_WARN,
248 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
249 cmd, arg0, arg1, arg2);
250 return -ENODEV;
251 }
252
253 vdbg_printk(FUJLAPTOP_DBG_TRACE,
254 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
255 cmd, arg0, arg1, arg2, (int)value);
256 return value;
257 }
258
259 #if IS_ENABLED(CONFIG_LEDS_CLASS)
260 /* LED class callbacks */
261
262 static int logolamp_set(struct led_classdev *cdev,
263 enum led_brightness brightness)
264 {
265 int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
266 int ret;
267
268 if (brightness < LED_HALF)
269 poweron = FUNC_LED_OFF;
270
271 if (brightness < LED_FULL)
272 always = FUNC_LED_OFF;
273
274 ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
275 if (ret < 0)
276 return ret;
277
278 return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
279 }
280
281 static int kblamps_set(struct led_classdev *cdev,
282 enum led_brightness brightness)
283 {
284 if (brightness >= LED_FULL)
285 return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
286 else
287 return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
288 }
289
290 static int radio_led_set(struct led_classdev *cdev,
291 enum led_brightness brightness)
292 {
293 if (brightness >= LED_FULL)
294 return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, RADIO_LED_ON);
295 else
296 return call_fext_func(FUNC_FLAGS, 0x5, RADIO_LED_ON, 0x0);
297 }
298
299 static int eco_led_set(struct led_classdev *cdev,
300 enum led_brightness brightness)
301 {
302 int curr;
303
304 curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0);
305 if (brightness >= LED_FULL)
306 return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON);
307 else
308 return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON);
309 }
310
311 static enum led_brightness logolamp_get(struct led_classdev *cdev)
312 {
313 int ret;
314
315 ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
316 if (ret == FUNC_LED_ON)
317 return LED_FULL;
318
319 ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
320 if (ret == FUNC_LED_ON)
321 return LED_HALF;
322
323 return LED_OFF;
324 }
325
326 static enum led_brightness kblamps_get(struct led_classdev *cdev)
327 {
328 enum led_brightness brightness = LED_OFF;
329
330 if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
331 brightness = LED_FULL;
332
333 return brightness;
334 }
335
336 static enum led_brightness radio_led_get(struct led_classdev *cdev)
337 {
338 enum led_brightness brightness = LED_OFF;
339
340 if (call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
341 brightness = LED_FULL;
342
343 return brightness;
344 }
345
346 static enum led_brightness eco_led_get(struct led_classdev *cdev)
347 {
348 enum led_brightness brightness = LED_OFF;
349
350 if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
351 brightness = LED_FULL;
352
353 return brightness;
354 }
355 #endif
356
357 /* Hardware access for LCD brightness control */
358
359 static int set_lcd_level(int level)
360 {
361 acpi_status status = AE_OK;
362 acpi_handle handle = NULL;
363
364 vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
365 level);
366
367 if (level < 0 || level >= fujitsu_bl->max_brightness)
368 return -EINVAL;
369
370 status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBLL", &handle);
371 if (ACPI_FAILURE(status)) {
372 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
373 return -ENODEV;
374 }
375
376
377 status = acpi_execute_simple_method(handle, NULL, level);
378 if (ACPI_FAILURE(status))
379 return -ENODEV;
380
381 return 0;
382 }
383
384 static int set_lcd_level_alt(int level)
385 {
386 acpi_status status = AE_OK;
387 acpi_handle handle = NULL;
388
389 vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
390 level);
391
392 if (level < 0 || level >= fujitsu_bl->max_brightness)
393 return -EINVAL;
394
395 status = acpi_get_handle(fujitsu_bl->acpi_handle, "SBL2", &handle);
396 if (ACPI_FAILURE(status)) {
397 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
398 return -ENODEV;
399 }
400
401 status = acpi_execute_simple_method(handle, NULL, level);
402 if (ACPI_FAILURE(status))
403 return -ENODEV;
404
405 return 0;
406 }
407
408 static int get_lcd_level(void)
409 {
410 unsigned long long state = 0;
411 acpi_status status = AE_OK;
412
413 vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
414
415 status = acpi_evaluate_integer(fujitsu_bl->acpi_handle, "GBLL", NULL,
416 &state);
417 if (ACPI_FAILURE(status))
418 return 0;
419
420 fujitsu_bl->brightness_level = state & 0x0fffffff;
421
422 if (state & 0x80000000)
423 fujitsu_bl->brightness_changed = 1;
424 else
425 fujitsu_bl->brightness_changed = 0;
426
427 return fujitsu_bl->brightness_level;
428 }
429
430 static int get_max_brightness(void)
431 {
432 unsigned long long state = 0;
433 acpi_status status = AE_OK;
434
435 vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
436
437 status = acpi_evaluate_integer(fujitsu_bl->acpi_handle, "RBLL", NULL,
438 &state);
439 if (ACPI_FAILURE(status))
440 return -1;
441
442 fujitsu_bl->max_brightness = state;
443
444 return fujitsu_bl->max_brightness;
445 }
446
447 /* Backlight device stuff */
448
449 static int bl_get_brightness(struct backlight_device *b)
450 {
451 return get_lcd_level();
452 }
453
454 static int bl_update_status(struct backlight_device *b)
455 {
456 int ret;
457 if (b->props.power == FB_BLANK_POWERDOWN)
458 ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
459 else
460 ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
461 if (ret != 0)
462 vdbg_printk(FUJLAPTOP_DBG_ERROR,
463 "Unable to adjust backlight power, error code %i\n",
464 ret);
465
466 if (use_alt_lcd_levels)
467 ret = set_lcd_level_alt(b->props.brightness);
468 else
469 ret = set_lcd_level(b->props.brightness);
470 if (ret != 0)
471 vdbg_printk(FUJLAPTOP_DBG_ERROR,
472 "Unable to adjust LCD brightness, error code %i\n",
473 ret);
474 return ret;
475 }
476
477 static const struct backlight_ops fujitsu_bl_ops = {
478 .get_brightness = bl_get_brightness,
479 .update_status = bl_update_status,
480 };
481
482 static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
483 char *buf)
484 {
485 if (!(fujitsu_laptop->flags_supported & FLAG_LID))
486 return sprintf(buf, "unknown\n");
487 if (fujitsu_laptop->flags_state & FLAG_LID)
488 return sprintf(buf, "open\n");
489 else
490 return sprintf(buf, "closed\n");
491 }
492
493 static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
494 char *buf)
495 {
496 if (!(fujitsu_laptop->flags_supported & FLAG_DOCK))
497 return sprintf(buf, "unknown\n");
498 if (fujitsu_laptop->flags_state & FLAG_DOCK)
499 return sprintf(buf, "docked\n");
500 else
501 return sprintf(buf, "undocked\n");
502 }
503
504 static ssize_t radios_show(struct device *dev, struct device_attribute *attr,
505 char *buf)
506 {
507 if (!(fujitsu_laptop->flags_supported & FLAG_RFKILL))
508 return sprintf(buf, "unknown\n");
509 if (fujitsu_laptop->flags_state & FLAG_RFKILL)
510 return sprintf(buf, "on\n");
511 else
512 return sprintf(buf, "killed\n");
513 }
514
515 static DEVICE_ATTR_RO(lid);
516 static DEVICE_ATTR_RO(dock);
517 static DEVICE_ATTR_RO(radios);
518
519 static struct attribute *fujitsu_pf_attributes[] = {
520 &dev_attr_lid.attr,
521 &dev_attr_dock.attr,
522 &dev_attr_radios.attr,
523 NULL
524 };
525
526 static struct attribute_group fujitsu_pf_attribute_group = {
527 .attrs = fujitsu_pf_attributes
528 };
529
530 static struct platform_driver fujitsu_pf_driver = {
531 .driver = {
532 .name = "fujitsu-laptop",
533 }
534 };
535
536 /* ACPI device for LCD brightness control */
537
538 static const struct key_entry keymap_backlight[] = {
539 { KE_KEY, true, { KEY_BRIGHTNESSUP } },
540 { KE_KEY, false, { KEY_BRIGHTNESSDOWN } },
541 { KE_END, 0 }
542 };
543
544 static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
545 {
546 struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device);
547 int ret;
548
549 fujitsu_bl->input = devm_input_allocate_device(&device->dev);
550 if (!fujitsu_bl->input)
551 return -ENOMEM;
552
553 snprintf(fujitsu_bl->phys, sizeof(fujitsu_bl->phys),
554 "%s/video/input0", acpi_device_hid(device));
555
556 fujitsu_bl->input->name = acpi_device_name(device);
557 fujitsu_bl->input->phys = fujitsu_bl->phys;
558 fujitsu_bl->input->id.bustype = BUS_HOST;
559 fujitsu_bl->input->id.product = 0x06;
560
561 ret = sparse_keymap_setup(fujitsu_bl->input, keymap_backlight, NULL);
562 if (ret)
563 return ret;
564
565 return input_register_device(fujitsu_bl->input);
566 }
567
568 static int fujitsu_backlight_register(void)
569 {
570 struct backlight_properties props = {
571 .brightness = fujitsu_bl->brightness_level,
572 .max_brightness = fujitsu_bl->max_brightness - 1,
573 .type = BACKLIGHT_PLATFORM
574 };
575 struct backlight_device *bd;
576
577 bd = backlight_device_register("fujitsu-laptop", NULL, NULL,
578 &fujitsu_bl_ops, &props);
579 if (IS_ERR(bd))
580 return PTR_ERR(bd);
581
582 fujitsu_bl->bl_device = bd;
583
584 return 0;
585 }
586
587 static int acpi_fujitsu_bl_add(struct acpi_device *device)
588 {
589 int state = 0;
590 int error;
591
592 if (!device)
593 return -EINVAL;
594
595 fujitsu_bl->acpi_handle = device->handle;
596 sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_BL_DEVICE_NAME);
597 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
598 device->driver_data = fujitsu_bl;
599
600 error = acpi_fujitsu_bl_input_setup(device);
601 if (error)
602 return error;
603
604 error = acpi_bus_update_power(fujitsu_bl->acpi_handle, &state);
605 if (error) {
606 pr_err("Error reading power state\n");
607 return error;
608 }
609
610 pr_info("ACPI: %s [%s] (%s)\n",
611 acpi_device_name(device), acpi_device_bid(device),
612 !device->power.state ? "on" : "off");
613
614 fujitsu_bl->dev = device;
615
616 if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
617 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
618 if (ACPI_FAILURE
619 (acpi_evaluate_object
620 (device->handle, METHOD_NAME__INI, NULL, NULL)))
621 pr_err("_INI Method failed\n");
622 }
623
624 if (use_alt_lcd_levels == -1) {
625 if (acpi_has_method(NULL, "\\_SB.PCI0.LPCB.FJEX.SBL2"))
626 use_alt_lcd_levels = 1;
627 else
628 use_alt_lcd_levels = 0;
629 vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as %i\n",
630 use_alt_lcd_levels);
631 }
632
633 /* do config (detect defaults) */
634 use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
635 disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
636 vdbg_printk(FUJLAPTOP_DBG_INFO,
637 "config: [alt interface: %d], [adjust disable: %d]\n",
638 use_alt_lcd_levels, disable_brightness_adjust);
639
640 if (get_max_brightness() <= 0)
641 fujitsu_bl->max_brightness = FUJITSU_LCD_N_LEVELS;
642 get_lcd_level();
643
644 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
645 error = fujitsu_backlight_register();
646 if (error)
647 return error;
648 }
649
650 return 0;
651 }
652
653 static int acpi_fujitsu_bl_remove(struct acpi_device *device)
654 {
655 struct fujitsu_bl *fujitsu_bl = acpi_driver_data(device);
656
657 backlight_device_unregister(fujitsu_bl->bl_device);
658
659 fujitsu_bl->acpi_handle = NULL;
660
661 return 0;
662 }
663
664 /* Brightness notify */
665
666 static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
667 {
668 struct input_dev *input;
669 int oldb, newb;
670
671 input = fujitsu_bl->input;
672
673 if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
674 vdbg_printk(FUJLAPTOP_DBG_WARN,
675 "unsupported event [0x%x]\n", event);
676 sparse_keymap_report_event(input, -1, 1, true);
677 return;
678 }
679
680 oldb = fujitsu_bl->brightness_level;
681 get_lcd_level();
682 newb = fujitsu_bl->brightness_level;
683
684 vdbg_printk(FUJLAPTOP_DBG_TRACE,
685 "brightness button event [%i -> %i (%i)]\n",
686 oldb, newb, fujitsu_bl->brightness_changed);
687
688 if (oldb == newb)
689 return;
690
691 if (disable_brightness_adjust != 1) {
692 if (use_alt_lcd_levels)
693 set_lcd_level_alt(newb);
694 else
695 set_lcd_level(newb);
696 }
697
698 sparse_keymap_report_event(input, oldb < newb, 1, true);
699 }
700
701 /* ACPI device for hotkey handling */
702
703 static const struct key_entry keymap_default[] = {
704 { KE_KEY, KEY1_CODE, { KEY_PROG1 } },
705 { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
706 { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
707 { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
708 { KE_KEY, KEY5_CODE, { KEY_RFKILL } },
709 { KE_KEY, BIT(26), { KEY_TOUCHPAD_TOGGLE } },
710 { KE_END, 0 }
711 };
712
713 static const struct key_entry keymap_s64x0[] = {
714 { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } }, /* "Lock" */
715 { KE_KEY, KEY2_CODE, { KEY_HELP } }, /* "Mobility Center */
716 { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
717 { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
718 { KE_END, 0 }
719 };
720
721 static const struct key_entry keymap_p8010[] = {
722 { KE_KEY, KEY1_CODE, { KEY_HELP } }, /* "Support" */
723 { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
724 { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */
725 { KE_KEY, KEY4_CODE, { KEY_WWW } }, /* "WWW" */
726 { KE_END, 0 }
727 };
728
729 static const struct key_entry *keymap = keymap_default;
730
731 static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id)
732 {
733 pr_info("Identified laptop model '%s'\n", id->ident);
734 keymap = id->driver_data;
735 return 1;
736 }
737
738 static const struct dmi_system_id fujitsu_laptop_dmi_table[] = {
739 {
740 .callback = fujitsu_laptop_dmi_keymap_override,
741 .ident = "Fujitsu Siemens S6410",
742 .matches = {
743 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
744 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
745 },
746 .driver_data = (void *)keymap_s64x0
747 },
748 {
749 .callback = fujitsu_laptop_dmi_keymap_override,
750 .ident = "Fujitsu Siemens S6420",
751 .matches = {
752 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
753 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
754 },
755 .driver_data = (void *)keymap_s64x0
756 },
757 {
758 .callback = fujitsu_laptop_dmi_keymap_override,
759 .ident = "Fujitsu LifeBook P8010",
760 .matches = {
761 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
762 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
763 },
764 .driver_data = (void *)keymap_p8010
765 },
766 {}
767 };
768
769 static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device)
770 {
771 struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device);
772 int ret;
773
774 fujitsu_laptop->input = devm_input_allocate_device(&device->dev);
775 if (!fujitsu_laptop->input)
776 return -ENOMEM;
777
778 snprintf(fujitsu_laptop->phys, sizeof(fujitsu_laptop->phys),
779 "%s/video/input0", acpi_device_hid(device));
780
781 fujitsu_laptop->input->name = acpi_device_name(device);
782 fujitsu_laptop->input->phys = fujitsu_laptop->phys;
783 fujitsu_laptop->input->id.bustype = BUS_HOST;
784 fujitsu_laptop->input->id.product = 0x06;
785
786 dmi_check_system(fujitsu_laptop_dmi_table);
787 ret = sparse_keymap_setup(fujitsu_laptop->input, keymap, NULL);
788 if (ret)
789 return ret;
790
791 return input_register_device(fujitsu_laptop->input);
792 }
793
794 static int fujitsu_laptop_platform_add(void)
795 {
796 int ret;
797
798 fujitsu_laptop->pf_device = platform_device_alloc("fujitsu-laptop", -1);
799 if (!fujitsu_laptop->pf_device)
800 return -ENOMEM;
801
802 ret = platform_device_add(fujitsu_laptop->pf_device);
803 if (ret)
804 goto err_put_platform_device;
805
806 ret = sysfs_create_group(&fujitsu_laptop->pf_device->dev.kobj,
807 &fujitsu_pf_attribute_group);
808 if (ret)
809 goto err_del_platform_device;
810
811 return 0;
812
813 err_del_platform_device:
814 platform_device_del(fujitsu_laptop->pf_device);
815 err_put_platform_device:
816 platform_device_put(fujitsu_laptop->pf_device);
817
818 return ret;
819 }
820
821 static void fujitsu_laptop_platform_remove(void)
822 {
823 sysfs_remove_group(&fujitsu_laptop->pf_device->dev.kobj,
824 &fujitsu_pf_attribute_group);
825 platform_device_unregister(fujitsu_laptop->pf_device);
826 }
827
828 static int acpi_fujitsu_laptop_add(struct acpi_device *device)
829 {
830 int result = 0;
831 int state = 0;
832 int error;
833 int i;
834
835 if (!device)
836 return -EINVAL;
837
838 fujitsu_laptop->acpi_handle = device->handle;
839 sprintf(acpi_device_name(device), "%s",
840 ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
841 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
842 device->driver_data = fujitsu_laptop;
843
844 /* kfifo */
845 spin_lock_init(&fujitsu_laptop->fifo_lock);
846 error = kfifo_alloc(&fujitsu_laptop->fifo, RINGBUFFERSIZE * sizeof(int),
847 GFP_KERNEL);
848 if (error) {
849 pr_err("kfifo_alloc failed\n");
850 goto err_stop;
851 }
852
853 error = acpi_fujitsu_laptop_input_setup(device);
854 if (error)
855 goto err_free_fifo;
856
857 error = acpi_bus_update_power(fujitsu_laptop->acpi_handle, &state);
858 if (error) {
859 pr_err("Error reading power state\n");
860 goto err_free_fifo;
861 }
862
863 pr_info("ACPI: %s [%s] (%s)\n",
864 acpi_device_name(device), acpi_device_bid(device),
865 !device->power.state ? "on" : "off");
866
867 fujitsu_laptop->dev = device;
868
869 if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
870 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
871 if (ACPI_FAILURE
872 (acpi_evaluate_object
873 (device->handle, METHOD_NAME__INI, NULL, NULL)))
874 pr_err("_INI Method failed\n");
875 }
876
877 i = 0;
878 while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
879 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
880 ; /* No action, result is discarded */
881 vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
882
883 fujitsu_laptop->flags_supported =
884 call_fext_func(FUNC_FLAGS, 0x0, 0x0, 0x0);
885
886 /* Make sure our bitmask of supported functions is cleared if the
887 RFKILL function block is not implemented, like on the S7020. */
888 if (fujitsu_laptop->flags_supported == UNSUPPORTED_CMD)
889 fujitsu_laptop->flags_supported = 0;
890
891 if (fujitsu_laptop->flags_supported)
892 fujitsu_laptop->flags_state =
893 call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0);
894
895 /* Suspect this is a keymap of the application panel, print it */
896 pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
897
898 /* Sync backlight power status */
899 if (fujitsu_bl->bl_device &&
900 acpi_video_get_backlight_type() == acpi_backlight_vendor) {
901 if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
902 fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN;
903 else
904 fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK;
905 }
906
907 error = fujitsu_laptop_platform_add();
908 if (error)
909 goto err_free_fifo;
910
911 #if IS_ENABLED(CONFIG_LEDS_CLASS)
912 if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
913 result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
914 &logolamp_led);
915 if (result == 0) {
916 fujitsu_laptop->logolamp_registered = 1;
917 } else {
918 pr_err("Could not register LED handler for logo lamp, error %i\n",
919 result);
920 }
921 }
922
923 if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
924 (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
925 result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
926 &kblamps_led);
927 if (result == 0) {
928 fujitsu_laptop->kblamps_registered = 1;
929 } else {
930 pr_err("Could not register LED handler for keyboard lamps, error %i\n",
931 result);
932 }
933 }
934
935 /*
936 * BTNI bit 24 seems to indicate the presence of a radio toggle
937 * button in place of a slide switch, and all such machines appear
938 * to also have an RF LED. Therefore use bit 24 as an indicator
939 * that an RF LED is present.
940 */
941 if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
942 result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
943 &radio_led);
944 if (result == 0) {
945 fujitsu_laptop->radio_led_registered = 1;
946 } else {
947 pr_err("Could not register LED handler for radio LED, error %i\n",
948 result);
949 }
950 }
951
952 /* Support for eco led is not always signaled in bit corresponding
953 * to the bit used to control the led. According to the DSDT table,
954 * bit 14 seems to indicate presence of said led as well.
955 * Confirm by testing the status.
956 */
957 if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
958 (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
959 result = led_classdev_register(&fujitsu_laptop->pf_device->dev,
960 &eco_led);
961 if (result == 0) {
962 fujitsu_laptop->eco_led_registered = 1;
963 } else {
964 pr_err("Could not register LED handler for eco LED, error %i\n",
965 result);
966 }
967 }
968 #endif
969
970 return result;
971
972 err_free_fifo:
973 kfifo_free(&fujitsu_laptop->fifo);
974 err_stop:
975 return error;
976 }
977
978 static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
979 {
980 struct fujitsu_laptop *fujitsu_laptop = acpi_driver_data(device);
981
982 #if IS_ENABLED(CONFIG_LEDS_CLASS)
983 if (fujitsu_laptop->logolamp_registered)
984 led_classdev_unregister(&logolamp_led);
985
986 if (fujitsu_laptop->kblamps_registered)
987 led_classdev_unregister(&kblamps_led);
988
989 if (fujitsu_laptop->radio_led_registered)
990 led_classdev_unregister(&radio_led);
991
992 if (fujitsu_laptop->eco_led_registered)
993 led_classdev_unregister(&eco_led);
994 #endif
995
996 fujitsu_laptop_platform_remove();
997
998 kfifo_free(&fujitsu_laptop->fifo);
999
1000 fujitsu_laptop->acpi_handle = NULL;
1001
1002 return 0;
1003 }
1004
1005 static void acpi_fujitsu_laptop_press(int scancode)
1006 {
1007 struct input_dev *input = fujitsu_laptop->input;
1008 int status;
1009
1010 status = kfifo_in_locked(&fujitsu_laptop->fifo,
1011 (unsigned char *)&scancode, sizeof(scancode),
1012 &fujitsu_laptop->fifo_lock);
1013 if (status != sizeof(scancode)) {
1014 vdbg_printk(FUJLAPTOP_DBG_WARN,
1015 "Could not push scancode [0x%x]\n", scancode);
1016 return;
1017 }
1018 sparse_keymap_report_event(input, scancode, 1, false);
1019 vdbg_printk(FUJLAPTOP_DBG_TRACE,
1020 "Push scancode into ringbuffer [0x%x]\n", scancode);
1021 }
1022
1023 static void acpi_fujitsu_laptop_release(void)
1024 {
1025 struct input_dev *input = fujitsu_laptop->input;
1026 int scancode, status;
1027
1028 while (true) {
1029 status = kfifo_out_locked(&fujitsu_laptop->fifo,
1030 (unsigned char *)&scancode,
1031 sizeof(scancode),
1032 &fujitsu_laptop->fifo_lock);
1033 if (status != sizeof(scancode))
1034 return;
1035 sparse_keymap_report_event(input, scancode, 0, false);
1036 vdbg_printk(FUJLAPTOP_DBG_TRACE,
1037 "Pop scancode from ringbuffer [0x%x]\n", scancode);
1038 }
1039 }
1040
1041 static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
1042 {
1043 struct input_dev *input;
1044 int scancode, i = 0;
1045 unsigned int irb;
1046
1047 input = fujitsu_laptop->input;
1048
1049 if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
1050 vdbg_printk(FUJLAPTOP_DBG_WARN,
1051 "Unsupported event [0x%x]\n", event);
1052 sparse_keymap_report_event(input, -1, 1, true);
1053 return;
1054 }
1055
1056 if (fujitsu_laptop->flags_supported)
1057 fujitsu_laptop->flags_state =
1058 call_fext_func(FUNC_FLAGS, 0x4, 0x0, 0x0);
1059
1060 while ((irb = call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
1061 i++ < MAX_HOTKEY_RINGBUFFER_SIZE) {
1062 scancode = irb & 0x4ff;
1063 if (sparse_keymap_entry_from_scancode(input, scancode))
1064 acpi_fujitsu_laptop_press(scancode);
1065 else if (scancode == 0)
1066 acpi_fujitsu_laptop_release();
1067 else
1068 vdbg_printk(FUJLAPTOP_DBG_WARN,
1069 "Unknown GIRB result [%x]\n", irb);
1070 }
1071
1072 /* On some models (first seen on the Skylake-based Lifebook
1073 * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
1074 * handled in software; its state is queried using FUNC_FLAGS
1075 */
1076 if ((fujitsu_laptop->flags_supported & BIT(26)) &&
1077 (call_fext_func(FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26)))
1078 sparse_keymap_report_event(input, BIT(26), 1, true);
1079 }
1080
1081 /* Initialization */
1082
1083 static const struct acpi_device_id fujitsu_bl_device_ids[] = {
1084 {ACPI_FUJITSU_BL_HID, 0},
1085 {"", 0},
1086 };
1087
1088 static struct acpi_driver acpi_fujitsu_bl_driver = {
1089 .name = ACPI_FUJITSU_BL_DRIVER_NAME,
1090 .class = ACPI_FUJITSU_CLASS,
1091 .ids = fujitsu_bl_device_ids,
1092 .ops = {
1093 .add = acpi_fujitsu_bl_add,
1094 .remove = acpi_fujitsu_bl_remove,
1095 .notify = acpi_fujitsu_bl_notify,
1096 },
1097 };
1098
1099 static const struct acpi_device_id fujitsu_laptop_device_ids[] = {
1100 {ACPI_FUJITSU_LAPTOP_HID, 0},
1101 {"", 0},
1102 };
1103
1104 static struct acpi_driver acpi_fujitsu_laptop_driver = {
1105 .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME,
1106 .class = ACPI_FUJITSU_CLASS,
1107 .ids = fujitsu_laptop_device_ids,
1108 .ops = {
1109 .add = acpi_fujitsu_laptop_add,
1110 .remove = acpi_fujitsu_laptop_remove,
1111 .notify = acpi_fujitsu_laptop_notify,
1112 },
1113 };
1114
1115 static const struct acpi_device_id fujitsu_ids[] __used = {
1116 {ACPI_FUJITSU_BL_HID, 0},
1117 {ACPI_FUJITSU_LAPTOP_HID, 0},
1118 {"", 0}
1119 };
1120 MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
1121
1122 static int __init fujitsu_init(void)
1123 {
1124 int ret;
1125
1126 if (acpi_disabled)
1127 return -ENODEV;
1128
1129 fujitsu_bl = kzalloc(sizeof(struct fujitsu_bl), GFP_KERNEL);
1130 if (!fujitsu_bl)
1131 return -ENOMEM;
1132
1133 ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver);
1134 if (ret)
1135 goto err_free_fujitsu_bl;
1136
1137 /* Register platform stuff */
1138
1139 ret = platform_driver_register(&fujitsu_pf_driver);
1140 if (ret)
1141 goto err_unregister_acpi;
1142
1143 /* Register laptop driver */
1144
1145 fujitsu_laptop = kzalloc(sizeof(struct fujitsu_laptop), GFP_KERNEL);
1146 if (!fujitsu_laptop) {
1147 ret = -ENOMEM;
1148 goto err_unregister_platform_driver;
1149 }
1150
1151 ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver);
1152 if (ret)
1153 goto err_free_fujitsu_laptop;
1154
1155 pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
1156
1157 return 0;
1158
1159 err_free_fujitsu_laptop:
1160 kfree(fujitsu_laptop);
1161 err_unregister_platform_driver:
1162 platform_driver_unregister(&fujitsu_pf_driver);
1163 err_unregister_acpi:
1164 acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
1165 err_free_fujitsu_bl:
1166 kfree(fujitsu_bl);
1167
1168 return ret;
1169 }
1170
1171 static void __exit fujitsu_cleanup(void)
1172 {
1173 acpi_bus_unregister_driver(&acpi_fujitsu_laptop_driver);
1174
1175 kfree(fujitsu_laptop);
1176
1177 platform_driver_unregister(&fujitsu_pf_driver);
1178
1179 acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver);
1180
1181 kfree(fujitsu_bl);
1182
1183 pr_info("driver unloaded\n");
1184 }
1185
1186 module_init(fujitsu_init);
1187 module_exit(fujitsu_cleanup);
1188
1189 module_param(use_alt_lcd_levels, uint, 0644);
1190 MODULE_PARM_DESC(use_alt_lcd_levels,
1191 "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
1192 module_param(disable_brightness_adjust, uint, 0644);
1193 MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
1194 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
1195 module_param_named(debug, dbg_level, uint, 0644);
1196 MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
1197 #endif
1198
1199 MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
1200 MODULE_DESCRIPTION("Fujitsu laptop extras support");
1201 MODULE_VERSION(FUJITSU_DRIVER_VERSION);
1202 MODULE_LICENSE("GPL");