|
@@ -37,6 +37,8 @@
|
|
#include <linux/workqueue.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
|
|
+#include <linux/input.h>
|
|
|
|
+#include <linux/input/sparse-keymap.h>
|
|
|
|
|
|
#include <acpi/acpi_drivers.h>
|
|
#include <acpi/acpi_drivers.h>
|
|
|
|
|
|
@@ -48,6 +50,7 @@ MODULE_LICENSE("GPL");
|
|
#define ACER_ERR KERN_ERR ACER_LOGPREFIX
|
|
#define ACER_ERR KERN_ERR ACER_LOGPREFIX
|
|
#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
|
|
#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
|
|
#define ACER_INFO KERN_INFO ACER_LOGPREFIX
|
|
#define ACER_INFO KERN_INFO ACER_LOGPREFIX
|
|
|
|
+#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
|
|
|
|
|
|
/*
|
|
/*
|
|
* Magic Number
|
|
* Magic Number
|
|
@@ -83,8 +86,39 @@ MODULE_LICENSE("GPL");
|
|
#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
|
|
#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
|
|
#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
|
|
#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:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
|
|
MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
|
|
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} }, /* Arcade */
|
|
|
|
+ {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
|
|
* 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 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;
|
|
|
|
+
|
|
|
|
+ status = wmi_install_notify_handler(ACERWMID_EVENT_GUID,
|
|
|
|
+ acer_wmi_notify, NULL);
|
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
|
+ err = -EIO;
|
|
|
|
+ goto err_free_keymap;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = input_register_device(acer_wmi_input_dev);
|
|
|
|
+ if (err)
|
|
|
|
+ goto err_uninstall_notifier;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+err_uninstall_notifier:
|
|
|
|
+ wmi_remove_notify_handler(ACERWMID_EVENT_GUID);
|
|
|
|
+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
|
|
* debugfs functions
|
|
*/
|
|
*/
|
|
@@ -1327,6 +1454,12 @@ static int __init acer_wmi_init(void)
|
|
"generic video driver\n");
|
|
"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);
|
|
err = platform_driver_register(&acer_platform_driver);
|
|
if (err) {
|
|
if (err) {
|
|
printk(ACER_ERR "Unable to register platform driver.\n");
|
|
printk(ACER_ERR "Unable to register platform driver.\n");
|
|
@@ -1368,11 +1501,17 @@ error_device_add:
|
|
error_device_alloc:
|
|
error_device_alloc:
|
|
platform_driver_unregister(&acer_platform_driver);
|
|
platform_driver_unregister(&acer_platform_driver);
|
|
error_platform_register:
|
|
error_platform_register:
|
|
|
|
+ if (wmi_has_guid(ACERWMID_EVENT_GUID))
|
|
|
|
+ acer_wmi_input_destroy();
|
|
|
|
+
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
static void __exit acer_wmi_exit(void)
|
|
static void __exit acer_wmi_exit(void)
|
|
{
|
|
{
|
|
|
|
+ if (wmi_has_guid(ACERWMID_EVENT_GUID))
|
|
|
|
+ acer_wmi_input_destroy();
|
|
|
|
+
|
|
remove_sysfs(acer_platform_device);
|
|
remove_sysfs(acer_platform_device);
|
|
remove_debugfs();
|
|
remove_debugfs();
|
|
platform_device_unregister(acer_platform_device);
|
|
platform_device_unregister(acer_platform_device);
|