All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Garrett <mjg59@srcf.ucam.org>
To: Carlos Corbacho <carlos@strangeworlds.co.uk>
Cc: linux-acpi@vger.kernel.org, Len Brown <lenb@kernel.org>,
	Alexey Starikovskiy <aystarik@gmail.com>,
	linux-input@vger.kernel.org
Subject: [PATCH, RFC] HP WMI hotkey driver
Date: Wed, 26 Dec 2007 22:48:12 +0000	[thread overview]
Message-ID: <20071226224812.GA32652@srcf.ucam.org> (raw)
In-Reply-To: <20071218235137.12838.75397.stgit@localhost>

This adds a driver for hotkey events generated through the WMI subsystem 
on some recent HP laptops. Mine only has a single key that works this 
way, so I'd be interested in getting some feedback from anyone else who 
has a recent HP machine which doesn't send hotkey events through the 
keyboard controller. It depends on Carlos's WMI patches, plus a couple 
of bugfixes I've suggested on linux-acpi (limit the memcpy into bus_id 
to 20 bytes and make sure it's null terminated, and invert the sense in 
wmi_register_notify so it's actually possible to register a callback.

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 8f5c7b9..2f96736 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -183,4 +183,13 @@ config HP_SDC_RTC
 	  Say Y here if you want to support the built-in real time clock
 	  of the HP SDC controller.
 
