From patchwork Wed Feb 9 18:17:53 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Colin Ian King X-Patchwork-Id: 82509 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 2319FB70E3 for ; Thu, 10 Feb 2011 05:18:09 +1100 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1PnEc6-0001v4-2y; Wed, 09 Feb 2011 18:18:02 +0000 Received: from adelie.canonical.com ([91.189.90.139]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1PnEc2-0001uH-7U for kernel-team@lists.ubuntu.com; Wed, 09 Feb 2011 18:17:58 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by adelie.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1PnEc2-0002td-63 for ; Wed, 09 Feb 2011 18:17:58 +0000 Received: from cpc7-craw6-2-0-cust128.croy.cable.virginmedia.com ([94.172.219.129] helo=localhost) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1PnEc1-0002GS-98 for kernel-team@lists.ubuntu.com; Wed, 09 Feb 2011 18:17:58 +0000 From: Colin King To: kernel-team@lists.ubuntu.com Subject: [PATCH 1/3] UBUNTU: SAUCE: Add WMI hotkeys support for Dell All-In-One series Date: Wed, 9 Feb 2011 18:17:53 +0000 Message-Id: <1297275475-31429-2-git-send-email-colin.king@canonical.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1297275475-31429-1-git-send-email-colin.king@canonical.com> References: <1297275475-31429-1-git-send-email-colin.king@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com From: Colin Ian King Enable WMI hotkeys on event GUID 284A0E6B-380E-472A-921F-E52786257FB4. This driver enables the volume up and down keys. BugLink: http://bugs.launchpad.net/bugs/676997 Signed-off-by: Eric Miao Signed-off-by: Colin Ian King Signed-off-by: Tim Gardner --- drivers/platform/x86/Kconfig | 12 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/dell-wmi-aio.c | 225 +++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+), 0 deletions(-) create mode 100644 drivers/platform/x86/dell-wmi-aio.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index d163bc2..b6fbb0c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -101,6 +101,18 @@ config DELL_WMI To compile this driver as a module, choose M here: the module will be called dell-wmi. +config DELL_WMI_AIO + tristate "WMI Hotkeys for Dell All-In-One series" + depends on ACPI_WMI + depends on INPUT + ---help--- + Say Y here if you want to support WMI-based hotkeys on Dell + All-In-One machines. + + To compile this driver as a module, choose M here: the module will + be called dell-wmi. + + config FUJITSU_LAPTOP tristate "Fujitsu Laptop Extras" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 4ec4ff8..26c6a57 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o +obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ACERHDF) += acerhdf.o obj-$(CONFIG_HP_WMI) += hp-wmi.o diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c new file mode 100644 index 0000000..c693473 --- /dev/null +++ b/drivers/platform/x86/dell-wmi-aio.c @@ -0,0 +1,225 @@ +/* + * WMI hotkeys support for Dell All-In-One series + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define AIO_PREFIX "dell-wmi-aio: " + +MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series"); +MODULE_LICENSE("GPL"); + +#define EVENT_GUID "284A0E6B-380E-472A-921F-E52786257FB4" + +MODULE_ALIAS("wmi:"EVENT_GUID); + +/* Temporary workaround until the WMI sysfs interface goes in. + Borrowed from acer-wmi */ +MODULE_ALIAS("dmi:*:*Dell*:*:"); + +struct key_entry { + char type; /* See KE_* below */ + u16 code; + u16 keycode; +}; + +enum { KE_KEY, KE_SW, KE_IGNORE, KE_END }; + +/* + * Certain keys are flagged as KE_IGNORE. All of these are either + * notifications (rather than requests for change) or are also sent + * via the keyboard controller so should not be sent again. + */ + +static struct key_entry dell_wmi_aio_keymap[] = { + { KE_KEY, 0xc0, KEY_VOLUMEUP }, + { KE_KEY, 0xc1, KEY_VOLUMEDOWN }, + { KE_END, 0 } +}; + +static struct input_dev *dell_wmi_aio_input_dev; + +static struct key_entry *dell_wmi_aio_get_entry_by_scancode(int code) +{ + struct key_entry *key; + + for (key = dell_wmi_aio_keymap; key->type != KE_END; key++) + if (code == key->code) + return key; + + return NULL; +} + +static struct key_entry *dell_wmi_aio_get_entry_by_keycode(int keycode) +{ + struct key_entry *key; + + for (key = dell_wmi_aio_keymap; key->type != KE_END; key++) + if (key->type == KE_KEY && keycode == key->keycode) + return key; + + return NULL; +} + +static int dell_wmi_aio_getkeycode(struct input_dev *dev, int scancode, + int *keycode) +{ + struct key_entry *key = dell_wmi_aio_get_entry_by_scancode(scancode); + + if (key && key->type == KE_KEY) { + *keycode = key->keycode; + return 0; + } + + return -EINVAL; +} + +static int dell_wmi_aio_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 = dell_wmi_aio_get_entry_by_scancode(scancode); + if (key && key->type == KE_KEY) { + old_keycode = key->keycode; + key->keycode = keycode; + set_bit(keycode, dev->keybit); + if (!dell_wmi_aio_get_entry_by_keycode(old_keycode)) + clear_bit(old_keycode, dev->keybit); + return 0; + } + return -EINVAL; +} + +static void dell_wmi_aio_notify(u32 value, void *context) +{ + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + static struct key_entry *key; + union acpi_object *obj; + acpi_status status; + + status = wmi_get_event_data(value, &response); + if (status != AE_OK) { + pr_info(AIO_PREFIX "bad event status 0x%x\n", status); + return; + } + + obj = (union acpi_object *)response.pointer; + + if (obj && obj->type == ACPI_TYPE_INTEGER) { + int scancode = obj->integer.value; + + key = dell_wmi_aio_get_entry_by_scancode(scancode); + if (key) { + input_report_key(dell_wmi_aio_input_dev, + key->keycode, 1); + input_sync(dell_wmi_aio_input_dev); + input_report_key(dell_wmi_aio_input_dev, + key->keycode, 0); + input_sync(dell_wmi_aio_input_dev); + } else if (scancode) + pr_info(AIO_PREFIX "Unknown key %x pressed\n", + scancode); + } + kfree(obj); +} + +static int __init dell_wmi_aio_input_setup(void) +{ + struct key_entry *key; + int err; + + dell_wmi_aio_input_dev = input_allocate_device(); + + if (!dell_wmi_aio_input_dev) + return -ENOMEM; + + dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys"; + dell_wmi_aio_input_dev->phys = "wmi/input0"; + dell_wmi_aio_input_dev->id.bustype = BUS_HOST; + dell_wmi_aio_input_dev->getkeycode = dell_wmi_aio_getkeycode; + dell_wmi_aio_input_dev->setkeycode = dell_wmi_aio_setkeycode; + + for (key = dell_wmi_aio_keymap; key->type != KE_END; key++) { + switch (key->type) { + case KE_KEY: + set_bit(EV_KEY, dell_wmi_aio_input_dev->evbit); + set_bit(key->keycode, dell_wmi_aio_input_dev->keybit); + break; + case KE_SW: + set_bit(EV_SW, dell_wmi_aio_input_dev->evbit); + set_bit(key->keycode, dell_wmi_aio_input_dev->swbit); + break; + } + } + + err = input_register_device(dell_wmi_aio_input_dev); + + if (err) { + input_free_device(dell_wmi_aio_input_dev); + return err; + } + + return 0; +} + +static int __init dell_wmi_aio_init(void) +{ + int err; + + if (wmi_has_guid(EVENT_GUID)) { + err = dell_wmi_aio_input_setup(); + + if (err) + return err; + + err = wmi_install_notify_handler(EVENT_GUID, + dell_wmi_aio_notify, NULL); + if (err) { + input_unregister_device(dell_wmi_aio_input_dev); + pr_err(AIO_PREFIX "Unable to register" + " notify handler - %d\n", err); + return err; + } + + } else + pr_warning(AIO_PREFIX "No known WMI GUID found\n"); + + return 0; +} + +static void __exit dell_wmi_aio_exit(void) +{ + if (wmi_has_guid(EVENT_GUID)) { + wmi_remove_notify_handler(EVENT_GUID); + input_unregister_device(dell_wmi_aio_input_dev); + } +} + +module_init(dell_wmi_aio_init); +module_exit(dell_wmi_aio_exit);