]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/platform/x86/fujitsu-laptop.c
x86/arch_prctl: Add ARCH_[GET|SET]_CPUID
[karo-tx-linux.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 exports a few files in /sys/devices/platform/fujitsu-laptop/;
36  * others may be added at a later date.
37  *
38  *   lcd_level - Screen brightness: contains a single integer in the
39  *   range 0..7. (rw)
40  *
41  * In addition to these platform device attributes the driver
42  * registers itself in the Linux backlight control subsystem and is
43  * available to userspace under /sys/class/backlight/fujitsu-laptop/.
44  *
45  * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
46  * also supported by this driver.
47  *
48  * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
49  * P8010.  It should work on most P-series and S-series Lifebooks, but
50  * YMMV.
51  *
52  * The module parameter use_alt_lcd_levels switches between different ACPI
53  * brightness controls which are used by different Fujitsu laptops.  In most
54  * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
55  * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
56  *
57  */
58
59 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
60
61 #include <linux/module.h>
62 #include <linux/kernel.h>
63 #include <linux/init.h>
64 #include <linux/acpi.h>
65 #include <linux/dmi.h>
66 #include <linux/backlight.h>
67 #include <linux/fb.h>
68 #include <linux/input.h>
69 #include <linux/kfifo.h>
70 #include <linux/platform_device.h>
71 #include <linux/slab.h>
72 #if IS_ENABLED(CONFIG_LEDS_CLASS)
73 #include <linux/leds.h>
74 #endif
75 #include <acpi/video.h>
76
77 #define FUJITSU_DRIVER_VERSION "0.6.0"
78
79 #define FUJITSU_LCD_N_LEVELS 8
80
81 #define ACPI_FUJITSU_CLASS              "fujitsu"
82 #define ACPI_FUJITSU_HID                "FUJ02B1"
83 #define ACPI_FUJITSU_DRIVER_NAME        "Fujitsu laptop FUJ02B1 ACPI brightness driver"
84 #define ACPI_FUJITSU_DEVICE_NAME        "Fujitsu FUJ02B1"
85 #define ACPI_FUJITSU_HOTKEY_HID         "FUJ02E3"
86 #define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
87 #define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3"
88
89 #define ACPI_FUJITSU_NOTIFY_CODE1     0x80
90
91 /* FUNC interface - command values */
92 #define FUNC_RFKILL     0x1000
93 #define FUNC_LEDS       0x1001
94 #define FUNC_BUTTONS    0x1002
95 #define FUNC_BACKLIGHT  0x1004
96
97 /* FUNC interface - responses */
98 #define UNSUPPORTED_CMD 0x80000000
99
100 #if IS_ENABLED(CONFIG_LEDS_CLASS)
101 /* FUNC interface - LED control */
102 #define FUNC_LED_OFF    0x1
103 #define FUNC_LED_ON     0x30001
104 #define KEYBOARD_LAMPS  0x100
105 #define LOGOLAMP_POWERON 0x2000
106 #define LOGOLAMP_ALWAYS  0x4000
107 #define RADIO_LED_ON    0x20
108 #define ECO_LED 0x10000
109 #define ECO_LED_ON      0x80000
110 #endif
111
112 /* Hotkey details */
113 #define KEY1_CODE       0x410   /* codes for the keys in the GIRB register */
114 #define KEY2_CODE       0x411
115 #define KEY3_CODE       0x412
116 #define KEY4_CODE       0x413
117 #define KEY5_CODE       0x420
118
119 #define MAX_HOTKEY_RINGBUFFER_SIZE 100
120 #define RINGBUFFERSIZE 40
121
122 /* Debugging */
123 #define FUJLAPTOP_DBG_ERROR       0x0001
124 #define FUJLAPTOP_DBG_WARN        0x0002
125 #define FUJLAPTOP_DBG_INFO        0x0004
126 #define FUJLAPTOP_DBG_TRACE       0x0008
127
128 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
129 #define vdbg_printk(a_dbg_level, format, arg...) \
130         do { if (dbg_level & a_dbg_level) \
131                 printk(KERN_DEBUG pr_fmt("%s: " format), __func__, ## arg); \
132         } while (0)
133 #else
134 #define vdbg_printk(a_dbg_level, format, arg...) \
135         do { } while (0)
136 #endif
137
138 /* Device controlling the backlight and associated keys */
139 struct fujitsu_t {
140         acpi_handle acpi_handle;
141         struct acpi_device *dev;
142         struct input_dev *input;
143         char phys[32];
144         struct backlight_device *bl_device;
145         struct platform_device *pf_device;
146         int keycode1, keycode2, keycode3, keycode4, keycode5;
147
148         unsigned int max_brightness;
149         unsigned int brightness_changed;
150         unsigned int brightness_level;
151 };
152
153 static struct fujitsu_t *fujitsu;
154 static int use_alt_lcd_levels = -1;
155 static int disable_brightness_adjust = -1;
156
157 /* Device used to access other hotkeys on the laptop */
158 struct fujitsu_hotkey_t {
159         acpi_handle acpi_handle;
160         struct acpi_device *dev;
161         struct input_dev *input;
162         char phys[32];
163         struct platform_device *pf_device;
164         struct kfifo fifo;
165         spinlock_t fifo_lock;
166         int rfkill_supported;
167         int rfkill_state;
168         int logolamp_registered;
169         int kblamps_registered;
170         int radio_led_registered;
171         int eco_led_registered;
172 };
173
174 static struct fujitsu_hotkey_t *fujitsu_hotkey;
175
176 static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event);
177
178 #if IS_ENABLED(CONFIG_LEDS_CLASS)
179 static enum led_brightness logolamp_get(struct led_classdev *cdev);
180 static int logolamp_set(struct led_classdev *cdev,
181                                enum led_brightness brightness);
182
183 static struct led_classdev logolamp_led = {
184  .name = "fujitsu::logolamp",
185  .brightness_get = logolamp_get,
186  .brightness_set_blocking = logolamp_set
187 };
188
189 static enum led_brightness kblamps_get(struct led_classdev *cdev);
190 static int kblamps_set(struct led_classdev *cdev,
191                                enum led_brightness brightness);
192
193 static struct led_classdev kblamps_led = {
194  .name = "fujitsu::kblamps",
195  .brightness_get = kblamps_get,
196  .brightness_set_blocking = kblamps_set
197 };
198
199 static enum led_brightness radio_led_get(struct led_classdev *cdev);
200 static int radio_led_set(struct led_classdev *cdev,
201                                enum led_brightness brightness);
202
203 static struct led_classdev radio_led = {
204  .name = "fujitsu::radio_led",
205  .default_trigger = "rfkill-any",
206  .brightness_get = radio_led_get,
207  .brightness_set_blocking = radio_led_set
208 };
209
210 static enum led_brightness eco_led_get(struct led_classdev *cdev);
211 static int eco_led_set(struct led_classdev *cdev,
212                                enum led_brightness brightness);
213
214 static struct led_classdev eco_led = {
215  .name = "fujitsu::eco_led",
216  .brightness_get = eco_led_get,
217  .brightness_set_blocking = eco_led_set
218 };
219 #endif
220
221 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
222 static u32 dbg_level = 0x03;
223 #endif
224
225 static void acpi_fujitsu_notify(struct acpi_device *device, u32 event);
226
227 /* Fujitsu ACPI interface function */
228
229 static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
230 {
231         acpi_status status = AE_OK;
232         union acpi_object params[4] = {
233         { .type = ACPI_TYPE_INTEGER },
234         { .type = ACPI_TYPE_INTEGER },
235         { .type = ACPI_TYPE_INTEGER },
236         { .type = ACPI_TYPE_INTEGER }
237         };
238         struct acpi_object_list arg_list = { 4, &params[0] };
239         unsigned long long value;
240         acpi_handle handle = NULL;
241
242         status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle);
243         if (ACPI_FAILURE(status)) {
244                 vdbg_printk(FUJLAPTOP_DBG_ERROR,
245                                 "FUNC interface is not present\n");
246                 return -ENODEV;
247         }
248
249         params[0].integer.value = cmd;
250         params[1].integer.value = arg0;
251         params[2].integer.value = arg1;
252         params[3].integer.value = arg2;
253
254         status = acpi_evaluate_integer(handle, NULL, &arg_list, &value);
255         if (ACPI_FAILURE(status)) {
256                 vdbg_printk(FUJLAPTOP_DBG_WARN,
257                         "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
258                                 cmd, arg0, arg1, arg2);
259                 return -ENODEV;
260         }
261
262         vdbg_printk(FUJLAPTOP_DBG_TRACE,
263                 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
264                         cmd, arg0, arg1, arg2, (int)value);
265         return value;
266 }
267
268 #if IS_ENABLED(CONFIG_LEDS_CLASS)
269 /* LED class callbacks */
270
271 static int logolamp_set(struct led_classdev *cdev,
272                                enum led_brightness brightness)
273 {
274         int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
275         int ret;
276
277         if (brightness < LED_HALF)
278                 poweron = FUNC_LED_OFF;
279
280         if (brightness < LED_FULL)
281                 always = FUNC_LED_OFF;
282
283         ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
284         if (ret < 0)
285                 return ret;
286
287         return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
288 }
289
290 static int kblamps_set(struct led_classdev *cdev,
291                                enum led_brightness brightness)
292 {
293         if (brightness >= LED_FULL)
294                 return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
295         else
296                 return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
297 }
298
299 static int radio_led_set(struct led_classdev *cdev,
300                                 enum led_brightness brightness)
301 {
302         if (brightness >= LED_FULL)
303                 return call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, RADIO_LED_ON);
304         else
305                 return call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0);
306 }
307
308 static int eco_led_set(struct led_classdev *cdev,
309                                 enum led_brightness brightness)
310 {
311         int curr;
312
313         curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0);
314         if (brightness >= LED_FULL)
315                 return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON);
316         else
317                 return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON);
318 }
319
320 static enum led_brightness logolamp_get(struct led_classdev *cdev)
321 {
322         int ret;
323
324         ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
325         if (ret == FUNC_LED_ON)
326                 return LED_FULL;
327
328         ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
329         if (ret == FUNC_LED_ON)
330                 return LED_HALF;
331
332         return LED_OFF;
333 }
334
335 static enum led_brightness kblamps_get(struct led_classdev *cdev)
336 {
337         enum led_brightness brightness = LED_OFF;
338
339         if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
340                 brightness = LED_FULL;
341
342         return brightness;
343 }
344
345 static enum led_brightness radio_led_get(struct led_classdev *cdev)
346 {
347         enum led_brightness brightness = LED_OFF;
348
349         if (call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0) & RADIO_LED_ON)
350                 brightness = LED_FULL;
351
352         return brightness;
353 }
354
355 static enum led_brightness eco_led_get(struct led_classdev *cdev)
356 {
357         enum led_brightness brightness = LED_OFF;
358
359         if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
360                 brightness = LED_FULL;
361
362         return brightness;
363 }
364 #endif
365
366 /* Hardware access for LCD brightness control */
367
368 static int set_lcd_level(int level)
369 {
370         acpi_status status = AE_OK;
371         acpi_handle handle = NULL;
372
373         vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
374                     level);
375
376         if (level < 0 || level >= fujitsu->max_brightness)
377                 return -EINVAL;
378
379         status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
380         if (ACPI_FAILURE(status)) {
381                 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
382                 return -ENODEV;
383         }
384
385
386         status = acpi_execute_simple_method(handle, NULL, level);
387         if (ACPI_FAILURE(status))
388                 return -ENODEV;
389
390         return 0;
391 }
392
393 static int set_lcd_level_alt(int level)
394 {
395         acpi_status status = AE_OK;
396         acpi_handle handle = NULL;
397
398         vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
399                     level);
400
401         if (level < 0 || level >= fujitsu->max_brightness)
402                 return -EINVAL;
403
404         status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle);
405         if (ACPI_FAILURE(status)) {
406                 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
407                 return -ENODEV;
408         }
409
410         status = acpi_execute_simple_method(handle, NULL, level);
411         if (ACPI_FAILURE(status))
412                 return -ENODEV;
413
414         return 0;
415 }
416
417 static int get_lcd_level(void)
418 {
419         unsigned long long state = 0;
420         acpi_status status = AE_OK;
421
422         vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
423
424         status =
425             acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
426         if (ACPI_FAILURE(status))
427                 return 0;
428
429         fujitsu->brightness_level = state & 0x0fffffff;
430
431         if (state & 0x80000000)
432                 fujitsu->brightness_changed = 1;
433         else
434                 fujitsu->brightness_changed = 0;
435
436         return fujitsu->brightness_level;
437 }
438
439 static int get_max_brightness(void)
440 {
441         unsigned long long state = 0;
442         acpi_status status = AE_OK;
443
444         vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
445
446         status =
447             acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
448         if (ACPI_FAILURE(status))
449                 return -1;
450
451         fujitsu->max_brightness = state;
452
453         return fujitsu->max_brightness;
454 }
455
456 /* Backlight device stuff */
457
458 static int bl_get_brightness(struct backlight_device *b)
459 {
460         return get_lcd_level();
461 }
462
463 static int bl_update_status(struct backlight_device *b)
464 {
465         int ret;
466         if (b->props.power == FB_BLANK_POWERDOWN)
467                 ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
468         else
469                 ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
470         if (ret != 0)
471                 vdbg_printk(FUJLAPTOP_DBG_ERROR,
472                         "Unable to adjust backlight power, error code %i\n",
473                         ret);
474
475         if (use_alt_lcd_levels)
476                 ret = set_lcd_level_alt(b->props.brightness);
477         else
478                 ret = set_lcd_level(b->props.brightness);
479         if (ret != 0)
480                 vdbg_printk(FUJLAPTOP_DBG_ERROR,
481                         "Unable to adjust LCD brightness, error code %i\n",
482                         ret);
483         return ret;
484 }
485
486 static const struct backlight_ops fujitsubl_ops = {
487         .get_brightness = bl_get_brightness,
488         .update_status = bl_update_status,
489 };
490
491 /* Platform LCD brightness device */
492
493 static ssize_t
494 show_max_brightness(struct device *dev,
495                     struct device_attribute *attr, char *buf)
496 {
497
498         int ret;
499
500         ret = get_max_brightness();
501         if (ret < 0)
502                 return ret;
503
504         return sprintf(buf, "%i\n", ret);
505 }
506
507 static ssize_t
508 show_brightness_changed(struct device *dev,
509                         struct device_attribute *attr, char *buf)
510 {
511
512         int ret;
513
514         ret = fujitsu->brightness_changed;
515         if (ret < 0)
516                 return ret;
517
518         return sprintf(buf, "%i\n", ret);
519 }
520
521 static ssize_t show_lcd_level(struct device *dev,
522                               struct device_attribute *attr, char *buf)
523 {
524
525         int ret;
526
527         ret = get_lcd_level();
528         if (ret < 0)
529                 return ret;
530
531         return sprintf(buf, "%i\n", ret);
532 }
533
534 static ssize_t store_lcd_level(struct device *dev,
535                                struct device_attribute *attr, const char *buf,
536                                size_t count)
537 {
538
539         int level, ret;
540
541         if (sscanf(buf, "%i", &level) != 1
542             || (level < 0 || level >= fujitsu->max_brightness))
543                 return -EINVAL;
544
545         if (use_alt_lcd_levels)
546                 ret = set_lcd_level_alt(level);
547         else
548                 ret = set_lcd_level(level);
549         if (ret < 0)
550                 return ret;
551
552         ret = get_lcd_level();
553         if (ret < 0)
554                 return ret;
555
556         return count;
557 }
558
559 static ssize_t
560 ignore_store(struct device *dev,
561              struct device_attribute *attr, const char *buf, size_t count)
562 {
563         return count;
564 }
565
566 static ssize_t
567 show_lid_state(struct device *dev,
568                         struct device_attribute *attr, char *buf)
569 {
570         if (!(fujitsu_hotkey->rfkill_supported & 0x100))
571                 return sprintf(buf, "unknown\n");
572         if (fujitsu_hotkey->rfkill_state & 0x100)
573                 return sprintf(buf, "open\n");
574         else
575                 return sprintf(buf, "closed\n");
576 }
577
578 static ssize_t
579 show_dock_state(struct device *dev,
580                         struct device_attribute *attr, char *buf)
581 {
582         if (!(fujitsu_hotkey->rfkill_supported & 0x200))
583                 return sprintf(buf, "unknown\n");
584         if (fujitsu_hotkey->rfkill_state & 0x200)
585                 return sprintf(buf, "docked\n");
586         else
587                 return sprintf(buf, "undocked\n");
588 }
589
590 static ssize_t
591 show_radios_state(struct device *dev,
592                         struct device_attribute *attr, char *buf)
593 {
594         if (!(fujitsu_hotkey->rfkill_supported & 0x20))
595                 return sprintf(buf, "unknown\n");
596         if (fujitsu_hotkey->rfkill_state & 0x20)
597                 return sprintf(buf, "on\n");
598         else
599                 return sprintf(buf, "killed\n");
600 }
601
602 static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
603 static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
604                    ignore_store);
605 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
606 static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store);
607 static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store);
608 static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store);
609
610 static struct attribute *fujitsupf_attributes[] = {
611         &dev_attr_brightness_changed.attr,
612         &dev_attr_max_brightness.attr,
613         &dev_attr_lcd_level.attr,
614         &dev_attr_lid.attr,
615         &dev_attr_dock.attr,
616         &dev_attr_radios.attr,
617         NULL
618 };
619
620 static struct attribute_group fujitsupf_attribute_group = {
621         .attrs = fujitsupf_attributes
622 };
623
624 static struct platform_driver fujitsupf_driver = {
625         .driver = {
626                    .name = "fujitsu-laptop",
627                    }
628 };
629
630 static void __init dmi_check_cb_common(const struct dmi_system_id *id)
631 {
632         pr_info("Identified laptop model '%s'\n", id->ident);
633         if (use_alt_lcd_levels == -1) {
634                 if (acpi_has_method(NULL,
635                                 "\\_SB.PCI0.LPCB.FJEX.SBL2"))
636                         use_alt_lcd_levels = 1;
637                 else
638                         use_alt_lcd_levels = 0;
639                 vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as "
640                         "%i\n", use_alt_lcd_levels);
641         }
642 }
643
644 static int __init dmi_check_cb_s6410(const struct dmi_system_id *id)
645 {
646         dmi_check_cb_common(id);
647         fujitsu->keycode1 = KEY_SCREENLOCK;     /* "Lock" */
648         fujitsu->keycode2 = KEY_HELP;   /* "Mobility Center" */
649         return 1;
650 }
651
652 static int __init dmi_check_cb_s6420(const struct dmi_system_id *id)
653 {
654         dmi_check_cb_common(id);
655         fujitsu->keycode1 = KEY_SCREENLOCK;     /* "Lock" */
656         fujitsu->keycode2 = KEY_HELP;   /* "Mobility Center" */
657         return 1;
658 }
659
660 static int __init dmi_check_cb_p8010(const struct dmi_system_id *id)
661 {
662         dmi_check_cb_common(id);
663         fujitsu->keycode1 = KEY_HELP;   /* "Support" */
664         fujitsu->keycode3 = KEY_SWITCHVIDEOMODE;        /* "Presentation" */
665         fujitsu->keycode4 = KEY_WWW;    /* "Internet" */
666         return 1;
667 }
668
669 static const struct dmi_system_id fujitsu_dmi_table[] __initconst = {
670         {
671          .ident = "Fujitsu Siemens S6410",
672          .matches = {
673                      DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
674                      DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
675                      },
676          .callback = dmi_check_cb_s6410},
677         {
678          .ident = "Fujitsu Siemens S6420",
679          .matches = {
680                      DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
681                      DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
682                      },
683          .callback = dmi_check_cb_s6420},
684         {
685          .ident = "Fujitsu LifeBook P8010",
686          .matches = {
687                      DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
688                      DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
689                      },
690          .callback = dmi_check_cb_p8010},
691         {}
692 };
693
694 /* ACPI device for LCD brightness control */
695
696 static int acpi_fujitsu_add(struct acpi_device *device)
697 {
698         int state = 0;
699         struct input_dev *input;
700         int error;
701
702         if (!device)
703                 return -EINVAL;
704
705         fujitsu->acpi_handle = device->handle;
706         sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
707         sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
708         device->driver_data = fujitsu;
709
710         fujitsu->input = input = input_allocate_device();
711         if (!input) {
712                 error = -ENOMEM;
713                 goto err_stop;
714         }
715
716         snprintf(fujitsu->phys, sizeof(fujitsu->phys),
717                  "%s/video/input0", acpi_device_hid(device));
718
719         input->name = acpi_device_name(device);
720         input->phys = fujitsu->phys;
721         input->id.bustype = BUS_HOST;
722         input->id.product = 0x06;
723         input->dev.parent = &device->dev;
724         input->evbit[0] = BIT(EV_KEY);
725         set_bit(KEY_BRIGHTNESSUP, input->keybit);
726         set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
727         set_bit(KEY_UNKNOWN, input->keybit);
728
729         error = input_register_device(input);
730         if (error)
731                 goto err_free_input_dev;
732
733         error = acpi_bus_update_power(fujitsu->acpi_handle, &state);
734         if (error) {
735                 pr_err("Error reading power state\n");
736                 goto err_unregister_input_dev;
737         }
738
739         pr_info("ACPI: %s [%s] (%s)\n",
740                acpi_device_name(device), acpi_device_bid(device),
741                !device->power.state ? "on" : "off");
742
743         fujitsu->dev = device;
744
745         if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
746                 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
747                 if (ACPI_FAILURE
748                     (acpi_evaluate_object
749                      (device->handle, METHOD_NAME__INI, NULL, NULL)))
750                         pr_err("_INI Method failed\n");
751         }
752
753         /* do config (detect defaults) */
754         use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
755         disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
756         vdbg_printk(FUJLAPTOP_DBG_INFO,
757                     "config: [alt interface: %d], [adjust disable: %d]\n",
758                     use_alt_lcd_levels, disable_brightness_adjust);
759
760         if (get_max_brightness() <= 0)
761                 fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
762         get_lcd_level();
763
764         return 0;
765
766 err_unregister_input_dev:
767         input_unregister_device(input);
768         input = NULL;
769 err_free_input_dev:
770         input_free_device(input);
771 err_stop:
772         return error;
773 }
774
775 static int acpi_fujitsu_remove(struct acpi_device *device)
776 {
777         struct fujitsu_t *fujitsu = acpi_driver_data(device);
778         struct input_dev *input = fujitsu->input;
779
780         input_unregister_device(input);
781
782         fujitsu->acpi_handle = NULL;
783
784         return 0;
785 }
786
787 /* Brightness notify */
788
789 static void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
790 {
791         struct input_dev *input;
792         int keycode;
793         int oldb, newb;
794
795         input = fujitsu->input;
796
797         switch (event) {
798         case ACPI_FUJITSU_NOTIFY_CODE1:
799                 keycode = 0;
800                 oldb = fujitsu->brightness_level;
801                 get_lcd_level();
802                 newb = fujitsu->brightness_level;
803
804                 vdbg_printk(FUJLAPTOP_DBG_TRACE,
805                             "brightness button event [%i -> %i (%i)]\n",
806                             oldb, newb, fujitsu->brightness_changed);
807
808                 if (oldb < newb) {
809                         if (disable_brightness_adjust != 1) {
810                                 if (use_alt_lcd_levels)
811                                         set_lcd_level_alt(newb);
812                                 else
813                                         set_lcd_level(newb);
814                         }
815                         keycode = KEY_BRIGHTNESSUP;
816                 } else if (oldb > newb) {
817                         if (disable_brightness_adjust != 1) {
818                                 if (use_alt_lcd_levels)
819                                         set_lcd_level_alt(newb);
820                                 else
821                                         set_lcd_level(newb);
822                         }
823                         keycode = KEY_BRIGHTNESSDOWN;
824                 }
825                 break;
826         default:
827                 keycode = KEY_UNKNOWN;
828                 vdbg_printk(FUJLAPTOP_DBG_WARN,
829                             "unsupported event [0x%x]\n", event);
830                 break;
831         }
832
833         if (keycode != 0) {
834                 input_report_key(input, keycode, 1);
835                 input_sync(input);
836                 input_report_key(input, keycode, 0);
837                 input_sync(input);
838         }
839 }
840
841 /* ACPI device for hotkey handling */
842
843 static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
844 {
845         int result = 0;
846         int state = 0;
847         struct input_dev *input;
848         int error;
849         int i;
850
851         if (!device)
852                 return -EINVAL;
853
854         fujitsu_hotkey->acpi_handle = device->handle;
855         sprintf(acpi_device_name(device), "%s",
856                 ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
857         sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
858         device->driver_data = fujitsu_hotkey;
859
860         /* kfifo */
861         spin_lock_init(&fujitsu_hotkey->fifo_lock);
862         error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
863                         GFP_KERNEL);
864         if (error) {
865                 pr_err("kfifo_alloc failed\n");
866                 goto err_stop;
867         }
868
869         fujitsu_hotkey->input = input = input_allocate_device();
870         if (!input) {
871                 error = -ENOMEM;
872                 goto err_free_fifo;
873         }
874
875         snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys),
876                  "%s/video/input0", acpi_device_hid(device));
877
878         input->name = acpi_device_name(device);
879         input->phys = fujitsu_hotkey->phys;
880         input->id.bustype = BUS_HOST;
881         input->id.product = 0x06;
882         input->dev.parent = &device->dev;
883
884         set_bit(EV_KEY, input->evbit);
885         set_bit(fujitsu->keycode1, input->keybit);
886         set_bit(fujitsu->keycode2, input->keybit);
887         set_bit(fujitsu->keycode3, input->keybit);
888         set_bit(fujitsu->keycode4, input->keybit);
889         set_bit(fujitsu->keycode5, input->keybit);
890         set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit);
891         set_bit(KEY_UNKNOWN, input->keybit);
892
893         error = input_register_device(input);
894         if (error)
895                 goto err_free_input_dev;
896
897         error = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
898         if (error) {
899                 pr_err("Error reading power state\n");
900                 goto err_unregister_input_dev;
901         }
902
903         pr_info("ACPI: %s [%s] (%s)\n",
904                 acpi_device_name(device), acpi_device_bid(device),
905                 !device->power.state ? "on" : "off");
906
907         fujitsu_hotkey->dev = device;
908
909         if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
910                 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
911                 if (ACPI_FAILURE
912                     (acpi_evaluate_object
913                      (device->handle, METHOD_NAME__INI, NULL, NULL)))
914                         pr_err("_INI Method failed\n");
915         }
916
917         i = 0;
918         while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
919                 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
920                 ; /* No action, result is discarded */
921         vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
922
923         fujitsu_hotkey->rfkill_supported =
924                 call_fext_func(FUNC_RFKILL, 0x0, 0x0, 0x0);
925
926         /* Make sure our bitmask of supported functions is cleared if the
927            RFKILL function block is not implemented, like on the S7020. */
928         if (fujitsu_hotkey->rfkill_supported == UNSUPPORTED_CMD)
929                 fujitsu_hotkey->rfkill_supported = 0;
930
931         if (fujitsu_hotkey->rfkill_supported)
932                 fujitsu_hotkey->rfkill_state =
933                         call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
934
935         /* Suspect this is a keymap of the application panel, print it */
936         pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
937
938 #if IS_ENABLED(CONFIG_LEDS_CLASS)
939         if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
940                 result = led_classdev_register(&fujitsu->pf_device->dev,
941                                                 &logolamp_led);
942                 if (result == 0) {
943                         fujitsu_hotkey->logolamp_registered = 1;
944                 } else {
945                         pr_err("Could not register LED handler for logo lamp, error %i\n",
946                                result);
947                 }
948         }
949
950         if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
951            (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
952                 result = led_classdev_register(&fujitsu->pf_device->dev,
953                                                 &kblamps_led);
954                 if (result == 0) {
955                         fujitsu_hotkey->kblamps_registered = 1;
956                 } else {
957                         pr_err("Could not register LED handler for keyboard lamps, error %i\n",
958                                result);
959                 }
960         }
961
962         /*
963          * BTNI bit 24 seems to indicate the presence of a radio toggle
964          * button in place of a slide switch, and all such machines appear
965          * to also have an RF LED.  Therefore use bit 24 as an indicator
966          * that an RF LED is present.
967          */
968         if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
969                 result = led_classdev_register(&fujitsu->pf_device->dev,
970                                                 &radio_led);
971                 if (result == 0) {
972                         fujitsu_hotkey->radio_led_registered = 1;
973                 } else {
974                         pr_err("Could not register LED handler for radio LED, error %i\n",
975                                result);
976                 }
977         }
978
979         /* Support for eco led is not always signaled in bit corresponding
980          * to the bit used to control the led. According to the DSDT table,
981          * bit 14 seems to indicate presence of said led as well.
982          * Confirm by testing the status.
983         */
984         if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
985            (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
986                 result = led_classdev_register(&fujitsu->pf_device->dev,
987                                                 &eco_led);
988                 if (result == 0) {
989                         fujitsu_hotkey->eco_led_registered = 1;
990                 } else {
991                         pr_err("Could not register LED handler for eco LED, error %i\n",
992                                result);
993                 }
994         }
995 #endif
996
997         return result;
998
999 err_unregister_input_dev:
1000         input_unregister_device(input);
1001         input = NULL;
1002 err_free_input_dev:
1003         input_free_device(input);
1004 err_free_fifo:
1005         kfifo_free(&fujitsu_hotkey->fifo);
1006 err_stop:
1007         return error;
1008 }
1009
1010 static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
1011 {
1012         struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device);
1013         struct input_dev *input = fujitsu_hotkey->input;
1014
1015 #if IS_ENABLED(CONFIG_LEDS_CLASS)
1016         if (fujitsu_hotkey->logolamp_registered)
1017                 led_classdev_unregister(&logolamp_led);
1018
1019         if (fujitsu_hotkey->kblamps_registered)
1020                 led_classdev_unregister(&kblamps_led);
1021
1022         if (fujitsu_hotkey->radio_led_registered)
1023                 led_classdev_unregister(&radio_led);
1024
1025         if (fujitsu_hotkey->eco_led_registered)
1026                 led_classdev_unregister(&eco_led);
1027 #endif
1028
1029         input_unregister_device(input);
1030
1031         kfifo_free(&fujitsu_hotkey->fifo);
1032
1033         fujitsu_hotkey->acpi_handle = NULL;
1034
1035         return 0;
1036 }
1037
1038 static void acpi_fujitsu_hotkey_press(int keycode)
1039 {
1040         struct input_dev *input = fujitsu_hotkey->input;
1041         int status;
1042
1043         status = kfifo_in_locked(&fujitsu_hotkey->fifo,
1044                                  (unsigned char *)&keycode, sizeof(keycode),
1045                                  &fujitsu_hotkey->fifo_lock);
1046         if (status != sizeof(keycode)) {
1047                 vdbg_printk(FUJLAPTOP_DBG_WARN,
1048                             "Could not push keycode [0x%x]\n", keycode);
1049                 return;
1050         }
1051         input_report_key(input, keycode, 1);
1052         input_sync(input);
1053         vdbg_printk(FUJLAPTOP_DBG_TRACE,
1054                     "Push keycode into ringbuffer [%d]\n", keycode);
1055 }
1056
1057 static void acpi_fujitsu_hotkey_release(void)
1058 {
1059         struct input_dev *input = fujitsu_hotkey->input;
1060         int keycode, status;
1061
1062         while (true) {
1063                 status = kfifo_out_locked(&fujitsu_hotkey->fifo,
1064                                           (unsigned char *)&keycode,
1065                                           sizeof(keycode),
1066                                           &fujitsu_hotkey->fifo_lock);
1067                 if (status != sizeof(keycode))
1068                         return;
1069                 input_report_key(input, keycode, 0);
1070                 input_sync(input);
1071                 vdbg_printk(FUJLAPTOP_DBG_TRACE,
1072                             "Pop keycode from ringbuffer [%d]\n", keycode);
1073         }
1074 }
1075
1076 static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
1077 {
1078         struct input_dev *input;
1079         int keycode;
1080         unsigned int irb = 1;
1081         int i;
1082
1083         input = fujitsu_hotkey->input;
1084
1085         if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
1086                 keycode = KEY_UNKNOWN;
1087                 vdbg_printk(FUJLAPTOP_DBG_WARN,
1088                             "Unsupported event [0x%x]\n", event);
1089                 input_report_key(input, keycode, 1);
1090                 input_sync(input);
1091                 input_report_key(input, keycode, 0);
1092                 input_sync(input);
1093                 return;
1094         }
1095
1096         if (fujitsu_hotkey->rfkill_supported)
1097                 fujitsu_hotkey->rfkill_state =
1098                         call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
1099
1100         i = 0;
1101         while ((irb =
1102                 call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
1103                         && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
1104                 switch (irb & 0x4ff) {
1105                 case KEY1_CODE:
1106                         keycode = fujitsu->keycode1;
1107                         break;
1108                 case KEY2_CODE:
1109                         keycode = fujitsu->keycode2;
1110                         break;
1111                 case KEY3_CODE:
1112                         keycode = fujitsu->keycode3;
1113                         break;
1114                 case KEY4_CODE:
1115                         keycode = fujitsu->keycode4;
1116                         break;
1117                 case KEY5_CODE:
1118                         keycode = fujitsu->keycode5;
1119                         break;
1120                 case 0:
1121                         keycode = 0;
1122                         break;
1123                 default:
1124                         vdbg_printk(FUJLAPTOP_DBG_WARN,
1125                                     "Unknown GIRB result [%x]\n", irb);
1126                         keycode = -1;
1127                         break;
1128                 }
1129
1130                 if (keycode > 0)
1131                         acpi_fujitsu_hotkey_press(keycode);
1132                 else if (keycode == 0)
1133                         acpi_fujitsu_hotkey_release();
1134         }
1135
1136         /* On some models (first seen on the Skylake-based Lifebook
1137          * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
1138          * handled in software; its state is queried using FUNC_RFKILL
1139          */
1140         if ((fujitsu_hotkey->rfkill_supported & BIT(26)) &&
1141             (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) {
1142                 keycode = KEY_TOUCHPAD_TOGGLE;
1143                 input_report_key(input, keycode, 1);
1144                 input_sync(input);
1145                 input_report_key(input, keycode, 0);
1146                 input_sync(input);
1147         }
1148
1149 }
1150
1151 /* Initialization */
1152
1153 static const struct acpi_device_id fujitsu_device_ids[] = {
1154         {ACPI_FUJITSU_HID, 0},
1155         {"", 0},
1156 };
1157
1158 static struct acpi_driver acpi_fujitsu_driver = {
1159         .name = ACPI_FUJITSU_DRIVER_NAME,
1160         .class = ACPI_FUJITSU_CLASS,
1161         .ids = fujitsu_device_ids,
1162         .ops = {
1163                 .add = acpi_fujitsu_add,
1164                 .remove = acpi_fujitsu_remove,
1165                 .notify = acpi_fujitsu_notify,
1166                 },
1167 };
1168
1169 static const struct acpi_device_id fujitsu_hotkey_device_ids[] = {
1170         {ACPI_FUJITSU_HOTKEY_HID, 0},
1171         {"", 0},
1172 };
1173
1174 static struct acpi_driver acpi_fujitsu_hotkey_driver = {
1175         .name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME,
1176         .class = ACPI_FUJITSU_CLASS,
1177         .ids = fujitsu_hotkey_device_ids,
1178         .ops = {
1179                 .add = acpi_fujitsu_hotkey_add,
1180                 .remove = acpi_fujitsu_hotkey_remove,
1181                 .notify = acpi_fujitsu_hotkey_notify,
1182                 },
1183 };
1184
1185 static const struct acpi_device_id fujitsu_ids[] __used = {
1186         {ACPI_FUJITSU_HID, 0},
1187         {ACPI_FUJITSU_HOTKEY_HID, 0},
1188         {"", 0}
1189 };
1190 MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
1191
1192 static int __init fujitsu_init(void)
1193 {
1194         int ret, result, max_brightness;
1195
1196         if (acpi_disabled)
1197                 return -ENODEV;
1198
1199         fujitsu = kzalloc(sizeof(struct fujitsu_t), GFP_KERNEL);
1200         if (!fujitsu)
1201                 return -ENOMEM;
1202         fujitsu->keycode1 = KEY_PROG1;
1203         fujitsu->keycode2 = KEY_PROG2;
1204         fujitsu->keycode3 = KEY_PROG3;
1205         fujitsu->keycode4 = KEY_PROG4;
1206         fujitsu->keycode5 = KEY_RFKILL;
1207         dmi_check_system(fujitsu_dmi_table);
1208
1209         result = acpi_bus_register_driver(&acpi_fujitsu_driver);
1210         if (result < 0) {
1211                 ret = -ENODEV;
1212                 goto fail_acpi;
1213         }
1214
1215         /* Register platform stuff */
1216
1217         fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1);
1218         if (!fujitsu->pf_device) {
1219                 ret = -ENOMEM;
1220                 goto fail_platform_driver;
1221         }
1222
1223         ret = platform_device_add(fujitsu->pf_device);
1224         if (ret)
1225                 goto fail_platform_device1;
1226
1227         ret =
1228             sysfs_create_group(&fujitsu->pf_device->dev.kobj,
1229                                &fujitsupf_attribute_group);
1230         if (ret)
1231                 goto fail_platform_device2;
1232
1233         /* Register backlight stuff */
1234
1235         if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1236                 struct backlight_properties props;
1237
1238                 memset(&props, 0, sizeof(struct backlight_properties));
1239                 max_brightness = fujitsu->max_brightness;
1240                 props.type = BACKLIGHT_PLATFORM;
1241                 props.max_brightness = max_brightness - 1;
1242                 fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
1243                                                                NULL, NULL,
1244                                                                &fujitsubl_ops,
1245                                                                &props);
1246                 if (IS_ERR(fujitsu->bl_device)) {
1247                         ret = PTR_ERR(fujitsu->bl_device);
1248                         fujitsu->bl_device = NULL;
1249                         goto fail_sysfs_group;
1250                 }
1251                 fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
1252         }
1253
1254         ret = platform_driver_register(&fujitsupf_driver);
1255         if (ret)
1256                 goto fail_backlight;
1257
1258         /* Register hotkey driver */
1259
1260         fujitsu_hotkey = kzalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL);
1261         if (!fujitsu_hotkey) {
1262                 ret = -ENOMEM;
1263                 goto fail_hotkey;
1264         }
1265
1266         result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver);
1267         if (result < 0) {
1268                 ret = -ENODEV;
1269                 goto fail_hotkey1;
1270         }
1271
1272         /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */
1273         if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1274                 if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
1275                         fujitsu->bl_device->props.power = FB_BLANK_POWERDOWN;
1276                 else
1277                         fujitsu->bl_device->props.power = FB_BLANK_UNBLANK;
1278         }
1279
1280         pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
1281
1282         return 0;
1283
1284 fail_hotkey1:
1285         kfree(fujitsu_hotkey);
1286 fail_hotkey:
1287         platform_driver_unregister(&fujitsupf_driver);
1288 fail_backlight:
1289         backlight_device_unregister(fujitsu->bl_device);
1290 fail_sysfs_group:
1291         sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
1292                            &fujitsupf_attribute_group);
1293 fail_platform_device2:
1294         platform_device_del(fujitsu->pf_device);
1295 fail_platform_device1:
1296         platform_device_put(fujitsu->pf_device);
1297 fail_platform_driver:
1298         acpi_bus_unregister_driver(&acpi_fujitsu_driver);
1299 fail_acpi:
1300         kfree(fujitsu);
1301
1302         return ret;
1303 }
1304
1305 static void __exit fujitsu_cleanup(void)
1306 {
1307         acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver);
1308
1309         kfree(fujitsu_hotkey);
1310
1311         platform_driver_unregister(&fujitsupf_driver);
1312
1313         backlight_device_unregister(fujitsu->bl_device);
1314
1315         sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
1316                            &fujitsupf_attribute_group);
1317
1318         platform_device_unregister(fujitsu->pf_device);
1319
1320         acpi_bus_unregister_driver(&acpi_fujitsu_driver);
1321
1322         kfree(fujitsu);
1323
1324         pr_info("driver unloaded\n");
1325 }
1326
1327 module_init(fujitsu_init);
1328 module_exit(fujitsu_cleanup);
1329
1330 module_param(use_alt_lcd_levels, uint, 0644);
1331 MODULE_PARM_DESC(use_alt_lcd_levels,
1332                  "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
1333 module_param(disable_brightness_adjust, uint, 0644);
1334 MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
1335 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
1336 module_param_named(debug, dbg_level, uint, 0644);
1337 MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
1338 #endif
1339
1340 MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
1341 MODULE_DESCRIPTION("Fujitsu laptop extras support");
1342 MODULE_VERSION(FUJITSU_DRIVER_VERSION);
1343 MODULE_LICENSE("GPL");
1344
1345 MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
1346 MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
1347 MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");