+config INPUT_HP_WMI
+       tristate "HP WMI hotkey interface"
+       depends on ACPI_WMI
+       help
+         Say Y here if you want to support WMI-based hotkeys on HP laptops.
+
+	 To compile this driver as a module, choose M here: the module will
+	 be called hp_wmi.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 3585b50..1bc3b15 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
+obj-$(CONFIG_INPUT_HP_WMI)		+= hp_wmi.o
\ No newline at end of file
diff --git a/drivers/input/misc/hp_wmi.c b/drivers/input/misc/hp_wmi.c
new file mode 100644
index 0000000..17c7d4b
--- /dev/null
+++ b/drivers/input/misc/hp_wmi.c
@@ -0,0 +1,189 @@
+/*
+ * HP WMI hotkeys
+ *
+ * Copyright (C) 2007 Matthew Garrett <mjg59@srcf.ucam.org>
+ *
+ * Portions based on wistron_btns.c:
+ * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
+ * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
+ * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
+ *
+ *  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>
+
+MODULE_AUTHOR("Matthew Garrett");
+MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
+
+#define HPWMI_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
+
+struct key_entry {
+        char type;              /* See KE_* below */
+        u8 code;
+        union {
+                u16 keycode;            /* For KE_KEY */
+                struct {                /* For KE_SW */
+                        u8 code;
+                        u8 value;
+                } sw;
+        };
+};
+
+enum {KE_KEY, KE_END };
+
+static struct key_entry hp_wmi_keymap[] = {
+	{ KE_KEY, 0x04, {KEY_HELP} },
+	{ KE_END, 0 }
+};
+
+static struct input_dev *hp_wmi_input_dev;
+
+static struct key_entry *hp_wmi_get_entry_by_scancode (int code)
+{
+	struct key_entry *key;
+
+        for (key = hp_wmi_keymap; key->type != KE_END; key++)
+                if (code == key->code)
+                        return key;
+
+        return NULL;
+}
+
+static struct key_entry *hp_wmi_get_entry_by_keycode(int keycode)
+{
+        struct key_entry *key;
+
+        for (key = hp_wmi_keymap; key->type != KE_END; key++)
+                if (key->type == KE_KEY && keycode == key->keycode)
+                        return key;
+
+        return NULL;
+}
+
+static int hp_wmi_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+	struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
+
+        if (key && key->type == KE_KEY) {
+                *keycode = key->keycode;
+                return 0;
+        }
+
+        return -EINVAL;
+}
+
+static int hp_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 = hp_wmi_get_entry_by_scancode(scancode);
+        if (key && key->type == KE_KEY) {
+                old_keycode = key->keycode;
+                key->keycode = keycode;
+                set_bit(keycode, dev->keybit);
+                if (!hp_wmi_get_entry_by_keycode(old_keycode))
+                        clear_bit(old_keycode, dev->keybit);
+                return 0;
+        }
+
+        return -EINVAL;
+}	
+
+void hp_wmi_notify (u32 value, void* context)
+{
+	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+	static struct key_entry *key;
+	union acpi_object *obj;
+
+	wmi_get_event_data (value, &response);
+	
+	obj = (union acpi_object *) response.pointer;
+
+	if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) {
+		key = hp_wmi_get_entry_by_scancode 
+			(*((u8 *) obj->buffer.pointer));
+		if (key) {
+			input_report_key (hp_wmi_input_dev, key->keycode, 1);
+			input_sync (hp_wmi_input_dev);
+			input_report_key (hp_wmi_input_dev, key->keycode, 0);
+			input_sync (hp_wmi_input_dev);
+		} else
+			printk (KERN_INFO "HP WMI: Unknown key pressed\n");
+	} else
+		printk (KERN_INFO "HP WMI: Unknown response received\n");
+
+	return;
+}
+
+static int __init hp_wmi_init(void)
+{
+	int err;
+	const struct key_entry *key;
+
+	if (!wmi_has_guid(HPWMI_GUID)) {
+		printk ("Unable to locate guid\n");
+		return -ENODEV;
+	}
+
+	err = wmi_install_notify_handler (hp_wmi_notify, NULL);
+	if (err)
+		return err;
+	
+	hp_wmi_input_dev = input_allocate_device();
+
+	hp_wmi_input_dev->name = "HP WMI hotkeys";
+	hp_wmi_input_dev->phys = "wmi/input0";
+	hp_wmi_input_dev->id.bustype = BUS_HOST;
+	hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
+	hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
+	
+	for (key = hp_wmi_keymap; key->type != KE_END; key++) {
+		set_bit(EV_KEY, hp_wmi_input_dev->evbit);
+		set_bit(key->keycode, hp_wmi_input_dev->keybit);
+	}
+	
+	err = input_register_device (hp_wmi_input_dev);
+
+	if (err) {
+		input_free_device (hp_wmi_input_dev);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __exit hp_wmi_exit(void)
+{
+	wmi_remove_notify_handler();
+	input_unregister_device (hp_wmi_input_dev);
+	input_free_device (hp_wmi_input_dev);
+}
+
+module_init(hp_wmi_init);
+module_exit(hp_wmi_exit);

-- 
Matthew Garrett | mjg59@srcf.ucam.org

  parent reply	other threads:[~2007-12-26 22:48 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-18 23:51 [PATCH 0/5] WMI Carlos Corbacho
2007-12-18 23:51 ` [PATCH 1/4] ACPI: WMI: Add ACPI-WMI mapping driver Carlos Corbacho
2007-12-26 21:17   ` Matthew Garrett
2007-12-27  1:09     ` Carlos Corbacho
2007-12-27  2:21       ` Matthew Garrett
2007-12-18 23:51 ` [PATCH 2/4] acer-wmi: Add driver for newer Acer laptops Carlos Corbacho
2007-12-19  1:58   ` Carlos Corbacho
2007-12-19  7:45     ` Matthew Garrett
2007-12-18 23:51 ` [PATCH 3/4] [RFC] tc1100-wmi: Add driver for HP Compaq TC1100 Tablets Carlos Corbacho
2007-12-18 23:52 ` [PATCH 4/4] [RFC] ACPI: WMI: Add sysfs userspace interface Carlos Corbacho
2007-12-26 19:38   ` Matthew Garrett
2007-12-27  0:54     ` Carlos Corbacho
2007-12-27  1:05       ` Carlos Corbacho
2007-12-26 22:48 ` Matthew Garrett [this message]
2008-01-03 16:58   ` [PATCH, RFC] HP WMI hotkey driver Dmitry Torokhov
2008-01-14 17:41     ` [PATCH, RFC] HP WMI hotkey driver, RFKill query? Matthew Garrett
2008-01-14 18:27       ` Carlos Corbacho
2008-01-14 22:25         ` Carlos Corbacho
2008-01-15 20:54           ` Dmitry Torokhov
2008-01-16  1:38             ` Carlos Corbacho
2008-01-16  1:49               ` Matthew Garrett
2008-02-07  3:54               ` Len Brown
2008-02-08 15:26                 ` Carlos Corbacho

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20071226224812.GA32652@srcf.ucam.org \
    --to=mjg59@srcf.ucam.org \
    --cc=aystarik@gmail.com \
    --cc=carlos@strangeworlds.co.uk \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.