/*-*-linux-c-*-*/
/*
Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
Copyright (C) 2008 Tony Vroon <tony@linx.net>
Based on earlier work:
Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
Adrian Yee <brewt-fujitsu@brewt.org>
Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
by its respective authors.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
/*
* fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
* features made available on a range of Fujitsu laptops including the
* P2xxx/P5xxx/S6xxx/S7xxx series.
*
* This driver exports a few files in /sys/devices/platform/fujitsu-laptop/;
* others may be added at a later date.
*
* lcd_level - Screen brightness: contains a single integer in the
* range 0..7. (rw)
*
* In addition to these platform device attributes the driver
* registers itself in the Linux backlight control subsystem and is
* available to userspace under /sys/class/backlight/fujitsu-laptop/.
*
* Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are
* also supported by this driver.
*
* This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
* P8010. It should work on most P-series and S-series Lifebooks, but
* YMMV.
*
* The module parameter use_alt_lcd_levels switches between different ACPI
* brightness controls which are used by different Fujitsu laptops. In most
* cases the correct method is automatically detected. "use_alt_lcd_levels=1"
* is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/input.h>
#include <linux/kfifo.h>
#include <linux/video_output.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
#include <linux/leds.h>
#endif
#define FUJITSU_DRIVER_VERSION "0.6.0"
#define FUJITSU_LCD_N_LEVELS 8
#define ACPI_FUJITSU_CLASS "fujitsu"
#define ACPI_FUJITSU_HID "FUJ02B1"
#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1"
#define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3"
#define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
#define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3"
#define ACPI_FUJITSU_NOTIFY_CODE1 0x80
#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
/* FUNC interface - command values */
#define FUNC_RFKILL 0x1000
#define FUNC_LEDS 0x1001
#define FUNC_BUTTONS 0x1002
#define FUNC_BACKLIGHT 0x1004
/* FUNC interface - responses */
#define UNSUPPORTED_CMD 0x80000000
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
/* FUNC interface - LED control */
#define FUNC_LED_OFF 0x1
#define FUNC_LED_ON 0x30001
#define KEYBOARD_LAMPS 0x100
#define LOGOLAMP_POWERON 0x2000
#define LOGOLAMP_ALWAYS 0x4000
#endif
/* Hotkey details */
#define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */
#define KEY2_CODE 0x411
#define KEY3_CODE 0x412
#define KEY4_CODE 0x413
#define MAX_HOTKEY_RINGBUFFER_SIZE 100
#define RINGBUFFERSIZE 40
/* Debugging */
#define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": "
#define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG
#define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG
#define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG
#define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG
#define FUJLAPTOP_DBG_ALL 0xffff
#define FUJLAPTOP_DBG_ERROR 0x0001
#define FUJLAPTOP_DBG_WARN 0x0002
#define FUJLAPTOP_DBG_INFO 0x0004
#define FUJLAPTOP_DBG_TRACE 0x0008
#define dbg_printk(a_dbg_level, format, arg...) \
do { if (dbg_level & a_dbg_level) \
printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
} while (0)
#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
#define vdbg_printk(a_dbg_level, format, arg...) \
dbg_printk(a_dbg_level, format, ## arg)
#else
#define vdbg_printk(a_dbg_level, format, arg...)
#endif
/* Device controlling the backlight and associated keys */
struct fujitsu_t {
acpi_handle acpi_handle;
struct acpi_device *dev;
struct input_dev *input;
char phys[32];
struct backlight_device *bl_device;
struct platform_device *pf_device;
int keycode1, keycode2, keycode3, keycode4;
unsigned int max_brightness;
unsigned int brightness_changed;
unsigned int brightness_level;
};
static struct fujitsu_t *fujitsu;
static int use_alt_lcd_levels = -1;
static int disable_brightness_adjust = -1;
/* Device used to access other hotkeys on the laptop */
struct fujitsu_hotkey_t {
acpi_handle acpi_handle;
struct acpi_device *dev;
struct input_dev *input;
char phys[32];
struct platform_device *pf_device;
struct kfifo fifo;
spinlock_t fifo_lock;
int rfkill_supported;
int rfkill_state;
int logolamp_registered;