From patchwork Thu Nov 25 01:56:52 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chun-Yi Lee X-Patchwork-Id: 355222 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oAP1wAow019261 for ; Thu, 25 Nov 2010 01:58:10 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754278Ab0KYB6I (ORCPT ); Wed, 24 Nov 2010 20:58:08 -0500 Received: from mail-qw0-f46.google.com ([209.85.216.46]:51540 "EHLO mail-qw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752555Ab0KYB6H (ORCPT ); Wed, 24 Nov 2010 20:58:07 -0500 Received: by qwb7 with SMTP id 7so407794qwb.19 for ; Wed, 24 Nov 2010 17:58:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=Fw1ECcyTIBL4Pms5FcTDE7NEu7xSHa3ShxA8VPEk+Us=; b=gDmasPDUsULmve2x4vLYIp1N3PitbADbqJw4/hxDb1gc3S/EmTTrI8MAGdGM6L3yeq d3izjqmNr0Q5crLRsAl5mjQ2yA0jeBaIDHzkCAzdzKlXr+ZnonL8C/yg52zkqpvO0zRy t46wwfN4PfyRauOSKEdwStwFiaSHIX1HoYuFs= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=d7MOuyMbUNRXOE7brc/+c4xs5TAP6NyZ5EDFqK3adVCQXCO0LTLzJ1JuqmzTqBc8p8 GLvAogg74O3wZ6OwMmfbLIlXb6dR/G0PzQJD+S4htsKdtwjzmLArMLY6UwFdRZ0pOCD/ 02jTeybxeap7FCiA8fYeiNhc/hEfg1rYFj/A8= Received: by 10.229.249.11 with SMTP id mi11mr102061qcb.217.1290650285437; Wed, 24 Nov 2010 17:58:05 -0800 (PST) Received: from localhost.localdomain ([61.14.133.18]) by mx.google.com with ESMTPS id t35sm129244qco.18.2010.11.24.17.57.58 (version=SSLv3 cipher=RC4-MD5); Wed, 24 Nov 2010 17:58:03 -0800 (PST) From: "Lee, Chun-Yi" To: carlos@strangeworlds.co.uk Cc: mjg59@srcf.ucam.org, corentin.chary@gmail.com, dmitry.torokhov@gmail.com, tiwai@novell.com, jbenc@suse.cz, jdelvare@suse.de, trenn@suse.de, linux-input@vger.kernel.org, platform-driver-x86@vger.kernel.org, corentincj@iksaif.net, "Lee, Chun-Yi" Subject: Re: [PATCH 1/4] Add acer wmi hotkey events support Date: Thu, 25 Nov 2010 09:56:52 +0800 Message-Id: <1290650212-14944-1-git-send-email-jlee@novell.com> X-Mailer: git-send-email 1.6.0.2 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 25 Nov 2010 01:58:11 +0000 (UTC) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index cff7cc2..c242fdd 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -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, diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 2badee2..930df56 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include @@ -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} }, /* 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 @@ -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; + + 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 */ @@ -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);