Message ID | 1290194207-13792-3-git-send-email-colin.king@canonical.com |
---|---|
State | Rejected |
Delegated to: | Tim Gardner |
Headers | show |
On Sat, Nov 20, 2010 at 3:16 AM, Colin King <colin.king@canonical.com> wrote: > From: Colin Ian King <colin.king@canonical.com> > > 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 <eric.miao@canonical.com> > Signed-off-by: Colin Ian King <colin.king@canonical.com> Looks good. Acked. > --- > drivers/platform/x86/Kconfig | 12 ++ > drivers/platform/x86/Makefile | 1 + > drivers/platform/x86/dell-wmi-aio.c | 221 +++++++++++++++++++++++++++++++++++ > 3 files changed, 234 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 3c02cf2..7730b4d 100644 > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -97,6 +97,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 7318fc2..590a8ba 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..5e2bc18 > --- /dev/null > +++ b/drivers/platform/x86/dell-wmi-aio.c > @@ -0,0 +1,221 @@ > +/* > + * 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 <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/init.h> > +#include <linux/types.h> > +#include <linux/input.h> > +#include <acpi/acpi_drivers.h> > +#include <linux/acpi.h> > +#include <linux/string.h> > + > +#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); > -- > 1.7.0.4 > > > -- > kernel-team mailing list > kernel-team@lists.ubuntu.com > https://lists.ubuntu.com/mailman/listinfo/kernel-team >
On 11/19/2010 12:16 PM, Colin King wrote: > From: Colin Ian King<colin.king@canonical.com> > > 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<eric.miao@canonical.com> > Signed-off-by: Colin Ian King<colin.king@canonical.com> > --- > drivers/platform/x86/Kconfig | 12 ++ > drivers/platform/x86/Makefile | 1 + > drivers/platform/x86/dell-wmi-aio.c | 221 +++++++++++++++++++++++++++++++++++ > 3 files changed, 234 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 3c02cf2..7730b4d 100644 > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -97,6 +97,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 7318fc2..590a8ba 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..5e2bc18 > --- /dev/null > +++ b/drivers/platform/x86/dell-wmi-aio.c > @@ -0,0 +1,221 @@ > +/* > + * 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<linux/kernel.h> > +#include<linux/module.h> > +#include<linux/init.h> > +#include<linux/types.h> > +#include<linux/input.h> > +#include<acpi/acpi_drivers.h> > +#include<linux/acpi.h> > +#include<linux/string.h> > + > +#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); Acked-by: Tim Gardner <tim.gardner@canonical.com> despite 3 checkpatch warnings: WARNING: line over 80 characters
On 11/19/2010 11:16 AM, Colin King wrote: > From: Colin Ian King<colin.king@canonical.com> > > 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<eric.miao@canonical.com> > Signed-off-by: Colin Ian King<colin.king@canonical.com> > --- > drivers/platform/x86/Kconfig | 12 ++ > drivers/platform/x86/Makefile | 1 + > drivers/platform/x86/dell-wmi-aio.c | 221 +++++++++++++++++++++++++++++++++++ > 3 files changed, 234 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 3c02cf2..7730b4d 100644 > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -97,6 +97,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 7318fc2..590a8ba 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..5e2bc18 > --- /dev/null > +++ b/drivers/platform/x86/dell-wmi-aio.c > @@ -0,0 +1,221 @@ > +/* > + * 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<linux/kernel.h> > +#include<linux/module.h> > +#include<linux/init.h> > +#include<linux/types.h> > +#include<linux/input.h> > +#include<acpi/acpi_drivers.h> > +#include<linux/acpi.h> > +#include<linux/string.h> > + > +#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); Acked-by: Brad Figg <brad.figg@canonical.com>
On Fri, Nov 19, 2010 at 07:16:46PM +0000, Colin King wrote: > +#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*:*:"); The WMI sysfs interface is present. Do you really need this? > +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. > + */ No they're not :) > +static struct key_entry dell_wmi_aio_keymap[] = { > + { KE_KEY, 0xc0, KEY_VOLUMEUP }, > + { KE_KEY, 0xc1, KEY_VOLUMEDOWN }, > + { KE_END, 0 } > +}; You ought to use sparse keymaps here. They'll let you get rid of a lot of this boilerplate. > + case KE_SW: > + set_bit(EV_SW, dell_wmi_aio_input_dev->evbit); > + set_bit(key->keycode, dell_wmi_aio_input_dev->swbit); > + break; There aren't any switches, and there's no interface to add one.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 3c02cf2..7730b4d 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -97,6 +97,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 7318fc2..590a8ba 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..5e2bc18 --- /dev/null +++ b/drivers/platform/x86/dell-wmi-aio.c @@ -0,0 +1,221 @@ +/* + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/input.h> +#include <acpi/acpi_drivers.h> +#include <linux/acpi.h> +#include <linux/string.h> + +#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);