aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/acer-wmi.c225
-rw-r--r--drivers/misc/asus-laptop.c17
-rw-r--r--drivers/misc/eeepc-laptop.c232
-rw-r--r--drivers/misc/fujitsu-laptop.c135
-rw-r--r--drivers/misc/intel_menlow.c29
-rw-r--r--drivers/misc/panasonic-laptop.c767
-rw-r--r--drivers/misc/sony-laptop.c2
-rw-r--r--drivers/misc/thinkpad_acpi.c65
10 files changed, 1295 insertions, 190 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index efd3aa08b88..9494400e8fd 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -145,6 +145,7 @@ config ACER_WMI
depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
+ depends on RFKILL
select ACPI_WMI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
@@ -245,6 +246,17 @@ config MSI_LAPTOP
If you have an MSI S270 laptop, say Y or M here.
+config PANASONIC_LAPTOP
+ tristate "Panasonic Laptop Extras"
+ depends on X86 && INPUT && ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This driver adds support for access to backlight control and hotkeys
+ on Panasonic Let's Note laptops.
+
+ If you have a Panasonic Let's note laptop (such as the R1(N variant),
+ R2, R3, R5, T2, W2 and Y2 series), say Y.
+
config COMPAL_LAPTOP
tristate "Compal Laptop Extras"
depends on X86
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c6c13f60b45..909e2468cdc 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
+obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index d8b0d326e45..0532a2de2ce 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -33,6 +33,8 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/i8042.h>
+#include <linux/rfkill.h>
+#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <acpi/acpi_drivers.h>
@@ -123,21 +125,15 @@ enum interface_flags {
static int max_brightness = 0xF;
-static int wireless = -1;
-static int bluetooth = -1;
static int mailled = -1;
static int brightness = -1;
static int threeg = -1;
static int force_series;
module_param(mailled, int, 0444);
-module_param(wireless, int, 0444);
-module_param(bluetooth, int, 0444);
module_param(brightness, int, 0444);
module_param(threeg, int, 0444);
module_param(force_series, int, 0444);
-MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
-MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
@@ -145,8 +141,6 @@ MODULE_PARM_DESC(force_series, "Force a different laptop series");
struct acer_data {
int mailled;
- int wireless;
- int bluetooth;
int threeg;
int brightness;
};
@@ -157,6 +151,9 @@ struct acer_debug {
u32 wmid_devices;
};
+static struct rfkill *wireless_rfkill;
+static struct rfkill *bluetooth_rfkill;
+
/* Each low-level interface must define at least some of the following */
struct wmi_interface {
/* The WMI device type */
@@ -476,7 +473,7 @@ struct wmi_interface *iface)
}
break;
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
return AE_OK;
}
@@ -514,7 +511,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
break;
}
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
/* Actually do the set */
@@ -689,7 +686,7 @@ struct wmi_interface *iface)
return 0;
}
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
status = WMI_execute_u32(method_id, 0, &result);
@@ -735,7 +732,7 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
}
break;
default:
- return AE_BAD_ADDRESS;
+ return AE_ERROR;
}
return WMI_execute_u32(method_id, (u32)value, NULL);
}
@@ -785,7 +782,7 @@ static struct wmi_interface wmid_interface = {
static acpi_status get_u32(u32 *value, u32 cap)
{
- acpi_status status = AE_BAD_ADDRESS;
+ acpi_status status = AE_ERROR;
switch (interface->type) {
case ACER_AMW0:
@@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
* capability isn't available on the given interface
*/
set_u32(mailled, ACER_CAP_MAILLED);
- set_u32(wireless, ACER_CAP_WIRELESS);
- set_u32(bluetooth, ACER_CAP_BLUETOOTH);
set_u32(threeg, ACER_CAP_THREEG);
set_u32(brightness, ACER_CAP_BRIGHTNESS);
}
@@ -933,40 +928,135 @@ static void acer_backlight_exit(void)
}
/*
- * Read/ write bool sysfs macro
+ * Rfkill devices
*/
-#define show_set_bool(value, cap) \
-static ssize_t \
-show_bool_##value(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- u32 result; \
- acpi_status status = get_u32(&result, cap); \
- if (ACPI_SUCCESS(status)) \
- return sprintf(buf, "%u\n", result); \
- return sprintf(buf, "Read error\n"); \
-} \
-\
-static ssize_t \
-set_bool_##value(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- u32 tmp = simple_strtoul(buf, NULL, 10); \
- acpi_status status = set_u32(tmp, cap); \
- if (ACPI_FAILURE(status)) \
- return -EINVAL; \
- return count; \
-} \
-static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
- show_bool_##value, set_bool_##value);
-
-show_set_bool(wireless, ACER_CAP_WIRELESS);
-show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
-show_set_bool(threeg, ACER_CAP_THREEG);
+static void acer_rfkill_update(struct work_struct *ignored);
+static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
+static void acer_rfkill_update(struct work_struct *ignored)
+{
+ u32 state;
+ acpi_status status;
+
+ status = get_u32(&state, ACER_CAP_WIRELESS);
+ if (ACPI_SUCCESS(status))
+ rfkill_force_state(wireless_rfkill, state ?
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
+
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ status = get_u32(&state, ACER_CAP_BLUETOOTH);
+ if (ACPI_SUCCESS(status))
+ rfkill_force_state(bluetooth_rfkill, state ?
+ RFKILL_STATE_UNBLOCKED :
+ RFKILL_STATE_SOFT_BLOCKED);
+ }
+
+ schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+}
+
+static int acer_rfkill_set(void *data, enum rfkill_state state)
+{
+ acpi_status status;
+ u32 *cap = data;
+ status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ return 0;
+}
+
+static struct rfkill * acer_rfkill_register(struct device *dev,
+enum rfkill_type type, char *name, u32 cap)
+{
+ int err;
+ u32 state;
+ u32 *data;
+ struct rfkill *rfkill_dev;
+
+ rfkill_dev = rfkill_allocate(dev, type);
+ if (!rfkill_dev)
+ return ERR_PTR(-ENOMEM);
+ rfkill_dev->name = name;
+ get_u32(&state, cap);
+ rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
+ RFKILL_STATE_SOFT_BLOCKED;
+ data = kzalloc(sizeof(u32), GFP_KERNEL);
+ if (!data) {
+ rfkill_free(rfkill_dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ *data = cap;
+ rfkill_dev->data = data;
+ rfkill_dev->toggle_radio = acer_rfkill_set;
+ rfkill_dev->user_claim_unsupported = 1;
+
+ err = rfkill_register(rfkill_dev);
+ if (err) {
+ kfree(rfkill_dev->data);
+ rfkill_free(rfkill_dev);
+ return ERR_PTR(err);
+ }
+ return rfkill_dev;
+}
+
+static int acer_rfkill_init(struct device *dev)
+{
+ wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
+ "acer-wireless", ACER_CAP_WIRELESS);
+ if (IS_ERR(wireless_rfkill))
+ return PTR_ERR(wireless_rfkill);
+
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ bluetooth_rfkill = acer_rfkill_register(dev,
+ RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
+ ACER_CAP_BLUETOOTH);
+ if (IS_ERR(bluetooth_rfkill)) {
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(wireless_rfkill);
+ return PTR_ERR(bluetooth_rfkill);
+ }
+ }
+
+ schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
+
+ return 0;
+}
+
+static void acer_rfkill_exit(void)
+{
+ cancel_delayed_work_sync(&acer_rfkill_work);
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(wireless_rfkill);
+ if (has_cap(ACER_CAP_BLUETOOTH)) {
+ kfree(wireless_rfkill->data);
+ rfkill_unregister(bluetooth_rfkill);
+ }
+ return;
+}
/*
- * Read interface sysfs macro
+ * sysfs interface
*/
+static ssize_t show_bool_threeg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 result; \
+ acpi_status status = get_u32(&result, ACER_CAP_THREEG);
+ if (ACPI_SUCCESS(status))
+ return sprintf(buf, "%u\n", result);
+ return sprintf(buf, "Read error\n");
+}
+
+static ssize_t set_bool_threeg(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ u32 tmp = simple_strtoul(buf, NULL, 10);
+ acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+ return count;
+}
+static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
+ set_bool_threeg);
+
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
goto error_brightness;
}
- return 0;
+ err = acer_rfkill_init(&device->dev);
+
+ return err;
error_brightness:
acer_led_exit();
@@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
acer_led_exit();
if (has_cap(ACER_CAP_BRIGHTNESS))
acer_backlight_exit();
+
+ acer_rfkill_exit();
return 0;
}
@@ -1052,16 +1146,6 @@ pm_message_t state)
if (!data)
return -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS)) {
- get_u32(&value, ACER_CAP_WIRELESS);
- data->wireless = value;
- }
-
- if (has_cap(ACER_CAP_BLUETOOTH)) {
- get_u32(&value, ACER_CAP_BLUETOOTH);
- data->bluetooth = value;
- }
-
if (has_cap(ACER_CAP_MAILLED)) {
get_u32(&value, ACER_CAP_MAILLED);
data->mailled = value;
@@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
if (!data)
return -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS))
- set_u32(data->wireless, ACER_CAP_WIRELESS);
-
- if (has_cap(ACER_CAP_BLUETOOTH))
- set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
-
- if (has_cap(ACER_CAP_THREEG))
- set_u32(data->threeg, ACER_CAP_THREEG);
-
if (has_cap(ACER_CAP_MAILLED))
set_u32(data->mailled, ACER_CAP_MAILLED);
@@ -1115,12 +1190,6 @@ static struct platform_device *acer_platform_device;
static int remove_sysfs(struct platform_device *device)
{
- if (has_cap(ACER_CAP_WIRELESS))
- device_remove_file(&device->dev, &dev_attr_wireless);
-
- if (has_cap(ACER_CAP_BLUETOOTH))
- device_remove_file(&device->dev, &dev_attr_bluetooth);
-
if (has_cap(ACER_CAP_THREEG))
device_remove_file(&device->dev, &dev_attr_threeg);
@@ -1133,20 +1202,6 @@ static int create_sysfs(void)
{
int retval = -ENOMEM;
- if (has_cap(ACER_CAP_WIRELESS)) {
- retval = device_create_file(&acer_platform_device->dev,
- &dev_attr_wireless);
- if (retval)
- goto error_sysfs;
- }
-
- if (has_cap(ACER_CAP_BLUETOOTH)) {
- retval = device_create_file(&acer_platform_device->dev,
- &dev_attr_bluetooth);
- if (retval)
- goto error_sysfs;
- }
-
if (has_cap(ACER_CAP_THREEG)) {
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_threeg);
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 7c6dfd03de9..a9d5228724a 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -139,6 +139,7 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
"\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
"\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
"\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
+ "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
"\\_SB.PCI0.PX40.Q10", /* S1x */
"\\Q10"); /* A2x, L2D, L3D, M2E */
@@ -280,7 +281,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
static int read_wireless_status(int mask)
{
- ulong status;
+ unsigned long long status;
acpi_status rv = AE_OK;
if (!wireless_status_handle)
@@ -297,7 +298,7 @@ static int read_wireless_status(int mask)
static int read_gps_status(void)
{
- ulong status;
+ unsigned long long status;
acpi_status rv = AE_OK;
rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
@@ -350,7 +351,7 @@ static void write_status(acpi_handle handle, int out, int mask)
static void object##_led_set(struct led_classdev *led_cdev, \
enum led_brightness value) \
{ \
- object##_led_wk = value; \
+ object##_led_wk = (value > 0) ? 1 : 0; \
queue_work(led_workqueue, &object##_led_work); \
} \
static void object##_led_update(struct work_struct *ignored) \
@@ -404,7 +405,7 @@ static void lcd_blank(int blank)
static int read_brightness(struct backlight_device *bd)
{
- ulong value;
+ unsigned long long value;
acpi_status rv = AE_OK;
rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
@@ -455,7 +456,7 @@ static ssize_t show_infos(struct device *dev,
struct device_attribute *attr, char *page)
{
int len = 0;
- ulong temp;
+ unsigned long long temp;
char buf[16]; //enough for all info
acpi_status rv = AE_OK;
@@ -603,7 +604,7 @@ static void set_display(int value)
static int read_display(void)
{
- ulong value = 0;
+ unsigned long long value = 0;
acpi_status rv = AE_OK;
/* In most of the case, we know how to set the display, but sometime
@@ -849,7 +850,7 @@ static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
- ulong bsts_result, hwrs_result;
+ unsigned long long bsts_result, hwrs_result;
char *string = NULL;
acpi_status status;
@@ -996,7 +997,7 @@ static int asus_hotk_add(struct acpi_device *device)
hotk->handle = device->handle;
strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
- acpi_driver_data(device) = hotk;
+ device->driver_data = hotk;
hotk->device = device;
result = asus_hotk_check();
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
index 1ee8501e90f..9ef98b2d503 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/misc/eeepc-laptop.c
@@ -28,6 +28,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <linux/uaccess.h>
+#include <linux/input.h>
+#include <linux/rfkill.h>
#define EEEPC_LAPTOP_VERSION "0.1"
@@ -125,6 +127,10 @@ struct eeepc_hotk {
by this BIOS */
uint init_flag; /* Init flags */
u16 event_count[128]; /* count for each event */
+ struct input_dev *inputdev;
+ u16 *keycode_map;
+ struct rfkill *eeepc_wlan_rfkill;
+ struct rfkill *eeepc_bluetooth_rfkill;
};
/* The actual device the driver binds to */
@@ -140,6 +146,27 @@ static struct platform_driver platform_driver = {
static struct platform_device *platform_device;
+struct key_entry {
+ char type;
+ u8 code;
+ u16 keycode;
+};
+
+enum { KE_KEY, KE_END };
+
+static struct key_entry eeepc_keymap[] = {
+ /* Sleep already handled via generic ACPI code */
+ {KE_KEY, 0x10, KEY_WLAN },
+ {KE_KEY, 0x12, KEY_PROG1 },
+ {KE_KEY, 0x13, KEY_MUTE },
+ {KE_KEY, 0x14, KEY_VOLUMEDOWN },
+ {KE_KEY, 0x15, KEY_VOLUMEUP },
+ {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
+ {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
+ {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
+ {KE_END, 0},
+};
+
/*
* The hotkey driver declaration
*/
@@ -204,7 +231,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
static int read_acpi_int(acpi_handle handle, const char *method, int *val)
{
acpi_status status;
- ulong result;
+ unsigned long long result;
status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
if (ACPI_FAILURE(status)) {
@@ -261,6 +288,44 @@ static int update_bl_status(struct backlight_device *bd)
}
/*
+ * Rfkill helpers
+ */
+
+static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
+{
+ if (state == RFKILL_STATE_SOFT_BLOCKED)
+ return set_acpi(CM_ASL_WLAN, 0);
+ else
+ return set_acpi(CM_ASL_WLAN, 1);
+}
+
+static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
+{
+ if (get_acpi(CM_ASL_WLAN) == 1)
+ *state = RFKILL_STATE_UNBLOCKED;
+ else
+ *state = RFKILL_STATE_SOFT_BLOCKED;
+ return 0;
+}
+
+static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
+{
+ if (state == RFKILL_STATE_SOFT_BLOCKED)
+ return set_acpi(CM_ASL_BLUETOOTH, 0);
+ else
+ return set_acpi(CM_ASL_BLUETOOTH, 1);
+}
+
+static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
+{
+ if (get_acpi(CM_ASL_BLUETOOTH) == 1)
+ *state = RFKILL_STATE_UNBLOCKED;
+ else
+ *state = RFKILL_STATE_SOFT_BLOCKED;
+ return 0;
+}
+
+/*
* Sys helpers
*/
static int parse_arg(const char *buf, unsigned long count, int *val)
@@ -311,13 +376,11 @@ static ssize_t show_sys_acpi(int cm, char *buf)
EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
-EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
static struct attribute *platform_attributes[] = {
&dev_attr_camera.attr,
&dev_attr_cardr.attr,
&dev_attr_disp.attr,
- &dev_attr_wlan.attr,
NULL
};
@@ -328,8 +391,64 @@ static struct attribute_group platform_attribute_group = {
/*
* Hotkey functions
*/
+static struct key_entry *eepc_get_entry_by_scancode(int code)
+{
+ struct key_entry *key;
+
+ for (key = eeepc_keymap; key->type != KE_END; key++)
+ if (code == key->code)
+ return key;
+
+ return NULL;
+}
+
+static struct key_entry *eepc_get_entry_by_keycode(int code)
+{
+ struct key_entry *key;
+
+ for (key = eeepc_keymap; key->type != KE_END; key++)
+ if (code == key->keycode && key->type == KE_KEY)
+ return key;
+
+ return NULL;
+}
+
+static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+ struct key_entry *key = eepc_get_entry_by_scancode(scancode);
+
+ if (key && key->type == KE_KEY) {
+ *keycode = key->keycode;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+{
+ struct key_entry *key;
+ int old_keycode;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ key = eepc_get_entry_by_scancode(scancode);
+ if (key && key->type == KE_KEY) {
+ old_keycode = key->keycode;
+ key->keycode = keycode;
+ set_bit(keycode, dev->keybit);
+ if (!eepc_get_entry_by_keycode(old_keycode))
+ clear_bit(old_keycode, dev->keybit);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int eeepc_hotk_check(void)
{
+ const struct key_entry *key;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
int result;
@@ -356,6 +475,31 @@ static int eeepc_hotk_check(void)
"Get control methods supported: 0x%x\n",
ehotk->cm_supported);
}
+ ehotk->inputdev = input_allocate_device();
+ if (!ehotk->inputdev) {
+ printk(EEEPC_INFO "Unable to allocate input device\n");
+ return 0;
+ }
+ ehotk->inputdev->name = "Asus EeePC extra buttons";
+ ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
+ ehotk->inputdev->id.bustype = BUS_HOST;
+ ehotk->inputdev->getkeycode = eeepc_getkeycode;
+ ehotk->inputdev->setkeycode = eeepc_setkeycode;
+
+ for (key = eeepc_keymap; key->type != KE_END; key++) {
+ switch (key->type) {
+ case KE_KEY:
+ set_bit(EV_KEY, ehotk->inputdev->evbit);
+ set_bit(key->keycode, ehotk->inputdev->keybit);
+ break;
+ }
+ }
+ result = input_register_device(ehotk->inputdev);
+ if (result) {
+ printk(EEEPC_INFO "Unable to register input device\n");
+ input_free_device(ehotk->inputdev);
+ return 0;
+ }
} else {
printk(EEEPC_ERR "Hotkey device not present, aborting\n");
return -EINVAL;
@@ -363,21 +507,6 @@ static int eeepc_hotk_check(void)
return 0;
}
-static void notify_wlan(u32 *event)
-{
- /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
- will always be 0x10 */
- if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
- const char *method = cm_getv[CM_ASL_WLAN];
- int value;
- if (read_acpi_int(ehotk->handle, method, &value))
- printk(EEEPC_WARNING "Error reading %s\n",
- method);
- else if (value == 1)
- *event = 0x11;
- }
-}
-
static void notify_brn(void)
{
struct backlight_device *bd = eeepc_backlight_device;
@@ -386,14 +515,28 @@ static void notify_brn(void)
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
{
+ static struct key_entry *key;
if (!ehotk)
return;
- if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
- notify_wlan(&event);
if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
notify_brn();
acpi_bus_generate_proc_event(ehotk->device, event,
ehotk->event_count[event % 128]++);
+ if (ehotk->inputdev) {
+ key = eepc_get_entry_by_scancode(event);
+ if (key) {
+ switch (key->type) {
+ case KE_KEY:
+ input_report_key(ehotk->inputdev, key->keycode,
+ 1);
+ input_sync(ehotk->inputdev);
+ input_report_key(ehotk->inputdev, key->keycode,
+ 0);
+ input_sync(ehotk->inputdev);
+ break;
+ }
+ }
+ }
}
static int eeepc_hotk_add(struct acpi_device *device)
@@ -411,7 +554,7 @@ static int eeepc_hotk_add(struct acpi_device *device)
ehotk->handle = device->handle;
strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
- acpi_driver_data(device) = ehotk;
+ device->driver_data = ehotk;
ehotk->device = device;
result = eeepc_hotk_check();
if (result)
@@ -420,6 +563,47 @@ static int eeepc_hotk_add(struct acpi_device *device)
eeepc_hotk_notify, ehotk);
if (ACPI_FAILURE(status))
printk(EEEPC_ERR "Error installing notify handler\n");
+
+ if (get_acpi(CM_ASL_WLAN) != -1) {
+ ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
+ RFKILL_TYPE_WLAN);
+
+ if (!ehotk->eeepc_wlan_rfkill)
+ goto end;
+
+ ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
+ ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
+ ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
+ if (get_acpi(CM_ASL_WLAN) == 1)
+ ehotk->eeepc_wlan_rfkill->state =
+ RFKILL_STATE_UNBLOCKED;
+ else
+ ehotk->eeepc_wlan_rfkill->state =
+ RFKILL_STATE_SOFT_BLOCKED;
+ rfkill_register(ehotk->eeepc_wlan_rfkill);
+ }
+
+ if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
+ ehotk->eeepc_bluetooth_rfkill =
+ rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
+
+ if (!ehotk->eeepc_bluetooth_rfkill)
+ goto end;
+
+ ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
+ ehotk->eeepc_bluetooth_rfkill->toggle_radio =
+ eeepc_bluetooth_rfkill_set;
+ ehotk->eeepc_bluetooth_rfkill->get_state =
+ eeepc_bluetooth_rfkill_state;
+ if (get_acpi(CM_ASL_BLUETOOTH) == 1)
+ ehotk->eeepc_bluetooth_rfkill->state =
+ RFKILL_STATE_UNBLOCKED;
+ else
+ ehotk->eeepc_bluetooth_rfkill->state =
+ RFKILL_STATE_SOFT_BLOCKED;
+ rfkill_register(ehotk->eeepc_bluetooth_rfkill);
+ }
+
end:
if (result) {
kfree(ehotk);
@@ -553,6 +737,12 @@ static void eeepc_backlight_exit(void)
{
if (eeepc_backlight_device)
backlight_device_unregister(eeepc_backlight_device);
+ if (ehotk->inputdev)
+ input_unregister_device(ehotk->inputdev);
+ if (ehotk->eeepc_wlan_rfkill)
+ rfkill_unregister(ehotk->eeepc_wlan_rfkill);
+ if (ehotk->eeepc_bluetooth_rfkill)
+ rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
eeepc_backlight_device = NULL;
}
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index 3e56203e494..d2cf0bfe316 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -44,8 +44,9 @@
* 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 and S7020. It
- * should work on most P-series and S-series Lifebooks, but YMMV.
+ * 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
@@ -65,7 +66,7 @@
#include <linux/video_output.h>
#include <linux/platform_device.h>
-#define FUJITSU_DRIVER_VERSION "0.4.2"
+#define FUJITSU_DRIVER_VERSION "0.4.3"
#define FUJITSU_LCD_N_LEVELS 8
@@ -83,10 +84,10 @@
#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
/* Hotkey details */
-#define LOCK_KEY 0x410 /* codes for the keys in the GIRB register */
-#define DISPLAY_KEY 0x411 /* keys are mapped to KEY_SCREENLOCK (the key with the key symbol) */
-#define ENERGY_KEY 0x412 /* KEY_MEDIA (the key with the laptop symbol, KEY_EMAIL (E key)) */
-#define REST_KEY 0x413 /* KEY_SUSPEND (R key) */
+#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
@@ -123,6 +124,7 @@ struct fujitsu_t {
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;
@@ -224,7 +226,7 @@ static int set_lcd_level_alt(int level)
static int get_lcd_level(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n");
@@ -246,7 +248,7 @@ static int get_lcd_level(void)
static int get_max_brightness(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n");
@@ -263,7 +265,7 @@ static int get_max_brightness(void)
static int get_lcd_level_alt(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n");
@@ -384,7 +386,7 @@ static ssize_t store_lcd_level(struct device *dev,
static int get_irb(void)
{
- unsigned long state = 0;
+ unsigned long long state = 0;
acpi_status status = AE_OK;
vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n");
@@ -430,7 +432,7 @@ static struct platform_driver fujitsupf_driver = {
}
};
-static int dmi_check_cb_s6410(const struct dmi_system_id *id)
+static void dmi_check_cb_common(const struct dmi_system_id *id)
{
acpi_handle handle;
int have_blnf;
@@ -452,24 +454,40 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
"auto-detecting disable_adjust\n");
disable_brightness_adjust = have_blnf ? 0 : 1;
}
+}
+
+static int dmi_check_cb_s6410(const struct dmi_system_id *id)
+{
+ dmi_check_cb_common(id);
+ fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */
+ fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */
+ return 0;
+}
+
+static int dmi_check_cb_p8010(const struct dmi_system_id *id)
+{
+ dmi_check_cb_common(id);
+ fujitsu->keycode1 = KEY_HELP; /* "Support" */
+ fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */
+ fujitsu->keycode4 = KEY_WWW; /* "Internet" */
return 0;
}
static struct dmi_system_id __initdata fujitsu_dmi_table[] = {
{
- .ident = "Fujitsu Siemens",
+ .ident = "Fujitsu Siemens S6410",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
},
.callback = dmi_check_cb_s6410},
{
- .ident = "FUJITSU LifeBook P8010",
+ .ident = "Fujitsu LifeBook P8010",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
- },
- .callback = dmi_check_cb_s6410},
+ },
+ .callback = dmi_check_cb_p8010},
{}
};
@@ -490,7 +508,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
fujitsu->acpi_handle = device->handle;
sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
- acpi_driver_data(device) = fujitsu;
+ device->driver_data = fujitsu;
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
@@ -547,7 +565,6 @@ static int acpi_fujitsu_add(struct acpi_device *device)
}
/* do config (detect defaults) */
- dmi_check_system(fujitsu_dmi_table);
use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0;
disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
@@ -623,17 +640,17 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
keycode = 0;
if (disable_brightness_keys != 1) {
if (oldb == 0) {
- acpi_bus_generate_proc_event(fujitsu->
- dev,
- ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
- 0);
+ acpi_bus_generate_proc_event
+ (fujitsu->dev,
+ ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
+ 0);
keycode = KEY_BRIGHTNESSDOWN;
} else if (oldb ==
(fujitsu->max_brightness) - 1) {
- acpi_bus_generate_proc_event(fujitsu->
- dev,
- ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
- 0);
+ acpi_bus_generate_proc_event
+ (fujitsu->dev,
+ ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
+ 0);
keycode = KEY_BRIGHTNESSUP;
}
}
@@ -646,8 +663,7 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
}
if (disable_brightness_keys != 1) {
acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
- 0);
+ ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
keycode = KEY_BRIGHTNESSUP;
}
} else if (oldb > newb) {
@@ -659,8 +675,7 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
}
if (disable_brightness_keys != 1) {
acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
- 0);
+ ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
keycode = KEY_BRIGHTNESSDOWN;
}
} else {
@@ -703,7 +718,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
sprintf(acpi_device_name(device), "%s",
ACPI_FUJITSU_HOTKEY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
- acpi_driver_data(device) = fujitsu_hotkey;
+ device->driver_data = fujitsu_hotkey;
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
@@ -742,10 +757,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
input->id.product = 0x06;
input->dev.parent = &device->dev;
input->evbit[0] = BIT(EV_KEY);
- set_bit(KEY_SCREENLOCK, input->keybit);
- set_bit(KEY_MEDIA, input->keybit);
- set_bit(KEY_EMAIL, input->keybit);
- set_bit(KEY_SUSPEND, input->keybit);
+ set_bit(fujitsu->keycode1, input->keybit);
+ set_bit(fujitsu->keycode2, input->keybit);
+ set_bit(fujitsu->keycode3, input->keybit);
+ set_bit(fujitsu->keycode4, input->keybit);
set_bit(KEY_UNKNOWN, input->keybit);
error = input_register_device(input);
@@ -833,24 +848,24 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
irb);
switch (irb & 0x4ff) {
- case LOCK_KEY:
- keycode = KEY_SCREENLOCK;
+ case KEY1_CODE:
+ keycode = fujitsu->keycode1;
break;
- case DISPLAY_KEY:
- keycode = KEY_MEDIA;
+ case KEY2_CODE:
+ keycode = fujitsu->keycode2;
break;
- case ENERGY_KEY:
- keycode = KEY_EMAIL;
+ case KEY3_CODE:
+ keycode = fujitsu->keycode3;
break;
- case REST_KEY:
- keycode = KEY_SUSPEND;
+ case KEY4_CODE:
+ keycode = fujitsu->keycode4;
break;
case 0:
keycode = 0;
break;
default:
vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Unknown GIRB result [%x]\n", irb);
+ "Unknown GIRB result [%x]\n", irb);
keycode = -1;
break;
}
@@ -859,12 +874,12 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
"Push keycode into ringbuffer [%d]\n",
keycode);
status = kfifo_put(fujitsu_hotkey->fifo,
- (unsigned char *)&keycode,
- sizeof(keycode));
+ (unsigned char *)&keycode,
+ sizeof(keycode));
if (status != sizeof(keycode)) {
vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Could not push keycode [0x%x]\n",
- keycode);
+ "Could not push keycode [0x%x]\n",
+ keycode);
} else {
input_report_key(input, keycode, 1);
input_sync(input);
@@ -879,8 +894,8 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
input_report_key(input, keycode_r, 0);
input_sync(input);
vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Pop keycode from ringbuffer [%d]\n",
- keycode_r);
+ "Pop keycode from ringbuffer [%d]\n",
+ keycode_r);
}
}
}
@@ -943,6 +958,11 @@ static int __init fujitsu_init(void)
if (!fujitsu)
return -ENOMEM;
memset(fujitsu, 0, sizeof(struct fujitsu_t));
+ fujitsu->keycode1 = KEY_PROG1;
+ fujitsu->keycode2 = KEY_PROG2;
+ fujitsu->keycode3 = KEY_PROG3;
+ fujitsu->keycode4 = KEY_PROG4;
+ dmi_check_system(fujitsu_dmi_table);
result = acpi_bus_register_driver(&acpi_fujitsu_driver);
if (result < 0) {
@@ -1076,15 +1096,14 @@ MODULE_DESCRIPTION("Fujitsu laptop extras support");
MODULE_VERSION(FUJITSU_DRIVER_VERSION);
MODULE_LICENSE("GPL");
-MODULE_ALIAS
- ("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
-MODULE_ALIAS
- ("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
+MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
+MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
static struct pnp_device_id pnp_ids[] = {
- { .id = "FUJ02bf" },
- { .id = "FUJ02B1" },
- { .id = "FUJ02E3" },
- { .id = "" }
+ {.id = "FUJ02bf"},
+ {.id = "FUJ02B1"},
+ {.id = "FUJ02E3"},
+ {.id = ""}
};
+
MODULE_DEVICE_TABLE(pnp, pnp_ids);
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index 80a13635240..a78274385d5 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -57,7 +57,7 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
- unsigned long value;
+ unsigned long long value;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
@@ -90,7 +90,7 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
- unsigned long value;
+ unsigned long long value;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
@@ -115,7 +115,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status;
- int temp;
+ unsigned long long temp;
unsigned long max_state;
if (memory_get_int_max_bandwidth(cdev, &max_state))
@@ -131,7 +131,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
status =
acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
- (unsigned long *)&temp);
+ &temp);
printk(KERN_INFO
"Bandwidth value was %d: status is %d\n", state, status);
@@ -175,7 +175,7 @@ static int intel_menlow_memory_add(struct acpi_device *device)
goto end;
}
- acpi_driver_data(device) = cdev;
+ device->driver_data = cdev;
result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, "thermal_cooling");
if (result)
@@ -252,7 +252,8 @@ static DEFINE_MUTEX(intel_menlow_attr_lock);
* @auxtype : AUX0/AUX1
* @buf: syfs buffer
*/
-static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
+static int sensor_get_auxtrip(acpi_handle handle, int index,
+ unsigned long long *value)
{
acpi_status status;
@@ -260,7 +261,7 @@ static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
- NULL, (unsigned long *)value);
+ NULL, value);
if (ACPI_FAILURE(status))
return -EIO;
@@ -282,13 +283,13 @@ static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
struct acpi_object_list args = {
1, &arg
};
- int temp;
+ unsigned long long temp;
if (index != 0 && index != 1)
return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
- NULL, (unsigned long *)&temp);
+ NULL, &temp);
if (ACPI_FAILURE(status))
return -EIO;
if ((index && value < temp) || (!index && value > temp))
@@ -296,7 +297,7 @@ static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
arg.integer.value = value;
status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
- &args, (unsigned long *)&temp);
+ &args, &temp);
if (ACPI_FAILURE(status))
return -EIO;
@@ -312,7 +313,7 @@ static ssize_t aux0_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
- int value;
+ unsigned long long value;
int result;
result = sensor_get_auxtrip(attr->handle, 0, &value);
@@ -324,7 +325,7 @@ static ssize_t aux1_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
- int value;
+ unsigned long long value;
int result;
result = sensor_get_auxtrip(attr->handle, 1, &value);
@@ -376,7 +377,7 @@ static ssize_t bios_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
acpi_status status;
- unsigned long bios_enabled;
+ unsigned long long bios_enabled;
status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
if (ACPI_FAILURE(status))
@@ -492,7 +493,7 @@ static int __init intel_menlow_module_init(void)
{
int result = -ENODEV;
acpi_status status;
- unsigned long enable;
+ unsigned long long enable;
if (acpi_disabled)
return result;
diff --git a/drivers/misc/panasonic-laptop.c b/drivers/misc/panasonic-laptop.c
new file mode 100644
index 00000000000..a2cb598d8ab
--- /dev/null
+++ b/drivers/misc/panasonic-laptop.c
@@ -0,0 +1,767 @@
+/*
+ * Panasonic HotKey and LCD brightness control driver
+ * (C) 2004 Hiroshi Miura <miura@da-cha.org>
+ * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
+ * (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
+ * (C) 2004 David Bronaugh <dbronaugh>
+ * (C) 2006-2008 Harald Welte <laforge@gnumonks.org>
+ *
+ * derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publicshed by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *---------------------------------------------------------------------------
+ *
+ * ChangeLog:
+ * Sep.23, 2008 Harald Welte <laforge@gnumonks.org>
+ * -v0.95 rename driver from drivers/acpi/pcc_acpi.c to
+ * drivers/misc/panasonic-laptop.c
+ *
+ * Jul.04, 2008 Harald Welte <laforge@gnumonks.org>
+ * -v0.94 replace /proc interface with device attributes
+ * support {set,get}keycode on th input device
+ *
+ * Jun.27, 2008 Harald Welte <laforge@gnumonks.org>
+ * -v0.92 merge with 2.6.26-rc6 input API changes
+ * remove broken <= 2.6.15 kernel support
+ * resolve all compiler warnings
+ * various coding style fixes (checkpatch.pl)
+ * add support for backlight api
+ * major code restructuring
+ *
+ * Dac.28, 2007 Harald Welte <laforge@gnumonks.org>
+ * -v0.91 merge with 2.6.24-rc6 ACPI changes
+ *
+ * Nov.04, 2006 Hiroshi Miura <miura@da-cha.org>
+ * -v0.9 remove warning about section reference.
+ * remove acpi_os_free
+ * add /proc/acpi/pcc/brightness interface for HAL access
+ * merge dbronaugh's enhancement
+ * Aug.17, 2004 David Bronaugh (dbronaugh)
+ * - Added screen brightness setting interface
+ * Thanks to FreeBSD crew (acpi_panasonic.c)
+ * for the ideas I needed to accomplish it
+ *
+ * May.29, 2006 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8.4 follow to change keyinput structure
+ * thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
+ * Jacob Bower <jacob.bower@ic.ac.uk> and
+ * Hiroshi Yokota for providing solutions.
+ *
+ * Oct.02, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8.2 merge code of YOKOTA Hiroshi
+ * <yokota@netlab.is.tsukuba.ac.jp>.
+ * Add sticky key mode interface.
+ * Refactoring acpi_pcc_generate_keyinput().
+ *
+ * Sep.15, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.8 Generate key input event on input subsystem.
+ * This is based on yet another driver written by
+ * Ryuta Nakanishi.
+ *
+ * Sep.10, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.7 Change proc interface functions using seq_file
+ * facility as same as other ACPI drivers.
+ *
+ * Aug.28, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.6.4 Fix a silly error with status checking
+ *
+ * Aug.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * -v0.6.3 replace read_acpi_int by standard function
+ * acpi_evaluate_integer
+ * some clean up and make smart copyright notice.
+ * fix return value of pcc_acpi_get_key()
+ * fix checking return value of acpi_bus_register_driver()
+ *
+ * Aug.22, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * -v0.6.2 Add check on ACPI data (num_sifr)
+ * Coding style cleanups, better error messages/handling
+ * Fixed an off-by-one error in memory allocation
+ *
+ * Aug.21, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * -v0.6.1 Fix a silly error with status checking
+ *
+ * Aug.20, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
+ * - v0.6 Correct brightness controls to reflect reality
+ * based on information gleaned by Hiroshi Miura
+ * and discussions with Hiroshi Miura
+ *
+ * Aug.10, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.5 support LCD brightness control
+ * based on the disclosed information by MEI.
+ *
+ * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.4 first post version
+ * add function to retrive SIFR
+ *
+ * Jul.24, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.3 get proper status of hotkey
+ *
+ * Jul.22, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.2 add HotKey handler
+ *
+ * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org>
+ * - v0.1 start from toshiba_acpi driver written by John Belmonte
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/backlight.h>
+#include <linux/ctype.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/input.h>
+
+
+#ifndef ACPI_HOTKEY_COMPONENT
+#define ACPI_HOTKEY_COMPONENT 0x10000000
+#endif
+
+#define _COMPONENT ACPI_HOTKEY_COMPONENT
+
+MODULE_AUTHOR("Hiroshi Miura, David Bronaugh and Harald Welte");
+MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
+MODULE_LICENSE("GPL");
+
+#define LOGPREFIX "pcc_acpi: "
+
+/* Define ACPI PATHs */
+/* Lets note hotkeys */
+#define METHOD_HKEY_QUERY "HINF"
+#define METHOD_HKEY_SQTY "SQTY"
+#define METHOD_HKEY_SINF "SINF"
+#define METHOD_HKEY_SSET "SSET"
+#define HKEY_NOTIFY 0x80
+
+#define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support"
+#define ACPI_PCC_DEVICE_NAME "Hotkey"
+#define ACPI_PCC_CLASS "pcc"
+
+#define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
+
+/* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
+ ENV_STATEs: Normal temp=0x01, High temp=0x81, N/A=0x00
+*/
+enum SINF_BITS { SINF_NUM_BATTERIES = 0,
+ SINF_LCD_TYPE,
+ SINF_AC_MAX_BRIGHT,
+ SINF_AC_MIN_BRIGHT,
+ SINF_AC_CUR_BRIGHT,
+ SINF_DC_MAX_BRIGHT,
+ SINF_DC_MIN_BRIGHT,
+ SINF_DC_CUR_BRIGHT,
+ SINF_MUTE,
+ SINF_RESERVED,
+ SINF_ENV_STATE,
+ SINF_STICKY_KEY = 0x80,
+ };
+/* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
+
+static int acpi_pcc_hotkey_add(struct acpi_device *device);
+static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
+static int acpi_pcc_hotkey_resume(struct acpi_device *device);
+
+static const struct acpi_device_id pcc_device_ids[] = {
+ { "MAT0012", 0},
+ { "MAT0013", 0},
+ { "MAT0018", 0},
+ { "MAT0019", 0},
+ { "", 0},
+};
+
+static struct acpi_driver acpi_pcc_driver = {
+ .name = ACPI_PCC_DRIVER_NAME,
+ .class = ACPI_PCC_CLASS,
+ .ids = pcc_device_ids,
+ .ops = {
+ .add = acpi_pcc_hotkey_add,
+ .remove = acpi_pcc_hotkey_remove,
+ .resume = acpi_pcc_hotkey_resume,
+ },
+};
+
+#define KEYMAP_SIZE 11
+static const int initial_keymap[KEYMAP_SIZE] = {
+ /* 0 */ KEY_RESERVED,
+ /* 1 */ KEY_BRIGHTNESSDOWN,
+ /* 2 */ KEY_BRIGHTNESSUP,
+ /* 3 */ KEY_DISPLAYTOGGLE,
+ /* 4 */ KEY_MUTE,
+ /* 5 */ KEY_VOLUMEDOWN,
+ /* 6 */ KEY_VOLUMEUP,
+ /* 7 */ KEY_SLEEP,
+ /* 8 */ KEY_PROG1, /* Change CPU boost */
+ /* 9 */ KEY_BATTERY,
+ /* 10 */ KEY_SUSPEND,
+};
+
+struct pcc_acpi {
+ acpi_handle handle;
+ unsigned long num_sifr;
+ int sticky_mode;
+ u32 *sinf;
+ struct acpi_device *device;
+ struct input_dev *input_dev;
+ struct backlight_device *backlight;
+ int keymap[KEYMAP_SIZE];
+};
+
+struct pcc_keyinput {
+ struct acpi_hotkey *hotkey;
+};
+
+/* method access functions */
+static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
+{
+ union acpi_object in_objs[] = {
+ { .integer.type = ACPI_TYPE_INTEGER,
+ .integer.value = func, },
+ { .integer.type = ACPI_TYPE_INTEGER,
+ .integer.value = val, },
+ };
+ struct acpi_object_list params = {
+ .count = ARRAY_SIZE(in_objs),
+ .pointer = in_objs,
+ };
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");
+
+ status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
+ &params, NULL);
+
+ return status == AE_OK;
+}
+
+static inline int acpi_pcc_get_sqty(struct acpi_device *device)
+{
+ unsigned long long s;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty");
+
+ status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY,
+ NULL, &s);
+ if (ACPI_SUCCESS(status))
+ return s;
+ else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "evaluation error HKEY.SQTY\n"));
+ return -EINVAL;
+ }
+}
+
+static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *hkey = NULL;
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata");
+
+ status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, 0,
+ &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "evaluation error HKEY.SINF\n"));
+ return 0;
+ }
+
+ hkey = buffer.pointer;
+ if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid HKEY.SINF\n"));
+ goto end;
+ }
+
+ if (pcc->num_sifr < hkey->package.count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "SQTY reports bad SINF length\n"));
+ status = AE_ERROR;
+ goto end;
+ }
+
+ for (i = 0; i < hkey->package.count; i++) {
+ union acpi_object *element = &(hkey->package.elements[i]);
+ if (likely(element->type == ACPI_TYPE_INTEGER)) {
+ sinf[i] = element->integer.value;
+ } else
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid HKEY.SINF data\n"));
+ }
+ sinf[hkey->package.count] = -1;
+
+end:
+ kfree(buffer.pointer);
+ return status == AE_OK;
+}
+
+/* backlight API interface functions */
+
+/* This driver currently treats AC and DC brightness identical,
+ * since we don't need to invent an interface to the core ACPI
+ * logic to receive events in case a power supply is plugged in
+ * or removed */
+
+static int bl_get(struct backlight_device *bd)
+{
+ struct pcc_acpi *pcc = bl_get_data(bd);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return pcc->sinf[SINF_AC_CUR_BRIGHT];
+}
+
+static int bl_set_status(struct backlight_device *bd)
+{
+ struct pcc_acpi *pcc = bl_get_data(bd);
+ int bright = bd->props.brightness;
+ int rc;
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
+ bright = pcc->sinf[SINF_AC_MIN_BRIGHT];
+
+ if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT])
+ bright = pcc->sinf[SINF_DC_MIN_BRIGHT];
+
+ if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] ||
+ bright > pcc->sinf[SINF_AC_MAX_BRIGHT])
+ return -EINVAL;
+
+ rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright);
+ if (rc < 0)
+ return rc;
+
+ return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
+}
+
+static struct backlight_ops pcc_backlight_ops = {
+ .get_brightness = bl_get,
+ .update_status = bl_set_status,
+};
+
+
+/* sysfs user interface functions */
+
+static ssize_t show_numbatt(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
+}
+
+static ssize_t show_lcdtype(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
+}
+
+static ssize_t show_mute(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_MUTE]);
+}
+
+static ssize_t show_sticky(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf))
+ return -EIO;
+
+ return sprintf(buf, "%u\n", pcc->sinf[SINF_STICKY_KEY]);
+}
+
+static ssize_t set_sticky(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pcc_acpi *pcc = acpi_driver_data(acpi);
+ int val;
+
+ if (count && sscanf(buf, "%i", &val) == 1 &&
+ (val == 0 || val == 1)) {
+ acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val);
+ pcc->sticky_mode = val;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(numbatt, S_IRUGO, show_numbatt, NULL);
+static DEVICE_ATTR(lcdtype, S_IRUGO, show_lcdtype, NULL);
+static DEVICE_ATTR(mute, S_IRUGO, show_mute, NULL);
+static DEVICE_ATTR(sticky_key, S_IRUGO | S_IWUSR, show_sticky, set_sticky);
+
+static struct attribute *pcc_sysfs_entries[] = {
+ &dev_attr_numbatt.attr,
+ &dev_attr_lcdtype.attr,
+ &dev_attr_mute.attr,
+ &dev_attr_sticky_key.attr,
+ NULL,
+};
+
+static struct attribute_group pcc_attr_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = pcc_sysfs_entries,
+};
+
+
+/* hotkey input device driver */
+
+static int pcc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+ struct pcc_acpi *pcc = input_get_drvdata(dev);
+
+ if (scancode >= ARRAY_SIZE(pcc->keymap))
+ return -EINVAL;
+
+ *keycode = pcc->keymap[scancode];
+
+ return 0;
+}
+
+static int keymap_get_by_keycode(struct pcc_acpi *pcc, int keycode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
+ if (pcc->keymap[i] == keycode)
+ return i+1;
+ }
+
+ return 0;
+}
+
+static int pcc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+{
+ struct pcc_acpi *pcc = input_get_drvdata(dev);
+ int oldkeycode;
+
+ if (scancode >= ARRAY_SIZE(pcc->keymap))
+ return -EINVAL;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ oldkeycode = pcc->keymap[scancode];
+ pcc->keymap[scancode] = keycode;
+
+ set_bit(keycode, dev->keybit);
+
+ if (!keymap_get_by_keycode(pcc, oldkeycode))
+ clear_bit(oldkeycode, dev->keybit);
+
+ return 0;
+}
+
+static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
+{
+ struct input_dev *hotk_input_dev = pcc->input_dev;
+ int rc;
+ int key_code, hkey_num;
+ unsigned long long result;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_generate_keyinput");
+
+ rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
+ NULL, &result);
+ if (!ACPI_SUCCESS(rc)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "error getting hotkey status\n"));
+ return;
+ }
+
+ acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
+
+ hkey_num = result & 0xf;
+
+ if (hkey_num < 0 || hkey_num > ARRAY_SIZE(pcc->keymap)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "hotkey number out of range: %d\n",
+ hkey_num));
+ return;
+ }
+
+ key_code = pcc->keymap[hkey_num];
+
+ if (key_code != KEY_RESERVED) {
+ int pushed = (result & 0x80) ? TRUE : FALSE;
+
+ input_report_key(hotk_input_dev, key_code, pushed);
+ input_sync(hotk_input_dev);
+ }
+
+ return;
+}
+
+static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct pcc_acpi *pcc = (struct pcc_acpi *) data;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify");
+
+ switch (event) {
+ case HKEY_NOTIFY:
+ acpi_pcc_generate_keyinput(pcc);
+ break;
+ default:
+ /* nothing to do */
+ break;
+ }
+}
+
+static int acpi_pcc_init_input(struct pcc_acpi *pcc)
+{
+ int i, rc;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_init_input");
+
+ pcc->input_dev = input_allocate_device();
+ if (!pcc->input_dev) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't allocate input device for hotkey"));
+ return -ENOMEM;
+ }
+
+ pcc->input_dev->evbit[0] = BIT(EV_KEY);
+
+ pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
+ pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
+ pcc->input_dev->id.bustype = BUS_HOST;
+ pcc->input_dev->id.vendor = 0x0001;
+ pcc->input_dev->id.product = 0x0001;
+ pcc->input_dev->id.version = 0x0100;
+ pcc->input_dev->getkeycode = pcc_getkeycode;
+ pcc->input_dev->setkeycode = pcc_setkeycode;
+
+ /* load initial keymap */
+ memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
+
+ for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
+ __set_bit(pcc->keymap[i], pcc->input_dev->keybit);
+ __clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
+
+ input_set_drvdata(pcc->input_dev, pcc);
+
+ rc = input_register_device(pcc->input_dev);
+ if (rc < 0)
+ input_free_device(pcc->input_dev);
+
+ return rc;
+}
+
+/* kernel module interface */
+
+static int acpi_pcc_hotkey_resume(struct acpi_device *device)
+{
+ struct pcc_acpi *pcc = acpi_driver_data(device);
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume");
+
+ if (device == NULL || pcc == NULL)
+ return -EINVAL;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
+ pcc->sticky_mode));
+
+ status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
+
+ return status == AE_OK ? 0 : -EINVAL;
+}
+
+static int acpi_pcc_hotkey_add(struct acpi_device *device)
+{
+ acpi_status status;
+ struct pcc_acpi *pcc;
+ int num_sifr, result;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");
+
+ if (!device)
+ return -EINVAL;
+
+ num_sifr = acpi_pcc_get_sqty(device);
+
+ if (num_sifr > 255) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large"));
+ return -ENODEV;
+ }
+
+ pcc = kzalloc(sizeof(struct pcc_acpi), GFP_KERNEL);
+ if (!pcc) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't allocate mem for pcc"));
+ return -ENOMEM;
+ }
+
+ pcc->sinf = kzalloc(sizeof(u32) * (num_sifr + 1), GFP_KERNEL);
+ if (!pcc->sinf) {
+ result = -ENOMEM;
+ goto out_hotkey;
+ }
+
+ pcc->device = device;
+ pcc->handle = device->handle;
+ pcc->num_sifr = num_sifr;
+ device->driver_data = pcc;
+ strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PCC_CLASS);
+
+ result = acpi_pcc_init_input(pcc);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing keyinput handler\n"));
+ goto out_sinf;
+ }
+
+ /* initialize hotkey input device */
+ status = acpi_install_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+ acpi_pcc_hotkey_notify, pcc);
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto out_input;
+ }
+
+ /* initialize backlight */
+ pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
+ &pcc_backlight_ops);
+ if (IS_ERR(pcc->backlight))
+ goto out_notify;
+
+ if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Couldn't retrieve BIOS data\n"));
+ goto out_backlight;
+ }
+
+ /* read the initial brightness setting from the hardware */
+ pcc->backlight->props.max_brightness =
+ pcc->sinf[SINF_AC_MAX_BRIGHT];
+ pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
+
+ /* read the initial sticky key mode from the hardware */
+ pcc->sticky_mode = pcc->sinf[SINF_STICKY_KEY];
+
+ /* add sysfs attributes */
+ result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
+ if (result)
+ goto out_backlight;
+
+ return 0;
+
+out_backlight:
+ backlight_device_unregister(pcc->backlight);
+out_notify:
+ acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+ acpi_pcc_hotkey_notify);
+out_input:
+ input_unregister_device(pcc->input_dev);
+ /* no need to input_free_device() since core input API refcount and
+ * free()s the device */
+out_sinf:
+ kfree(pcc->sinf);
+out_hotkey:
+ kfree(pcc);
+
+ return result;
+}
+
+static int __init acpi_pcc_init(void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_init");
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&acpi_pcc_driver);
+ if (result < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error registering hotkey driver\n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
+{
+ struct pcc_acpi *pcc = acpi_driver_data(device);
+
+ ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove");
+
+ if (!device || !pcc)
+ return -EINVAL;
+
+ sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
+
+ backlight_device_unregister(pcc->backlight);
+
+ acpi_remove_notify_handler(pcc->handle, ACPI_DEVICE_NOTIFY,
+ acpi_pcc_hotkey_notify);
+
+ input_unregister_device(pcc->input_dev);
+ /* no need to input_free_device() since core input API refcount and
+ * free()s the device */
+
+ kfree(pcc->sinf);
+ kfree(pcc);
+
+ return 0;
+}
+
+static void __exit acpi_pcc_exit(void)
+{
+ ACPI_FUNCTION_TRACE("acpi_pcc_exit");
+
+ acpi_bus_unregister_driver(&acpi_pcc_driver);
+}
+
+module_init(acpi_pcc_init);
+module_exit(acpi_pcc_exit);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 60775be2282..5a97d3a9d74 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -970,7 +970,7 @@ static int sony_nc_resume(struct acpi_device *device)
/* set the last requested brightness level */
if (sony_backlight_device &&
!sony_backlight_update_status(sony_backlight_device))
- printk(KERN_WARNING DRV_PFX "unable to restore brightness level");
+ printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
/* re-initialize models with specific requirements */
dmi_check_system(sony_nc_ids);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 6b9300779a4..4db1cf9078d 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -159,7 +159,6 @@ enum {
#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
#define TPACPI_DBG_ALL 0xffff
-#define TPACPI_DBG_ALL 0xffff
#define TPACPI_DBG_INIT 0x0001
#define TPACPI_DBG_EXIT 0x0002
#define dbg_printk(a_dbg_level, format, arg...) \
@@ -543,7 +542,7 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
return -ENODEV;
}
- acpi_driver_data(ibm->acpi->device) = ibm;
+ ibm->acpi->device->driver_data = ibm;
sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
TPACPI_ACPI_EVENT_PREFIX,
ibm->name);
@@ -582,7 +581,8 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
if (!ibm->acpi->driver) {
- printk(TPACPI_ERR "kzalloc(ibm->driver) failed\n");
+ printk(TPACPI_ERR
+ "failed to allocate memory for ibm->acpi->driver\n");
return -ENOMEM;
}
@@ -838,6 +838,13 @@ static int parse_strtoul(const char *buf,
return 0;
}
+static void tpacpi_disable_brightness_delay(void)
+{
+ if (acpi_evalf(hkey_handle, NULL, "PWMS", "qvd", 0))
+ printk(TPACPI_NOTICE
+ "ACPI backlight control delay disabled\n");
+}
+
static int __init tpacpi_query_bcl_levels(acpi_handle handle)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -2139,6 +2146,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
if (!tp_features.hotkey)
return 1;
+ tpacpi_disable_brightness_delay();
+
hotkey_dev_attributes = create_attr_set(13, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
@@ -2512,6 +2521,8 @@ static void hotkey_suspend(pm_message_t state)
static void hotkey_resume(void)
{
+ tpacpi_disable_brightness_delay();
+
if (hotkey_mask_get())
printk(TPACPI_ERR
"error while trying to read hot key mask "
@@ -5983,6 +5994,52 @@ static void fan_exit(void)
flush_workqueue(tpacpi_wq);
}
+static void fan_suspend(pm_message_t state)
+{
+ if (!fan_control_allowed)
+ return;
+
+ /* Store fan status in cache */
+ fan_get_status_safe(NULL);
+ if (tp_features.fan_ctrl_status_undef)
+ fan_control_desired_level = TP_EC_FAN_AUTO;
+}
+
+static void fan_resume(void)
+{
+ u8 saved_fan_level;
+ u8 current_level = 7;
+ bool do_set = false;
+
+ /* DSDT *always* updates status on resume */
+ tp_features.fan_ctrl_status_undef = 0;
+
+ saved_fan_level = fan_control_desired_level;
+ if (!fan_control_allowed ||
+ (fan_get_status_safe(&current_level) < 0))
+ return;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ do_set = (saved_fan_level > current_level);
+ break;
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ do_set = ((saved_fan_level & TP_EC_FAN_FULLSPEED) ||
+ (saved_fan_level == 7 &&
+ !(current_level & TP_EC_FAN_FULLSPEED)));
+ break;
+ default:
+ return;
+ }
+ if (do_set) {
+ printk(TPACPI_NOTICE
+ "restoring fan level to 0x%02x\n",
+ saved_fan_level);
+ fan_set_level_safe(saved_fan_level);
+ }
+}
+
static int fan_read(char *p)
{
int len = 0;
@@ -6174,6 +6231,8 @@ static struct ibm_struct fan_driver_data = {
.read = fan_read,
.write = fan_write,
.exit = fan_exit,
+ .suspend = fan_suspend,
+ .resume = fan_resume,
};
/****************************************************************************