1d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe/*-*-linux-c-*-*/
2d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
3d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe/*
4409a3e98132c3a4f2aa2854995f8a9dd16cf11acJonathan Woithe  Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe  Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
63a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon  Copyright (C) 2008 Tony Vroon <tony@linx.net>
7d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  Based on earlier work:
8d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe    Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
9d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe    Adrian Yee <brewt-fujitsu@brewt.org>
10d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe  Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
1220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe  by its respective authors.
13d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
14d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  This program is free software; you can redistribute it and/or modify
15d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  it under the terms of the GNU General Public License as published by
16d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  the Free Software Foundation; either version 2 of the License, or
17d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  (at your option) any later version.
18d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
19d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  This program is distributed in the hope that it will be useful, but
20d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  WITHOUT ANY WARRANTY; without even the implied warranty of
21d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  General Public License for more details.
23d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
24d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  You should have received a copy of the GNU General Public License
25d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  along with this program; if not, write to the Free Software
26d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe  02110-1301, USA.
28d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe */
29d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
30d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe/*
31d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
32d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * features made available on a range of Fujitsu laptops including the
33d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * P2xxx/P5xxx/S6xxx/S7xxx series.
34d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe *
35d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/;
36d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * others may be added at a later date.
37d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe *
38d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe *   lcd_level - Screen brightness: contains a single integer in the
39d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe *   range 0..7. (rw)
40d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe *
41d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * In addition to these platform device attributes the driver
42d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * registers itself in the Linux backlight control subsystem and is
43d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe * available to userspace under /sys/class/backlight/fujitsu-laptop/.
44d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe *
4520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
4620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe * also supported by this driver.
4720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe *
480e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
490e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe * P8010.  It should work on most P-series and S-series Lifebooks, but
500e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe * YMMV.
5120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe *
5220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe * The module parameter use_alt_lcd_levels switches between different ACPI
5320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe * brightness controls which are used by different Fujitsu laptops.  In most
5420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
5520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
5620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe *
57d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe */
58d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
5977bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6077bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches
61d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#include <linux/module.h>
62d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#include <linux/kernel.h>
63d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#include <linux/init.h>
64d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#include <linux/acpi.h>
65d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#include <linux/dmi.h>
66d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#include <linux/backlight.h>
6720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#include <linux/input.h>
6820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#include <linux/kfifo.h>
69d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#include <linux/platform_device.h>
705a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
711e384cb0f9a940f2a431d1708f963987e61d71e3Stephen Gildea#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
723a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#include <linux/leds.h>
733a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#endif
74d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
7584a6ce267296dabdf427ea4aff73dc58164863bbJonathan Woithe#define FUJITSU_DRIVER_VERSION "0.6.0"
76d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
77d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#define FUJITSU_LCD_N_LEVELS 8
78d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
79d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#define ACPI_FUJITSU_CLASS              "fujitsu"
80d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#define ACPI_FUJITSU_HID                "FUJ02B1"
8120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define ACPI_FUJITSU_DRIVER_NAME	"Fujitsu laptop FUJ02B1 ACPI brightness driver"
82d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe#define ACPI_FUJITSU_DEVICE_NAME        "Fujitsu FUJ02B1"
8320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define ACPI_FUJITSU_HOTKEY_HID 	"FUJ02E3"
8420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
8520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3"
8620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
8720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define ACPI_FUJITSU_NOTIFY_CODE1     0x80
8820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
8920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS     0x86
9020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS     0x87
9120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
923a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon/* FUNC interface - command values */
933a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define FUNC_RFKILL	0x1000
943a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define FUNC_LEDS	0x1001
953a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define FUNC_BUTTONS	0x1002
963a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define FUNC_BACKLIGHT  0x1004
973a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
983a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon/* FUNC interface - responses */
993a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define UNSUPPORTED_CMD 0x80000000
1003a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
1011e384cb0f9a940f2a431d1708f963987e61d71e3Stephen Gildea#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
1023a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon/* FUNC interface - LED control */
1033a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define FUNC_LED_OFF	0x1
1043a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define FUNC_LED_ON	0x30001
1053a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define KEYBOARD_LAMPS	0x100
1063a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define LOGOLAMP_POWERON 0x2000
1073a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#define LOGOLAMP_ALWAYS  0x4000
1083a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#endif
1093a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
11020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Hotkey details */
1110e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe#define KEY1_CODE	0x410	/* codes for the keys in the GIRB register */
1120e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe#define KEY2_CODE	0x411
1130e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe#define KEY3_CODE	0x412
1140e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe#define KEY4_CODE	0x413
11520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
11620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define MAX_HOTKEY_RINGBUFFER_SIZE 100
11720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define RINGBUFFERSIZE 40
11820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
11920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Debugging */
12020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_LOG	   ACPI_FUJITSU_HID ": "
12120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_ERR	   KERN_ERR FUJLAPTOP_LOG
12220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_NOTICE   KERN_NOTICE FUJLAPTOP_LOG
12320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_INFO	   KERN_INFO FUJLAPTOP_LOG
12420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_DEBUG    KERN_DEBUG FUJLAPTOP_LOG
12520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
12620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_DBG_ALL	  0xffff
12720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_DBG_ERROR	  0x0001
12820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_DBG_WARN	  0x0002
12920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_DBG_INFO	  0x0004
13020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#define FUJLAPTOP_DBG_TRACE	  0x0008
13120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
132c4960cf01f70d86c6440ad5dd540d0c82381785dJean Delvare#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
133c4960cf01f70d86c6440ad5dd540d0c82381785dJean Delvare#define vdbg_printk(a_dbg_level, format, arg...) \
13420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	do { if (dbg_level & a_dbg_level) \
13520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
13620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	} while (0)
13720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#else
138c4960cf01f70d86c6440ad5dd540d0c82381785dJean Delvare#define vdbg_printk(a_dbg_level, format, arg...) \
139c4960cf01f70d86c6440ad5dd540d0c82381785dJean Delvare	do { } while (0)
14020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#endif
14120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
14220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Device controlling the backlight and associated keys */
143d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestruct fujitsu_t {
144d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	acpi_handle acpi_handle;
14520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct acpi_device *dev;
14620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct input_dev *input;
14720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	char phys[32];
148d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	struct backlight_device *bl_device;
149d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	struct platform_device *pf_device;
1500e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	int keycode1, keycode2, keycode3, keycode4;
151d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
15220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	unsigned int max_brightness;
153d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	unsigned int brightness_changed;
154d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	unsigned int brightness_level;
155d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe};
156d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
157d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic struct fujitsu_t *fujitsu;
15820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic int use_alt_lcd_levels = -1;
15920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic int disable_brightness_adjust = -1;
16020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
16120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Device used to access other hotkeys on the laptop */
16220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestruct fujitsu_hotkey_t {
16320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	acpi_handle acpi_handle;
16420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct acpi_device *dev;
16520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct input_dev *input;
16620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	char phys[32];
16720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct platform_device *pf_device;
16845465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold	struct kfifo fifo;
16920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	spinlock_t fifo_lock;
1704898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	int rfkill_supported;
1713a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	int rfkill_state;
1723a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	int logolamp_registered;
1733a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	int kblamps_registered;
17420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe};
175d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
17620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic struct fujitsu_hotkey_t *fujitsu_hotkey;
17720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
178b4ec0275464756f4fd4108b4a4ca7aff61358ad3Bjorn Helgaasstatic void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event);
17920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
1801e384cb0f9a940f2a431d1708f963987e61d71e3Stephen Gildea#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
1813a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic enum led_brightness logolamp_get(struct led_classdev *cdev);
1823a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic void logolamp_set(struct led_classdev *cdev,
1833a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			       enum led_brightness brightness);
1843a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
18567af7111689b0b615d27b1a5fcc553bee4639831Axel Linstatic struct led_classdev logolamp_led = {
1863a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon .name = "fujitsu::logolamp",
1873a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon .brightness_get = logolamp_get,
1883a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon .brightness_set = logolamp_set
1893a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon};
1903a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
1913a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic enum led_brightness kblamps_get(struct led_classdev *cdev);
1923a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic void kblamps_set(struct led_classdev *cdev,
1933a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			       enum led_brightness brightness);
1943a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
19567af7111689b0b615d27b1a5fcc553bee4639831Axel Linstatic struct led_classdev kblamps_led = {
1963a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon .name = "fujitsu::kblamps",
1973a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon .brightness_get = kblamps_get,
1983a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon .brightness_set = kblamps_set
1993a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon};
2003a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#endif
2013a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
20220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
20320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic u32 dbg_level = 0x03;
20420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#endif
20520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
206700b6721cd1b891b67c2dcee046be12154a21fd6Bjorn Helgaasstatic void acpi_fujitsu_notify(struct acpi_device *device, u32 event);
20720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
2083a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon/* Fujitsu ACPI interface function */
2093a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2103a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic int call_fext_func(int cmd, int arg0, int arg1, int arg2)
2113a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon{
2123a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	acpi_status status = AE_OK;
2133a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	union acpi_object params[4] = {
2143a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	{ .type = ACPI_TYPE_INTEGER },
2153a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	{ .type = ACPI_TYPE_INTEGER },
2163a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	{ .type = ACPI_TYPE_INTEGER },
2173a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	{ .type = ACPI_TYPE_INTEGER }
2183a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	};
2193a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	struct acpi_object_list arg_list = { 4, &params[0] };
22029c29a9bb4d5abdb92480375e42e48a9190306e8Zhang Rui	unsigned long long value;
2213a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	acpi_handle handle = NULL;
2223a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2233a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle);
2243a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (ACPI_FAILURE(status)) {
2253a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		vdbg_printk(FUJLAPTOP_DBG_ERROR,
2263a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon				"FUNC interface is not present\n");
2273a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return -ENODEV;
2283a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	}
2293a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2303a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	params[0].integer.value = cmd;
2313a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	params[1].integer.value = arg0;
2323a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	params[2].integer.value = arg1;
2333a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	params[3].integer.value = arg2;
2343a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
23529c29a9bb4d5abdb92480375e42e48a9190306e8Zhang Rui	status = acpi_evaluate_integer(handle, NULL, &arg_list, &value);
2363a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (ACPI_FAILURE(status)) {
2373a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		vdbg_printk(FUJLAPTOP_DBG_WARN,
2383a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
2393a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon				cmd, arg0, arg1, arg2);
2403a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return -ENODEV;
2413a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	}
2423a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2433a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	vdbg_printk(FUJLAPTOP_DBG_TRACE,
2443a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
24529c29a9bb4d5abdb92480375e42e48a9190306e8Zhang Rui			cmd, arg0, arg1, arg2, (int)value);
24629c29a9bb4d5abdb92480375e42e48a9190306e8Zhang Rui	return value;
2473a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon}
2483a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2491e384cb0f9a940f2a431d1708f963987e61d71e3Stephen Gildea#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
2503a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon/* LED class callbacks */
2513a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2523a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic void logolamp_set(struct led_classdev *cdev,
2533a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			       enum led_brightness brightness)
2543a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon{
2553a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (brightness >= LED_FULL) {
2563a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
2573a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON);
2583a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	} else if (brightness >= LED_HALF) {
2593a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
2603a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF);
2613a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	} else {
2623a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF);
2633a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	}
2643a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon}
2653a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2663a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic void kblamps_set(struct led_classdev *cdev,
2673a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			       enum led_brightness brightness)
2683a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon{
2693a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (brightness >= LED_FULL)
2703a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
2713a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	else
2723a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
2733a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon}
2743a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2753a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic enum led_brightness logolamp_get(struct led_classdev *cdev)
2763a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon{
2773a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	enum led_brightness brightness = LED_OFF;
2783a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	int poweron, always;
2793a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2803a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
2813a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (poweron == FUNC_LED_ON) {
2823a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		brightness = LED_HALF;
2833a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
2843a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		if (always == FUNC_LED_ON)
2853a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			brightness = LED_FULL;
2863a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	}
2873a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	return brightness;
2883a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon}
2893a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2903a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic enum led_brightness kblamps_get(struct led_classdev *cdev)
2913a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon{
2923a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	enum led_brightness brightness = LED_OFF;
2933a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2943a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
2953a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		brightness = LED_FULL;
2963a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
2973a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	return brightness;
2983a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon}
2993a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon#endif
3003a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
30120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Hardware access for LCD brightness control */
302d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
303d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic int set_lcd_level(int level)
304d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
305d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	acpi_status status = AE_OK;
306d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	acpi_handle handle = NULL;
307d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
30820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n",
30920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		    level);
31020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
31120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (level < 0 || level >= fujitsu->max_brightness)
312d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return -EINVAL;
313d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
314d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
315d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (ACPI_FAILURE(status)) {
31620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n");
31720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		return -ENODEV;
31820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
31920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
32020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
3216c7fe47a4a3c6e243830ba5f9c6908a38f5ee3edZhang Rui	status = acpi_execute_simple_method(handle, NULL, level);
32220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (ACPI_FAILURE(status))
32320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		return -ENODEV;
32420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
32520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	return 0;
32620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
32720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
32820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic int set_lcd_level_alt(int level)
32920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
33020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	acpi_status status = AE_OK;
33120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	acpi_handle handle = NULL;
33220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
33320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n",
33420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		    level);
33520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
33620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (level < 0 || level >= fujitsu->max_brightness)
33720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		return -EINVAL;
33820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
33920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle);
34020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (ACPI_FAILURE(status)) {
34120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n");
342d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return -ENODEV;
343d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	}
344d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
3456c7fe47a4a3c6e243830ba5f9c6908a38f5ee3edZhang Rui	status = acpi_execute_simple_method(handle, NULL, level);
346d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (ACPI_FAILURE(status))
347d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return -ENODEV;
348d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
349d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	return 0;
350d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
351d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
352d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic int get_lcd_level(void)
353d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
35427663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox	unsigned long long state = 0;
355d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	acpi_status status = AE_OK;
356d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
35720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
35820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
359d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	status =
360d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	    acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
3613b1c37cab3765b87efbd4ed40301ceaf72b9f5c2Jonathan Woithe	if (ACPI_FAILURE(status))
3623b1c37cab3765b87efbd4ed40301ceaf72b9f5c2Jonathan Woithe		return 0;
363d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
36420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	fujitsu->brightness_level = state & 0x0fffffff;
36520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
36620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (state & 0x80000000)
36720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		fujitsu->brightness_changed = 1;
36820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	else
36920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		fujitsu->brightness_changed = 0;
37020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
37120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	return fujitsu->brightness_level;
37220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
37320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
37420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic int get_max_brightness(void)
37520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
37627663c5855b10af9ec67bc7dfba001426ba21222Matthew Wilcox	unsigned long long state = 0;
37720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	acpi_status status = AE_OK;
37820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
37920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
38020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
38120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	status =
38220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	    acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state);
3833b1c37cab3765b87efbd4ed40301ceaf72b9f5c2Jonathan Woithe	if (ACPI_FAILURE(status))
3843b1c37cab3765b87efbd4ed40301ceaf72b9f5c2Jonathan Woithe		return -1;
38520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
38620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	fujitsu->max_brightness = state;
38720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
38820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	return fujitsu->max_brightness;
38920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
39020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
391d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe/* Backlight device stuff */
392d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
393d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic int bl_get_brightness(struct backlight_device *b)
394d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
395f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon	return get_lcd_level();
396d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
397d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
398d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic int bl_update_status(struct backlight_device *b)
399d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
4003a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	int ret;
4013a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (b->props.power == 4)
4023a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
4033a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	else
4043a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
4053a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (ret != 0)
4063a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		vdbg_printk(FUJLAPTOP_DBG_ERROR,
4073a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			"Unable to adjust backlight power, error code %i\n",
4083a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			ret);
4093a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
41020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (use_alt_lcd_levels)
4113a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		ret = set_lcd_level_alt(b->props.brightness);
41220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	else
4133a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		ret = set_lcd_level(b->props.brightness);
4143a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (ret != 0)
4153a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		vdbg_printk(FUJLAPTOP_DBG_ERROR,
4163a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			"Unable to adjust LCD brightness, error code %i\n",
4173a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			ret);
4183a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	return ret;
419d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
420d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
421acc2472ed33fc5e72482cc3b3b846077d97c2f8bLionel Debrouxstatic const struct backlight_ops fujitsubl_ops = {
422d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.get_brightness = bl_get_brightness,
423d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.update_status = bl_update_status,
424d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe};
425d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
42620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Platform LCD brightness device */
42720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
42820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic ssize_t
42920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woitheshow_max_brightness(struct device *dev,
43020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		    struct device_attribute *attr, char *buf)
43120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
43220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
43320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int ret;
43420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
43520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	ret = get_max_brightness();
43620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (ret < 0)
43720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		return ret;
43820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
43920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	return sprintf(buf, "%i\n", ret);
44020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
44120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
44220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic ssize_t
44320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woitheshow_brightness_changed(struct device *dev,
44420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			struct device_attribute *attr, char *buf)
44520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
44620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
44720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int ret;
44820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
44920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	ret = fujitsu->brightness_changed;
45020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (ret < 0)
45120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		return ret;
45220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
45320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	return sprintf(buf, "%i\n", ret);
45420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
455d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
456d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic ssize_t show_lcd_level(struct device *dev,
457d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe			      struct device_attribute *attr, char *buf)
458d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
459d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
460d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	int ret;
461d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
462f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon	ret = get_lcd_level();
463d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (ret < 0)
464d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return ret;
465d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
466d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	return sprintf(buf, "%i\n", ret);
467d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
468d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
469d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic ssize_t store_lcd_level(struct device *dev,
470d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe			       struct device_attribute *attr, const char *buf,
471d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe			       size_t count)
472d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
473d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
474d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	int level, ret;
475d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
476d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (sscanf(buf, "%i", &level) != 1
47720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	    || (level < 0 || level >= fujitsu->max_brightness))
478d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return -EINVAL;
479d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
48020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (use_alt_lcd_levels)
48120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		ret = set_lcd_level_alt(level);
48220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	else
48320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		ret = set_lcd_level(level);
48420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (ret < 0)
48520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		return ret;
48620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
487f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon	ret = get_lcd_level();
488d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (ret < 0)
489d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return ret;
490d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
491d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	return count;
492d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
493d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
4943a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic ssize_t
4953a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonignore_store(struct device *dev,
4963a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	     struct device_attribute *attr, const char *buf, size_t count)
49720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
4983a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	return count;
4993a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon}
50020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
5013a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic ssize_t
5023a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonshow_lid_state(struct device *dev,
5033a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			struct device_attribute *attr, char *buf)
5043a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon{
5054898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	if (!(fujitsu_hotkey->rfkill_supported & 0x100))
5063a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "unknown\n");
5073a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (fujitsu_hotkey->rfkill_state & 0x100)
5083a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "open\n");
5093a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	else
5103a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "closed\n");
5113a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon}
51220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
5133a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic ssize_t
5143a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonshow_dock_state(struct device *dev,
5153a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			struct device_attribute *attr, char *buf)
5163a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon{
5174898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	if (!(fujitsu_hotkey->rfkill_supported & 0x200))
5183a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "unknown\n");
5193a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (fujitsu_hotkey->rfkill_state & 0x200)
5203a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "docked\n");
5213a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	else
5223a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "undocked\n");
52320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
52420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
52520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic ssize_t
5263a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonshow_radios_state(struct device *dev,
5273a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			struct device_attribute *attr, char *buf)
52820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
5294898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	if (!(fujitsu_hotkey->rfkill_supported & 0x20))
5303a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "unknown\n");
5313a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (fujitsu_hotkey->rfkill_state & 0x20)
5323a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "on\n");
5333a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	else
5343a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		return sprintf(buf, "killed\n");
53520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
53620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
53720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
53820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
53920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		   ignore_store);
540d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
5413a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store);
5423a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store);
5433a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroonstatic DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store);
544d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
545d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic struct attribute *fujitsupf_attributes[] = {
54620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	&dev_attr_brightness_changed.attr,
54720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	&dev_attr_max_brightness.attr,
548d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	&dev_attr_lcd_level.attr,
5493a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	&dev_attr_lid.attr,
5503a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	&dev_attr_dock.attr,
5513a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	&dev_attr_radios.attr,
552d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	NULL
553d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe};
554d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
555d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic struct attribute_group fujitsupf_attribute_group = {
556d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.attrs = fujitsupf_attributes
557d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe};
558d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
559d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic struct platform_driver fujitsupf_driver = {
560d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.driver = {
561d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		   .name = "fujitsu-laptop",
562d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		   .owner = THIS_MODULE,
563d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		   }
564d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe};
565d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
566fbe9b79f8c574de1dfbd9eb933f4065af8738357Mathias Krausestatic void __init dmi_check_cb_common(const struct dmi_system_id *id)
56720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
56877bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches	pr_info("Identified laptop model '%s'\n", id->ident);
56920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (use_alt_lcd_levels == -1) {
570dd13b9a6d58d15a2cc596e1eb0baa043705c7bc8Zhang Rui		if (acpi_has_method(NULL,
571dd13b9a6d58d15a2cc596e1eb0baa043705c7bc8Zhang Rui				"\\_SB.PCI0.LPCB.FJEX.SBL2"))
572f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon			use_alt_lcd_levels = 1;
573f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon		else
574f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon			use_alt_lcd_levels = 0;
575f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon		vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as "
576f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon			"%i\n", use_alt_lcd_levels);
57720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
5780e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe}
5790e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe
580fbe9b79f8c574de1dfbd9eb933f4065af8738357Mathias Krausestatic int __init dmi_check_cb_s6410(const struct dmi_system_id *id)
5810e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe{
5820e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	dmi_check_cb_common(id);
5830e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode1 = KEY_SCREENLOCK;	/* "Lock" */
5840e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode2 = KEY_HELP;	/* "Mobility Center" */
58580183a4b637982d56965e4a27b823c9a29d185b3Axel Lin	return 1;
5860e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe}
5870e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe
588fbe9b79f8c574de1dfbd9eb933f4065af8738357Mathias Krausestatic int __init dmi_check_cb_s6420(const struct dmi_system_id *id)
58956960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon{
59056960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon	dmi_check_cb_common(id);
59156960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon	fujitsu->keycode1 = KEY_SCREENLOCK;	/* "Lock" */
59256960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon	fujitsu->keycode2 = KEY_HELP;	/* "Mobility Center" */
59380183a4b637982d56965e4a27b823c9a29d185b3Axel Lin	return 1;
59456960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon}
59556960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon
596fbe9b79f8c574de1dfbd9eb933f4065af8738357Mathias Krausestatic int __init dmi_check_cb_p8010(const struct dmi_system_id *id)
5970e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe{
5980e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	dmi_check_cb_common(id);
5990e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode1 = KEY_HELP;	/* "Support" */
6000e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode3 = KEY_SWITCHVIDEOMODE;	/* "Presentation" */
6010e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode4 = KEY_WWW;	/* "Internet" */
60280183a4b637982d56965e4a27b823c9a29d185b3Axel Lin	return 1;
60320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
60420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
605fbe9b79f8c574de1dfbd9eb933f4065af8738357Mathias Krausestatic const struct dmi_system_id fujitsu_dmi_table[] __initconst = {
60620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	{
6070e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	 .ident = "Fujitsu Siemens S6410",
60820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	 .matches = {
60920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
61020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		     DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
61120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		     },
61220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	 .callback = dmi_check_cb_s6410},
613d8196a93b1ce9a5abb410f39f9375912c9e53675Jonathan Woithe	{
61456960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon	 .ident = "Fujitsu Siemens S6420",
61556960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon	 .matches = {
61656960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
61756960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon		     DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
61856960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon		     },
61956960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon	 .callback = dmi_check_cb_s6420},
62056960b546a88844a6f5295a9f81aab9e6b81edc9Tony Vroon	{
6210e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	 .ident = "Fujitsu LifeBook P8010",
622d8196a93b1ce9a5abb410f39f9375912c9e53675Jonathan Woithe	 .matches = {
623d8196a93b1ce9a5abb410f39f9375912c9e53675Jonathan Woithe		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
624d8196a93b1ce9a5abb410f39f9375912c9e53675Jonathan Woithe		     DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
6250e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe		     },
6260e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	 .callback = dmi_check_cb_p8010},
62720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	{}
62820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe};
62920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
63020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* ACPI device for LCD brightness control */
631d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
632b6f03ae6defb61bb4b8e7a8e4b9081a1dd1d3ef9Adrian Bunkstatic int acpi_fujitsu_add(struct acpi_device *device)
633d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
634d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	int state = 0;
63520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct input_dev *input;
63620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int error;
637d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
638d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (!device)
639d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return -EINVAL;
640d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
641d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	fujitsu->acpi_handle = device->handle;
642d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
643d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
644db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek	device->driver_data = fujitsu;
645d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
64620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	fujitsu->input = input = input_allocate_device();
64720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (!input) {
64820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		error = -ENOMEM;
649700b6721cd1b891b67c2dcee046be12154a21fd6Bjorn Helgaas		goto err_stop;
65020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
65120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
65220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	snprintf(fujitsu->phys, sizeof(fujitsu->phys),
65320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		 "%s/video/input0", acpi_device_hid(device));
65420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
65520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->name = acpi_device_name(device);
65620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->phys = fujitsu->phys;
65720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->id.bustype = BUS_HOST;
65820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->id.product = 0x06;
65920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->dev.parent = &device->dev;
66020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->evbit[0] = BIT(EV_KEY);
66120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	set_bit(KEY_BRIGHTNESSUP, input->keybit);
66220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
66320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	set_bit(KEY_UNKNOWN, input->keybit);
66420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
66520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	error = input_register_device(input);
66620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (error)
66720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		goto err_free_input_dev;
66820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
669b30bb89f0fb29502f573d01419391a1e2a4cc4f1Julia Lawall	error = acpi_bus_update_power(fujitsu->acpi_handle, &state);
670b30bb89f0fb29502f573d01419391a1e2a4cc4f1Julia Lawall	if (error) {
67177bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches		pr_err("Error reading power state\n");
67272afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz		goto err_unregister_input_dev;
673d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	}
674d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
67577bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches	pr_info("ACPI: %s [%s] (%s)\n",
676d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	       acpi_device_name(device), acpi_device_bid(device),
677d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	       !device->power.state ? "on" : "off");
678d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
67920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	fujitsu->dev = device;
68020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
681dd13b9a6d58d15a2cc596e1eb0baa043705c7bc8Zhang Rui	if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
68220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
68320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		if (ACPI_FAILURE
68420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		    (acpi_evaluate_object
68520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		     (device->handle, METHOD_NAME__INI, NULL, NULL)))
68677bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches			pr_err("_INI Method failed\n");
68720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
68820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
68920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	/* do config (detect defaults) */
69020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
69120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
69220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	vdbg_printk(FUJLAPTOP_DBG_INFO,
693f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon		    "config: [alt interface: %d], [adjust disable: %d]\n",
694f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon		    use_alt_lcd_levels, disable_brightness_adjust);
69520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
69620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (get_max_brightness() <= 0)
69720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
698f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon	get_lcd_level();
69920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
700b30bb89f0fb29502f573d01419391a1e2a4cc4f1Julia Lawall	return 0;
70120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
70272afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewiczerr_unregister_input_dev:
70372afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	input_unregister_device(input);
7048e4e2efdfab5448b0a01be8883d62fc90cce2a7eAxel Lin	input = NULL;
70520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woitheerr_free_input_dev:
70620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input_free_device(input);
70720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woitheerr_stop:
708b30bb89f0fb29502f573d01419391a1e2a4cc4f1Julia Lawall	return error;
709d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
710d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
71151fac8388a0325a43f0ae67453ece2c373e2ec28Rafael J. Wysockistatic int acpi_fujitsu_remove(struct acpi_device *device)
712d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
71372afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	struct fujitsu_t *fujitsu = acpi_driver_data(device);
71472afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	struct input_dev *input = fujitsu->input;
715d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
71672afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	input_unregister_device(input);
71720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
7185cf83b9b1279dbcdbcf91522bf766c998270ec44Al Viro	fujitsu->acpi_handle = NULL;
719d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
720d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	return 0;
721d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
722d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
72320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Brightness notify */
72420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
725700b6721cd1b891b67c2dcee046be12154a21fd6Bjorn Helgaasstatic void acpi_fujitsu_notify(struct acpi_device *device, u32 event)
72620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
72720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct input_dev *input;
72820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int keycode;
72920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int oldb, newb;
73020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
73120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input = fujitsu->input;
73220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
73320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	switch (event) {
73420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	case ACPI_FUJITSU_NOTIFY_CODE1:
73520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		keycode = 0;
73620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		oldb = fujitsu->brightness_level;
737f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon		get_lcd_level();
73820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		newb = fujitsu->brightness_level;
73920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
74020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		vdbg_printk(FUJLAPTOP_DBG_TRACE,
74120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			    "brightness button event [%i -> %i (%i)]\n",
74220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			    oldb, newb, fujitsu->brightness_changed);
74320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
744f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon		if (oldb < newb) {
74520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			if (disable_brightness_adjust != 1) {
74620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				if (use_alt_lcd_levels)
74720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					set_lcd_level_alt(newb);
74820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				else
74920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					set_lcd_level(newb);
75020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			}
751f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon			keycode = KEY_BRIGHTNESSUP;
75220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		} else if (oldb > newb) {
75320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			if (disable_brightness_adjust != 1) {
75420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				if (use_alt_lcd_levels)
75520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					set_lcd_level_alt(newb);
75620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				else
75720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					set_lcd_level(newb);
75820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			}
759f87a1a5f6cdaff6232fed2ef0ae0479df9e781e8Tony Vroon			keycode = KEY_BRIGHTNESSDOWN;
76020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		}
76120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		break;
76220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	default:
76320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		keycode = KEY_UNKNOWN;
76420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		vdbg_printk(FUJLAPTOP_DBG_WARN,
76520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			    "unsupported event [0x%x]\n", event);
76620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		break;
76720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
76820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
76920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (keycode != 0) {
77020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_report_key(input, keycode, 1);
77120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_sync(input);
77220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_report_key(input, keycode, 0);
77320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_sync(input);
77420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
77520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
77620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
77720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* ACPI device for hotkey handling */
77820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
77920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic int acpi_fujitsu_hotkey_add(struct acpi_device *device)
78020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
78120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int result = 0;
78220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int state = 0;
78320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct input_dev *input;
78420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int error;
78520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int i;
78620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
78720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (!device)
78820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		return -EINVAL;
78920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
79020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	fujitsu_hotkey->acpi_handle = device->handle;
79120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	sprintf(acpi_device_name(device), "%s",
79220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
79320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
794db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek	device->driver_data = fujitsu_hotkey;
79520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
79620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	/* kfifo */
79720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	spin_lock_init(&fujitsu_hotkey->fifo_lock);
79845465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold	error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
799c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold			GFP_KERNEL);
80045465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold	if (error) {
80177bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches		pr_err("kfifo_alloc failed\n");
80220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		goto err_stop;
80320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
80420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
80520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	fujitsu_hotkey->input = input = input_allocate_device();
80620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (!input) {
80720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		error = -ENOMEM;
808b4ec0275464756f4fd4108b4a4ca7aff61358ad3Bjorn Helgaas		goto err_free_fifo;
80920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
81020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
81120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys),
81220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		 "%s/video/input0", acpi_device_hid(device));
81320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
81420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->name = acpi_device_name(device);
81520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->phys = fujitsu_hotkey->phys;
81620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->id.bustype = BUS_HOST;
81720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->id.product = 0x06;
81820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input->dev.parent = &device->dev;
8193a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
8203a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	set_bit(EV_KEY, input->evbit);
8210e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	set_bit(fujitsu->keycode1, input->keybit);
8220e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	set_bit(fujitsu->keycode2, input->keybit);
8230e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	set_bit(fujitsu->keycode3, input->keybit);
8240e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	set_bit(fujitsu->keycode4, input->keybit);
82520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	set_bit(KEY_UNKNOWN, input->keybit);
82620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
82720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	error = input_register_device(input);
82820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (error)
82920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		goto err_free_input_dev;
83020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
831b30bb89f0fb29502f573d01419391a1e2a4cc4f1Julia Lawall	error = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
832b30bb89f0fb29502f573d01419391a1e2a4cc4f1Julia Lawall	if (error) {
83377bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches		pr_err("Error reading power state\n");
83472afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz		goto err_unregister_input_dev;
83520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
83620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
83777bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches	pr_info("ACPI: %s [%s] (%s)\n",
83877bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches		acpi_device_name(device), acpi_device_bid(device),
83977bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches		!device->power.state ? "on" : "off");
84020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
84120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	fujitsu_hotkey->dev = device;
84220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
843dd13b9a6d58d15a2cc596e1eb0baa043705c7bc8Zhang Rui	if (acpi_has_method(device->handle, METHOD_NAME__INI)) {
84420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n");
84520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		if (ACPI_FAILURE
84620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		    (acpi_evaluate_object
84720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		     (device->handle, METHOD_NAME__INI, NULL, NULL)))
84877bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches			pr_err("_INI Method failed\n");
84920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
85020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
8513a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	i = 0;
8523a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
8533a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		&& (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
8543a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		; /* No action, result is discarded */
85520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
85620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
8574898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	fujitsu_hotkey->rfkill_supported =
8584898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon		call_fext_func(FUNC_RFKILL, 0x0, 0x0, 0x0);
8594898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon
8604898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	/* Make sure our bitmask of supported functions is cleared if the
8614898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	   RFKILL function block is not implemented, like on the S7020. */
8624898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	if (fujitsu_hotkey->rfkill_supported == UNSUPPORTED_CMD)
8634898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon		fujitsu_hotkey->rfkill_supported = 0;
8644898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon
8654898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	if (fujitsu_hotkey->rfkill_supported)
8664898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon		fujitsu_hotkey->rfkill_state =
8674898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon			call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
8683a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
8693a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	/* Suspect this is a keymap of the application panel, print it */
87077bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches	pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
8713a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
87272afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
8733a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
8743a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		result = led_classdev_register(&fujitsu->pf_device->dev,
8753a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon						&logolamp_led);
8763a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		if (result == 0) {
8773a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			fujitsu_hotkey->logolamp_registered = 1;
8783a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		} else {
87977bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches			pr_err("Could not register LED handler for logo lamp, error %i\n",
88077bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches			       result);
8813a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		}
8823a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	}
8833a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
8843a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
8853a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	   (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
8863a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		result = led_classdev_register(&fujitsu->pf_device->dev,
8873a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon						&kblamps_led);
8883a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		if (result == 0) {
8893a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			fujitsu_hotkey->kblamps_registered = 1;
8903a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		} else {
89177bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches			pr_err("Could not register LED handler for keyboard lamps, error %i\n",
89277bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches			       result);
8933a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		}
8943a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	}
89572afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz#endif
8963a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
89720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	return result;
89820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
89972afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewiczerr_unregister_input_dev:
90072afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	input_unregister_device(input);
9018e4e2efdfab5448b0a01be8883d62fc90cce2a7eAxel Lin	input = NULL;
90220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woitheerr_free_input_dev:
90320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input_free_device(input);
904b4ec0275464756f4fd4108b4a4ca7aff61358ad3Bjorn Helgaaserr_free_fifo:
90545465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold	kfifo_free(&fujitsu_hotkey->fifo);
90620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woitheerr_stop:
907b30bb89f0fb29502f573d01419391a1e2a4cc4f1Julia Lawall	return error;
90820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
90920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
91051fac8388a0325a43f0ae67453ece2c373e2ec28Rafael J. Wysockistatic int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
91120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
91272afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device);
91372afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	struct input_dev *input = fujitsu_hotkey->input;
91420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
9152906206350b7e13e2047467cc29a0a2d78d71cb2Jonathan Woithe#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
91672afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	if (fujitsu_hotkey->logolamp_registered)
91772afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz		led_classdev_unregister(&logolamp_led);
91820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
91972afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	if (fujitsu_hotkey->kblamps_registered)
92072afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz		led_classdev_unregister(&kblamps_led);
92172afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz#endif
92220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
92372afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	input_unregister_device(input);
92420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
92545465487897a1c6d508b14b904dc5777f7ec7e04Stefani Seibold	kfifo_free(&fujitsu_hotkey->fifo);
92620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
92772afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	fujitsu_hotkey->acpi_handle = NULL;
92872afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz
92920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	return 0;
93020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
93120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
932b4ec0275464756f4fd4108b4a4ca7aff61358ad3Bjorn Helgaasstatic void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
93320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe{
93420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	struct input_dev *input;
93520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int keycode, keycode_r;
93620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	unsigned int irb = 1;
93720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int i, status;
93820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
93920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	input = fujitsu_hotkey->input;
94020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
9414898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon	if (fujitsu_hotkey->rfkill_supported)
9424898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon		fujitsu_hotkey->rfkill_state =
9434898c2b2f04051e19f4230683c0f0b15f71af887Tony Vroon			call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
94420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
94520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	switch (event) {
94620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	case ACPI_FUJITSU_NOTIFY_CODE1:
94720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		i = 0;
9483a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		while ((irb =
9493a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
9503a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon				&& (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
95120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			switch (irb & 0x4ff) {
9520e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe			case KEY1_CODE:
9530e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe				keycode = fujitsu->keycode1;
95420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				break;
9550e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe			case KEY2_CODE:
9560e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe				keycode = fujitsu->keycode2;
95720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				break;
9580e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe			case KEY3_CODE:
9590e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe				keycode = fujitsu->keycode3;
96020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				break;
9610e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe			case KEY4_CODE:
9620e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe				keycode = fujitsu->keycode4;
96320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				break;
96420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			case 0:
96520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				keycode = 0;
96620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				break;
96720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			default:
96820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				vdbg_printk(FUJLAPTOP_DBG_WARN,
9690e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe					    "Unknown GIRB result [%x]\n", irb);
97020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				keycode = -1;
97120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				break;
97220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			}
97320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			if (keycode > 0) {
97420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				vdbg_printk(FUJLAPTOP_DBG_TRACE,
97520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					"Push keycode into ringbuffer [%d]\n",
97620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					keycode);
9777acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold				status = kfifo_in_locked(&fujitsu_hotkey->fifo,
9780e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe						   (unsigned char *)&keycode,
979c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold						   sizeof(keycode),
980c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold						   &fujitsu_hotkey->fifo_lock);
98120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				if (status != sizeof(keycode)) {
98220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					vdbg_printk(FUJLAPTOP_DBG_WARN,
9830e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe					    "Could not push keycode [0x%x]\n",
9840e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe					    keycode);
98520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				} else {
98620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					input_report_key(input, keycode, 1);
98720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					input_sync(input);
98820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				}
98920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			} else if (keycode == 0) {
99020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				while ((status =
9917acd72eb85f1c7a15e8b5eb554994949241737f1Stefani Seibold					kfifo_out_locked(
992c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold					 &fujitsu_hotkey->fifo,
993c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold					 (unsigned char *) &keycode_r,
994c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold					 sizeof(keycode_r),
995c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold					 &fujitsu_hotkey->fifo_lock))
996c1e13f25674ed564948ecb7dfe5f83e578892896Stefani Seibold					 == sizeof(keycode_r)) {
99720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					input_report_key(input, keycode_r, 0);
99820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					input_sync(input);
99920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe					vdbg_printk(FUJLAPTOP_DBG_TRACE,
10000e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe					  "Pop keycode from ringbuffer [%d]\n",
10010e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe					  keycode_r);
100220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe				}
100320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			}
100420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		}
100520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
100620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		break;
100720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	default:
100820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		keycode = KEY_UNKNOWN;
100920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		vdbg_printk(FUJLAPTOP_DBG_WARN,
101020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe			    "Unsupported event [0x%x]\n", event);
101120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_report_key(input, keycode, 1);
101220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_sync(input);
101320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_report_key(input, keycode, 0);
101420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		input_sync(input);
101520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		break;
101620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
101720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe}
101820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
101920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe/* Initialization */
102020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
1021d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic const struct acpi_device_id fujitsu_device_ids[] = {
1022d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	{ACPI_FUJITSU_HID, 0},
1023d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	{"", 0},
1024d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe};
1025d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1026d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic struct acpi_driver acpi_fujitsu_driver = {
1027d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.name = ACPI_FUJITSU_DRIVER_NAME,
1028d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.class = ACPI_FUJITSU_CLASS,
1029d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.ids = fujitsu_device_ids,
1030d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	.ops = {
1031d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		.add = acpi_fujitsu_add,
1032d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		.remove = acpi_fujitsu_remove,
1033700b6721cd1b891b67c2dcee046be12154a21fd6Bjorn Helgaas		.notify = acpi_fujitsu_notify,
1034d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		},
1035d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe};
1036d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
103720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic const struct acpi_device_id fujitsu_hotkey_device_ids[] = {
103820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	{ACPI_FUJITSU_HOTKEY_HID, 0},
103920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	{"", 0},
104020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe};
104120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
104220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithestatic struct acpi_driver acpi_fujitsu_hotkey_driver = {
104320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	.name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME,
104420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	.class = ACPI_FUJITSU_CLASS,
104520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	.ids = fujitsu_hotkey_device_ids,
104620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	.ops = {
104720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		.add = acpi_fujitsu_hotkey_add,
104820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		.remove = acpi_fujitsu_hotkey_remove,
1049b4ec0275464756f4fd4108b4a4ca7aff61358ad3Bjorn Helgaas		.notify = acpi_fujitsu_hotkey_notify,
105020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		},
105120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe};
1052d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
10534990141496b82f91cb96b37100ac882ea5cee8b7Zhang Ruistatic const struct acpi_device_id fujitsu_ids[] __used = {
10544990141496b82f91cb96b37100ac882ea5cee8b7Zhang Rui	{ACPI_FUJITSU_HID, 0},
10554990141496b82f91cb96b37100ac882ea5cee8b7Zhang Rui	{ACPI_FUJITSU_HOTKEY_HID, 0},
10564990141496b82f91cb96b37100ac882ea5cee8b7Zhang Rui	{"", 0}
10574990141496b82f91cb96b37100ac882ea5cee8b7Zhang Rui};
10584990141496b82f91cb96b37100ac882ea5cee8b7Zhang RuiMODULE_DEVICE_TABLE(acpi, fujitsu_ids);
10594990141496b82f91cb96b37100ac882ea5cee8b7Zhang Rui
1060d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic int __init fujitsu_init(void)
1061d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
106220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	int ret, result, max_brightness;
1063d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1064d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (acpi_disabled)
1065d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return -ENODEV;
1066d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
10676c75dd0f965b7b3480d0e0e9b8d9747988dfe815Julia Lawall	fujitsu = kzalloc(sizeof(struct fujitsu_t), GFP_KERNEL);
1068d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (!fujitsu)
1069d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		return -ENOMEM;
10700e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode1 = KEY_PROG1;
10710e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode2 = KEY_PROG2;
10720e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode3 = KEY_PROG3;
10730e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	fujitsu->keycode4 = KEY_PROG4;
10740e6a66e9cf231140d2e49064d48162728edb7746Jonathan Woithe	dmi_check_system(fujitsu_dmi_table);
1075d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1076d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	result = acpi_bus_register_driver(&acpi_fujitsu_driver);
1077d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (result < 0) {
1078d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		ret = -ENODEV;
1079d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		goto fail_acpi;
1080d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	}
1081d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1082d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	/* Register platform stuff */
1083d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1084d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1);
1085d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (!fujitsu->pf_device) {
1086d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		ret = -ENOMEM;
1087d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		goto fail_platform_driver;
1088d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	}
1089d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1090d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	ret = platform_device_add(fujitsu->pf_device);
1091d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (ret)
1092d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		goto fail_platform_device1;
1093d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1094d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	ret =
1095d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	    sysfs_create_group(&fujitsu->pf_device->dev.kobj,
1096d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe			       &fujitsupf_attribute_group);
1097d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	if (ret)
1098d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe		goto fail_platform_device2;
1099d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
110020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	/* Register backlight stuff */
110120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
11027d5c89a615c5dae039094a3cf4a56fe6aab81765Thomas Renninger	if (!acpi_video_backlight_support()) {
1103a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett		struct backlight_properties props;
1104a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett
1105a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett		memset(&props, 0, sizeof(struct backlight_properties));
1106a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett		max_brightness = fujitsu->max_brightness;
1107bb7ca747f8d6243b3943c5b133048652020f4a50Matthew Garrett		props.type = BACKLIGHT_PLATFORM;
1108a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett		props.max_brightness = max_brightness - 1;
1109a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett		fujitsu->bl_device = backlight_device_register("fujitsu-laptop",
1110a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett							       NULL, NULL,
1111a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett							       &fujitsubl_ops,
1112a19a6ee6cad2b20292a774c2f56ba8039b0fac9cMatthew Garrett							       &props);
111372afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz		if (IS_ERR(fujitsu->bl_device)) {
111472afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz			ret = PTR_ERR(fujitsu->bl_device);
111572afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz			fujitsu->bl_device = NULL;
111672afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz			goto fail_sysfs_group;
111772afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz		}
11187d5c89a615c5dae039094a3cf4a56fe6aab81765Thomas Renninger		fujitsu->bl_device->props.brightness = fujitsu->brightness_level;
11197d5c89a615c5dae039094a3cf4a56fe6aab81765Thomas Renninger	}
112020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
112120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	ret = platform_driver_register(&fujitsupf_driver);
112220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (ret)
112320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		goto fail_backlight;
112420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
112520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	/* Register hotkey driver */
112620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
11276c75dd0f965b7b3480d0e0e9b8d9747988dfe815Julia Lawall	fujitsu_hotkey = kzalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL);
112820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (!fujitsu_hotkey) {
112920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		ret = -ENOMEM;
113020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		goto fail_hotkey;
113120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
113220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
113320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver);
113420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	if (result < 0) {
113520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		ret = -ENODEV;
113620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		goto fail_hotkey1;
113720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	}
113820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
11393a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	/* Sync backlight power status (needs FUJ02E3 device, hence deferred) */
11403a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
11413a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	if (!acpi_video_backlight_support()) {
11423a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
11433a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			fujitsu->bl_device->props.power = 4;
11443a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon		else
11453a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon			fujitsu->bl_device->props.power = 0;
11463a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon	}
11473a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
114877bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches	pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
1149d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1150d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	return 0;
1151d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
115220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithefail_hotkey1:
115320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	kfree(fujitsu_hotkey);
115420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithefail_hotkey:
1155d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	platform_driver_unregister(&fujitsupf_driver);
115620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithefail_backlight:
11577d5c89a615c5dae039094a3cf4a56fe6aab81765Thomas Renninger	if (fujitsu->bl_device)
11587d5c89a615c5dae039094a3cf4a56fe6aab81765Thomas Renninger		backlight_device_unregister(fujitsu->bl_device);
115972afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewiczfail_sysfs_group:
116072afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
116172afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz			   &fujitsupf_attribute_group);
116220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithefail_platform_device2:
116320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	platform_device_del(fujitsu->pf_device);
116420b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithefail_platform_device1:
116520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	platform_device_put(fujitsu->pf_device);
116620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithefail_platform_driver:
116720b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe	acpi_bus_unregister_driver(&acpi_fujitsu_driver);
116820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithefail_acpi:
1169d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	kfree(fujitsu);
1170d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1171d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	return ret;
1172d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
1173d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1174d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithestatic void __exit fujitsu_cleanup(void)
1175d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe{
117672afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver);
11773a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
117872afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	kfree(fujitsu_hotkey);
11793a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony Vroon
1180d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe	platform_driver_unregister(&fujitsupf_driver);
118172afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz
11827d5c89a615c5dae039094a3cf4a56fe6aab81765Thomas Renninger	if (fujitsu->bl_device)
11837d5c89a615c5dae039094a3cf4a56fe6aab81765Thomas Renninger		backlight_device_unregister(fujitsu->bl_device);
1184d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
118572afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
118672afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz			   &fujitsupf_attribute_group);
1187d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
118872afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	platform_device_unregister(fujitsu->pf_device);
1189d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
119072afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	acpi_bus_unregister_driver(&acpi_fujitsu_driver);
119120b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
119272afeeafe54853881a4e53dc78d538e249130ad8Bartlomiej Zolnierkiewicz	kfree(fujitsu);
119320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
119477bad7c830e20085deba6a760ce85c13ecb12f4dJoe Perches	pr_info("driver unloaded\n");
1195d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe}
1196d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
1197d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithemodule_init(fujitsu_init);
1198d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithemodule_exit(fujitsu_cleanup);
1199d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan Woithe
120020b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithemodule_param(use_alt_lcd_levels, uint, 0644);
120120b937343e55c16e37b1a4ad2176760b4a11002cJonathan WoitheMODULE_PARM_DESC(use_alt_lcd_levels,
120220b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe		 "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
120320b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithemodule_param(disable_brightness_adjust, uint, 0644);
120420b937343e55c16e37b1a4ad2176760b4a11002cJonathan WoitheMODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
120520b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
120620b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithemodule_param_named(debug, dbg_level, uint, 0644);
120720b937343e55c16e37b1a4ad2176760b4a11002cJonathan WoitheMODULE_PARM_DESC(debug, "Sets debug level bit-mask");
120820b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe#endif
120920b937343e55c16e37b1a4ad2176760b4a11002cJonathan Woithe
12103a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony VroonMODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
1211d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan WoitheMODULE_DESCRIPTION("Fujitsu laptop extras support");
1212d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan WoitheMODULE_VERSION(FUJITSU_DRIVER_VERSION);
1213d0482533c73a8685f7ce0951a10280cfd58b8825Jonathan WoitheMODULE_LICENSE("GPL");
1214a361a82c10c20eff402d72ce83b66913d04894eeDan Williams
12150e6a66e9cf231140d2e49064d48162728edb7746Jonathan WoitheMODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
12163a407086090bb4fa1908d4dc3739c9ebc8ad6686Tony VroonMODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
12170e6a66e9cf231140d2e49064d48162728edb7746Jonathan WoitheMODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
1218