From patchwork Wed Dec 2 18:26:03 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Anisse Astier X-Patchwork-Id: 64331 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id nB2JLb6C024768 for ; Wed, 2 Dec 2009 19:21:37 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752305AbZLBTVa (ORCPT ); Wed, 2 Dec 2009 14:21:30 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1754200AbZLBTVa (ORCPT ); Wed, 2 Dec 2009 14:21:30 -0500 Received: from mail-ew0-f219.google.com ([209.85.219.219]:52786 "EHLO mail-ew0-f219.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752305AbZLBTV3 convert rfc822-to-8bit (ORCPT ); Wed, 2 Dec 2009 14:21:29 -0500 Received: by ewy19 with SMTP id 19so599309ewy.21 for ; Wed, 02 Dec 2009 11:21:34 -0800 (PST) Received: by 10.213.50.9 with SMTP id x9mr5452472ebf.38.1259778458115; Wed, 02 Dec 2009 10:27:38 -0800 (PST) Received: from destiny.ordissimo (253.175.70-86.rev.gaoland.net [86.70.175.253]) by mx.google.com with ESMTPS id 7sm2271413eyb.26.2009.12.02.10.27.34 (version=SSLv3 cipher=RC4-MD5); Wed, 02 Dec 2009 10:27:37 -0800 (PST) Date: Wed, 2 Dec 2009 19:26:03 +0100 From: Anisse Astier To: linux-input@vger.kernel.org, linux-acpi@vger.kernel.org Cc: Len Brown , Carlos Corbacho , Dmitry Torokhov Subject: [RFC PATCH 1/2] Input: add msi-wmi driver to support hotkeys in =?UTF-8?B?TVNJwqBXaW5kdG9w?= AE1900-WT Message-ID: <20091202192603.3e1de98a@destiny.ordissimo> X-Mailer: Claws Mail 3.5.0 (GTK+ 2.12.12; i486-pc-linux-gnu) Mime-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 1b27e4d..fe142af 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -441,4 +441,15 @@ config ACPI_TOSHIBA If you have a legacy free Toshiba laptop (such as the Libretto L1 series), say Y. + +config MSI_WMI + tristate "MSI WMI extras" + depends on ACPI_WMI + depends on INPUT + ---help--- + Say Y here if you want to support WMI-based hotkeys on MSI all-in-one + WindTop AE1900-WT. + + To compile this driver as a module, choose M here: the module will + be called msi-wmi. endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index d1c1621..22a0c78 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o +obj-$(CONFIG_MSI_WMI) += msi-wmi.o diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c new file mode 100644 index 0000000..fb6d5bd --- /dev/null +++ b/drivers/platform/x86/msi-wmi.c @@ -0,0 +1,212 @@ +/* + * MSI WMI hotkeys + * + * Copyright (C) 2009 Jérôme Pouiller + * + * Portions based on hp-wmi.c: + * Copyright (C) 2008 Red Hat + * + * Portions based on wistron_btns.c: + * Copyright (C) 2005 Miloslav Trmac + * Copyright (C) 2005 Bernhard Rosenkraenzer + * Copyright (C) 2005 Dmitry Torokhov + * + * 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 + +#define MSIWMI_EVENT_GUID "b6f3eef2-3d2f-49dc-9de3-85bce18c62f2" + +struct key_entry { + u16 code; + u16 keycode; +}; + +static struct key_entry msi_wmi_keymap[] = { + /*Brightness keys should be used for a backlight driver*/ + {208, KEY_BRIGHTNESSUP}, + {209, KEY_BRIGHTNESSDOWN}, + {210, KEY_VOLUMEUP}, + {211, KEY_VOLUMEDOWN}, + {0} +}; + +static struct input_dev *msi_wmi_input_dev; +static unsigned long long msi_wmi_time_last_press; +static unsigned pression_timeout = 10; + +static struct key_entry *msi_wmi_get_entry_by_scancode(int code) +{ + struct key_entry *key; + + for (key = msi_wmi_keymap; key->code; key++) + if (code == key->code) + return key; + + return NULL; +} + +static struct key_entry *msi_wmi_get_entry_by_keycode(int keycode) +{ + struct key_entry *key; + + for (key = msi_wmi_keymap; key->code; key++) + if (keycode == key->keycode) + return key; + + return NULL; +} + +static void msi_wmi_notify(u32 value, void *context) +{ + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + static struct key_entry *key; + union acpi_object *obj; + + acpi_status ret; + ret = wmi_get_event_data(value, &response); + obj = (union acpi_object *)response.pointer; + + if (!obj || obj->type != ACPI_TYPE_INTEGER) { + printk(KERN_INFO "MSI WMI: Unknown response received\n"); + return; + } + + if (jiffies_to_msecs(get_jiffies_64() - msi_wmi_time_last_press) + > pression_timeout) { + printk(KERN_DEBUG + "MSI WMI: event correctly received: %llu\n", + obj->integer.value); + msi_wmi_time_last_press = get_jiffies_64(); + key = msi_wmi_get_entry_by_scancode(obj->integer.value); + input_report_key(msi_wmi_input_dev, key->keycode, 1); + input_sync(msi_wmi_input_dev); + input_report_key(msi_wmi_input_dev, key->keycode, 0); + input_sync(msi_wmi_input_dev); + } +} + +static int msi_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode) +{ + struct key_entry *key = msi_wmi_get_entry_by_scancode(scancode); + + if (key && key->code) { + *keycode = key->keycode; + return 0; + } + + return -EINVAL; +} + +static int msi_wmi_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 = msi_wmi_get_entry_by_scancode(scancode); + if (key && key->code) { + old_keycode = key->keycode; + key->keycode = keycode; + set_bit(keycode, dev->keybit); + if (!msi_wmi_get_entry_by_keycode(old_keycode)) + clear_bit(old_keycode, dev->keybit); + return 0; + } + + return -EINVAL; +} + +static int __init msi_wmi_input_setup(void) +{ + struct key_entry *key; + int err; + + msi_wmi_input_dev = input_allocate_device(); + + msi_wmi_input_dev->name = "MSI WMI hotkeys"; + msi_wmi_input_dev->phys = "wmi/input0"; + msi_wmi_input_dev->id.bustype = BUS_HOST; + msi_wmi_input_dev->getkeycode = msi_wmi_getkeycode; + msi_wmi_input_dev->setkeycode = msi_wmi_setkeycode; + + for (key = msi_wmi_keymap; key->code; key++) { + set_bit(EV_KEY, msi_wmi_input_dev->evbit); + set_bit(key->keycode, msi_wmi_input_dev->keybit); + } + + err = input_register_device(msi_wmi_input_dev); + + if (err) + input_free_device(msi_wmi_input_dev); + + return err; +} + +static int __init msi_wmi_init(void) +{ + int err; + + msi_wmi_time_last_press = get_jiffies_64(); + if (!wmi_has_guid(MSIWMI_EVENT_GUID)) { + printk(KERN_ERR + "This machine doesn't have MSI-hotkeys through WMI\n"); + goto load_error; + } + err = wmi_install_notify_handler(MSIWMI_EVENT_GUID, + msi_wmi_notify, NULL); + if (err) { + printk(KERN_ERR + "MSI WMI: Error while installing notify handler\n"); + goto load_error; + } + + msi_wmi_input_setup(); + + return 0; +load_error: + return -ENODEV; +} + +static void __exit msi_wmi_exit(void) +{ + if (wmi_has_guid(MSIWMI_EVENT_GUID)) { + wmi_remove_notify_handler(MSIWMI_EVENT_GUID); + input_unregister_device(msi_wmi_input_dev); + } +} + +module_init(msi_wmi_init); +module_exit(msi_wmi_exit); +module_param(pression_timeout, uint, 0); + +MODULE_AUTHOR("Jérôme Pouiller "); +MODULE_AUTHOR("Michael Bouchaud