@@ -23,7 +23,9 @@ config ACER_WMI
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
depends on RFKILL || RFKILL = n
+ depends on INPUT
select ACPI_WMI
+ select INPUT_SPARSEKMAP
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
wireless radio and bluetooth control, and on some laptops,
b/drivers/platform/x86/acer-wmi.c
@@ -37,6 +37,8 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
#include <acpi/acpi_drivers.h>
@@ -48,6 +50,7 @@ MODULE_LICENSE("GPL");
#define ACER_ERR KERN_ERR ACER_LOGPREFIX
#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
#define ACER_INFO KERN_INFO ACER_LOGPREFIX
+#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
/*
* Magic Number
@@ -83,8 +86,39 @@ MODULE_LICENSE("GPL");
#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
+/*
+ * Acer ACPI event GUIDs
+ */
+#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
+
MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
+MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
+
+enum acer_wmi_event_ids {
+ WMID_HOTKEY_EVENT = 0x1,
+};
+
+static const struct key_entry acer_wmi_keymap[] = {
+ {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
+ {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */
+ {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */
+ {KE_KEY, 0x22, {KEY_PROG2} }, /* Aracade */
+ {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
+ {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
+ {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
+ {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */
+ {KE_END, 0}
+};
+
+static struct input_dev *acer_wmi_input_dev;
+
+struct event_return_value {
+ u8 function;
+ u8 key_num;
+ u16 device_state;
+ u32 reserved;
+} __attribute__((packed));
/*
* Interface capability flags
@@ -1085,6 +1119,99 @@ static ssize_t show_interface(struct device *dev,
struct device_attribute *attr,
static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
+static void acer_wmi_notify(u32 value, void *context)
+{
+ struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ struct event_return_value return_value;
+ acpi_status status;
+
+ status = wmi_get_event_data(value, &response);
+ if (status != AE_OK) {
+ printk(ACER_WARNING "bad event status 0x%x\n", status);
+ return;
+ }
+
+ obj = (union acpi_object *)response.pointer;
+
+ if (!obj)
+ return;
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ printk(ACER_WARNING "Unknown response received %d\n",
+ obj->type);
+ kfree(obj);
+ return;
+ }
+ if (obj->buffer.length != 8) {
+ printk(ACER_WARNING "Unknown buffer length %d\n",
+ obj->buffer.length);
+ kfree(obj);
+ return;
+ }
+
+ return_value = *((struct event_return_value *)obj->buffer.pointer);
+ kfree(obj);
+
+ switch (return_value.function) {
+ case WMID_HOTKEY_EVENT:
+ if (!sparse_keymap_report_event(acer_wmi_input_dev,
+ return_value.key_num, 1, true))
+ printk(ACER_WARNING "Unknown key number - 0x%x\n",
+ return_value.key_num);
+ break;
+ default:
+ printk(ACER_WARNING "Unknown function number - %d - %d\n",
+ return_value.function, return_value.key_num);
+ break;
+ }
+}
+
+static int __init acer_wmi_input_setup(void)
+{
+ acpi_status status;
+ int err;
+
+ acer_wmi_input_dev = input_allocate_device();
+ if (!acer_wmi_input_dev)
+ return -ENOMEM;
+
+ acer_wmi_input_dev->name = "Acer WMI hotkeys";
+ acer_wmi_input_dev->phys = "wmi/input0";
+ acer_wmi_input_dev->id.bustype = BUS_HOST;
+
+ err = sparse_keymap_setup(acer_wmi_input_dev, acer_wmi_keymap, NULL);
+ if (err)
+ goto err_free_dev;
+
+ err = input_register_device(acer_wmi_input_dev);
+ if (err)
+ goto err_free_keymap;
+
+ status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
+ acer_wmi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ err = -EIO;
+ goto err_unregister_input;
+ }
+
+ return 0;
+
+err_unregister_input:
+ input_unregister_device(acer_wmi_input_dev);
+err_free_keymap:
+ sparse_keymap_free(acer_wmi_input_dev);
+err_free_dev:
+ input_free_device(acer_wmi_input_dev);
+ return err;
+}
+
+static void acer_wmi_input_destroy(void)
+{
+ wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
+ sparse_keymap_free(acer_wmi_input_dev);
+ input_unregister_device(acer_wmi_input_dev);
+}
+
/*
* debugfs functions
*/
@@ -1327,6 +1454,12 @@ static int __init acer_wmi_init(void)
"generic video driver\n");
}
+ if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
+ err = acer_wmi_input_setup();
+ if (err)
+ return err;
+ }
+
err = platform_driver_register(&acer_platform_driver);
if (err) {
printk(ACER_ERR "Unable to register platform driver.\n");
@@ -1368,11 +1501,17 @@ error_device_add:
error_device_alloc:
platform_driver_unregister(&acer_platform_driver);
error_platform_register:
+ if (wmi_has_guid(ACERWMID_EVENT_GUID))
+ acer_wmi_input_destroy();
+
return err;
}
static void __exit acer_wmi_exit(void)
{
+ if (wmi_has_guid(ACERWMID_EVENT_GUID))
+ acer_wmi_input_destroy();
+
remove_sysfs(acer_platform_device);
remove_debugfs();
platform_device_unregister(acer_platform_device);
--
1.6.0.2
>From 1957b6b7cd071de95c0e1fb0e35cd5c9c9332630 Mon Sep 17 00:00:00 2001
From: Lee, Chun-Yi <jlee@novell.com>
Date: Tue, 12 Oct 2010 09:27:23 +0800
Subject: [PATCH 2/2] Support enable Acer Launch Manager mode
Add a launch_manager parameter for support to enable Acer Launch Manager
mode. After enable it, the communication key will stop the default
behavior to control WLAN/Bluetooth/WWAN rfkill state. It leave usernland
application to handle the rfkill state changed.
Signed-off-by: Lee, Chun-Yi <jlee@novell.com>
---
drivers/platform/x86/acer-wmi.c | 74
+++++++++++++++++++++++++++++++++++++++
1 files changed, 74 insertions(+), 0 deletions(-)
b/drivers/platform/x86/acer-wmi.c
@@ -85,6 +85,7 @@ MODULE_LICENSE("GPL");
#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
+#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
/*
* Acer ACPI event GUIDs
@@ -120,6 +121,20 @@ struct event_return_value {
u32 reserved;
} __attribute__((packed));
+struct lm_input_params {
+ u8 function_num; /* Function Number */
+ u16 commun_devices; /* Communication type devices default status */
+ u16 devices; /* Other type devices default status */
+ u8 lm_status; /* Launch Manager Status */
+ u16 reserved;
+} __attribute__((packed));
+
+struct lm_return_value {
+ u8 error_code; /* Error Code */
+ u8 ec_return_value; /* EC Return Value */
+ u16 reserved;
+} __attribute__((packed));
+
/*
* Interface capability flags
*/
@@ -150,15 +165,18 @@ static int mailled = -1;
static int brightness = -1;
static int threeg = -1;
static int force_series;
+static bool launch_manager;
module_param(mailled, int, 0444);
module_param(brightness, int, 0444);
module_param(threeg, int, 0444);
module_param(force_series, int, 0444);
+module_param(launch_manager, bool, 0444);
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");
MODULE_PARM_DESC(force_series, "Force a different laptop series");
+MODULE_PARM_DESC(launch_manager, "Enable Acer Launch Manager mode");
struct acer_data {
int mailled;
@@ -1393,6 +1411,53 @@ error_debugfs:
return -ENOMEM;
}
+static int acer_wmi_enable_lm(void)
+{
+ struct lm_return_value return_value;
+ acpi_status status;
+ union acpi_object *obj;
+ struct lm_input_params params = {
+ .function_num = 0x1,
+ .commun_devices = 0x0041, /* WiFi on, 3G on, BT off */
+ .devices = 0xFFFF,
+ .lm_status = 0x41, /* Launch Manager Active */
+ };
+
+ struct acpi_buffer input = { sizeof(struct lm_input_params),
¶ms };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ obj = output.pointer;
+
+ if (!obj)
+ return -EINVAL;
+ else if (obj->type != ACPI_TYPE_BUFFER) {
+ kfree(obj);
+ return -EINVAL;
+ }
+ if (obj->buffer.length != 4) {
+ printk(ACER_WARNING "Unknown buffer length %d\n",
+ obj->buffer.length);
+ kfree(obj);
+ return -EINVAL;
+ }
+
+ return_value = *((struct lm_return_value *)obj->buffer.pointer);
+ kfree(obj);
+
+ if (return_value.error_code || return_value.ec_return_value)
+ printk(ACER_WARNING "Enabling Launch Manager failed: "
+ "0x%x - 0x%x\n", return_value.error_code,
+ return_value.ec_return_value);
+ else
+ printk(ACER_INFO "Enabled Launch Manager");
+
+ return status;
+}
+
static int __init acer_wmi_init(void)
{